1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
12 #pragma implementation "window.h"
15 // For compilers that support precompilation, includes "wx.h".
16 #include "wx/wxprec.h"
19 #define XWarpPointer XWARPPOINTER
22 #include "wx/window.h"
23 #include "wx/dcclient.h"
26 #include "wx/layout.h"
28 #include "wx/dialog.h"
29 #include "wx/msgdlg.h"
30 #include "wx/module.h"
32 #if wxUSE_DRAG_AND_DROP
37 #include "wx/tooltip.h"
45 #include "wx/textctrl.h"
49 #include "wx/statusbr.h"
51 #include "wx/settings.h"
53 #include "wx/fontutil.h"
56 #include "wx/thread.h"
62 #include "wx/gtk/private.h"
63 #include <gdk/gdkprivate.h>
64 #include <gdk/gdkkeysyms.h>
68 #include <gtk/gtkprivate.h>
70 #include "wx/gtk/win_gtk.h"
73 #include <pango/pangox.h>
84 extern GtkContainerClass
*pizza_parent_class
;
87 //-----------------------------------------------------------------------------
88 // documentation on internals
89 //-----------------------------------------------------------------------------
92 I have been asked several times about writing some documentation about
93 the GTK port of wxWidgets, especially its internal structures. Obviously,
94 you cannot understand wxGTK without knowing a little about the GTK, but
95 some more information about what the wxWindow, which is the base class
96 for all other window classes, does seems required as well.
100 What does wxWindow do? It contains the common interface for the following
101 jobs of its descendants:
103 1) Define the rudimentary behaviour common to all window classes, such as
104 resizing, intercepting user input (so as to make it possible to use these
105 events for special purposes in a derived class), window names etc.
107 2) Provide the possibility to contain and manage children, if the derived
108 class is allowed to contain children, which holds true for those window
109 classes which do not display a native GTK widget. To name them, these
110 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
111 work classes are a special case and are handled a bit differently from
112 the rest. The same holds true for the wxNotebook class.
114 3) Provide the possibility to draw into a client area of a window. This,
115 too, only holds true for classes that do not display a native GTK widget
118 4) Provide the entire mechanism for scrolling widgets. This actual inter-
119 face for this is usually in wxScrolledWindow, but the GTK implementation
122 5) A multitude of helper or extra methods for special purposes, such as
123 Drag'n'Drop, managing validators etc.
125 6) Display a border (sunken, raised, simple or none).
127 Normally one might expect, that one wxWidgets window would always correspond
128 to one GTK widget. Under GTK, there is no such allround widget that has all
129 the functionality. Moreover, the GTK defines a client area as a different
130 widget from the actual widget you are handling. Last but not least some
131 special classes (e.g. wxFrame) handle different categories of widgets and
132 still have the possibility to draw something in the client area.
133 It was therefore required to write a special purpose GTK widget, that would
134 represent a client area in the sense of wxWidgets capable to do the jobs
135 2), 3) and 4). I have written this class and it resides in win_gtk.c of
138 All windows must have a widget, with which they interact with other under-
139 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
140 thw wxWindow class has a member variable called m_widget which holds a
141 pointer to this widget. When the window class represents a GTK native widget,
142 this is (in most cases) the only GTK widget the class manages. E.g. the
143 wxStaticText class handles only a GtkLabel widget a pointer to which you
144 can find in m_widget (defined in wxWindow)
146 When the class has a client area for drawing into and for containing children
147 it has to handle the client area widget (of the type GtkPizza, defined in
148 win_gtk.c), but there could be any number of widgets, handled by a class
149 The common rule for all windows is only, that the widget that interacts with
150 the rest of GTK must be referenced in m_widget and all other widgets must be
151 children of this widget on the GTK level. The top-most widget, which also
152 represents the client area, must be in the m_wxwindow field and must be of
155 As I said, the window classes that display a GTK native widget only have
156 one widget, so in the case of e.g. the wxButton class m_widget holds a
157 pointer to a GtkButton widget. But windows with client areas (for drawing
158 and children) have a m_widget field that is a pointer to a GtkScrolled-
159 Window and a m_wxwindow field that is pointer to a GtkPizza and this
160 one is (in the GTK sense) a child of the GtkScrolledWindow.
162 If the m_wxwindow field is set, then all input to this widget is inter-
163 cepted and sent to the wxWidgets class. If not, all input to the widget
164 that gets pointed to by m_widget gets intercepted and sent to the class.
168 The design of scrolling in wxWidgets is markedly different from that offered
169 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
170 clicking on a scrollbar belonging to scrolled window will inevitably move
171 the window. In wxWidgets, the scrollbar will only emit an event, send this
172 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
173 which actually moves the window and its subchildren. Note that GtkPizza
174 memorizes how much it has been scrolled but that wxWidgets forgets this
175 so that the two coordinates systems have to be kept in synch. This is done
176 in various places using the pizza->xoffset and pizza->yoffset values.
180 Singularily the most broken code in GTK is the code that is supposes to
181 inform subwindows (child windows) about new positions. Very often, duplicate
182 events are sent without changes in size or position, equally often no
183 events are sent at all (All this is due to a bug in the GtkContainer code
184 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
185 GTK's own system and it simply waits for size events for toplevel windows
186 and then iterates down the respective size events to all window. This has
187 the disadvantage, that windows might get size events before the GTK widget
188 actually has the reported size. This doesn't normally pose any problem, but
189 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
190 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
191 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
192 window that is used for OpenGl output really has that size (as reported by
197 If someone at some point of time feels the immense desire to have a look at,
198 change or attempt to optimse the Refresh() logic, this person will need an
199 intimate understanding of what a "draw" and what an "expose" events are and
200 what there are used for, in particular when used in connection with GTK's
201 own windowless widgets. Beware.
205 Cursors, too, have been a constant source of pleasure. The main difficulty
206 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
207 for the parent. To prevent this from doing too much harm, I use idle time
208 to set the cursor over and over again, starting from the toplevel windows
209 and ending with the youngest generation (speaking of parent and child windows).
210 Also don't forget that cursors (like much else) are connected to GdkWindows,
211 not GtkWidgets and that the "window" field of a GtkWidget might very well
212 point to the GdkWindow of the parent widget (-> "window less widget") and
213 that the two obviously have very different meanings.
217 //-----------------------------------------------------------------------------
219 //-----------------------------------------------------------------------------
221 extern wxList wxPendingDelete
;
222 extern bool g_blockEventsOnDrag
;
223 extern bool g_blockEventsOnScroll
;
224 extern wxCursor g_globalCursor
;
226 static GdkGC
*g_eraseGC
= NULL
;
228 // mouse capture state: the window which has it and if the mouse is currently
230 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
231 static bool g_captureWindowHasMouse
= FALSE
;
233 wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
235 // the last window which had the focus - this is normally never NULL (except
236 // if we never had focus at all) as even when g_focusWindow is NULL it still
237 // keeps its previous value
238 wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
240 // If a window get the focus set but has not been realized
241 // yet, defer setting the focus to idle time.
242 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
244 // hack: we need something to pass to gtk_menu_popup, so we store the time of
245 // the last click here
246 static guint32 gs_timeLastClick
= 0;
248 extern bool g_mainThreadLocked
;
250 //-----------------------------------------------------------------------------
252 //-----------------------------------------------------------------------------
257 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
259 # define DEBUG_MAIN_THREAD
262 #define DEBUG_MAIN_THREAD
265 // the trace mask used for the focus debugging messages
266 #define TRACE_FOCUS _T("focus")
268 //-----------------------------------------------------------------------------
269 // missing gdk functions
270 //-----------------------------------------------------------------------------
273 gdk_window_warp_pointer (GdkWindow
*window
,
278 GdkWindowPrivate
*priv
;
282 window
= GDK_ROOT_PARENT();
285 if (!GDK_WINDOW_DESTROYED(window
))
287 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
288 None
, /* not source window -> move from anywhere */
289 GDK_WINDOW_XID(window
), /* dest window */
290 0, 0, 0, 0, /* not source window -> move from anywhere */
294 priv
= (GdkWindowPrivate
*) window
;
296 if (!priv
->destroyed
)
298 XWarpPointer (priv
->xdisplay
,
299 None
, /* not source window -> move from anywhere */
300 priv
->xwindow
, /* dest window */
301 0, 0, 0, 0, /* not source window -> move from anywhere */
307 //-----------------------------------------------------------------------------
309 //-----------------------------------------------------------------------------
311 extern void wxapp_install_idle_handler();
312 extern bool g_isIdle
;
314 //-----------------------------------------------------------------------------
315 // local code (see below)
316 //-----------------------------------------------------------------------------
318 // returns the child of win which currently has focus or NULL if not found
320 // Note: can't be static, needed by textctrl.cpp.
321 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
323 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
325 return (wxWindow
*)NULL
;
327 if ( winFocus
== win
)
328 return (wxWindow
*)win
;
330 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
332 node
= node
->GetNext() )
334 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
339 return (wxWindow
*)NULL
;
342 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
344 // wxUniversal widgets draw the borders and scrollbars themselves
345 #ifndef __WXUNIVERSAL__
352 if (win
->m_hasScrolling
)
354 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
356 GtkRequisition vscroll_req
;
357 vscroll_req
.width
= 2;
358 vscroll_req
.height
= 2;
359 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
360 (scroll_window
->vscrollbar
, &vscroll_req
);
362 GtkRequisition hscroll_req
;
363 hscroll_req
.width
= 2;
364 hscroll_req
.height
= 2;
365 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
366 (scroll_window
->hscrollbar
, &hscroll_req
);
368 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
370 if (scroll_window
->vscrollbar_visible
)
372 dw
+= vscroll_req
.width
;
373 dw
+= scroll_class
->scrollbar_spacing
;
376 if (scroll_window
->hscrollbar_visible
)
378 dh
+= hscroll_req
.height
;
379 dh
+= scroll_class
->scrollbar_spacing
;
385 if (GTK_WIDGET_NO_WINDOW (widget
))
387 dx
+= widget
->allocation
.x
;
388 dy
+= widget
->allocation
.y
;
391 if (win
->HasFlag(wxRAISED_BORDER
))
393 gtk_draw_shadow( widget
->style
,
398 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
402 if (win
->HasFlag(wxSUNKEN_BORDER
))
404 gtk_draw_shadow( widget
->style
,
409 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
413 if (win
->HasFlag(wxSIMPLE_BORDER
))
416 gc
= gdk_gc_new( widget
->window
);
417 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
418 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
420 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
424 #endif // __WXUNIVERSAL__
427 //-----------------------------------------------------------------------------
428 // "expose_event" of m_widget
429 //-----------------------------------------------------------------------------
431 gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
433 if (gdk_event
->count
> 0) return FALSE
;
435 draw_frame( widget
, win
);
439 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
445 //-----------------------------------------------------------------------------
446 // "draw" of m_widget
447 //-----------------------------------------------------------------------------
451 static void gtk_window_own_draw_callback( GtkWidget
*widget
, GdkRectangle
*WXUNUSED(rect
), wxWindowGTK
*win
)
453 draw_frame( widget
, win
);
458 //-----------------------------------------------------------------------------
459 // "size_request" of m_widget
460 //-----------------------------------------------------------------------------
462 // make it extern because wxStatitText needs to disconnect this one
464 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
465 GtkRequisition
*requisition
,
469 win
->GetSize( &w
, &h
);
475 requisition
->height
= h
;
476 requisition
->width
= w
;
479 //-----------------------------------------------------------------------------
480 // "expose_event" of m_wxwindow
481 //-----------------------------------------------------------------------------
483 static int gtk_window_expose_callback( GtkWidget
*widget
,
484 GdkEventExpose
*gdk_event
,
490 wxapp_install_idle_handler();
493 // This callback gets called in drawing-idle time under
494 // GTK 2.0, so we don't need to defer anything to idle
497 GtkPizza
*pizza
= GTK_PIZZA( widget
);
498 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
503 wxPrintf( wxT("OnExpose from ") );
504 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
505 wxPrintf( win
->GetClassInfo()->GetClassName() );
506 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
507 (int)gdk_event
->area
.y
,
508 (int)gdk_event
->area
.width
,
509 (int)gdk_event
->area
.height
);
514 win
->m_wxwindow
->style
,
518 (GdkRectangle
*) NULL
,
520 (char *)"button", // const_cast
525 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
527 win
->GtkSendPaintEvents();
530 // Let parent window draw window less widgets
531 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
533 // This gets called immediately after an expose event
534 // under GTK 1.2 so we collect the calls and wait for
535 // the idle handler to pick things up.
537 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
539 gdk_event
->area
.width
,
540 gdk_event
->area
.height
);
541 win
->m_clearRegion
.Union( gdk_event
->area
.x
,
543 gdk_event
->area
.width
,
544 gdk_event
->area
.height
);
546 // Actual redrawing takes place in idle time.
553 //-----------------------------------------------------------------------------
554 // "event" of m_wxwindow
555 //-----------------------------------------------------------------------------
557 // GTK thinks it is clever and filters out a certain amount of "unneeded"
558 // expose events. We need them, of course, so we override the main event
559 // procedure in GtkWidget by giving our own handler for all system events.
560 // There, we look for expose events ourselves whereas all other events are
563 gint
gtk_window_event_event_callback( GtkWidget
*widget
,
564 GdkEventExpose
*event
,
567 if (event
->type
== GDK_EXPOSE
)
569 gint ret
= gtk_window_expose_callback( widget
, event
, win
);
576 //-----------------------------------------------------------------------------
577 // "draw" of m_wxwindow
578 //-----------------------------------------------------------------------------
582 // This callback is a complete replacement of the gtk_pizza_draw() function,
583 // which is disabled.
585 static void gtk_window_draw_callback( GtkWidget
*widget
,
592 wxapp_install_idle_handler();
594 // if there are any children we must refresh everything
597 if ( !win
->HasFlag(wxFULL_REPAINT_ON_RESIZE
) &&
598 win
->GetChildren().IsEmpty() )
606 wxPrintf( wxT("OnDraw from ") );
607 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
608 wxPrintf( win
->GetClassInfo()->GetClassName() );
609 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect
->x
,
616 #ifndef __WXUNIVERSAL__
617 GtkPizza
*pizza
= GTK_PIZZA (widget
);
619 if (win
->GetThemeEnabled() && win
->GetBackgroundStyle() == wxBG_STYLE_SYSTEM
)
621 wxWindow
*parent
= win
->GetParent();
622 while (parent
&& !parent
->IsTopLevel())
623 parent
= parent
->GetParent();
627 gtk_paint_flat_box (parent
->m_widget
->style
,
638 win
->m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
639 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
641 // Update immediately, not in idle time.
644 #ifndef __WXUNIVERSAL__
645 // Redraw child widgets
646 GList
*children
= pizza
->children
;
649 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
650 children
= children
->next
;
652 GdkRectangle child_area
;
653 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
655 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
663 //-----------------------------------------------------------------------------
664 // "key_press_event" from any window
665 //-----------------------------------------------------------------------------
667 // set WXTRACE to this to see the key event codes on the console
668 #define TRACE_KEYS _T("keyevent")
670 // translates an X key symbol to WXK_XXX value
672 // if isChar is true it means that the value returned will be used for EVT_CHAR
673 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
674 // for example, while if it is false it means that the value is going to be
675 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
677 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
683 // Shift, Control and Alt don't generate the CHAR events at all
686 key_code
= isChar
? 0 : WXK_SHIFT
;
690 key_code
= isChar
? 0 : WXK_CONTROL
;
698 key_code
= isChar
? 0 : WXK_ALT
;
701 // neither do the toggle modifies
702 case GDK_Scroll_Lock
:
703 key_code
= isChar
? 0 : WXK_SCROLL
;
707 key_code
= isChar
? 0 : WXK_CAPITAL
;
711 key_code
= isChar
? 0 : WXK_NUMLOCK
;
715 // various other special keys
728 case GDK_ISO_Left_Tab
:
735 key_code
= WXK_RETURN
;
739 key_code
= WXK_CLEAR
;
743 key_code
= WXK_PAUSE
;
747 key_code
= WXK_SELECT
;
751 key_code
= WXK_PRINT
;
755 key_code
= WXK_EXECUTE
;
759 key_code
= WXK_ESCAPE
;
762 // cursor and other extended keyboard keys
764 key_code
= WXK_DELETE
;
780 key_code
= WXK_RIGHT
;
787 case GDK_Prior
: // == GDK_Page_Up
788 key_code
= WXK_PRIOR
;
791 case GDK_Next
: // == GDK_Page_Down
804 key_code
= WXK_INSERT
;
819 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
823 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
827 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
831 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
835 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
839 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
843 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
847 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
851 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
855 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
859 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
863 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
867 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
870 case GDK_KP_Prior
: // == GDK_KP_Page_Up
871 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
874 case GDK_KP_Next
: // == GDK_KP_Page_Down
875 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
879 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
883 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
887 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
891 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
895 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
898 case GDK_KP_Multiply
:
899 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
903 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
906 case GDK_KP_Separator
:
907 // FIXME: what is this?
908 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
911 case GDK_KP_Subtract
:
912 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
916 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
920 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
937 key_code
= WXK_F1
+ keysym
- GDK_F1
;
947 static inline bool wxIsAsciiKeysym(KeySym ks
)
952 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
954 GdkEventKey
*gdk_event
)
958 GdkModifierType state
;
959 if (gdk_event
->window
)
960 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
962 event
.SetTimestamp( gdk_event
->time
);
963 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
964 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
965 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
966 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
967 event
.m_scanCode
= gdk_event
->keyval
;
968 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
969 event
.m_rawFlags
= 0;
971 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
975 event
.SetEventObject( win
);
980 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
982 GdkEventKey
*gdk_event
)
984 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
985 // but only event->keyval which is quite useless to us, so remember
986 // the last character from GDK_KEY_PRESS and reuse it as last resort
988 // NB: should be MT-safe as we're always called from the main thread only
993 } s_lastKeyPress
= { 0, 0 };
995 KeySym keysym
= gdk_event
->keyval
;
997 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
998 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
1002 long key_code
= wxTranslateKeySymToWXKey(keysym
, FALSE
/* !isChar */);
1006 // do we have the translation or is it a plain ASCII character?
1007 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
1009 // we should use keysym if it is ASCII as X does some translations
1010 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
1011 // which we don't want here (but which we do use for OnChar())
1012 if ( !wxIsAsciiKeysym(keysym
) )
1014 keysym
= (KeySym
)gdk_event
->string
[0];
1017 // we want to always get the same key code when the same key is
1018 // pressed regardless of the state of the modifies, i.e. on a
1019 // standard US keyboard pressing '5' or '%' ('5' key with
1020 // Shift) should result in the same key code in OnKeyDown():
1021 // '5' (although OnChar() will get either '5' or '%').
1023 // to do it we first translate keysym to keycode (== scan code)
1024 // and then back but always using the lower register
1025 Display
*dpy
= (Display
*)wxGetDisplay();
1026 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
1028 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
1030 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
1032 // use the normalized, i.e. lower register, keysym if we've
1034 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
1036 // as explained above, we want to have lower register key codes
1037 // normally but for the letter keys we want to have the upper ones
1039 // NB: don't use XConvertCase() here, we want to do it for letters
1041 key_code
= toupper(key_code
);
1043 else // non ASCII key, what to do?
1045 // by default, ignore it
1048 // but if we have cached information from the last KEY_PRESS
1049 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
1052 if ( keysym
== s_lastKeyPress
.keysym
)
1054 key_code
= s_lastKeyPress
.keycode
;
1059 if ( gdk_event
->type
== GDK_KEY_PRESS
)
1061 // remember it to be reused for KEY_UP event later
1062 s_lastKeyPress
.keysym
= keysym
;
1063 s_lastKeyPress
.keycode
= key_code
;
1067 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
1069 // sending unknown key events doesn't really make sense
1073 // now fill all the other fields
1074 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
1076 event
.m_keyCode
= key_code
;
1085 GtkIMContext
*context
;
1086 GdkEventKey
*lastKeyEvent
;
1090 context
= gtk_im_multicontext_new();
1091 lastKeyEvent
= NULL
;
1095 g_object_unref(context
);
1100 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1101 GdkEventKey
*gdk_event
,
1107 wxapp_install_idle_handler();
1111 if (g_blockEventsOnDrag
)
1115 // We have to pass key press events through GTK+'s Input Method context
1116 // object in order to get correct characters. By doing so, we loose the
1117 // ability to let other GTK+'s handlers (namely, widgets' default signal
1118 // handlers) handle the signal by returning false from this callback.
1119 // Because GTK+ sends the events to parent widgets as well, we can't
1120 // afford loosing it, otherwise native widgets inserted into wxPanel
1121 // would break in subtle ways (e.g. spacebar would no longer toggle
1122 // wxCheckButton's state). Therefore, we only pass the event to IM if it
1123 // originated in this window's widget, which we detect by checking if we've
1124 // seen the same event before (no events from children are lost this way,
1125 // because gtk_window_key_press_callback is installed for native controls
1126 // as well and the wxKeyEvent it creates propagates upwards).
1127 static GdkEventKey s_lastEvent
;
1129 bool useIM
= (win
->m_imData
!= NULL
) &&
1130 memcmp(gdk_event
, &s_lastEvent
, sizeof(GdkEventKey
)) != 0;
1132 s_lastEvent
= *gdk_event
;
1135 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1136 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1138 // unknown key pressed, ignore (the event would be useless anyhow)
1142 // it may be useful for the input method, though:
1143 win
->m_imData
->lastKeyEvent
= gdk_event
;
1144 bool ret
= gtk_im_context_filter_keypress(win
->m_imData
->context
,
1146 win
->m_imData
->lastKeyEvent
= NULL
;
1153 // Emit KEY_DOWN event
1154 bool ret
= win
->GetEventHandler()->ProcessEvent( event
);
1159 wxWindowGTK
*ancestor
= win
;
1162 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1165 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1166 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1169 if (ancestor
->IsTopLevel())
1171 ancestor
= ancestor
->GetParent();
1174 #endif // wxUSE_ACCEL
1176 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1177 // will only be sent if it is not in an accelerator table.
1183 // In GTK 2.0, we need to hand over the key event to an input method
1184 // and the IM will emit a "commit" event containing the actual utf8
1185 // character. In that case the EVT_CHAR events will be sent from
1187 win
->m_imData
->lastKeyEvent
= gdk_event
;
1188 if ( gtk_im_context_filter_keypress(win
->m_imData
->context
,
1191 win
->m_imData
->lastKeyEvent
= NULL
;
1192 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1196 win
->m_imData
->lastKeyEvent
= NULL
;
1201 KeySym keysym
= gdk_event
->keyval
;
1202 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1203 key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1206 if ( gdk_event
->length
== 1 )
1208 key_code
= (unsigned char)gdk_event
->string
[0];
1210 else if ( wxIsAsciiKeysym(keysym
) )
1213 key_code
= (unsigned char)keysym
;
1219 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1221 event
.m_keyCode
= key_code
;
1223 // Implement OnCharHook by checking ancesteror top level windows
1224 wxWindow
*parent
= win
;
1225 while (parent
&& !parent
->IsTopLevel())
1226 parent
= parent
->GetParent();
1229 event
.SetEventType( wxEVT_CHAR_HOOK
);
1230 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1235 event
.SetEventType(wxEVT_CHAR
);
1236 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1241 // win is a control: tab can be propagated up
1243 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1244 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1245 // have this style, yet choose not to process this particular TAB in which
1246 // case TAB must still work as a navigational character
1247 // JS: enabling again to make consistent with other platforms
1248 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1249 // navigation behaviour)
1251 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1253 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1255 wxNavigationKeyEvent new_event
;
1256 new_event
.SetEventObject( win
->GetParent() );
1257 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1258 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1259 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1260 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1261 new_event
.SetCurrentFocus( win
);
1262 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1265 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1267 (gdk_event
->keyval
== GDK_Escape
) )
1269 // however only do it if we have a Cancel button in the dialog,
1270 // otherwise the user code may get confused by the events from a
1271 // non-existing button and, worse, a wxButton might get button event
1272 // from another button which is not really expected
1273 wxWindow
*winForCancel
= win
,
1275 while ( winForCancel
)
1277 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1280 // found a cancel button
1284 if ( winForCancel
->IsTopLevel() )
1286 // no need to look further
1290 // maybe our parent has a cancel button?
1291 winForCancel
= winForCancel
->GetParent();
1296 wxCommandEvent
event(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1297 event
.SetEventObject(btnCancel
);
1298 ret
= btnCancel
->GetEventHandler()->ProcessEvent(event
);
1304 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1312 static void gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1316 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1318 // take modifiers, cursor position, timestamp etc. from the last
1319 // key_press_event that was fed into Input Method:
1320 if (window
->m_imData
->lastKeyEvent
)
1322 wxFillOtherKeyEventFields(event
,
1323 window
, window
->m_imData
->lastKeyEvent
);
1327 const wxWCharBuffer data
= wxConvUTF8
.cMB2WC( (char*)str
);
1329 const wxWCharBuffer wdata
= wxConvUTF8
.cMB2WC( (char*)str
);
1330 const wxCharBuffer data
= wxConvLocal
.cWC2MB( wdata
);
1331 #endif // wxUSE_UNICODE
1332 if( !(const wxChar
*)data
)
1337 // Implement OnCharHook by checking ancestor top level windows
1338 wxWindow
*parent
= window
;
1339 while (parent
&& !parent
->IsTopLevel())
1340 parent
= parent
->GetParent();
1342 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1345 event
.m_uniChar
= *pstr
;
1346 // Backward compatible for ISO-8859
1347 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1348 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1350 event
.m_keyCode
= *pstr
;
1351 #endif // wxUSE_UNICODE
1354 event
.SetEventType( wxEVT_CHAR_HOOK
);
1355 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1360 event
.SetEventType(wxEVT_CHAR
);
1361 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1368 //-----------------------------------------------------------------------------
1369 // "key_release_event" from any window
1370 //-----------------------------------------------------------------------------
1372 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1373 GdkEventKey
*gdk_event
,
1379 wxapp_install_idle_handler();
1384 if (g_blockEventsOnDrag
)
1387 wxKeyEvent
event( wxEVT_KEY_UP
);
1388 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1390 // unknown key pressed, ignore (the event would be useless anyhow
1394 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1397 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1401 // ============================================================================
1403 // ============================================================================
1405 // ----------------------------------------------------------------------------
1406 // mouse event processing helpers
1407 // ----------------------------------------------------------------------------
1409 // init wxMouseEvent with the info from GdkEventXXX struct
1410 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1411 wxMouseEvent
& event
,
1414 event
.SetTimestamp( gdk_event
->time
);
1415 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1416 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1417 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1418 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1419 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1420 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1421 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1422 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1424 event
.m_linesPerAction
= 3;
1425 event
.m_wheelDelta
= 120;
1426 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1427 event
.m_wheelRotation
= 120;
1428 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1429 event
.m_wheelRotation
= -120;
1432 wxPoint pt
= win
->GetClientAreaOrigin();
1433 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1434 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1436 event
.SetEventObject( win
);
1437 event
.SetId( win
->GetId() );
1438 event
.SetTimestamp( gdk_event
->time
);
1441 static void AdjustEventButtonState(wxMouseEvent
& event
)
1443 // GDK reports the old state of the button for a button press event, but
1444 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1445 // for a LEFT_DOWN event, not FALSE, so we will invert
1446 // left/right/middleDown for the corresponding click events
1448 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1449 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1450 (event
.GetEventType() == wxEVT_LEFT_UP
))
1452 event
.m_leftDown
= !event
.m_leftDown
;
1456 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1457 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1458 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1460 event
.m_middleDown
= !event
.m_middleDown
;
1464 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1465 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1466 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1468 event
.m_rightDown
= !event
.m_rightDown
;
1473 // find the window to send the mouse event too
1475 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1480 if (win
->m_wxwindow
)
1482 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1483 xx
+= pizza
->xoffset
;
1484 yy
+= pizza
->yoffset
;
1487 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1490 wxWindowGTK
*child
= node
->GetData();
1492 node
= node
->GetNext();
1493 if (!child
->IsShown())
1496 if (child
->IsTransparentForMouse())
1498 // wxStaticBox is transparent in the box itself
1499 int xx1
= child
->m_x
;
1500 int yy1
= child
->m_y
;
1501 int xx2
= child
->m_x
+ child
->m_width
;
1502 int yy2
= child
->m_y
+ child
->m_height
;
1505 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1507 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1509 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1511 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1522 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1523 (child
->m_x
<= xx
) &&
1524 (child
->m_y
<= yy
) &&
1525 (child
->m_x
+child
->m_width
>= xx
) &&
1526 (child
->m_y
+child
->m_height
>= yy
))
1539 //-----------------------------------------------------------------------------
1540 // "button_press_event"
1541 //-----------------------------------------------------------------------------
1543 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1544 GdkEventButton
*gdk_event
,
1550 wxapp_install_idle_handler();
1553 wxPrintf( wxT("1) OnButtonPress from ") );
1554 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1555 wxPrintf( win->GetClassInfo()->GetClassName() );
1556 wxPrintf( wxT(".\n") );
1558 if (!win
->m_hasVMT
) return FALSE
;
1559 if (g_blockEventsOnDrag
) return TRUE
;
1560 if (g_blockEventsOnScroll
) return TRUE
;
1562 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1564 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1566 gtk_widget_grab_focus( win
->m_wxwindow
);
1568 wxPrintf( wxT("GrabFocus from ") );
1569 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1570 wxPrintf( win->GetClassInfo()->GetClassName() );
1571 wxPrintf( wxT(".\n") );
1575 // GDK sends surplus button down event
1576 // before a double click event. We
1577 // need to filter these out.
1578 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1580 GdkEvent
*peek_event
= gdk_event_peek();
1583 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1584 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1586 gdk_event_free( peek_event
);
1591 gdk_event_free( peek_event
);
1596 wxEventType event_type
= wxEVT_NULL
;
1598 // GdkDisplay is a GTK+ 2.2.0 thing
1599 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1600 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1601 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1603 // Reset GDK internal timestamp variables in order to disable GDK
1604 // triple click events. GDK will then next time believe no button has
1605 // been clicked just before, and send a normal button click event.
1606 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1607 display
->button_click_time
[1] = 0;
1608 display
->button_click_time
[0] = 0;
1612 if (gdk_event
->button
== 1)
1614 // note that GDK generates triple click events which are not supported
1615 // by wxWidgets but still have to be passed to the app as otherwise
1616 // clicks would simply go missing
1617 switch (gdk_event
->type
)
1619 // we shouldn't get triple clicks at all for GTK2 because we
1620 // suppress them artificially using the code above but we still
1621 // should map them to something for GTK1 and not just ignore them
1622 // as this would lose clicks
1623 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1624 case GDK_BUTTON_PRESS
:
1625 event_type
= wxEVT_LEFT_DOWN
;
1628 case GDK_2BUTTON_PRESS
:
1629 event_type
= wxEVT_LEFT_DCLICK
;
1633 // just to silence gcc warnings
1637 else if (gdk_event
->button
== 2)
1639 switch (gdk_event
->type
)
1641 case GDK_3BUTTON_PRESS
:
1642 case GDK_BUTTON_PRESS
:
1643 event_type
= wxEVT_MIDDLE_DOWN
;
1646 case GDK_2BUTTON_PRESS
:
1647 event_type
= wxEVT_MIDDLE_DCLICK
;
1654 else if (gdk_event
->button
== 3)
1656 switch (gdk_event
->type
)
1658 case GDK_3BUTTON_PRESS
:
1659 case GDK_BUTTON_PRESS
:
1660 event_type
= wxEVT_RIGHT_DOWN
;
1663 case GDK_2BUTTON_PRESS
:
1664 event_type
= wxEVT_RIGHT_DCLICK
;
1671 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1673 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1675 event_type
= wxEVT_MOUSEWHEEL
;
1679 if ( event_type
== wxEVT_NULL
)
1681 // unknown mouse button or click type
1685 wxMouseEvent
event( event_type
);
1686 InitMouseEvent( win
, event
, gdk_event
);
1688 AdjustEventButtonState(event
);
1690 // wxListBox actually get mouse events from the item, so we need to give it
1691 // a chance to correct this
1692 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1694 if ( event_type
== wxEVT_RIGHT_DOWN
)
1696 // generate a "context menu" event: this is similar to right mouse
1697 // click under many GUIs except that it is generated differently
1698 // (right up under MSW, ctrl-click under Mac, right down here) and
1700 // (a) it's a command event and so is propagated to the parent
1701 // (b) under MSW it can be generated from kbd too
1702 // (c) it uses screen coords (because of (a))
1703 wxContextMenuEvent
evtCtx(wxEVT_CONTEXT_MENU
,
1705 win
->ClientToScreen(event
.GetPosition()));
1706 (void)win
->GetEventHandler()->ProcessEvent(evtCtx
);
1709 // find the correct window to send the event too: it may be a different one
1710 // from the one which got it at GTK+ level because some control don't have
1711 // their own X window and thus cannot get any events.
1712 if ( !g_captureWindow
)
1713 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1715 gs_timeLastClick
= gdk_event
->time
;
1718 if (event_type
== wxEVT_LEFT_DCLICK
)
1720 // GTK 1.2 crashes when intercepting double
1721 // click events from both wxSpinButton and
1723 if (GTK_IS_SPIN_BUTTON(win
->m_widget
))
1725 // Just disable this event for now.
1731 if (win
->GetEventHandler()->ProcessEvent( event
))
1733 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1740 //-----------------------------------------------------------------------------
1741 // "button_release_event"
1742 //-----------------------------------------------------------------------------
1744 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1745 GdkEventButton
*gdk_event
,
1751 wxapp_install_idle_handler();
1753 if (!win
->m_hasVMT
) return FALSE
;
1754 if (g_blockEventsOnDrag
) return FALSE
;
1755 if (g_blockEventsOnScroll
) return FALSE
;
1757 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1759 wxEventType event_type
= wxEVT_NULL
;
1761 switch (gdk_event
->button
)
1764 event_type
= wxEVT_LEFT_UP
;
1768 event_type
= wxEVT_MIDDLE_UP
;
1772 event_type
= wxEVT_RIGHT_UP
;
1776 // unknwon button, don't process
1780 wxMouseEvent
event( event_type
);
1781 InitMouseEvent( win
, event
, gdk_event
);
1783 AdjustEventButtonState(event
);
1785 // same wxListBox hack as above
1786 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1788 if ( !g_captureWindow
)
1789 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1791 if (win
->GetEventHandler()->ProcessEvent( event
))
1793 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1800 //-----------------------------------------------------------------------------
1801 // "motion_notify_event"
1802 //-----------------------------------------------------------------------------
1804 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1805 GdkEventMotion
*gdk_event
,
1811 wxapp_install_idle_handler();
1813 if (!win
->m_hasVMT
) return FALSE
;
1814 if (g_blockEventsOnDrag
) return FALSE
;
1815 if (g_blockEventsOnScroll
) return FALSE
;
1817 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1819 if (gdk_event
->is_hint
)
1823 GdkModifierType state
;
1824 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1830 printf( "OnMotion from " );
1831 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1832 printf( win->GetClassInfo()->GetClassName() );
1836 wxMouseEvent
event( wxEVT_MOTION
);
1837 InitMouseEvent(win
, event
, gdk_event
);
1839 if ( g_captureWindow
)
1841 // synthetize a mouse enter or leave event if needed
1842 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1843 // This seems to be necessary and actually been added to
1844 // GDK itself in version 2.0.X
1847 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1848 if ( hasMouse
!= g_captureWindowHasMouse
)
1850 // the mouse changed window
1851 g_captureWindowHasMouse
= hasMouse
;
1853 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1854 : wxEVT_LEAVE_WINDOW
);
1855 InitMouseEvent(win
, event
, gdk_event
);
1856 event
.SetEventObject(win
);
1857 win
->GetEventHandler()->ProcessEvent(event
);
1862 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1865 if (win
->GetEventHandler()->ProcessEvent( event
))
1867 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1875 //-----------------------------------------------------------------------------
1876 // "mouse_wheel_event"
1877 //-----------------------------------------------------------------------------
1879 static gint
gtk_window_wheel_callback (GtkWidget
* widget
,
1880 GdkEventScroll
* gdk_event
,
1886 wxapp_install_idle_handler();
1888 wxEventType event_type
= wxEVT_NULL
;
1889 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1890 event_type
= wxEVT_MOUSEWHEEL
;
1891 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1892 event_type
= wxEVT_MOUSEWHEEL
;
1896 wxMouseEvent
event( event_type
);
1897 // Can't use InitMouse macro because scroll events don't have button
1898 event
.SetTimestamp( gdk_event
->time
);
1899 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1900 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1901 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1902 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1903 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1904 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1905 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1906 event
.m_linesPerAction
= 3;
1907 event
.m_wheelDelta
= 120;
1908 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1909 event
.m_wheelRotation
= 120;
1911 event
.m_wheelRotation
= -120;
1913 wxPoint pt
= win
->GetClientAreaOrigin();
1914 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1915 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1917 event
.SetEventObject( win
);
1918 event
.SetId( win
->GetId() );
1919 event
.SetTimestamp( gdk_event
->time
);
1921 if (win
->GetEventHandler()->ProcessEvent( event
))
1923 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "scroll_event" );
1931 //-----------------------------------------------------------------------------
1933 //-----------------------------------------------------------------------------
1935 // send the wxChildFocusEvent and wxFocusEvent, common code of
1936 // gtk_window_focus_in_callback() and SetFocus()
1937 static bool DoSendFocusEvents(wxWindow
*win
)
1939 // Notify the parent keeping track of focus for the kbd navigation
1940 // purposes that we got it.
1941 wxChildFocusEvent
eventChildFocus(win
);
1942 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1944 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1945 eventFocus
.SetEventObject(win
);
1947 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1950 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1951 GdkEvent
*WXUNUSED(event
),
1957 wxapp_install_idle_handler();
1961 gtk_im_context_focus_in(win
->m_imData
->context
);
1965 g_focusWindow
= win
;
1967 wxLogTrace(TRACE_FOCUS
,
1968 _T("%s: focus in"), win
->GetName().c_str());
1972 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1976 // caret needs to be informed about focus change
1977 wxCaret
*caret
= win
->GetCaret();
1980 caret
->OnSetFocus();
1982 #endif // wxUSE_CARET
1984 // does the window itself think that it has the focus?
1985 if ( !win
->m_hasFocus
)
1987 // not yet, notify it
1988 win
->m_hasFocus
= TRUE
;
1990 if ( DoSendFocusEvents(win
) )
1992 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
2000 //-----------------------------------------------------------------------------
2001 // "focus_out_event"
2002 //-----------------------------------------------------------------------------
2004 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
2009 wxapp_install_idle_handler();
2013 gtk_im_context_focus_out(win
->m_imData
->context
);
2016 wxLogTrace( TRACE_FOCUS
,
2017 _T("%s: focus out"), win
->GetName().c_str() );
2020 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
2024 g_focusWindow
= (wxWindowGTK
*)NULL
;
2032 // caret needs to be informed about focus change
2033 wxCaret
*caret
= win
->GetCaret();
2036 caret
->OnKillFocus();
2038 #endif // wxUSE_CARET
2040 // don't send the window a kill focus event if it thinks that it doesn't
2041 // have focus already
2042 if ( win
->m_hasFocus
)
2044 win
->m_hasFocus
= FALSE
;
2046 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
2047 event
.SetEventObject( win
);
2049 // even if we did process the event in wx code, still let GTK itself
2050 // process it too as otherwise bad things happen, especially in GTK2
2051 // where the text control simply aborts the program if it doesn't get
2052 // the matching focus out event
2053 (void)win
->GetEventHandler()->ProcessEvent( event
);
2059 //-----------------------------------------------------------------------------
2060 // "enter_notify_event"
2061 //-----------------------------------------------------------------------------
2064 gint
gtk_window_enter_callback( GtkWidget
*widget
,
2065 GdkEventCrossing
*gdk_event
,
2071 wxapp_install_idle_handler();
2073 if (!win
->m_hasVMT
) return FALSE
;
2074 if (g_blockEventsOnDrag
) return FALSE
;
2076 // Event was emitted after a grab
2077 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2079 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2083 GdkModifierType state
= (GdkModifierType
)0;
2085 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2087 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2088 InitMouseEvent(win
, event
, gdk_event
);
2089 wxPoint pt
= win
->GetClientAreaOrigin();
2090 event
.m_x
= x
+ pt
.x
;
2091 event
.m_y
= y
+ pt
.y
;
2093 if (win
->GetEventHandler()->ProcessEvent( event
))
2095 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
2102 //-----------------------------------------------------------------------------
2103 // "leave_notify_event"
2104 //-----------------------------------------------------------------------------
2106 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
2111 wxapp_install_idle_handler();
2113 if (!win
->m_hasVMT
) return FALSE
;
2114 if (g_blockEventsOnDrag
) return FALSE
;
2116 // Event was emitted after an ungrab
2117 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2119 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2121 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2122 event
.SetTimestamp( gdk_event
->time
);
2123 event
.SetEventObject( win
);
2127 GdkModifierType state
= (GdkModifierType
)0;
2129 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2131 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2132 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2133 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2134 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2135 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2136 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2137 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2139 wxPoint pt
= win
->GetClientAreaOrigin();
2140 event
.m_x
= x
+ pt
.x
;
2141 event
.m_y
= y
+ pt
.y
;
2143 if (win
->GetEventHandler()->ProcessEvent( event
))
2145 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
2152 //-----------------------------------------------------------------------------
2153 // "value_changed" from m_vAdjust
2154 //-----------------------------------------------------------------------------
2156 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2163 wxapp_install_idle_handler();
2165 if (g_blockEventsOnDrag
) return;
2167 if (!win
->m_hasVMT
) return;
2169 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2170 if (fabs(diff
) < 0.2) return;
2172 win
->m_oldVerticalPos
= adjust
->value
;
2175 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2177 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
2179 int value
= (int)(adjust
->value
+0.5);
2181 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2182 event
.SetEventObject( win
);
2183 win
->GetEventHandler()->ProcessEvent( event
);
2186 //-----------------------------------------------------------------------------
2187 // "value_changed" from m_hAdjust
2188 //-----------------------------------------------------------------------------
2190 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2197 wxapp_install_idle_handler();
2199 if (g_blockEventsOnDrag
) return;
2200 if (!win
->m_hasVMT
) return;
2202 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2203 if (fabs(diff
) < 0.2) return;
2206 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2208 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
2210 win
->m_oldHorizontalPos
= adjust
->value
;
2212 int value
= (int)(adjust
->value
+0.5);
2214 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2215 event
.SetEventObject( win
);
2216 win
->GetEventHandler()->ProcessEvent( event
);
2219 //-----------------------------------------------------------------------------
2220 // "button_press_event" from scrollbar
2221 //-----------------------------------------------------------------------------
2223 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2224 GdkEventButton
*gdk_event
,
2230 wxapp_install_idle_handler();
2233 g_blockEventsOnScroll
= TRUE
;
2235 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2237 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2243 //-----------------------------------------------------------------------------
2244 // "button_release_event" from scrollbar
2245 //-----------------------------------------------------------------------------
2247 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2248 GdkEventButton
*WXUNUSED(gdk_event
),
2253 // don't test here as we can release the mouse while being over
2254 // a different window than the slider
2256 // if (gdk_event->window != widget->slider) return FALSE;
2258 g_blockEventsOnScroll
= FALSE
;
2260 if (win
->m_isScrolling
)
2262 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2266 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2267 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2269 value
= (int)(win
->m_hAdjust
->value
+0.5);
2272 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2274 value
= (int)(win
->m_vAdjust
->value
+0.5);
2278 wxScrollWinEvent
event( command
, value
, dir
);
2279 event
.SetEventObject( win
);
2280 win
->GetEventHandler()->ProcessEvent( event
);
2283 win
->m_isScrolling
= FALSE
;
2288 // ----------------------------------------------------------------------------
2289 // this wxWindowBase function is implemented here (in platform-specific file)
2290 // because it is static and so couldn't be made virtual
2291 // ----------------------------------------------------------------------------
2293 wxWindow
*wxWindowBase::DoFindFocus()
2295 // the cast is necessary when we compile in wxUniversal mode
2296 return (wxWindow
*)g_focusWindow
;
2300 //-----------------------------------------------------------------------------
2301 // "realize" from m_widget
2302 //-----------------------------------------------------------------------------
2304 /* We cannot set colours and fonts before the widget has
2305 been realized, so we do this directly after realization. */
2308 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2313 wxapp_install_idle_handler();
2318 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2319 gtk_im_context_set_client_window( win
->m_imData
->context
,
2320 pizza
->bin_window
);
2324 wxWindowCreateEvent
event( win
);
2325 event
.SetEventObject( win
);
2326 win
->GetEventHandler()->ProcessEvent( event
);
2331 //-----------------------------------------------------------------------------
2333 //-----------------------------------------------------------------------------
2336 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2337 GtkAllocation
*WXUNUSED(alloc
),
2341 wxapp_install_idle_handler();
2343 if (!win
->m_hasScrolling
) return;
2345 int client_width
= 0;
2346 int client_height
= 0;
2347 win
->GetClientSize( &client_width
, &client_height
);
2348 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2351 win
->m_oldClientWidth
= client_width
;
2352 win
->m_oldClientHeight
= client_height
;
2354 if (!win
->m_nativeSizeEvent
)
2356 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2357 event
.SetEventObject( win
);
2358 win
->GetEventHandler()->ProcessEvent( event
);
2364 #define WXUNUSED_UNLESS_XIM(param) param
2366 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2369 /* Resize XIM window */
2372 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2373 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2374 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2377 wxapp_install_idle_handler();
2383 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2387 gdk_window_get_size (widget
->window
, &width
, &height
);
2388 win
->m_icattr
->preedit_area
.width
= width
;
2389 win
->m_icattr
->preedit_area
.height
= height
;
2390 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2395 //-----------------------------------------------------------------------------
2396 // "realize" from m_wxwindow
2397 //-----------------------------------------------------------------------------
2399 /* Initialize XIM support */
2402 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2403 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2406 wxapp_install_idle_handler();
2409 if (win
->m_ic
) return FALSE
;
2410 if (!widget
) return FALSE
;
2411 if (!gdk_im_ready()) return FALSE
;
2413 win
->m_icattr
= gdk_ic_attr_new();
2414 if (!win
->m_icattr
) return FALSE
;
2418 GdkColormap
*colormap
;
2419 GdkICAttr
*attr
= win
->m_icattr
;
2420 unsigned attrmask
= GDK_IC_ALL_REQ
;
2422 GdkIMStyle supported_style
= (GdkIMStyle
)
2423 (GDK_IM_PREEDIT_NONE
|
2424 GDK_IM_PREEDIT_NOTHING
|
2425 GDK_IM_PREEDIT_POSITION
|
2426 GDK_IM_STATUS_NONE
|
2427 GDK_IM_STATUS_NOTHING
);
2429 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2430 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2432 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2433 attr
->client_window
= widget
->window
;
2435 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2436 gtk_widget_get_default_colormap ())
2438 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2439 attr
->preedit_colormap
= colormap
;
2442 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2443 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2444 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2445 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2447 switch (style
& GDK_IM_PREEDIT_MASK
)
2449 case GDK_IM_PREEDIT_POSITION
:
2450 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2452 g_warning ("over-the-spot style requires fontset");
2456 gdk_window_get_size (widget
->window
, &width
, &height
);
2458 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2459 attr
->spot_location
.x
= 0;
2460 attr
->spot_location
.y
= height
;
2461 attr
->preedit_area
.x
= 0;
2462 attr
->preedit_area
.y
= 0;
2463 attr
->preedit_area
.width
= width
;
2464 attr
->preedit_area
.height
= height
;
2465 attr
->preedit_fontset
= widget
->style
->font
;
2470 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2472 if (win
->m_ic
== NULL
)
2473 g_warning ("Can't create input context.");
2476 mask
= gdk_window_get_events (widget
->window
);
2477 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2478 gdk_window_set_events (widget
->window
, mask
);
2480 if (GTK_WIDGET_HAS_FOCUS(widget
))
2481 gdk_im_begin (win
->m_ic
, widget
->window
);
2488 //-----------------------------------------------------------------------------
2489 // InsertChild for wxWindowGTK.
2490 //-----------------------------------------------------------------------------
2492 /* Callback for wxWindowGTK. This very strange beast has to be used because
2493 * C++ has no virtual methods in a constructor. We have to emulate a
2494 * virtual function here as wxNotebook requires a different way to insert
2495 * a child in it. I had opted for creating a wxNotebookPage window class
2496 * which would have made this superfluous (such in the MDI window system),
2497 * but no-one was listening to me... */
2499 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2501 /* the window might have been scrolled already, do we
2502 have to adapt the position */
2503 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2504 child
->m_x
+= pizza
->xoffset
;
2505 child
->m_y
+= pizza
->yoffset
;
2507 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2508 GTK_WIDGET(child
->m_widget
),
2515 //-----------------------------------------------------------------------------
2517 //-----------------------------------------------------------------------------
2519 wxWindow
*wxGetActiveWindow()
2521 return wxWindow::FindFocus();
2524 //-----------------------------------------------------------------------------
2526 //-----------------------------------------------------------------------------
2528 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2530 #ifdef __WXUNIVERSAL__
2531 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2533 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2534 #endif // __WXUNIVERSAL__/__WXGTK__
2536 void wxWindowGTK::Init()
2539 m_widget
= (GtkWidget
*) NULL
;
2540 m_wxwindow
= (GtkWidget
*) NULL
;
2541 m_focusWidget
= (GtkWidget
*) NULL
;
2551 m_needParent
= TRUE
;
2552 m_isBeingDeleted
= FALSE
;
2555 m_nativeSizeEvent
= FALSE
;
2557 m_hasScrolling
= FALSE
;
2558 m_isScrolling
= FALSE
;
2560 m_hAdjust
= (GtkAdjustment
*) NULL
;
2561 m_vAdjust
= (GtkAdjustment
*) NULL
;
2562 m_oldHorizontalPos
=
2563 m_oldVerticalPos
= 0.0;
2565 m_oldClientHeight
= 0;
2569 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2571 m_acceptsFocus
= FALSE
;
2574 m_clipPaintRegion
= FALSE
;
2576 m_needsStyleChange
= false;
2578 m_cursor
= *wxSTANDARD_CURSOR
;
2582 m_x11Context
= NULL
;
2583 m_dirtyTabOrder
= false;
2586 m_ic
= (GdkIC
*) NULL
;
2587 m_icattr
= (GdkICAttr
*) NULL
;
2592 wxWindowGTK::wxWindowGTK()
2597 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2602 const wxString
&name
)
2606 Create( parent
, id
, pos
, size
, style
, name
);
2609 bool wxWindowGTK::Create( wxWindow
*parent
,
2614 const wxString
&name
)
2616 if (!PreCreation( parent
, pos
, size
) ||
2617 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2619 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2623 m_insertCallback
= wxInsertChildInWindow
;
2625 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2626 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2628 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2630 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2631 scroll_class
->scrollbar_spacing
= 0;
2633 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2635 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2636 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2638 m_wxwindow
= gtk_pizza_new();
2640 #ifndef __WXUNIVERSAL__
2641 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2643 if (HasFlag(wxRAISED_BORDER
))
2645 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2647 else if (HasFlag(wxSUNKEN_BORDER
))
2649 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2651 else if (HasFlag(wxSIMPLE_BORDER
))
2653 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2657 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2659 #endif // __WXUNIVERSAL__
2661 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2663 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2664 m_acceptsFocus
= TRUE
;
2666 // I _really_ don't want scrollbars in the beginning
2667 m_vAdjust
->lower
= 0.0;
2668 m_vAdjust
->upper
= 1.0;
2669 m_vAdjust
->value
= 0.0;
2670 m_vAdjust
->step_increment
= 1.0;
2671 m_vAdjust
->page_increment
= 1.0;
2672 m_vAdjust
->page_size
= 5.0;
2673 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2674 m_hAdjust
->lower
= 0.0;
2675 m_hAdjust
->upper
= 1.0;
2676 m_hAdjust
->value
= 0.0;
2677 m_hAdjust
->step_increment
= 1.0;
2678 m_hAdjust
->page_increment
= 1.0;
2679 m_hAdjust
->page_size
= 5.0;
2680 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2682 // these handlers block mouse events to any window during scrolling such as
2683 // motion events and prevent GTK and wxWidgets from fighting over where the
2686 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2687 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2689 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2690 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2692 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2693 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2695 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2696 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2698 // these handlers get notified when screen updates are required either when
2699 // scrolling or when the window size (and therefore scrollbar configuration)
2702 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2703 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2704 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2705 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2707 gtk_widget_show( m_wxwindow
);
2710 m_parent
->DoAddChild( this );
2712 m_focusWidget
= m_wxwindow
;
2719 wxWindowGTK::~wxWindowGTK()
2723 if (g_focusWindow
== this)
2724 g_focusWindow
= NULL
;
2726 if ( g_delayedFocus
== this )
2727 g_delayedFocus
= NULL
;
2729 m_isBeingDeleted
= TRUE
;
2739 gdk_ic_destroy (m_ic
);
2741 gdk_ic_attr_destroy (m_icattr
);
2746 gtk_widget_destroy( m_wxwindow
);
2747 m_wxwindow
= (GtkWidget
*) NULL
;
2752 gtk_widget_destroy( m_widget
);
2753 m_widget
= (GtkWidget
*) NULL
;
2761 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2763 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2765 // Use either the given size, or the default if -1 is given.
2766 // See wxWindowBase for these functions.
2767 m_width
= WidthDefault(size
.x
) ;
2768 m_height
= HeightDefault(size
.y
);
2776 void wxWindowGTK::PostCreation()
2778 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2784 // these get reported to wxWidgets -> wxPaintEvent
2786 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2788 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2789 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2792 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2793 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2795 if (!HasFlag(wxFULL_REPAINT_ON_RESIZE
))
2797 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2798 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2801 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2806 // Create input method handler
2807 m_imData
= new wxGtkIMData
;
2809 // Cannot handle drawing preedited text yet
2810 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2812 g_signal_connect (G_OBJECT (m_imData
->context
), "commit",
2813 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2816 // these are called when the "sunken" or "raised" borders are drawn
2817 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2818 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2821 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2822 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2828 if (!GTK_IS_WINDOW(m_widget
))
2830 if (m_focusWidget
== NULL
)
2831 m_focusWidget
= m_widget
;
2833 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2834 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2836 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2837 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2840 // connect to the various key and mouse handlers
2842 GtkWidget
*connect_widget
= GetConnectWidget();
2844 ConnectWidget( connect_widget
);
2846 /* We cannot set colours, fonts and cursors before the widget has
2847 been realized, so we do this directly after realization */
2848 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2849 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2853 // Catch native resize events
2854 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2855 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2857 // Initialize XIM support
2858 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2859 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2861 // And resize XIM window
2862 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2863 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2866 if ( !GTK_IS_COMBO(m_widget
))
2868 // This is needed if we want to add our windows into native
2869 // GTK control, such as the toolbar. With this callback, the
2870 // toolbar gets to know the correct size (the one set by the
2871 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2872 // when moving to GTK 2.0.
2873 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2874 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback
),
2878 InheritAttributes();
2882 // unless the window was created initially hidden (i.e. Hide() had been
2883 // called before Create()), we should show it at GTK+ level as well
2885 gtk_widget_show( m_widget
);
2888 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2890 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2891 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2893 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2894 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2896 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2897 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2899 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2900 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2902 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2903 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2906 gtk_signal_connect( GTK_OBJECT(widget
), "scroll_event",
2907 GTK_SIGNAL_FUNC(gtk_window_wheel_callback
), (gpointer
)this );
2910 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2911 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2913 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2914 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2917 bool wxWindowGTK::Destroy()
2919 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2923 return wxWindowBase::Destroy();
2926 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2928 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2931 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2933 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2934 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2937 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2940 if (m_resizing
) return; /* I don't like recursions */
2943 int currentX
, currentY
;
2944 GetPosition(¤tX
, ¤tY
);
2945 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2947 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2949 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2951 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2953 /* don't set the size for children of wxNotebook, just take the values. */
2961 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2962 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2964 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2965 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2969 m_x
= x
+ pizza
->xoffset
;
2970 m_y
= y
+ pizza
->yoffset
;
2973 // calculate the best size if we should auto size the window
2974 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2975 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2977 const wxSize sizeBest
= GetBestSize();
2978 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2980 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2981 height
= sizeBest
.y
;
2989 int minWidth
= GetMinWidth(),
2990 minHeight
= GetMinHeight(),
2991 maxWidth
= GetMaxWidth(),
2992 maxHeight
= GetMaxHeight();
2994 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2995 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2996 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2997 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
3000 int bottom_border
= 0;
3003 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
3005 /* the default button has a border around it */
3011 DoMoveWindow( m_x
-border
,
3014 m_height
+border
+bottom_border
);
3019 /* Sometimes the client area changes size without the
3020 whole windows's size changing, but if the whole
3021 windows's size doesn't change, no wxSizeEvent will
3022 normally be sent. Here we add an extra test if
3023 the client test has been changed and this will
3025 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
3029 wxPrintf( "OnSize sent from " );
3030 if (GetClassInfo() && GetClassInfo()->GetClassName())
3031 wxPrintf( GetClassInfo()->GetClassName() );
3032 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3035 if (!m_nativeSizeEvent
)
3037 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
3038 event
.SetEventObject( this );
3039 GetEventHandler()->ProcessEvent( event
);
3045 void wxWindowGTK::OnInternalIdle()
3048 if ( m_dirtyTabOrder
)
3051 // Update style if the window was not yet realized
3052 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
3053 if (m_needsStyleChange
)
3055 SetBackgroundStyle(GetBackgroundStyle());
3056 m_needsStyleChange
= false;
3059 // Update invalidated regions.
3062 wxCursor cursor
= m_cursor
;
3063 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3067 /* I now set the cursor anew in every OnInternalIdle call
3068 as setting the cursor in a parent window also effects the
3069 windows above so that checking for the current cursor is
3074 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3076 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3078 if (!g_globalCursor
.Ok())
3079 cursor
= *wxSTANDARD_CURSOR
;
3081 window
= m_widget
->window
;
3082 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3083 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3089 GdkWindow
*window
= m_widget
->window
;
3090 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3091 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3096 if (wxUpdateUIEvent::CanUpdate(this))
3097 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3100 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3102 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3104 if (width
) (*width
) = m_width
;
3105 if (height
) (*height
) = m_height
;
3108 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3110 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3114 SetSize( width
, 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 SetSize( width
+dw
, height
+dh
);
3171 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3173 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3177 if (width
) (*width
) = m_width
;
3178 if (height
) (*height
) = m_height
;
3185 #ifndef __WXUNIVERSAL__
3186 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3188 /* when using GTK 1.2 we set the shadow border size to 2 */
3192 if (HasFlag(wxSIMPLE_BORDER
))
3194 /* when using GTK 1.2 we set the simple border size to 1 */
3198 #endif // __WXUNIVERSAL__
3202 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3204 GtkRequisition vscroll_req
;
3205 vscroll_req
.width
= 2;
3206 vscroll_req
.height
= 2;
3207 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3208 (scroll_window
->vscrollbar
, &vscroll_req
);
3210 GtkRequisition hscroll_req
;
3211 hscroll_req
.width
= 2;
3212 hscroll_req
.height
= 2;
3213 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3214 (scroll_window
->hscrollbar
, &hscroll_req
);
3216 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3218 if (scroll_window
->vscrollbar_visible
)
3220 dw
+= vscroll_req
.width
;
3221 dw
+= scroll_class
->scrollbar_spacing
;
3224 if (scroll_window
->hscrollbar_visible
)
3226 dh
+= hscroll_req
.height
;
3227 dh
+= scroll_class
->scrollbar_spacing
;
3231 if (width
) (*width
) = m_width
- dw
;
3232 if (height
) (*height
) = m_height
- dh
;
3236 printf( "GetClientSize, name %s ", GetName().c_str() );
3237 if (width) printf( " width = %d", (*width) );
3238 if (height) printf( " height = %d", (*height) );
3243 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3245 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3249 if (m_parent
&& m_parent
->m_wxwindow
)
3251 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3252 dx
= pizza
->xoffset
;
3253 dy
= pizza
->yoffset
;
3256 if (x
) (*x
) = m_x
- dx
;
3257 if (y
) (*y
) = m_y
- dy
;
3260 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3262 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3264 if (!m_widget
->window
) return;
3266 GdkWindow
*source
= (GdkWindow
*) NULL
;
3268 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3270 source
= m_widget
->window
;
3274 gdk_window_get_origin( source
, &org_x
, &org_y
);
3278 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3280 org_x
+= m_widget
->allocation
.x
;
3281 org_y
+= m_widget
->allocation
.y
;
3289 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3291 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3293 if (!m_widget
->window
) return;
3295 GdkWindow
*source
= (GdkWindow
*) NULL
;
3297 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3299 source
= m_widget
->window
;
3303 gdk_window_get_origin( source
, &org_x
, &org_y
);
3307 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3309 org_x
+= m_widget
->allocation
.x
;
3310 org_y
+= m_widget
->allocation
.y
;
3318 bool wxWindowGTK::Show( bool show
)
3320 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3322 if (!wxWindowBase::Show(show
))
3329 gtk_widget_show( m_widget
);
3331 gtk_widget_hide( m_widget
);
3333 wxShowEvent
eventShow(GetId(), show
);
3334 eventShow
.m_eventObject
= this;
3336 GetEventHandler()->ProcessEvent(eventShow
);
3341 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3343 win
->OnParentEnable(enable
);
3345 // Recurse, so that children have the opportunity to Do The Right Thing
3346 // and reset colours that have been messed up by a parent's (really ancestor's)
3348 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3350 node
= node
->GetNext() )
3352 wxWindow
*child
= node
->GetData();
3353 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3354 wxWindowNotifyEnable(child
, enable
);
3358 bool wxWindowGTK::Enable( bool enable
)
3360 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3362 if (!wxWindowBase::Enable(enable
))
3368 gtk_widget_set_sensitive( m_widget
, enable
);
3370 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3372 wxWindowNotifyEnable(this, enable
);
3377 int wxWindowGTK::GetCharHeight() const
3379 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3381 wxFont font
= GetFont();
3382 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3385 PangoContext
*context
= NULL
;
3387 context
= gtk_widget_get_pango_context( m_widget
);
3392 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3393 PangoLayout
*layout
= pango_layout_new(context
);
3394 pango_layout_set_font_description(layout
, desc
);
3395 pango_layout_set_text(layout
, "H", 1);
3396 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3398 PangoRectangle rect
;
3399 pango_layout_line_get_extents(line
, NULL
, &rect
);
3401 g_object_unref( G_OBJECT( layout
) );
3403 return (int) PANGO_PIXELS(rect
.height
);
3405 GdkFont
*gfont
= font
.GetInternalFont( 1.0 );
3407 return gfont
->ascent
+ gfont
->descent
;
3411 int wxWindowGTK::GetCharWidth() const
3413 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3415 wxFont font
= GetFont();
3416 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3419 PangoContext
*context
= NULL
;
3421 context
= gtk_widget_get_pango_context( m_widget
);
3426 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3427 PangoLayout
*layout
= pango_layout_new(context
);
3428 pango_layout_set_font_description(layout
, desc
);
3429 pango_layout_set_text(layout
, "g", 1);
3430 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3432 PangoRectangle rect
;
3433 pango_layout_line_get_extents(line
, NULL
, &rect
);
3435 g_object_unref( G_OBJECT( layout
) );
3437 return (int) PANGO_PIXELS(rect
.width
);
3439 GdkFont
*gfont
= font
.GetInternalFont( 1.0 );
3441 return gdk_string_width( gfont
, "g" );
3445 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3449 int *externalLeading
,
3450 const wxFont
*theFont
) const
3452 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3454 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3456 if (string
.IsEmpty())
3464 PangoContext
*context
= NULL
;
3466 context
= gtk_widget_get_pango_context( m_widget
);
3475 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3476 PangoLayout
*layout
= pango_layout_new(context
);
3477 pango_layout_set_font_description(layout
, desc
);
3480 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3481 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3483 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3484 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3485 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3489 PangoRectangle rect
;
3490 pango_layout_get_extents(layout
, NULL
, &rect
);
3492 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3493 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3496 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3497 int baseline
= pango_layout_iter_get_baseline(iter
);
3498 pango_layout_iter_free(iter
);
3499 *descent
= *y
- PANGO_PIXELS(baseline
);
3501 if (externalLeading
) (*externalLeading
) = 0; // ??
3503 g_object_unref( G_OBJECT( layout
) );
3505 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3506 if (x
) (*x
) = gdk_string_width( font
, wxGTK_CONV( string
) );
3507 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3508 if (descent
) (*descent
) = font
->descent
;
3509 if (externalLeading
) (*externalLeading
) = 0; // ??
3513 void wxWindowGTK::SetFocus()
3515 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3518 // don't do anything if we already have focus
3524 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3526 gtk_widget_grab_focus (m_wxwindow
);
3532 if (GTK_IS_CONTAINER(m_widget
))
3534 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3538 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3541 if (!GTK_WIDGET_REALIZED(m_widget
))
3543 // we can't set the focus to the widget now so we remember that
3544 // it should be focused and will do it later, during the idle
3545 // time, as soon as we can
3546 wxLogTrace(TRACE_FOCUS
,
3547 _T("Delaying setting focus to %s(%s)"),
3548 GetClassInfo()->GetClassName(), GetLabel().c_str());
3550 g_delayedFocus
= this;
3554 wxLogTrace(TRACE_FOCUS
,
3555 _T("Setting focus to %s(%s)"),
3556 GetClassInfo()->GetClassName(), GetLabel().c_str());
3558 gtk_widget_grab_focus (m_widget
);
3563 if (GTK_IS_CONTAINER(m_widget
))
3565 gtk_container_focus( GTK_CONTAINER(m_widget
), GTK_DIR_TAB_FORWARD
);
3570 wxLogTrace(TRACE_FOCUS
,
3571 _T("Can't set focus to %s(%s)"),
3572 GetClassInfo()->GetClassName(), GetLabel().c_str());
3577 bool wxWindowGTK::AcceptsFocus() const
3579 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3582 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3584 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3586 wxWindowGTK
*oldParent
= m_parent
,
3587 *newParent
= (wxWindowGTK
*)newParentBase
;
3589 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3591 if ( !wxWindowBase::Reparent(newParent
) )
3594 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3596 /* prevent GTK from deleting the widget arbitrarily */
3597 gtk_widget_ref( m_widget
);
3601 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3604 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3608 /* insert GTK representation */
3609 (*(newParent
->m_insertCallback
))(newParent
, this);
3612 /* reverse: prevent GTK from deleting the widget arbitrarily */
3613 gtk_widget_unref( m_widget
);
3618 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3620 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3622 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3624 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3629 /* insert GTK representation */
3630 (*m_insertCallback
)(this, child
);
3635 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3637 wxWindowBase::AddChild(child
);
3638 m_dirtyTabOrder
= true;
3640 wxapp_install_idle_handler();
3643 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3645 wxWindowBase::RemoveChild(child
);
3646 m_dirtyTabOrder
= true;
3648 wxapp_install_idle_handler();
3651 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3653 wxWindowBase::DoMoveInTabOrder(win
, move
);
3654 m_dirtyTabOrder
= true;
3656 wxapp_install_idle_handler();
3659 void wxWindowGTK::RealizeTabOrder()
3663 if (m_children
.size() > 0)
3665 GList
*chain
= NULL
;
3667 for (wxWindowList::const_iterator i
= m_children
.begin();
3668 i
!= m_children
.end(); ++i
)
3670 chain
= g_list_prepend(chain
, (*i
)->m_widget
);
3673 chain
= g_list_reverse(chain
);
3675 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3680 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3684 m_dirtyTabOrder
= false;
3687 #endif // __WXGTK20__
3689 void wxWindowGTK::Raise()
3691 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3693 if (!m_widget
->window
) return;
3695 gdk_window_raise( m_widget
->window
);
3698 void wxWindowGTK::Lower()
3700 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3702 if (!m_widget
->window
) return;
3704 gdk_window_lower( m_widget
->window
);
3707 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3709 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3711 if (cursor
== m_cursor
)
3715 wxapp_install_idle_handler();
3717 if (cursor
== wxNullCursor
)
3718 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3720 return wxWindowBase::SetCursor( cursor
);
3723 void wxWindowGTK::WarpPointer( int x
, int y
)
3725 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3727 // We provide this function ourselves as it is
3728 // missing in GDK (top of this file).
3730 GdkWindow
*window
= (GdkWindow
*) NULL
;
3732 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3734 window
= GetConnectWidget()->window
;
3737 gdk_window_warp_pointer( window
, x
, y
);
3741 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3743 if (!m_widget
) return;
3744 if (!m_widget
->window
) return;
3748 wxapp_install_idle_handler();
3750 wxRect
myRect(0,0,0,0);
3751 if (m_wxwindow
&& rect
)
3753 myRect
.SetSize(wxSize( m_wxwindow
->allocation
.width
,
3754 m_wxwindow
->allocation
.height
));
3755 myRect
.Intersect(*rect
);
3756 if (!myRect
.width
|| !myRect
.height
)
3757 // nothing to do, rectangle is empty
3762 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3766 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3767 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3771 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3772 m_clearRegion
.Clear();
3773 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3781 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3782 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3786 GdkRectangle gdk_rect
;
3787 gdk_rect
.x
= rect
->x
;
3788 gdk_rect
.y
= rect
->y
;
3789 gdk_rect
.width
= rect
->width
;
3790 gdk_rect
.height
= rect
->height
;
3791 gtk_widget_draw( m_widget
, &gdk_rect
);
3798 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3799 m_updateRegion
.Clear();
3800 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3804 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3812 GdkRectangle gdk_rect
;
3813 gdk_rect
.x
= rect
->x
;
3814 gdk_rect
.y
= rect
->y
;
3815 gdk_rect
.width
= rect
->width
;
3816 gdk_rect
.height
= rect
->height
;
3817 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3821 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3827 void wxWindowGTK::Update()
3832 void wxWindowGTK::GtkUpdate()
3835 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3836 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3838 if (!m_updateRegion
.IsEmpty())
3839 GtkSendPaintEvents();
3843 void wxWindowGTK::GtkSendPaintEvents()
3848 m_clearRegion
.Clear();
3850 m_updateRegion
.Clear();
3854 // Clip to paint region in wxClientDC
3855 m_clipPaintRegion
= TRUE
;
3857 // widget to draw on
3858 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3860 if (GetThemeEnabled() && GetBackgroundStyle() == wxBG_STYLE_SYSTEM
)
3862 // find ancestor from which to steal background
3863 wxWindow
*parent
= GetParent();
3864 while (parent
&& !parent
->IsTopLevel())
3865 parent
= parent
->GetParent();
3867 parent
= (wxWindow
*)this;
3869 wxRegionIterator
upd( m_updateRegion
);
3873 rect
.x
= upd
.GetX();
3874 rect
.y
= upd
.GetY();
3875 rect
.width
= upd
.GetWidth();
3876 rect
.height
= upd
.GetHeight();
3878 gtk_paint_flat_box( parent
->m_widget
->style
,
3880 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3894 wxWindowDC
dc( (wxWindow
*)this );
3895 dc
.SetClippingRegion( m_updateRegion
);
3897 wxEraseEvent
erase_event( GetId(), &dc
);
3898 erase_event
.SetEventObject( this );
3900 GetEventHandler()->ProcessEvent(erase_event
);
3903 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
3905 wxWindowDC
dc( (wxWindow
*)this );
3906 if (m_clearRegion
.IsEmpty())
3907 dc
.SetClippingRegion( m_updateRegion
);
3909 dc
.SetClippingRegion( m_clearRegion
);
3911 wxEraseEvent
erase_event( GetId(), &dc
);
3912 erase_event
.SetEventObject( this );
3914 if (!GetEventHandler()->ProcessEvent(erase_event
) && GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3918 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
3919 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3921 gdk_gc_set_foreground( g_eraseGC
, GetBackgroundColour().GetColor() );
3923 wxRegionIterator
upd( m_clearRegion
);
3926 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3927 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3931 m_clearRegion
.Clear();
3935 wxNcPaintEvent
nc_paint_event( GetId() );
3936 nc_paint_event
.SetEventObject( this );
3937 GetEventHandler()->ProcessEvent( nc_paint_event
);
3939 wxPaintEvent
paint_event( GetId() );
3940 paint_event
.SetEventObject( this );
3941 GetEventHandler()->ProcessEvent( paint_event
);
3943 m_clipPaintRegion
= FALSE
;
3945 #ifndef __WXUNIVERSAL__
3947 // The following code will result in all window-less widgets
3948 // being redrawn because the wxWidgets class is allowed to
3949 // paint over the window-less widgets.
3951 GList
*children
= pizza
->children
;
3954 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3955 children
= children
->next
;
3957 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3958 GTK_WIDGET_DRAWABLE (child
->widget
))
3960 // Get intersection of widget area and update region
3961 wxRegion
region( m_updateRegion
);
3963 GdkEventExpose gdk_event
;
3964 gdk_event
.type
= GDK_EXPOSE
;
3965 gdk_event
.window
= pizza
->bin_window
;
3966 gdk_event
.count
= 0;
3968 wxRegionIterator
upd( m_updateRegion
);
3972 rect
.x
= upd
.GetX();
3973 rect
.y
= upd
.GetY();
3974 rect
.width
= upd
.GetWidth();
3975 rect
.height
= upd
.GetHeight();
3977 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3979 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3989 m_updateRegion
.Clear();
3992 void wxWindowGTK::ClearBackground()
3994 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3997 if (m_wxwindow
&& m_wxwindow
->window
)
3999 m_clearRegion
.Clear();
4000 wxSize
size( GetClientSize() );
4001 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
4003 // Better do this in idle?
4010 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
4012 wxWindowBase::DoSetToolTip(tip
);
4015 m_tooltip
->Apply( (wxWindow
*)this );
4018 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
4020 wxString
tmp( tip
);
4021 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
4023 #endif // wxUSE_TOOLTIPS
4025 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
4027 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4029 if (!wxWindowBase::SetBackgroundColour(colour
))
4034 // We need the pixel value e.g. for background clearing.
4035 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
4038 // apply style change (forceStyle=true so that new style is applied
4039 // even if the bg colour changed from valid to wxNullColour)
4040 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
4041 ApplyWidgetStyle(true);
4046 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
4048 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4050 if (!wxWindowBase::SetForegroundColour(colour
))
4057 // We need the pixel value e.g. for background clearing.
4058 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
4061 // apply style change (forceStyle=true so that new style is applied
4062 // even if the bg colour changed from valid to wxNullColour):
4063 ApplyWidgetStyle(true);
4069 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
4071 return gtk_widget_get_pango_context( m_widget
);
4074 PangoContext
*wxWindowGTK::GtkGetPangoX11Context()
4077 m_x11Context
= pango_x_get_context( gdk_display
);
4079 return m_x11Context
;
4083 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
4085 // do we need to apply any changes at all?
4088 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
4093 GtkRcStyle
*style
= gtk_rc_style_new();
4099 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
4101 wxString xfontname
= m_font
.GetNativeFontInfo()->GetXFontName();
4102 style
->fontset_name
= g_strdup(xfontname
.c_str());
4106 if ( m_foregroundColour
.Ok() )
4108 GdkColor
*fg
= m_foregroundColour
.GetColor();
4110 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
4111 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
4113 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
4114 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
4116 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
4117 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
4120 if ( m_backgroundColour
.Ok() )
4122 GdkColor
*bg
= m_backgroundColour
.GetColor();
4124 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
4125 style
->base
[GTK_STATE_NORMAL
] = *bg
;
4126 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
4127 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
4129 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
4130 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
4131 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
4132 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
4134 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
4135 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
4136 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
4137 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4139 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
4140 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
4141 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
4142 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4148 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
4150 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
4153 DoApplyWidgetStyle(style
);
4154 gtk_rc_style_unref(style
);
4157 // Style change may affect GTK+'s size calculation:
4158 InvalidateBestSize();
4161 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
4164 gtk_widget_modify_style(m_wxwindow
, style
);
4165 gtk_widget_modify_style(m_widget
, style
);
4168 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
4170 wxWindowBase::SetBackgroundStyle(style
);
4172 if (style
== wxBG_STYLE_CUSTOM
)
4174 GdkWindow
*window
= (GdkWindow
*) NULL
;
4176 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4178 window
= GetConnectWidget()->window
;
4182 // Make sure GDK/X11 doesn't refresh the window
4184 gdk_window_set_back_pixmap( window
, None
, False
);
4186 Display
* display
= GDK_WINDOW_DISPLAY(window
);
4189 m_needsStyleChange
= false;
4192 // Do in OnIdle, because the window is not yet available
4193 m_needsStyleChange
= true;
4195 // Don't apply widget style, or we get a grey background
4199 // apply style change (forceStyle=true so that new style is applied
4200 // even if the bg colour changed from valid to wxNullColour):
4201 ApplyWidgetStyle(true);
4206 //-----------------------------------------------------------------------------
4207 // Pop-up menu stuff
4208 //-----------------------------------------------------------------------------
4210 #if wxUSE_MENUS_NATIVE
4213 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
4215 *is_waiting
= FALSE
;
4218 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
4220 menu
->SetInvokingWindow( win
);
4221 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
4224 wxMenuItem
*menuitem
= node
->GetData();
4225 if (menuitem
->IsSubMenu())
4227 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
4230 node
= node
->GetNext();
4234 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
4237 gboolean
* WXUNUSED(whatever
),
4239 gpointer user_data
)
4241 // ensure that the menu appears entirely on screen
4243 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
4245 wxSize sizeScreen
= wxGetDisplaySize();
4246 wxPoint
*pos
= (wxPoint
*)user_data
;
4248 gint xmax
= sizeScreen
.x
- req
.width
,
4249 ymax
= sizeScreen
.y
- req
.height
;
4251 *x
= pos
->x
< xmax
? pos
->x
: xmax
;
4252 *y
= pos
->y
< ymax
? pos
->y
: ymax
;
4255 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4257 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4259 wxCHECK_MSG( menu
!= NULL
, false, wxT("invalid popup-menu") );
4261 SetInvokingWindow( menu
, this );
4265 bool is_waiting
= true;
4267 gulong handler
= gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
4269 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
4270 (gpointer
)&is_waiting
);
4274 GtkMenuPositionFunc posfunc
;
4275 if ( x
== -1 && y
== -1 )
4277 // use GTK's default positioning algorithm
4283 pos
= ClientToScreen(wxPoint(x
, y
));
4285 posfunc
= wxPopupMenuPositionCallback
;
4289 GTK_MENU(menu
->m_menu
),
4290 (GtkWidget
*) NULL
, // parent menu shell
4291 (GtkWidget
*) NULL
, // parent menu item
4292 posfunc
, // function to position it
4293 userdata
, // client data
4294 0, // button used to activate it
4296 gtk_get_current_event_time()
4298 gs_timeLastClick
// the time of activation
4304 gtk_main_iteration();
4307 gtk_signal_disconnect(GTK_OBJECT(menu
->m_menu
), handler
);
4312 #endif // wxUSE_MENUS_NATIVE
4314 #if wxUSE_DRAG_AND_DROP
4316 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4318 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4320 GtkWidget
*dnd_widget
= GetConnectWidget();
4322 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4324 if (m_dropTarget
) delete m_dropTarget
;
4325 m_dropTarget
= dropTarget
;
4327 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4330 #endif // wxUSE_DRAG_AND_DROP
4332 GtkWidget
* wxWindowGTK::GetConnectWidget()
4334 GtkWidget
*connect_widget
= m_widget
;
4335 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4337 return connect_widget
;
4340 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4343 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4345 return (window
== m_widget
->window
);
4348 bool wxWindowGTK::SetFont( const wxFont
&font
)
4350 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4352 if (!wxWindowBase::SetFont(font
))
4355 // apply style change (forceStyle=true so that new style is applied
4356 // even if the font changed from valid to wxNullFont):
4357 ApplyWidgetStyle(true);
4362 void wxWindowGTK::DoCaptureMouse()
4364 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4366 GdkWindow
*window
= (GdkWindow
*) NULL
;
4368 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4370 window
= GetConnectWidget()->window
;
4372 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4374 wxCursor
* cursor
= & m_cursor
;
4376 cursor
= wxSTANDARD_CURSOR
;
4378 gdk_pointer_grab( window
, FALSE
,
4380 (GDK_BUTTON_PRESS_MASK
|
4381 GDK_BUTTON_RELEASE_MASK
|
4382 GDK_POINTER_MOTION_HINT_MASK
|
4383 GDK_POINTER_MOTION_MASK
),
4385 cursor
->GetCursor(),
4386 (guint32
)GDK_CURRENT_TIME
);
4387 g_captureWindow
= this;
4388 g_captureWindowHasMouse
= TRUE
;
4391 void wxWindowGTK::DoReleaseMouse()
4393 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4395 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4397 g_captureWindow
= (wxWindowGTK
*) NULL
;
4399 GdkWindow
*window
= (GdkWindow
*) NULL
;
4401 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4403 window
= GetConnectWidget()->window
;
4408 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4412 wxWindow
*wxWindowBase::GetCapture()
4414 return (wxWindow
*)g_captureWindow
;
4417 bool wxWindowGTK::IsRetained() const
4422 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4423 int range
, bool refresh
)
4425 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4427 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4429 m_hasScrolling
= TRUE
;
4431 if (orient
== wxHORIZONTAL
)
4433 float fpos
= (float)pos
;
4434 float frange
= (float)range
;
4435 float fthumb
= (float)thumbVisible
;
4436 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4437 if (fpos
< 0.0) fpos
= 0.0;
4439 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4440 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4442 SetScrollPos( orient
, pos
, refresh
);
4446 m_oldHorizontalPos
= fpos
;
4448 m_hAdjust
->lower
= 0.0;
4449 m_hAdjust
->upper
= frange
;
4450 m_hAdjust
->value
= fpos
;
4451 m_hAdjust
->step_increment
= 1.0;
4452 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4453 m_hAdjust
->page_size
= fthumb
;
4457 float fpos
= (float)pos
;
4458 float frange
= (float)range
;
4459 float fthumb
= (float)thumbVisible
;
4460 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4461 if (fpos
< 0.0) fpos
= 0.0;
4463 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4464 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4466 SetScrollPos( orient
, pos
, refresh
);
4470 m_oldVerticalPos
= fpos
;
4472 m_vAdjust
->lower
= 0.0;
4473 m_vAdjust
->upper
= frange
;
4474 m_vAdjust
->value
= fpos
;
4475 m_vAdjust
->step_increment
= 1.0;
4476 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4477 m_vAdjust
->page_size
= fthumb
;
4480 if (orient
== wxHORIZONTAL
)
4481 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4483 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4486 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4488 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4490 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4492 if (orient
== wxHORIZONTAL
)
4494 float fpos
= (float)pos
;
4495 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4496 if (fpos
< 0.0) fpos
= 0.0;
4497 m_oldHorizontalPos
= fpos
;
4499 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4500 m_hAdjust
->value
= fpos
;
4504 float fpos
= (float)pos
;
4505 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4506 if (fpos
< 0.0) fpos
= 0.0;
4507 m_oldVerticalPos
= fpos
;
4509 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4510 m_vAdjust
->value
= fpos
;
4513 if (m_wxwindow
->window
)
4515 if (orient
== wxHORIZONTAL
)
4517 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4518 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4520 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4522 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4523 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4527 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4528 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4530 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4532 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4533 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4538 int wxWindowGTK::GetScrollThumb( int orient
) const
4540 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4542 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4544 if (orient
== wxHORIZONTAL
)
4545 return (int)(m_hAdjust
->page_size
+0.5);
4547 return (int)(m_vAdjust
->page_size
+0.5);
4550 int wxWindowGTK::GetScrollPos( int orient
) const
4552 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4554 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4556 if (orient
== wxHORIZONTAL
)
4557 return (int)(m_hAdjust
->value
+0.5);
4559 return (int)(m_vAdjust
->value
+0.5);
4562 int wxWindowGTK::GetScrollRange( int orient
) const
4564 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4566 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4568 if (orient
== wxHORIZONTAL
)
4569 return (int)(m_hAdjust
->upper
+0.5);
4571 return (int)(m_vAdjust
->upper
+0.5);
4574 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4576 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4578 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4580 // No scrolling requested.
4581 if ((dx
== 0) && (dy
== 0)) return;
4584 if (!m_updateRegion
.IsEmpty())
4586 m_updateRegion
.Offset( dx
, dy
);
4590 GetClientSize( &cw
, &ch
);
4591 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4594 if (!m_clearRegion
.IsEmpty())
4596 m_clearRegion
.Offset( dx
, dy
);
4600 GetClientSize( &cw
, &ch
);
4601 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4605 m_clipPaintRegion
= TRUE
;
4607 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4609 m_clipPaintRegion
= FALSE
;
4613 // Find the wxWindow at the current mouse position, also returning the mouse
4615 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4617 pt
= wxGetMousePosition();
4618 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4622 // Get the current mouse position.
4623 wxPoint
wxGetMousePosition()
4625 /* This crashes when used within wxHelpContext,
4626 so we have to use the X-specific implementation below.
4628 GdkModifierType *mask;
4629 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4631 return wxPoint(x, y);
4635 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4637 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4638 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4639 Window rootReturn
, childReturn
;
4640 int rootX
, rootY
, winX
, winY
;
4641 unsigned int maskReturn
;
4643 XQueryPointer (display
,
4647 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4648 return wxPoint(rootX
, rootY
);
4652 // ----------------------------------------------------------------------------
4654 // ----------------------------------------------------------------------------
4656 class wxWinModule
: public wxModule
4663 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4666 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4668 bool wxWinModule::OnInit()
4670 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4671 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4676 void wxWinModule::OnExit()
4679 gdk_gc_unref( g_eraseGC
);