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::compatibility_iterator 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 // make it extern because wxStatitText needs to disconnect this one
482 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
483 GtkRequisition
*requisition
,
487 win
->GetSize( &w
, &h
);
493 requisition
->height
= h
;
494 requisition
->width
= w
;
497 //-----------------------------------------------------------------------------
498 // "expose_event" of m_wxwindow
499 //-----------------------------------------------------------------------------
501 static int gtk_window_expose_callback( GtkWidget
*widget
,
502 GdkEventExpose
*gdk_event
,
508 wxapp_install_idle_handler();
511 // This callback gets called in drawing-idle time under
512 // GTK 2.0, so we don't need to defer anything to idle
515 GtkPizza
*pizza
= GTK_PIZZA( widget
);
516 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
521 wxPrintf( wxT("OnExpose from ") );
522 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
523 wxPrintf( win
->GetClassInfo()->GetClassName() );
524 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
525 (int)gdk_event
->area
.y
,
526 (int)gdk_event
->area
.width
,
527 (int)gdk_event
->area
.height
);
531 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
533 win
->GtkSendPaintEvents();
536 // Let parent window draw window less widgets
537 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
539 // This gets called immediately after an expose event
540 // under GTK 1.2 so we collect the calls and wait for
541 // the idle handler to pick things up.
543 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
545 gdk_event
->area
.width
,
546 gdk_event
->area
.height
);
547 win
->m_clearRegion
.Union( gdk_event
->area
.x
,
549 gdk_event
->area
.width
,
550 gdk_event
->area
.height
);
552 // Actual redrawing takes place in idle time.
559 //-----------------------------------------------------------------------------
560 // "event" of m_wxwindow
561 //-----------------------------------------------------------------------------
563 // GTK thinks it is clever and filters out a certain amount of "unneeded"
564 // expose events. We need them, of course, so we override the main event
565 // procedure in GtkWidget by giving our own handler for all system events.
566 // There, we look for expose events ourselves whereas all other events are
569 gint
gtk_window_event_event_callback( GtkWidget
*widget
,
570 GdkEventExpose
*event
,
573 if (event
->type
== GDK_EXPOSE
)
575 gint ret
= gtk_window_expose_callback( widget
, event
, win
);
582 //-----------------------------------------------------------------------------
583 // "draw" of m_wxwindow
584 //-----------------------------------------------------------------------------
588 // This callback is a complete replacement of the gtk_pizza_draw() function,
589 // which is disabled.
591 static void gtk_window_draw_callback( GtkWidget
*widget
,
598 wxapp_install_idle_handler();
600 // The wxNO_FULL_REPAINT_ON_RESIZE flag only works if
601 // there are no child windows.
602 if ((win
->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
)) &&
603 (win
->GetChildren().GetCount() == 0))
611 wxPrintf( wxT("OnDraw from ") );
612 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
613 wxPrintf( win
->GetClassInfo()->GetClassName() );
614 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect
->x
,
621 #ifndef __WXUNIVERSAL__
622 GtkPizza
*pizza
= GTK_PIZZA (widget
);
624 if (win
->GetThemeEnabled())
626 wxWindow
*parent
= win
->GetParent();
627 while (parent
&& !parent
->IsTopLevel())
628 parent
= parent
->GetParent();
632 gtk_paint_flat_box (parent
->m_widget
->style
,
643 win
->m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
644 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
646 // Update immediately, not in idle time.
649 #ifndef __WXUNIVERSAL__
650 // Redraw child widgets
651 GList
*children
= pizza
->children
;
654 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
655 children
= children
->next
;
657 GdkRectangle child_area
;
658 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
660 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
668 //-----------------------------------------------------------------------------
669 // "key_press_event" from any window
670 //-----------------------------------------------------------------------------
672 // set WXTRACE to this to see the key event codes on the console
673 #define TRACE_KEYS _T("keyevent")
675 // translates an X key symbol to WXK_XXX value
677 // if isChar is true it means that the value returned will be used for EVT_CHAR
678 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
679 // for example, while if it is false it means that the value is going to be
680 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
682 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
688 // Shift, Control and Alt don't generate the CHAR events at all
691 key_code
= isChar
? 0 : WXK_SHIFT
;
695 key_code
= isChar
? 0 : WXK_CONTROL
;
703 key_code
= isChar
? 0 : WXK_ALT
;
706 // neither do the toggle modifies
707 case GDK_Scroll_Lock
:
708 key_code
= isChar
? 0 : WXK_SCROLL
;
712 key_code
= isChar
? 0 : WXK_CAPITAL
;
716 key_code
= isChar
? 0 : WXK_NUMLOCK
;
720 // various other special keys
733 case GDK_ISO_Left_Tab
:
740 key_code
= WXK_RETURN
;
744 key_code
= WXK_CLEAR
;
748 key_code
= WXK_PAUSE
;
752 key_code
= WXK_SELECT
;
756 key_code
= WXK_PRINT
;
760 key_code
= WXK_EXECUTE
;
764 key_code
= WXK_ESCAPE
;
767 // cursor and other extended keyboard keys
769 key_code
= WXK_DELETE
;
785 key_code
= WXK_RIGHT
;
792 case GDK_Prior
: // == GDK_Page_Up
793 key_code
= WXK_PRIOR
;
796 case GDK_Next
: // == GDK_Page_Down
809 key_code
= WXK_INSERT
;
824 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
828 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
832 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
836 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
840 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
844 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
848 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
852 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
856 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
860 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
864 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
868 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
872 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
875 case GDK_KP_Prior
: // == GDK_KP_Page_Up
876 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
879 case GDK_KP_Next
: // == GDK_KP_Page_Down
880 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
884 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
888 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
892 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
896 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
900 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
903 case GDK_KP_Multiply
:
904 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
908 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
911 case GDK_KP_Separator
:
912 // FIXME: what is this?
913 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
916 case GDK_KP_Subtract
:
917 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
921 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
925 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
942 key_code
= WXK_F1
+ keysym
- GDK_F1
;
952 static inline bool wxIsAsciiKeysym(KeySym ks
)
958 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
960 GdkEventKey
*gdk_event
)
962 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
963 // but only event->keyval which is quite useless to us, so remember
964 // the last character from GDK_KEY_PRESS and reuse it as last resort
966 // NB: should be MT-safe as we're always called from the main thread only
971 } s_lastKeyPress
= { 0, 0 };
973 KeySym keysym
= gdk_event
->keyval
;
975 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
976 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
980 long key_code
= wxTranslateKeySymToWXKey(keysym
, FALSE
/* !isChar */);
984 // do we have the translation or is it a plain ASCII character?
985 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
987 // we should use keysym if it is ASCII as X does some translations
988 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
989 // which we don't want here (but which we do use for OnChar())
990 if ( !wxIsAsciiKeysym(keysym
) )
992 keysym
= (KeySym
)gdk_event
->string
[0];
995 // we want to always get the same key code when the same key is
996 // pressed regardless of the state of the modifies, i.e. on a
997 // standard US keyboard pressing '5' or '%' ('5' key with
998 // Shift) should result in the same key code in OnKeyDown():
999 // '5' (although OnChar() will get either '5' or '%').
1001 // to do it we first translate keysym to keycode (== scan code)
1002 // and then back but always using the lower register
1003 Display
*dpy
= (Display
*)wxGetDisplay();
1004 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
1006 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
1008 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
1010 // use the normalized, i.e. lower register, keysym if we've
1012 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
1014 // as explained above, we want to have lower register key codes
1015 // normally but for the letter keys we want to have the upper ones
1017 // NB: don't use XConvertCase() here, we want to do it for letters
1019 key_code
= toupper(key_code
);
1021 else // non ASCII key, what to do?
1023 // by default, ignore it
1026 // but if we have cached information from the last KEY_PRESS
1027 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
1030 if ( keysym
== s_lastKeyPress
.keysym
)
1032 key_code
= s_lastKeyPress
.keycode
;
1037 if ( gdk_event
->type
== GDK_KEY_PRESS
)
1039 // remember it to be reused for KEY_UP event later
1040 s_lastKeyPress
.keysym
= keysym
;
1041 s_lastKeyPress
.keycode
= key_code
;
1045 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
1047 // sending unknown key events doesn't really make sense
1051 // now fill all the other fields
1054 GdkModifierType state
;
1055 if (gdk_event
->window
)
1056 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1058 event
.SetTimestamp( gdk_event
->time
);
1059 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
1060 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
1061 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
1062 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
1063 event
.m_keyCode
= key_code
;
1064 event
.m_scanCode
= gdk_event
->keyval
;
1065 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
1066 event
.m_rawFlags
= 0;
1069 event
.SetEventObject( win
);
1075 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1076 GdkEventKey
*gdk_event
,
1082 wxapp_install_idle_handler();
1086 if (g_blockEventsOnDrag
)
1090 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1091 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1093 // unknown key pressed, ignore (the event would be useless anyhow)
1097 // Emit KEY_DOWN event
1098 bool ret
= win
->GetEventHandler()->ProcessEvent( event
);
1103 wxWindowGTK
*ancestor
= win
;
1106 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1109 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1110 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1113 if (ancestor
->IsTopLevel())
1115 ancestor
= ancestor
->GetParent();
1118 #endif // wxUSE_ACCEL
1120 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1121 // will only be sent if it is not in an accelerator table.
1125 KeySym keysym
= gdk_event
->keyval
;
1127 // In GTK 2.0, we need to hand over the key event to an input method
1128 // and the IM will emit a "commit" event containing the actual utf8
1129 // character. In that case the EVT_CHAR events will be sent from
1130 // there. But only do it this way for non-KeySym keys.
1131 key_code
= wxTranslateKeySymToWXKey(gdk_event
->keyval
, FALSE
/* isChar */);
1132 if ( !key_code
&& win
->m_imContext
)
1134 gtk_im_context_filter_keypress ( (GtkIMContext
*) win
->m_imContext
, gdk_event
);
1140 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1141 key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1144 if ( gdk_event
->length
== 1 )
1146 key_code
= (unsigned char)gdk_event
->string
[0];
1148 else if ( wxIsAsciiKeysym(keysym
) )
1151 key_code
= (unsigned char)keysym
;
1157 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1159 event
.m_keyCode
= key_code
;
1161 // Implement OnCharHook by checking ancesteror top level windows
1162 wxWindow
*parent
= win
;
1163 while (parent
&& !parent
->IsTopLevel())
1164 parent
= parent
->GetParent();
1167 event
.SetEventType( wxEVT_CHAR_HOOK
);
1168 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1173 event
.SetEventType(wxEVT_CHAR
);
1174 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1180 // win is a control: tab can be propagated up
1182 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1183 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1184 // have this style, yet choose not to process this particular TAB in which
1185 // case TAB must still work as a navigational character
1187 !win
->HasFlag(wxTE_PROCESS_TAB
) &&
1189 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1191 wxNavigationKeyEvent new_event
;
1192 new_event
.SetEventObject( win
->GetParent() );
1193 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1194 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1195 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1196 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1197 new_event
.SetCurrentFocus( win
);
1198 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1201 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1203 (gdk_event
->keyval
== GDK_Escape
) )
1205 // however only do it if we have a Cancel button in the dialog,
1206 // otherwise the user code may get confused by the events from a
1207 // non-existing button and, worse, a wxButton might get button event
1208 // from another button which is not really expected
1209 wxWindow
*winForCancel
= win
,
1211 while ( winForCancel
)
1213 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1216 // found a cancel button
1220 if ( winForCancel
->IsTopLevel() )
1222 // no need to look further
1226 // maybe our parent has a cancel button?
1227 winForCancel
= winForCancel
->GetParent();
1232 wxCommandEvent
event(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1233 event
.SetEventObject(btnCancel
);
1234 ret
= btnCancel
->GetEventHandler()->ProcessEvent(event
);
1240 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1248 static void gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1254 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1257 event
.m_uniChar
= g_utf8_get_char( str
);
1259 // Backward compatible for ISO-8859
1260 if (event
.m_uniChar
< 256)
1261 event
.m_keyCode
= event
.m_uniChar
;
1263 gunichar uniChar
= g_utf8_get_char( str
);
1264 // We cannot handle Unicode in non-Unicode mode
1265 if (uniChar
> 255) return;
1267 event
.m_keyCode
= uniChar
;
1271 // TODO: We still need to set all the extra attributes of the
1272 // event, modifiers and such...
1275 // Implement OnCharHook by checking ancestor top level windows
1276 wxWindow
*parent
= window
;
1277 while (parent
&& !parent
->IsTopLevel())
1278 parent
= parent
->GetParent();
1281 event
.SetEventType( wxEVT_CHAR_HOOK
);
1282 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1287 event
.SetEventType(wxEVT_CHAR
);
1288 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1294 //-----------------------------------------------------------------------------
1295 // "key_release_event" from any window
1296 //-----------------------------------------------------------------------------
1298 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1299 GdkEventKey
*gdk_event
,
1305 wxapp_install_idle_handler();
1310 if (g_blockEventsOnDrag
)
1313 wxKeyEvent
event( wxEVT_KEY_UP
);
1314 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1316 // unknown key pressed, ignore (the event would be useless anyhow
1320 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1323 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1327 // ============================================================================
1329 // ============================================================================
1331 // ----------------------------------------------------------------------------
1332 // mouse event processing helpers
1333 // ----------------------------------------------------------------------------
1335 // init wxMouseEvent with the info from gdk_event
1337 // NB: this has to be a macro as gdk_event type is different for different
1338 // events we're used with
1339 #define InitMouseEvent(/* wxWindowGTK * */ win, \
1340 /* wxMouseEvent& */ event, \
1341 /* GdkEventXXX * */ gdk_event) \
1343 event.SetTimestamp( gdk_event->time ); \
1344 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1345 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1346 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1347 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1348 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1349 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1350 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1351 if (event.GetEventType()==wxEVT_MOUSEWHEEL) \
1353 if (((GdkEventButton*)gdk_event)->button == 4) \
1354 event.m_wheelRotation = 120; \
1355 else if (((GdkEventButton*)gdk_event)->button == 5) \
1356 event.m_wheelRotation = -120; \
1359 wxPoint pt = win->GetClientAreaOrigin(); \
1360 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1361 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1363 event.SetEventObject( win ); \
1364 event.SetId( win->GetId() ); \
1365 event.SetTimestamp( gdk_event->time ); \
1368 static void AdjustEventButtonState(wxMouseEvent& event)
1370 // GDK reports the old state of the button for a button press event, but
1371 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1372 // for a LEFT_DOWN event, not FALSE, so we will invert
1373 // left/right/middleDown for the corresponding click events
1375 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1376 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1377 (event
.GetEventType() == wxEVT_LEFT_UP
))
1379 event
.m_leftDown
= !event
.m_leftDown
;
1383 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1384 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1385 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1387 event
.m_middleDown
= !event
.m_middleDown
;
1391 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1392 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1393 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1395 event
.m_rightDown
= !event
.m_rightDown
;
1400 // find the window to send the mouse event too
1402 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1407 if (win
->m_wxwindow
)
1409 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1410 xx
+= pizza
->xoffset
;
1411 yy
+= pizza
->yoffset
;
1414 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1417 wxWindowGTK
*child
= node
->GetData();
1419 node
= node
->GetNext();
1420 if (!child
->IsShown())
1423 if (child
->IsTransparentForMouse())
1425 // wxStaticBox is transparent in the box itself
1426 int xx1
= child
->m_x
;
1427 int yy1
= child
->m_y
;
1428 int xx2
= child
->m_x
+ child
->m_width
;
1429 int yy2
= child
->m_y
+ child
->m_height
;
1432 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1434 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1436 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1438 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1449 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1450 (child
->m_x
<= xx
) &&
1451 (child
->m_y
<= yy
) &&
1452 (child
->m_x
+child
->m_width
>= xx
) &&
1453 (child
->m_y
+child
->m_height
>= yy
))
1466 //-----------------------------------------------------------------------------
1467 // "button_press_event"
1468 //-----------------------------------------------------------------------------
1470 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1471 GdkEventButton
*gdk_event
,
1477 wxapp_install_idle_handler();
1480 wxPrintf( wxT("1) OnButtonPress from ") );
1481 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1482 wxPrintf( win->GetClassInfo()->GetClassName() );
1483 wxPrintf( wxT(".\n") );
1485 if (!win
->m_hasVMT
) return FALSE
;
1486 if (g_blockEventsOnDrag
) return TRUE
;
1487 if (g_blockEventsOnScroll
) return TRUE
;
1489 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1491 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1493 gtk_widget_grab_focus( win
->m_wxwindow
);
1495 wxPrintf( wxT("GrabFocus from ") );
1496 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1497 wxPrintf( win->GetClassInfo()->GetClassName() );
1498 wxPrintf( wxT(".\n") );
1502 // GDK sends surplus button down event
1503 // before a double click event. We
1504 // need to filter these out.
1505 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1507 GdkEvent
*peek_event
= gdk_event_peek();
1510 if (peek_event
->type
== GDK_2BUTTON_PRESS
)
1512 gdk_event_free( peek_event
);
1517 gdk_event_free( peek_event
);
1522 wxEventType event_type
= wxEVT_NULL
;
1524 if (gdk_event
->button
== 1)
1526 switch (gdk_event
->type
)
1528 case GDK_BUTTON_PRESS
: event_type
= wxEVT_LEFT_DOWN
; break;
1529 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_LEFT_DCLICK
; break;
1533 else if (gdk_event
->button
== 2)
1535 switch (gdk_event
->type
)
1537 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DOWN
; break;
1538 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DCLICK
; break;
1542 else if (gdk_event
->button
== 3)
1544 switch (gdk_event
->type
)
1546 case GDK_BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DOWN
; break;
1547 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DCLICK
; break;
1551 else if (gdk_event
->button
== 4)
1553 switch (gdk_event
->type
)
1555 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MOUSEWHEEL
; break;
1559 else if (gdk_event
->button
== 5)
1561 switch (gdk_event
->type
)
1563 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MOUSEWHEEL
; break;
1568 if ( event_type
== wxEVT_NULL
)
1570 // unknown mouse button or click type
1574 wxMouseEvent
event( event_type
);
1575 InitMouseEvent( win
, event
, gdk_event
);
1577 AdjustEventButtonState(event
);
1579 // wxListBox actually get mouse events from the item, so we need to give it
1580 // a chance to correct this
1581 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1583 // find the correct window to send the event too: it may be a different one
1584 // from the one which got it at GTK+ level because some control don't have
1585 // their own X window and thus cannot get any events.
1586 if ( !g_captureWindow
)
1587 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1589 gs_timeLastClick
= gdk_event
->time
;
1592 wxPrintf( wxT("2) OnButtonPress from ") );
1593 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1594 wxPrintf( win->GetClassInfo()->GetClassName() );
1595 wxPrintf( wxT(".\n") );
1599 if (event_type
== wxEVT_LEFT_DCLICK
)
1601 // GTK 1.2 crashes when intercepting double
1602 // click events from both wxSpinButton and
1604 if (GTK_IS_SPIN_BUTTON(win
->m_widget
))
1606 // Just disable this event for now.
1612 if (win
->GetEventHandler()->ProcessEvent( event
))
1614 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1621 //-----------------------------------------------------------------------------
1622 // "button_release_event"
1623 //-----------------------------------------------------------------------------
1625 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1626 GdkEventButton
*gdk_event
,
1632 wxapp_install_idle_handler();
1634 if (!win
->m_hasVMT
) return FALSE
;
1635 if (g_blockEventsOnDrag
) return FALSE
;
1636 if (g_blockEventsOnScroll
) return FALSE
;
1638 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1640 wxEventType event_type
= wxEVT_NULL
;
1642 switch (gdk_event
->button
)
1645 event_type
= wxEVT_LEFT_UP
;
1649 event_type
= wxEVT_MIDDLE_UP
;
1653 event_type
= wxEVT_RIGHT_UP
;
1657 // unknwon button, don't process
1661 wxMouseEvent
event( event_type
);
1662 InitMouseEvent( win
, event
, gdk_event
);
1664 AdjustEventButtonState(event
);
1666 // same wxListBox hack as above
1667 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1669 if ( event_type
== wxEVT_RIGHT_UP
)
1671 // generate a "context menu" event: this is similar to wxEVT_RIGHT_UP
1674 // (a) it's a command event and so is propagated to the parent
1675 // (b) under MSW it can be generated from kbd too
1676 // (c) it uses screen coords (because of (a))
1677 wxContextMenuEvent
evtCtx(wxEVT_CONTEXT_MENU
,
1679 win
->ClientToScreen(event
.GetPosition()));
1680 (void)win
->GetEventHandler()->ProcessEvent(evtCtx
);
1683 if ( !g_captureWindow
)
1684 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1686 if (win
->GetEventHandler()->ProcessEvent( event
))
1688 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1695 //-----------------------------------------------------------------------------
1696 // "motion_notify_event"
1697 //-----------------------------------------------------------------------------
1699 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1700 GdkEventMotion
*gdk_event
,
1706 wxapp_install_idle_handler();
1708 if (!win
->m_hasVMT
) return FALSE
;
1709 if (g_blockEventsOnDrag
) return FALSE
;
1710 if (g_blockEventsOnScroll
) return FALSE
;
1712 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1714 if (gdk_event
->is_hint
)
1718 GdkModifierType state
;
1719 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1725 printf( "OnMotion from " );
1726 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1727 printf( win->GetClassInfo()->GetClassName() );
1731 wxMouseEvent
event( wxEVT_MOTION
);
1732 InitMouseEvent(win
, event
, gdk_event
);
1734 if ( g_captureWindow
)
1736 // synthetize a mouse enter or leave event if needed
1737 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1738 // This seems to be necessary and actually been added to
1739 // GDK itself in version 2.0.X
1742 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1743 if ( hasMouse
!= g_captureWindowHasMouse
)
1745 // the mouse changed window
1746 g_captureWindowHasMouse
= hasMouse
;
1748 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1749 : wxEVT_LEAVE_WINDOW
);
1750 InitMouseEvent(win
, event
, gdk_event
);
1751 event
.SetEventObject(win
);
1752 win
->GetEventHandler()->ProcessEvent(event
);
1757 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1760 if (win
->GetEventHandler()->ProcessEvent( event
))
1762 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1769 //-----------------------------------------------------------------------------
1771 //-----------------------------------------------------------------------------
1773 // send the wxChildFocusEvent and wxFocusEvent, common code of
1774 // gtk_window_focus_in_callback() and SetFocus()
1775 static bool DoSendFocusEvents(wxWindow
*win
)
1777 // Notify the parent keeping track of focus for the kbd navigation
1778 // purposes that we got it.
1779 wxChildFocusEvent
eventChildFocus(win
);
1780 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1782 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1783 eventFocus
.SetEventObject(win
);
1785 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1788 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1789 GdkEvent
*WXUNUSED(event
),
1795 wxapp_install_idle_handler();
1797 if (!win
->m_hasVMT
) return FALSE
;
1798 if (g_blockEventsOnDrag
) return FALSE
;
1800 switch ( g_sendActivateEvent
)
1803 // we've got focus from outside, synthetize wxActivateEvent
1804 g_sendActivateEvent
= 1;
1808 // another our window just lost focus, it was already ours before
1809 // - don't send any wxActivateEvent
1810 g_sendActivateEvent
= -1;
1815 g_focusWindow
= win
;
1817 wxLogTrace(TRACE_FOCUS
,
1818 _T("%s: focus in"), win
->GetName().c_str());
1822 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1826 // caret needs to be informed about focus change
1827 wxCaret
*caret
= win
->GetCaret();
1830 caret
->OnSetFocus();
1832 #endif // wxUSE_CARET
1834 g_activeFrameLostFocus
= FALSE
;
1836 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1837 if ( active
!= g_activeFrame
)
1839 if ( g_activeFrame
)
1841 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1842 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1843 event
.SetEventObject(g_activeFrame
);
1844 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1847 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1848 g_activeFrame
= active
;
1849 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1850 event
.SetEventObject(g_activeFrame
);
1851 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1853 // Don't send focus events in addition to activate
1854 // if (win == g_activeFrame)
1858 // does the window itself think that it has the focus?
1859 if ( !win
->m_hasFocus
)
1861 // not yet, notify it
1862 win
->m_hasFocus
= TRUE
;
1864 if ( DoSendFocusEvents(win
) )
1866 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1874 //-----------------------------------------------------------------------------
1875 // "focus_out_event"
1876 //-----------------------------------------------------------------------------
1878 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1883 wxapp_install_idle_handler();
1885 if (!win
->m_hasVMT
) return FALSE
;
1886 if (g_blockEventsOnDrag
) return FALSE
;
1888 wxLogTrace( TRACE_FOCUS
,
1889 _T("%s: focus out"), win
->GetName().c_str() );
1891 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1893 // VZ: commenting this out because it does happen (although not easy
1894 // to reproduce, I only see it when using wxMiniFrame and not
1895 // always) and makes using Mahogany quite annoying
1897 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1898 wxT("unfocusing window that hasn't gained focus properly") );
1901 g_activeFrameLostFocus
= TRUE
;
1904 // if the focus goes out of our app alltogether, OnIdle() will send
1905 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1906 // g_sendActivateEvent to -1
1907 g_sendActivateEvent
= 0;
1909 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1913 g_focusWindow
= (wxWindowGTK
*)NULL
;
1921 // caret needs to be informed about focus change
1922 wxCaret
*caret
= win
->GetCaret();
1925 caret
->OnKillFocus();
1927 #endif // wxUSE_CARET
1929 // don't send the window a kill focus event if it thinks that it doesn't
1930 // have focus already
1931 if ( win
->m_hasFocus
)
1933 win
->m_hasFocus
= FALSE
;
1935 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1936 event
.SetEventObject( win
);
1938 if (win
->GetEventHandler()->ProcessEvent( event
))
1940 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
1948 //-----------------------------------------------------------------------------
1949 // "enter_notify_event"
1950 //-----------------------------------------------------------------------------
1953 gint
gtk_window_enter_callback( GtkWidget
*widget
,
1954 GdkEventCrossing
*gdk_event
,
1960 wxapp_install_idle_handler();
1962 if (!win
->m_hasVMT
) return FALSE
;
1963 if (g_blockEventsOnDrag
) return FALSE
;
1965 // Event was emitted after a grab
1966 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1968 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1972 GdkModifierType state
= (GdkModifierType
)0;
1974 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1976 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1977 InitMouseEvent(win
, event
, gdk_event
);
1978 wxPoint pt
= win
->GetClientAreaOrigin();
1979 event
.m_x
= x
+ pt
.x
;
1980 event
.m_y
= y
+ pt
.y
;
1982 if (win
->GetEventHandler()->ProcessEvent( event
))
1984 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
1991 //-----------------------------------------------------------------------------
1992 // "leave_notify_event"
1993 //-----------------------------------------------------------------------------
1995 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
2000 wxapp_install_idle_handler();
2002 if (!win
->m_hasVMT
) return FALSE
;
2003 if (g_blockEventsOnDrag
) return FALSE
;
2005 // Event was emitted after an ungrab
2006 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2008 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2010 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2011 event
.SetTimestamp( gdk_event
->time
);
2012 event
.SetEventObject( win
);
2016 GdkModifierType state
= (GdkModifierType
)0;
2018 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2020 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2021 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2022 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2023 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2024 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2025 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2026 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2028 wxPoint pt
= win
->GetClientAreaOrigin();
2029 event
.m_x
= x
+ pt
.x
;
2030 event
.m_y
= y
+ pt
.y
;
2032 if (win
->GetEventHandler()->ProcessEvent( event
))
2034 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
2041 //-----------------------------------------------------------------------------
2042 // "value_changed" from m_vAdjust
2043 //-----------------------------------------------------------------------------
2045 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2052 wxapp_install_idle_handler();
2054 if (g_blockEventsOnDrag
) return;
2056 if (!win
->m_hasVMT
) return;
2058 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2059 if (fabs(diff
) < 0.2) return;
2061 win
->m_oldVerticalPos
= adjust
->value
;
2064 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2066 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
2068 int value
= (int)(adjust
->value
+0.5);
2070 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2071 event
.SetEventObject( win
);
2072 win
->GetEventHandler()->ProcessEvent( event
);
2075 //-----------------------------------------------------------------------------
2076 // "value_changed" from m_hAdjust
2077 //-----------------------------------------------------------------------------
2079 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2086 wxapp_install_idle_handler();
2088 if (g_blockEventsOnDrag
) return;
2089 if (!win
->m_hasVMT
) return;
2091 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2092 if (fabs(diff
) < 0.2) return;
2095 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2097 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
2099 win
->m_oldHorizontalPos
= adjust
->value
;
2101 int value
= (int)(adjust
->value
+0.5);
2103 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2104 event
.SetEventObject( win
);
2105 win
->GetEventHandler()->ProcessEvent( event
);
2108 //-----------------------------------------------------------------------------
2109 // "button_press_event" from scrollbar
2110 //-----------------------------------------------------------------------------
2112 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2113 GdkEventButton
*gdk_event
,
2119 wxapp_install_idle_handler();
2122 g_blockEventsOnScroll
= TRUE
;
2124 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2126 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2132 //-----------------------------------------------------------------------------
2133 // "button_release_event" from scrollbar
2134 //-----------------------------------------------------------------------------
2136 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2137 GdkEventButton
*WXUNUSED(gdk_event
),
2142 // don't test here as we can release the mouse while being over
2143 // a different window than the slider
2145 // if (gdk_event->window != widget->slider) return FALSE;
2147 g_blockEventsOnScroll
= FALSE
;
2149 if (win
->m_isScrolling
)
2151 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2155 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2156 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2158 value
= (int)(win
->m_hAdjust
->value
+0.5);
2161 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2163 value
= (int)(win
->m_vAdjust
->value
+0.5);
2167 wxScrollWinEvent
event( command
, value
, dir
);
2168 event
.SetEventObject( win
);
2169 win
->GetEventHandler()->ProcessEvent( event
);
2172 win
->m_isScrolling
= FALSE
;
2177 // ----------------------------------------------------------------------------
2178 // this wxWindowBase function is implemented here (in platform-specific file)
2179 // because it is static and so couldn't be made virtual
2180 // ----------------------------------------------------------------------------
2182 wxWindow
*wxWindowBase::FindFocus()
2184 // the cast is necessary when we compile in wxUniversal mode
2185 return (wxWindow
*)g_focusWindow
;
2189 //-----------------------------------------------------------------------------
2190 // "realize" from m_widget
2191 //-----------------------------------------------------------------------------
2193 /* We cannot set colours and fonts before the widget has
2194 been realized, so we do this directly after realization. */
2197 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2202 wxapp_install_idle_handler();
2204 if (win
->m_delayedBackgroundColour
&& !win
->GetThemeEnabled())
2205 win
->GtkSetBackgroundColour( win
->GetBackgroundColour() );
2207 if (win
->m_delayedForegroundColour
&& !win
->GetThemeEnabled())
2208 win
->GtkSetForegroundColour( win
->GetForegroundColour() );
2211 if (win
->m_imContext
)
2213 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2214 gtk_im_context_set_client_window( (GtkIMContext
*) win
->m_imContext
, pizza
->bin_window
);
2218 wxWindowCreateEvent
event( win
);
2219 event
.SetEventObject( win
);
2220 win
->GetEventHandler()->ProcessEvent( event
);
2225 //-----------------------------------------------------------------------------
2227 //-----------------------------------------------------------------------------
2230 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2231 GtkAllocation
*WXUNUSED(alloc
),
2235 wxapp_install_idle_handler();
2237 if (!win
->m_hasScrolling
) return;
2239 int client_width
= 0;
2240 int client_height
= 0;
2241 win
->GetClientSize( &client_width
, &client_height
);
2242 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2245 win
->m_oldClientWidth
= client_width
;
2246 win
->m_oldClientHeight
= client_height
;
2248 if (!win
->m_nativeSizeEvent
)
2250 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2251 event
.SetEventObject( win
);
2252 win
->GetEventHandler()->ProcessEvent( event
);
2258 #define WXUNUSED_UNLESS_XIM(param) param
2260 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2263 /* Resize XIM window */
2266 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2267 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2268 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2271 wxapp_install_idle_handler();
2277 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2281 gdk_window_get_size (widget
->window
, &width
, &height
);
2282 win
->m_icattr
->preedit_area
.width
= width
;
2283 win
->m_icattr
->preedit_area
.height
= height
;
2284 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2289 //-----------------------------------------------------------------------------
2290 // "realize" from m_wxwindow
2291 //-----------------------------------------------------------------------------
2293 /* Initialize XIM support */
2296 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2297 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2300 wxapp_install_idle_handler();
2303 if (win
->m_ic
) return FALSE
;
2304 if (!widget
) return FALSE
;
2305 if (!gdk_im_ready()) return FALSE
;
2307 win
->m_icattr
= gdk_ic_attr_new();
2308 if (!win
->m_icattr
) return FALSE
;
2312 GdkColormap
*colormap
;
2313 GdkICAttr
*attr
= win
->m_icattr
;
2314 unsigned attrmask
= GDK_IC_ALL_REQ
;
2316 GdkIMStyle supported_style
= (GdkIMStyle
)
2317 (GDK_IM_PREEDIT_NONE
|
2318 GDK_IM_PREEDIT_NOTHING
|
2319 GDK_IM_PREEDIT_POSITION
|
2320 GDK_IM_STATUS_NONE
|
2321 GDK_IM_STATUS_NOTHING
);
2323 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2324 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2326 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2327 attr
->client_window
= widget
->window
;
2329 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2330 gtk_widget_get_default_colormap ())
2332 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2333 attr
->preedit_colormap
= colormap
;
2336 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2337 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2338 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2339 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2341 switch (style
& GDK_IM_PREEDIT_MASK
)
2343 case GDK_IM_PREEDIT_POSITION
:
2344 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2346 g_warning ("over-the-spot style requires fontset");
2350 gdk_window_get_size (widget
->window
, &width
, &height
);
2352 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2353 attr
->spot_location
.x
= 0;
2354 attr
->spot_location
.y
= height
;
2355 attr
->preedit_area
.x
= 0;
2356 attr
->preedit_area
.y
= 0;
2357 attr
->preedit_area
.width
= width
;
2358 attr
->preedit_area
.height
= height
;
2359 attr
->preedit_fontset
= widget
->style
->font
;
2364 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2366 if (win
->m_ic
== NULL
)
2367 g_warning ("Can't create input context.");
2370 mask
= gdk_window_get_events (widget
->window
);
2371 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2372 gdk_window_set_events (widget
->window
, mask
);
2374 if (GTK_WIDGET_HAS_FOCUS(widget
))
2375 gdk_im_begin (win
->m_ic
, widget
->window
);
2382 //-----------------------------------------------------------------------------
2383 // InsertChild for wxWindowGTK.
2384 //-----------------------------------------------------------------------------
2386 /* Callback for wxWindowGTK. This very strange beast has to be used because
2387 * C++ has no virtual methods in a constructor. We have to emulate a
2388 * virtual function here as wxNotebook requires a different way to insert
2389 * a child in it. I had opted for creating a wxNotebookPage window class
2390 * which would have made this superfluous (such in the MDI window system),
2391 * but no-one was listening to me... */
2393 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2395 /* the window might have been scrolled already, do we
2396 have to adapt the position */
2397 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2398 child
->m_x
+= pizza
->xoffset
;
2399 child
->m_y
+= pizza
->yoffset
;
2401 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2402 GTK_WIDGET(child
->m_widget
),
2409 //-----------------------------------------------------------------------------
2411 //-----------------------------------------------------------------------------
2413 wxWindow
*wxGetActiveWindow()
2415 return wxWindow::FindFocus();
2418 //-----------------------------------------------------------------------------
2420 //-----------------------------------------------------------------------------
2422 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2424 #ifdef __WXUNIVERSAL__
2425 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2427 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2428 #endif // __WXUNIVERSAL__/__WXGTK__
2430 void wxWindowGTK::Init()
2436 m_widget
= (GtkWidget
*) NULL
;
2437 m_wxwindow
= (GtkWidget
*) NULL
;
2438 m_focusWidget
= (GtkWidget
*) NULL
;
2448 m_needParent
= TRUE
;
2449 m_isBeingDeleted
= FALSE
;
2452 m_nativeSizeEvent
= FALSE
;
2454 m_hasScrolling
= FALSE
;
2455 m_isScrolling
= FALSE
;
2457 m_hAdjust
= (GtkAdjustment
*) NULL
;
2458 m_vAdjust
= (GtkAdjustment
*) NULL
;
2459 m_oldHorizontalPos
=
2460 m_oldVerticalPos
= 0.0;
2462 m_oldClientHeight
= 0;
2465 m_widgetStyle
= (GtkStyle
*) NULL
;
2467 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2469 m_acceptsFocus
= FALSE
;
2472 m_clipPaintRegion
= FALSE
;
2474 m_cursor
= *wxSTANDARD_CURSOR
;
2476 m_delayedForegroundColour
= FALSE
;
2477 m_delayedBackgroundColour
= FALSE
;
2481 m_x11Context
= NULL
;
2484 m_ic
= (GdkIC
*) NULL
;
2485 m_icattr
= (GdkICAttr
*) NULL
;
2490 wxWindowGTK::wxWindowGTK()
2495 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2500 const wxString
&name
)
2504 Create( parent
, id
, pos
, size
, style
, name
);
2507 bool wxWindowGTK::Create( wxWindow
*parent
,
2512 const wxString
&name
)
2514 if (!PreCreation( parent
, pos
, size
) ||
2515 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2517 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2521 m_insertCallback
= wxInsertChildInWindow
;
2523 // always needed for background clearing
2524 m_delayedBackgroundColour
= TRUE
;
2526 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2527 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2529 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2531 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2532 scroll_class
->scrollbar_spacing
= 0;
2534 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2536 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2537 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2539 m_wxwindow
= gtk_pizza_new();
2541 #ifndef __WXUNIVERSAL__
2542 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2544 if (HasFlag(wxRAISED_BORDER
))
2546 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2548 else if (HasFlag(wxSUNKEN_BORDER
))
2550 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2552 else if (HasFlag(wxSIMPLE_BORDER
))
2554 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2558 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2560 #endif // __WXUNIVERSAL__
2562 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2564 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2565 m_acceptsFocus
= TRUE
;
2567 // I _really_ don't want scrollbars in the beginning
2568 m_vAdjust
->lower
= 0.0;
2569 m_vAdjust
->upper
= 1.0;
2570 m_vAdjust
->value
= 0.0;
2571 m_vAdjust
->step_increment
= 1.0;
2572 m_vAdjust
->page_increment
= 1.0;
2573 m_vAdjust
->page_size
= 5.0;
2574 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2575 m_hAdjust
->lower
= 0.0;
2576 m_hAdjust
->upper
= 1.0;
2577 m_hAdjust
->value
= 0.0;
2578 m_hAdjust
->step_increment
= 1.0;
2579 m_hAdjust
->page_increment
= 1.0;
2580 m_hAdjust
->page_size
= 5.0;
2581 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2583 // these handlers block mouse events to any window during scrolling such as
2584 // motion events and prevent GTK and wxWindows from fighting over where the
2587 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2588 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2590 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2591 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2593 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2594 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2596 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2597 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2599 // these handlers get notified when screen updates are required either when
2600 // scrolling or when the window size (and therefore scrollbar configuration)
2603 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2604 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2605 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2606 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2609 // Create input method handler
2610 m_imContext
= (GtkIMMulticontext
*) gtk_im_multicontext_new ();
2612 // Cannot handle drawing preedited text yet
2613 gtk_im_context_set_use_preedit( (GtkIMContext
*) m_imContext
, FALSE
);
2615 g_signal_connect (G_OBJECT (m_imContext
), "commit",
2616 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2619 gtk_widget_show( m_wxwindow
);
2622 m_parent
->DoAddChild( this );
2624 m_focusWidget
= m_wxwindow
;
2633 wxWindowGTK::~wxWindowGTK()
2637 if (g_focusWindow
== this)
2638 g_focusWindow
= NULL
;
2640 if (g_activeFrame
== this)
2641 g_activeFrame
= NULL
;
2643 if ( g_delayedFocus
== this )
2644 g_delayedFocus
= NULL
;
2646 m_isBeingDeleted
= TRUE
;
2655 m_parent
->RemoveChild( this );
2659 gdk_ic_destroy (m_ic
);
2661 gdk_ic_attr_destroy (m_icattr
);
2666 #if DISABLE_STYLE_IF_BROKEN_THEME
2667 // don't delete if it's a pixmap theme style
2668 if (!m_widgetStyle
->engine_data
)
2669 gtk_style_unref( m_widgetStyle
);
2671 m_widgetStyle
= (GtkStyle
*) NULL
;
2676 gtk_widget_destroy( m_wxwindow
);
2677 m_wxwindow
= (GtkWidget
*) NULL
;
2682 gtk_widget_destroy( m_widget
);
2683 m_widget
= (GtkWidget
*) NULL
;
2687 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2689 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2691 // This turns -1 into 30 so that a minimal window is
2692 // visible even although -1,-1 has been given as the
2693 // size of the window. the same trick is used in other
2694 // ports and should make debugging easier.
2695 m_width
= WidthDefault(size
.x
) ;
2696 m_height
= HeightDefault(size
.y
);
2701 // some reasonable defaults
2706 m_x
= (gdk_screen_width () - m_width
) / 2;
2707 if (m_x
< 10) m_x
= 10;
2711 m_y
= (gdk_screen_height () - m_height
) / 2;
2712 if (m_y
< 10) m_y
= 10;
2719 void wxWindowGTK::PostCreation()
2721 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2727 // these get reported to wxWindows -> wxPaintEvent
2729 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2731 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2732 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2735 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2736 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2738 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
))
2740 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2741 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2744 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), HasFlag( wxNO_FULL_REPAINT_ON_RESIZE ) );
2748 // Create input method handler
2749 m_imContext
= (GtkIMMulticontext
*) gtk_im_multicontext_new ();
2751 // Cannot handle drawing preedited text yet
2752 gtk_im_context_set_use_preedit( (GtkIMContext
*) m_imContext
, FALSE
);
2754 g_signal_connect (G_OBJECT (m_imContext
), "commit",
2755 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2759 // these are called when the "sunken" or "raised" borders are drawn
2760 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2761 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2764 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2765 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2771 if (m_focusWidget
== NULL
)
2772 m_focusWidget
= m_widget
;
2774 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2775 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2777 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2778 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2780 // connect to the various key and mouse handlers
2782 GtkWidget
*connect_widget
= GetConnectWidget();
2784 ConnectWidget( connect_widget
);
2786 /* We cannot set colours, fonts and cursors before the widget has
2787 been realized, so we do this directly after realization */
2788 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2789 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2793 // Catch native resize events
2794 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2795 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2797 // Initialize XIM support
2798 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2799 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2801 // And resize XIM window
2802 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2803 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2806 if ( !GTK_IS_COMBO(m_widget
))
2808 // This is needed if we want to add our windows into native
2809 // GTK control, such as the toolbar. With this callback, the
2810 // toolbar gets to know the correct size (the one set by the
2811 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2812 // when moving to GTK 2.0.
2813 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2814 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback
),
2821 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2823 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2824 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2826 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2827 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2829 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2830 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2832 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2833 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2835 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2836 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2838 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2839 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2841 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2842 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2845 bool wxWindowGTK::Destroy()
2847 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2851 return wxWindowBase::Destroy();
2854 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2856 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2859 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2861 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2862 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2865 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2868 if (m_resizing
) return; /* I don't like recursions */
2871 int currentX
, currentY
;
2872 GetPosition(¤tX
, ¤tY
);
2877 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2879 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2881 /* don't set the size for children of wxNotebook, just take the values. */
2889 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2890 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2892 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2893 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2897 m_x
= x
+ pizza
->xoffset
;
2898 m_y
= y
+ pizza
->yoffset
;
2900 if (width
!= -1) m_width
= width
;
2901 if (height
!= -1) m_height
= height
;
2903 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2905 if (width
== -1) m_width
= 80;
2908 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2910 if (height
== -1) m_height
= 26;
2913 int minWidth
= GetMinWidth(),
2914 minHeight
= GetMinHeight(),
2915 maxWidth
= GetMaxWidth(),
2916 maxHeight
= GetMaxHeight();
2918 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2919 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2920 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2921 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2924 int bottom_border
= 0;
2927 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2929 /* the default button has a border around it */
2935 DoMoveWindow( m_x
-border
,
2938 m_height
+border
+bottom_border
);
2943 /* Sometimes the client area changes size without the
2944 whole windows's size changing, but if the whole
2945 windows's size doesn't change, no wxSizeEvent will
2946 normally be sent. Here we add an extra test if
2947 the client test has been changed and this will
2949 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2953 wxPrintf( "OnSize sent from " );
2954 if (GetClassInfo() && GetClassInfo()->GetClassName())
2955 wxPrintf( GetClassInfo()->GetClassName() );
2956 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2959 if (!m_nativeSizeEvent
)
2961 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2962 event
.SetEventObject( this );
2963 GetEventHandler()->ProcessEvent( event
);
2969 void wxWindowGTK::OnInternalIdle()
2971 // Update invalidated regions.
2974 // Synthetize activate events.
2975 if ( g_sendActivateEvent
!= -1 )
2977 bool activate
= g_sendActivateEvent
!= 0;
2980 g_sendActivateEvent
= -1;
2982 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
2985 if ( g_activeFrameLostFocus
)
2987 if ( g_activeFrame
)
2989 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
2990 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
2991 event
.SetEventObject(g_activeFrame
);
2992 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
2993 g_activeFrame
= NULL
;
2995 g_activeFrameLostFocus
= FALSE
;
2998 wxCursor cursor
= m_cursor
;
2999 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3003 /* I now set the cursor anew in every OnInternalIdle call
3004 as setting the cursor in a parent window also effects the
3005 windows above so that checking for the current cursor is
3010 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3012 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3014 if (!g_globalCursor
.Ok())
3015 cursor
= *wxSTANDARD_CURSOR
;
3017 window
= m_widget
->window
;
3018 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3019 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3025 GdkWindow
*window
= m_widget
->window
;
3026 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3027 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3032 if (wxUpdateUIEvent::CanUpdate(this))
3033 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3036 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3038 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3040 if (width
) (*width
) = m_width
;
3041 if (height
) (*height
) = m_height
;
3044 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3046 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3050 SetSize( width
, height
);
3057 #ifndef __WXUNIVERSAL__
3058 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3060 /* when using GTK 1.2 we set the shadow border size to 2 */
3064 if (HasFlag(wxSIMPLE_BORDER
))
3066 /* when using GTK 1.2 we set the simple border size to 1 */
3070 #endif // __WXUNIVERSAL__
3074 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3076 GtkRequisition vscroll_req
;
3077 vscroll_req
.width
= 2;
3078 vscroll_req
.height
= 2;
3079 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3080 (scroll_window
->vscrollbar
, &vscroll_req
);
3082 GtkRequisition hscroll_req
;
3083 hscroll_req
.width
= 2;
3084 hscroll_req
.height
= 2;
3085 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3086 (scroll_window
->hscrollbar
, &hscroll_req
);
3088 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3090 if (scroll_window
->vscrollbar_visible
)
3092 dw
+= vscroll_req
.width
;
3093 dw
+= scroll_class
->scrollbar_spacing
;
3096 if (scroll_window
->hscrollbar_visible
)
3098 dh
+= hscroll_req
.height
;
3099 dh
+= scroll_class
->scrollbar_spacing
;
3103 SetSize( width
+dw
, height
+dh
);
3107 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3109 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3113 if (width
) (*width
) = m_width
;
3114 if (height
) (*height
) = m_height
;
3121 #ifndef __WXUNIVERSAL__
3122 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3124 /* when using GTK 1.2 we set the shadow border size to 2 */
3128 if (HasFlag(wxSIMPLE_BORDER
))
3130 /* when using GTK 1.2 we set the simple border size to 1 */
3134 #endif // __WXUNIVERSAL__
3138 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3140 GtkRequisition vscroll_req
;
3141 vscroll_req
.width
= 2;
3142 vscroll_req
.height
= 2;
3143 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3144 (scroll_window
->vscrollbar
, &vscroll_req
);
3146 GtkRequisition hscroll_req
;
3147 hscroll_req
.width
= 2;
3148 hscroll_req
.height
= 2;
3149 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3150 (scroll_window
->hscrollbar
, &hscroll_req
);
3152 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3154 if (scroll_window
->vscrollbar_visible
)
3156 dw
+= vscroll_req
.width
;
3157 dw
+= scroll_class
->scrollbar_spacing
;
3160 if (scroll_window
->hscrollbar_visible
)
3162 dh
+= hscroll_req
.height
;
3163 dh
+= scroll_class
->scrollbar_spacing
;
3167 if (width
) (*width
) = m_width
- dw
;
3168 if (height
) (*height
) = m_height
- dh
;
3172 printf( "GetClientSize, name %s ", GetName().c_str() );
3173 if (width) printf( " width = %d", (*width) );
3174 if (height) printf( " height = %d", (*height) );
3179 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3181 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3185 if (m_parent
&& m_parent
->m_wxwindow
)
3187 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3188 dx
= pizza
->xoffset
;
3189 dy
= pizza
->yoffset
;
3192 if (x
) (*x
) = m_x
- dx
;
3193 if (y
) (*y
) = m_y
- dy
;
3196 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3198 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3200 if (!m_widget
->window
) return;
3202 GdkWindow
*source
= (GdkWindow
*) NULL
;
3204 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3206 source
= m_widget
->window
;
3210 gdk_window_get_origin( source
, &org_x
, &org_y
);
3214 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3216 org_x
+= m_widget
->allocation
.x
;
3217 org_y
+= m_widget
->allocation
.y
;
3225 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3227 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3229 if (!m_widget
->window
) return;
3231 GdkWindow
*source
= (GdkWindow
*) NULL
;
3233 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3235 source
= m_widget
->window
;
3239 gdk_window_get_origin( source
, &org_x
, &org_y
);
3243 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3245 org_x
+= m_widget
->allocation
.x
;
3246 org_y
+= m_widget
->allocation
.y
;
3254 bool wxWindowGTK::Show( bool show
)
3256 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3258 if (!wxWindowBase::Show(show
))
3265 gtk_widget_show( m_widget
);
3267 gtk_widget_hide( m_widget
);
3269 wxShowEvent
eventShow(GetId(), show
);
3270 eventShow
.m_eventObject
= this;
3272 GetEventHandler()->ProcessEvent(eventShow
);
3277 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3279 win
->OnParentEnable(enable
);
3281 // Recurse, so that children have the opportunity to Do The Right Thing
3282 // and reset colours that have been messed up by a parent's (really ancestor's)
3284 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3286 node
= node
->GetNext() )
3288 wxWindow
*child
= node
->GetData();
3289 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3290 wxWindowNotifyEnable(child
, enable
);
3294 bool wxWindowGTK::Enable( bool enable
)
3296 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3298 if (!wxWindowBase::Enable(enable
))
3304 gtk_widget_set_sensitive( m_widget
, enable
);
3306 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3308 wxWindowNotifyEnable(this, enable
);
3313 int wxWindowGTK::GetCharHeight() const
3315 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3317 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3320 PangoContext
*context
= NULL
;
3322 context
= gtk_widget_get_pango_context( m_widget
);
3327 PangoFontDescription
*desc
= m_font
.GetNativeFontInfo()->description
;
3328 PangoLayout
*layout
= pango_layout_new(context
);
3329 pango_layout_set_font_description(layout
, desc
);
3330 pango_layout_set_text(layout
, "H", 1);
3331 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3333 PangoRectangle rect
;
3334 pango_layout_line_get_extents(line
, NULL
, &rect
);
3336 g_object_unref( G_OBJECT( layout
) );
3338 return (int) (rect
.height
/ PANGO_SCALE
);
3340 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3342 return font
->ascent
+ font
->descent
;
3346 int wxWindowGTK::GetCharWidth() const
3348 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3350 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3353 PangoContext
*context
= NULL
;
3355 context
= gtk_widget_get_pango_context( m_widget
);
3360 PangoFontDescription
*desc
= m_font
.GetNativeFontInfo()->description
;
3361 PangoLayout
*layout
= pango_layout_new(context
);
3362 pango_layout_set_font_description(layout
, desc
);
3363 pango_layout_set_text(layout
, "H", 1);
3364 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3366 PangoRectangle rect
;
3367 pango_layout_line_get_extents(line
, NULL
, &rect
);
3369 g_object_unref( G_OBJECT( layout
) );
3371 return (int) (rect
.width
/ PANGO_SCALE
);
3373 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3375 return gdk_string_width( font
, "H" );
3379 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3383 int *externalLeading
,
3384 const wxFont
*theFont
) const
3386 wxFont fontToUse
= m_font
;
3387 if (theFont
) fontToUse
= *theFont
;
3389 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3391 if (string
.IsEmpty())
3399 PangoContext
*context
= NULL
;
3401 context
= gtk_widget_get_pango_context( m_widget
);
3410 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3411 PangoLayout
*layout
= pango_layout_new(context
);
3412 pango_layout_set_font_description(layout
, desc
);
3415 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3416 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3418 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3419 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3420 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3423 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3425 PangoRectangle rect
;
3426 pango_layout_line_get_extents(line
, NULL
, &rect
);
3428 if (x
) (*x
) = (wxCoord
) (rect
.width
/ PANGO_SCALE
);
3429 if (y
) (*y
) = (wxCoord
) (rect
.height
/ PANGO_SCALE
);
3432 // Do something about metrics here
3435 if (externalLeading
) (*externalLeading
) = 0; // ??
3437 g_object_unref( G_OBJECT( layout
) );
3439 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3440 if (x
) (*x
) = gdk_string_width( font
, wxGTK_CONV( string
) );
3441 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3442 if (descent
) (*descent
) = font
->descent
;
3443 if (externalLeading
) (*externalLeading
) = 0; // ??
3447 void wxWindowGTK::SetFocus()
3449 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3453 // don't do anything if we already have focus
3459 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3461 gtk_widget_grab_focus (m_wxwindow
);
3466 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3468 if (!GTK_WIDGET_REALIZED(m_widget
))
3470 // we can't set the focus to the widget now so we remember that
3471 // it should be focused and will do it later, during the idle
3472 // time, as soon as we can
3473 wxLogTrace(TRACE_FOCUS
,
3474 _T("Delaying setting focus to %s(%s)"),
3475 GetClassInfo()->GetClassName(), GetLabel().c_str());
3477 g_delayedFocus
= this;
3481 wxLogTrace(TRACE_FOCUS
,
3482 _T("Setting focus to %s(%s)"),
3483 GetClassInfo()->GetClassName(), GetLabel().c_str());
3485 gtk_widget_grab_focus (m_widget
);
3488 else if (GTK_IS_CONTAINER(m_widget
))
3490 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3494 wxLogTrace(TRACE_FOCUS
,
3495 _T("Can't set focus to %s(%s)"),
3496 GetClassInfo()->GetClassName(), GetLabel().c_str());
3501 bool wxWindowGTK::AcceptsFocus() const
3503 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3506 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3508 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3510 wxWindowGTK
*oldParent
= m_parent
,
3511 *newParent
= (wxWindowGTK
*)newParentBase
;
3513 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3515 if ( !wxWindowBase::Reparent(newParent
) )
3518 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3520 /* prevent GTK from deleting the widget arbitrarily */
3521 gtk_widget_ref( m_widget
);
3525 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3528 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3532 /* insert GTK representation */
3533 (*(newParent
->m_insertCallback
))(newParent
, this);
3536 /* reverse: prevent GTK from deleting the widget arbitrarily */
3537 gtk_widget_unref( m_widget
);
3542 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3544 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3546 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3548 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3553 /* insert GTK representation */
3554 (*m_insertCallback
)(this, child
);
3557 void wxWindowGTK::Raise()
3559 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3561 if (!m_widget
->window
) return;
3563 gdk_window_raise( m_widget
->window
);
3566 void wxWindowGTK::Lower()
3568 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3570 if (!m_widget
->window
) return;
3572 gdk_window_lower( m_widget
->window
);
3575 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3577 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3579 if (cursor
== m_cursor
)
3583 wxapp_install_idle_handler();
3585 if (cursor
== wxNullCursor
)
3586 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3588 return wxWindowBase::SetCursor( cursor
);
3591 void wxWindowGTK::WarpPointer( int x
, int y
)
3593 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3595 // We provide this function ourselves as it is
3596 // missing in GDK (top of this file).
3598 GdkWindow
*window
= (GdkWindow
*) NULL
;
3600 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3602 window
= GetConnectWidget()->window
;
3605 gdk_window_warp_pointer( window
, x
, y
);
3609 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3611 if (!m_widget
) return;
3612 if (!m_widget
->window
) return;
3616 wxapp_install_idle_handler();
3618 wxRect
myRect(0,0,0,0);
3619 if (m_wxwindow
&& rect
)
3621 myRect
.SetSize(wxSize( m_wxwindow
->allocation
.width
,
3622 m_wxwindow
->allocation
.height
));
3623 myRect
.Intersect(*rect
);
3624 if (!myRect
.width
|| !myRect
.height
)
3625 // nothing to do, rectangle is empty
3630 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3634 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3635 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3639 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3640 m_clearRegion
.Clear();
3641 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3649 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3650 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3654 GdkRectangle gdk_rect
;
3655 gdk_rect
.x
= rect
->x
;
3656 gdk_rect
.y
= rect
->y
;
3657 gdk_rect
.width
= rect
->width
;
3658 gdk_rect
.height
= rect
->height
;
3659 gtk_widget_draw( m_widget
, &gdk_rect
);
3666 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3667 m_updateRegion
.Clear();
3668 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3672 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3680 GdkRectangle gdk_rect
;
3681 gdk_rect
.x
= rect
->x
;
3682 gdk_rect
.y
= rect
->y
;
3683 gdk_rect
.width
= rect
->width
;
3684 gdk_rect
.height
= rect
->height
;
3685 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3689 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3695 void wxWindowGTK::Update()
3700 void wxWindowGTK::GtkUpdate()
3703 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3704 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3706 if (!m_updateRegion
.IsEmpty())
3707 GtkSendPaintEvents();
3711 void wxWindowGTK::GtkSendPaintEvents()
3716 m_clearRegion
.Clear();
3718 m_updateRegion
.Clear();
3722 // Clip to paint region in wxClientDC
3723 m_clipPaintRegion
= TRUE
;
3726 // widget to draw on
3727 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3729 // later for GTK 2.0, too.
3730 if (GetThemeEnabled())
3732 // find ancestor from which to steal background
3733 wxWindow
*parent
= GetParent();
3734 while (parent
&& !parent
->IsTopLevel())
3735 parent
= parent
->GetParent();
3737 parent
= (wxWindow
*)this;
3739 wxRegionIterator
upd( m_updateRegion
);
3743 rect
.x
= upd
.GetX();
3744 rect
.y
= upd
.GetY();
3745 rect
.width
= upd
.GetWidth();
3746 rect
.height
= upd
.GetHeight();
3748 gtk_paint_flat_box( parent
->m_widget
->style
,
3765 wxWindowDC
dc( (wxWindow
*)this );
3766 dc
.SetClippingRegion( m_updateRegion
);
3768 wxEraseEvent
erase_event( GetId(), &dc
);
3769 erase_event
.SetEventObject( this );
3771 GetEventHandler()->ProcessEvent(erase_event
);
3774 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
3776 wxWindowDC
dc( (wxWindow
*)this );
3777 if (m_clearRegion
.IsEmpty())
3778 dc
.SetClippingRegion( m_updateRegion
);
3780 dc
.SetClippingRegion( m_clearRegion
);
3782 wxEraseEvent
erase_event( GetId(), &dc
);
3783 erase_event
.SetEventObject( this );
3785 if (!GetEventHandler()->ProcessEvent(erase_event
))
3789 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
3790 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3792 gdk_gc_set_foreground( g_eraseGC
, m_backgroundColour
.GetColor() );
3794 wxRegionIterator
upd( m_clearRegion
);
3797 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3798 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3802 m_clearRegion
.Clear();
3806 wxNcPaintEvent
nc_paint_event( GetId() );
3807 nc_paint_event
.SetEventObject( this );
3808 GetEventHandler()->ProcessEvent( nc_paint_event
);
3810 wxPaintEvent
paint_event( GetId() );
3811 paint_event
.SetEventObject( this );
3812 GetEventHandler()->ProcessEvent( paint_event
);
3814 m_clipPaintRegion
= FALSE
;
3816 #ifndef __WXUNIVERSAL__
3818 // The following code will result in all window-less widgets
3819 // being redrawn because the wxWindows class is allowed to
3820 // paint over the window-less widgets.
3822 GList
*children
= pizza
->children
;
3825 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3826 children
= children
->next
;
3828 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3829 GTK_WIDGET_DRAWABLE (child
->widget
))
3831 // Get intersection of widget area and update region
3832 wxRegion
region( m_updateRegion
);
3834 GdkEventExpose gdk_event
;
3835 gdk_event
.type
= GDK_EXPOSE
;
3836 gdk_event
.window
= pizza
->bin_window
;
3837 gdk_event
.count
= 0;
3839 wxRegionIterator
upd( m_updateRegion
);
3843 rect
.x
= upd
.GetX();
3844 rect
.y
= upd
.GetY();
3845 rect
.width
= upd
.GetWidth();
3846 rect
.height
= upd
.GetHeight();
3848 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3850 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3860 m_updateRegion
.Clear();
3863 void wxWindowGTK::Clear()
3865 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3868 if (m_wxwindow
&& m_wxwindow
->window
)
3870 m_clearRegion
.Clear();
3871 wxSize
size( GetClientSize() );
3872 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
3874 // Better do this in idle?
3881 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3883 wxWindowBase::DoSetToolTip(tip
);
3886 m_tooltip
->Apply( (wxWindow
*)this );
3889 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3891 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3893 #endif // wxUSE_TOOLTIPS
3895 void wxWindowGTK::GtkSetBackgroundColour( const wxColour
&colour
)
3897 GdkWindow
*window
= (GdkWindow
*) NULL
;
3899 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3901 window
= GetConnectWidget()->window
;
3905 // We need the pixel value e.g. for background clearing.
3906 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3910 // wxMSW doesn't clear the window here, either.
3911 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3917 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3919 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3921 if (!wxWindowBase::SetBackgroundColour(colour
))
3924 GdkWindow
*window
= (GdkWindow
*) NULL
;
3926 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3928 window
= GetConnectWidget()->window
;
3932 // indicate that a new style has been set
3933 // but it couldn't get applied as the
3934 // widget hasn't been realized yet.
3935 m_delayedBackgroundColour
= TRUE
;
3940 GtkSetBackgroundColour( colour
);
3946 void wxWindowGTK::GtkSetForegroundColour( const wxColour
&colour
)
3948 GdkWindow
*window
= (GdkWindow
*) NULL
;
3950 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3952 window
= GetConnectWidget()->window
;
3959 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3961 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3963 if (!wxWindowBase::SetForegroundColour(colour
))
3965 // don't leave if the GTK widget has just
3967 if (!m_delayedForegroundColour
) return FALSE
;
3970 GdkWindow
*window
= (GdkWindow
*) NULL
;
3972 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3974 window
= GetConnectWidget()->window
;
3978 // indicate that a new style has been set
3979 // but it couldn't get applied as the
3980 // widget hasn't been realized yet.
3981 m_delayedForegroundColour
= TRUE
;
3985 GtkSetForegroundColour( colour
);
3992 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3994 return gtk_widget_get_pango_context( m_widget
);
3997 PangoContext
*wxWindowGTK::GtkGetPangoX11Context()
4000 m_x11Context
= pango_x_get_context( gdk_display
);
4002 return m_x11Context
;
4006 GtkStyle
*wxWindowGTK::GetWidgetStyle()
4010 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
4012 // FIXME: no more klass in 2.0
4014 remake
->klass
= m_widgetStyle
->klass
;
4017 gtk_style_unref( m_widgetStyle
);
4018 m_widgetStyle
= remake
;
4022 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4025 def
= gtk_widget_get_default_style();
4027 m_widgetStyle
= gtk_style_copy( def
);
4029 // FIXME: no more klass in 2.0
4031 m_widgetStyle
->klass
= def
->klass
;
4035 return m_widgetStyle
;
4038 void wxWindowGTK::SetWidgetStyle()
4040 #if DISABLE_STYLE_IF_BROKEN_THEME
4041 if (m_widget
->style
->engine_data
)
4043 static bool s_warningPrinted
= FALSE
;
4044 if (!s_warningPrinted
)
4046 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
4047 s_warningPrinted
= TRUE
;
4049 m_widgetStyle
= m_widget
->style
;
4054 GtkStyle
*style
= GetWidgetStyle();
4056 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
4059 pango_font_description_free( style
->font_desc
);
4060 style
->font_desc
= pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
4062 gdk_font_unref( style
->font
);
4063 style
->font
= gdk_font_ref( m_font
.GetInternalFont( 1.0 ) );
4067 if (m_foregroundColour
.Ok())
4069 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
4070 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
4072 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
4073 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
4074 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
4078 // Try to restore the gtk default style. This is still a little
4079 // oversimplified for what is probably really needed here for controls
4080 // other than buttons, but is better than not being able to (re)set a
4081 // control's foreground colour to *wxBLACK -- RL
4082 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4085 def
= gtk_widget_get_default_style();
4087 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
4088 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
4089 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
4093 if (m_backgroundColour
.Ok())
4095 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
4096 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
4098 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
4099 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
4100 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
4101 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
4102 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
4103 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
4104 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
4105 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
4109 // Try to restore the gtk default style. This is still a little
4110 // oversimplified for what is probably really needed here for controls
4111 // other than buttons, but is better than not being able to (re)set a
4112 // control's background colour to default grey and means resetting a
4113 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
4115 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4118 def
= gtk_widget_get_default_style();
4120 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
4121 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
4122 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
4123 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
4124 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
4125 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
4126 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
4127 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
4132 void wxWindowGTK::ApplyWidgetStyle()
4136 //-----------------------------------------------------------------------------
4137 // Pop-up menu stuff
4138 //-----------------------------------------------------------------------------
4140 #if wxUSE_MENUS_NATIVE
4143 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
4145 *is_waiting
= FALSE
;
4148 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
4150 menu
->SetInvokingWindow( win
);
4151 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
4154 wxMenuItem
*menuitem
= node
->GetData();
4155 if (menuitem
->IsSubMenu())
4157 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
4160 node
= node
->GetNext();
4164 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
4165 // wxPopupMenuPositionCallback()
4167 // should be safe even in the MT case as the user can hardly popup 2 menus
4168 // simultaneously, can he?
4169 static gint gs_pop_x
= 0;
4170 static gint gs_pop_y
= 0;
4172 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
4175 gboolean
* WXUNUSED(whatever
),
4177 gpointer
WXUNUSED(user_data
) )
4179 // ensure that the menu appears entirely on screen
4181 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
4183 wxSize sizeScreen
= wxGetDisplaySize();
4185 gint xmax
= sizeScreen
.x
- req
.width
,
4186 ymax
= sizeScreen
.y
- req
.height
;
4188 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
4189 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
4192 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4194 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4196 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
4198 SetInvokingWindow( menu
, this );
4204 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
4206 bool is_waiting
= TRUE
;
4208 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
4210 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
4211 (gpointer
)&is_waiting
);
4214 GTK_MENU(menu
->m_menu
),
4215 (GtkWidget
*) NULL
, // parent menu shell
4216 (GtkWidget
*) NULL
, // parent menu item
4217 wxPopupMenuPositionCallback
, // function to position it
4218 NULL
, // client data
4219 0, // button used to activate it
4220 gs_timeLastClick
// the time of activation
4225 gtk_main_iteration();
4231 #endif // wxUSE_MENUS_NATIVE
4233 #if wxUSE_DRAG_AND_DROP
4235 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4237 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4239 GtkWidget
*dnd_widget
= GetConnectWidget();
4241 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4243 if (m_dropTarget
) delete m_dropTarget
;
4244 m_dropTarget
= dropTarget
;
4246 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4249 #endif // wxUSE_DRAG_AND_DROP
4251 GtkWidget
* wxWindowGTK::GetConnectWidget()
4253 GtkWidget
*connect_widget
= m_widget
;
4254 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4256 return connect_widget
;
4259 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4262 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4264 return (window
== m_widget
->window
);
4267 bool wxWindowGTK::SetFont( const wxFont
&font
)
4269 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4271 if (!wxWindowBase::SetFont(font
))
4276 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
4277 if ( sysbg
== m_backgroundColour
)
4279 m_backgroundColour
= wxNullColour
;
4281 m_backgroundColour
= sysbg
;
4291 void wxWindowGTK::DoCaptureMouse()
4293 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4295 GdkWindow
*window
= (GdkWindow
*) NULL
;
4297 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4299 window
= GetConnectWidget()->window
;
4301 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4303 wxCursor
* cursor
= & m_cursor
;
4305 cursor
= wxSTANDARD_CURSOR
;
4307 gdk_pointer_grab( window
, FALSE
,
4309 (GDK_BUTTON_PRESS_MASK
|
4310 GDK_BUTTON_RELEASE_MASK
|
4311 GDK_POINTER_MOTION_HINT_MASK
|
4312 GDK_POINTER_MOTION_MASK
),
4314 cursor
->GetCursor(),
4315 (guint32
)GDK_CURRENT_TIME
);
4316 g_captureWindow
= this;
4317 g_captureWindowHasMouse
= TRUE
;
4320 void wxWindowGTK::DoReleaseMouse()
4322 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4324 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4326 g_captureWindow
= (wxWindowGTK
*) NULL
;
4328 GdkWindow
*window
= (GdkWindow
*) NULL
;
4330 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4332 window
= GetConnectWidget()->window
;
4337 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4341 wxWindow
*wxWindowBase::GetCapture()
4343 return (wxWindow
*)g_captureWindow
;
4346 bool wxWindowGTK::IsRetained() const
4351 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4352 int range
, bool refresh
)
4354 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4356 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4358 m_hasScrolling
= TRUE
;
4360 if (orient
== wxHORIZONTAL
)
4362 float fpos
= (float)pos
;
4363 float frange
= (float)range
;
4364 float fthumb
= (float)thumbVisible
;
4365 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4366 if (fpos
< 0.0) fpos
= 0.0;
4368 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4369 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4371 SetScrollPos( orient
, pos
, refresh
);
4375 m_oldHorizontalPos
= fpos
;
4377 m_hAdjust
->lower
= 0.0;
4378 m_hAdjust
->upper
= frange
;
4379 m_hAdjust
->value
= fpos
;
4380 m_hAdjust
->step_increment
= 1.0;
4381 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4382 m_hAdjust
->page_size
= fthumb
;
4386 float fpos
= (float)pos
;
4387 float frange
= (float)range
;
4388 float fthumb
= (float)thumbVisible
;
4389 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4390 if (fpos
< 0.0) fpos
= 0.0;
4392 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4393 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4395 SetScrollPos( orient
, pos
, refresh
);
4399 m_oldVerticalPos
= fpos
;
4401 m_vAdjust
->lower
= 0.0;
4402 m_vAdjust
->upper
= frange
;
4403 m_vAdjust
->value
= fpos
;
4404 m_vAdjust
->step_increment
= 1.0;
4405 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4406 m_vAdjust
->page_size
= fthumb
;
4409 if (orient
== wxHORIZONTAL
)
4410 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4412 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4415 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4417 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4419 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4421 if (orient
== wxHORIZONTAL
)
4423 float fpos
= (float)pos
;
4424 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4425 if (fpos
< 0.0) fpos
= 0.0;
4426 m_oldHorizontalPos
= fpos
;
4428 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4429 m_hAdjust
->value
= fpos
;
4433 float fpos
= (float)pos
;
4434 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4435 if (fpos
< 0.0) fpos
= 0.0;
4436 m_oldVerticalPos
= fpos
;
4438 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4439 m_vAdjust
->value
= fpos
;
4442 if (m_wxwindow
->window
)
4444 if (orient
== wxHORIZONTAL
)
4446 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4447 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4449 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4451 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4452 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4456 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4457 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4459 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4461 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4462 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4467 int wxWindowGTK::GetScrollThumb( int orient
) const
4469 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4471 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4473 if (orient
== wxHORIZONTAL
)
4474 return (int)(m_hAdjust
->page_size
+0.5);
4476 return (int)(m_vAdjust
->page_size
+0.5);
4479 int wxWindowGTK::GetScrollPos( int orient
) const
4481 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4483 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4485 if (orient
== wxHORIZONTAL
)
4486 return (int)(m_hAdjust
->value
+0.5);
4488 return (int)(m_vAdjust
->value
+0.5);
4491 int wxWindowGTK::GetScrollRange( int orient
) const
4493 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4495 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4497 if (orient
== wxHORIZONTAL
)
4498 return (int)(m_hAdjust
->upper
+0.5);
4500 return (int)(m_vAdjust
->upper
+0.5);
4503 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4505 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4507 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4509 // No scrolling requested.
4510 if ((dx
== 0) && (dy
== 0)) return;
4513 if (!m_updateRegion
.IsEmpty())
4515 m_updateRegion
.Offset( dx
, dy
);
4519 GetClientSize( &cw
, &ch
);
4520 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4523 if (!m_clearRegion
.IsEmpty())
4525 m_clearRegion
.Offset( dx
, dy
);
4529 GetClientSize( &cw
, &ch
);
4530 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4534 m_clipPaintRegion
= TRUE
;
4536 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4538 m_clipPaintRegion
= FALSE
;
4542 // Find the wxWindow at the current mouse position, also returning the mouse
4544 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4546 pt
= wxGetMousePosition();
4547 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4551 // Get the current mouse position.
4552 wxPoint
wxGetMousePosition()
4554 /* This crashes when used within wxHelpContext,
4555 so we have to use the X-specific implementation below.
4557 GdkModifierType *mask;
4558 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4560 return wxPoint(x, y);
4564 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4566 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4567 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4568 Window rootReturn
, childReturn
;
4569 int rootX
, rootY
, winX
, winY
;
4570 unsigned int maskReturn
;
4572 XQueryPointer (display
,
4576 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4577 return wxPoint(rootX
, rootY
);
4581 // ----------------------------------------------------------------------------
4583 // ----------------------------------------------------------------------------
4585 class wxWinModule
: public wxModule
4592 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4595 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4597 bool wxWinModule::OnInit()
4599 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4600 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4605 void wxWinModule::OnExit()
4608 gdk_gc_unref( g_eraseGC
);