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 ( wxIsAsciiKeysym(keysym
) )
1209 key_code
= (unsigned char)keysym
;
1211 // gdk_event->string is actually deprecated
1212 else if ( gdk_event
->length
== 1 )
1214 key_code
= (unsigned char)gdk_event
->string
[0];
1220 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1222 event
.m_keyCode
= key_code
;
1224 // Implement OnCharHook by checking ancesteror top level windows
1225 wxWindow
*parent
= win
;
1226 while (parent
&& !parent
->IsTopLevel())
1227 parent
= parent
->GetParent();
1230 event
.SetEventType( wxEVT_CHAR_HOOK
);
1231 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1236 event
.SetEventType(wxEVT_CHAR
);
1237 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1242 // win is a control: tab can be propagated up
1244 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1245 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1246 // have this style, yet choose not to process this particular TAB in which
1247 // case TAB must still work as a navigational character
1248 // JS: enabling again to make consistent with other platforms
1249 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1250 // navigation behaviour)
1252 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1254 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1256 wxNavigationKeyEvent new_event
;
1257 new_event
.SetEventObject( win
->GetParent() );
1258 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1259 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1260 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1261 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1262 new_event
.SetCurrentFocus( win
);
1263 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1266 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1268 (gdk_event
->keyval
== GDK_Escape
) )
1270 // however only do it if we have a Cancel button in the dialog,
1271 // otherwise the user code may get confused by the events from a
1272 // non-existing button and, worse, a wxButton might get button event
1273 // from another button which is not really expected
1274 wxWindow
*winForCancel
= win
,
1276 while ( winForCancel
)
1278 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1281 // found a cancel button
1285 if ( winForCancel
->IsTopLevel() )
1287 // no need to look further
1291 // maybe our parent has a cancel button?
1292 winForCancel
= winForCancel
->GetParent();
1297 wxCommandEvent
event(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1298 event
.SetEventObject(btnCancel
);
1299 ret
= btnCancel
->GetEventHandler()->ProcessEvent(event
);
1305 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1313 static void gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1317 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1319 // take modifiers, cursor position, timestamp etc. from the last
1320 // key_press_event that was fed into Input Method:
1321 if (window
->m_imData
->lastKeyEvent
)
1323 wxFillOtherKeyEventFields(event
,
1324 window
, window
->m_imData
->lastKeyEvent
);
1328 const wxWCharBuffer data
= wxConvUTF8
.cMB2WC( (char*)str
);
1330 const wxWCharBuffer wdata
= wxConvUTF8
.cMB2WC( (char*)str
);
1331 const wxCharBuffer data
= wxConvLocal
.cWC2MB( wdata
);
1332 #endif // wxUSE_UNICODE
1333 if( !(const wxChar
*)data
)
1338 // Implement OnCharHook by checking ancestor top level windows
1339 wxWindow
*parent
= window
;
1340 while (parent
&& !parent
->IsTopLevel())
1341 parent
= parent
->GetParent();
1343 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1346 event
.m_uniChar
= *pstr
;
1347 // Backward compatible for ISO-8859
1348 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1349 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1351 event
.m_keyCode
= *pstr
;
1352 #endif // wxUSE_UNICODE
1355 event
.SetEventType( wxEVT_CHAR_HOOK
);
1356 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1361 event
.SetEventType(wxEVT_CHAR
);
1362 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1369 //-----------------------------------------------------------------------------
1370 // "key_release_event" from any window
1371 //-----------------------------------------------------------------------------
1373 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1374 GdkEventKey
*gdk_event
,
1380 wxapp_install_idle_handler();
1385 if (g_blockEventsOnDrag
)
1388 wxKeyEvent
event( wxEVT_KEY_UP
);
1389 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1391 // unknown key pressed, ignore (the event would be useless anyhow
1395 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1398 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1402 // ============================================================================
1404 // ============================================================================
1406 // ----------------------------------------------------------------------------
1407 // mouse event processing helpers
1408 // ----------------------------------------------------------------------------
1410 // init wxMouseEvent with the info from GdkEventXXX struct
1411 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1412 wxMouseEvent
& event
,
1415 event
.SetTimestamp( gdk_event
->time
);
1416 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1417 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1418 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1419 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1420 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1421 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1422 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1423 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1425 event
.m_linesPerAction
= 3;
1426 event
.m_wheelDelta
= 120;
1427 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1428 event
.m_wheelRotation
= 120;
1429 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1430 event
.m_wheelRotation
= -120;
1433 wxPoint pt
= win
->GetClientAreaOrigin();
1434 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1435 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1437 event
.SetEventObject( win
);
1438 event
.SetId( win
->GetId() );
1439 event
.SetTimestamp( gdk_event
->time
);
1442 static void AdjustEventButtonState(wxMouseEvent
& event
)
1444 // GDK reports the old state of the button for a button press event, but
1445 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1446 // for a LEFT_DOWN event, not FALSE, so we will invert
1447 // left/right/middleDown for the corresponding click events
1449 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1450 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1451 (event
.GetEventType() == wxEVT_LEFT_UP
))
1453 event
.m_leftDown
= !event
.m_leftDown
;
1457 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1458 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1459 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1461 event
.m_middleDown
= !event
.m_middleDown
;
1465 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1466 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1467 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1469 event
.m_rightDown
= !event
.m_rightDown
;
1474 // find the window to send the mouse event too
1476 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1481 if (win
->m_wxwindow
)
1483 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1484 xx
+= pizza
->xoffset
;
1485 yy
+= pizza
->yoffset
;
1488 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1491 wxWindowGTK
*child
= node
->GetData();
1493 node
= node
->GetNext();
1494 if (!child
->IsShown())
1497 if (child
->IsTransparentForMouse())
1499 // wxStaticBox is transparent in the box itself
1500 int xx1
= child
->m_x
;
1501 int yy1
= child
->m_y
;
1502 int xx2
= child
->m_x
+ child
->m_width
;
1503 int yy2
= child
->m_y
+ child
->m_height
;
1506 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1508 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1510 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1512 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1523 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1524 (child
->m_x
<= xx
) &&
1525 (child
->m_y
<= yy
) &&
1526 (child
->m_x
+child
->m_width
>= xx
) &&
1527 (child
->m_y
+child
->m_height
>= yy
))
1540 //-----------------------------------------------------------------------------
1541 // "button_press_event"
1542 //-----------------------------------------------------------------------------
1544 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1545 GdkEventButton
*gdk_event
,
1551 wxapp_install_idle_handler();
1554 wxPrintf( wxT("1) OnButtonPress from ") );
1555 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1556 wxPrintf( win->GetClassInfo()->GetClassName() );
1557 wxPrintf( wxT(".\n") );
1559 if (!win
->m_hasVMT
) return FALSE
;
1560 if (g_blockEventsOnDrag
) return TRUE
;
1561 if (g_blockEventsOnScroll
) return TRUE
;
1563 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1565 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1567 gtk_widget_grab_focus( win
->m_wxwindow
);
1569 wxPrintf( wxT("GrabFocus from ") );
1570 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1571 wxPrintf( win->GetClassInfo()->GetClassName() );
1572 wxPrintf( wxT(".\n") );
1576 // GDK sends surplus button down event
1577 // before a double click event. We
1578 // need to filter these out.
1579 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1581 GdkEvent
*peek_event
= gdk_event_peek();
1584 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1585 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1587 gdk_event_free( peek_event
);
1592 gdk_event_free( peek_event
);
1597 wxEventType event_type
= wxEVT_NULL
;
1599 // GdkDisplay is a GTK+ 2.2.0 thing
1600 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1601 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1602 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1604 // Reset GDK internal timestamp variables in order to disable GDK
1605 // triple click events. GDK will then next time believe no button has
1606 // been clicked just before, and send a normal button click event.
1607 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1608 display
->button_click_time
[1] = 0;
1609 display
->button_click_time
[0] = 0;
1613 if (gdk_event
->button
== 1)
1615 // note that GDK generates triple click events which are not supported
1616 // by wxWidgets but still have to be passed to the app as otherwise
1617 // clicks would simply go missing
1618 switch (gdk_event
->type
)
1620 // we shouldn't get triple clicks at all for GTK2 because we
1621 // suppress them artificially using the code above but we still
1622 // should map them to something for GTK1 and not just ignore them
1623 // as this would lose clicks
1624 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1625 case GDK_BUTTON_PRESS
:
1626 event_type
= wxEVT_LEFT_DOWN
;
1629 case GDK_2BUTTON_PRESS
:
1630 event_type
= wxEVT_LEFT_DCLICK
;
1634 // just to silence gcc warnings
1638 else if (gdk_event
->button
== 2)
1640 switch (gdk_event
->type
)
1642 case GDK_3BUTTON_PRESS
:
1643 case GDK_BUTTON_PRESS
:
1644 event_type
= wxEVT_MIDDLE_DOWN
;
1647 case GDK_2BUTTON_PRESS
:
1648 event_type
= wxEVT_MIDDLE_DCLICK
;
1655 else if (gdk_event
->button
== 3)
1657 switch (gdk_event
->type
)
1659 case GDK_3BUTTON_PRESS
:
1660 case GDK_BUTTON_PRESS
:
1661 event_type
= wxEVT_RIGHT_DOWN
;
1664 case GDK_2BUTTON_PRESS
:
1665 event_type
= wxEVT_RIGHT_DCLICK
;
1672 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1674 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1676 event_type
= wxEVT_MOUSEWHEEL
;
1680 if ( event_type
== wxEVT_NULL
)
1682 // unknown mouse button or click type
1686 wxMouseEvent
event( event_type
);
1687 InitMouseEvent( win
, event
, gdk_event
);
1689 AdjustEventButtonState(event
);
1691 // wxListBox actually get mouse events from the item, so we need to give it
1692 // a chance to correct this
1693 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1695 if ( event_type
== wxEVT_RIGHT_DOWN
)
1697 // generate a "context menu" event: this is similar to right mouse
1698 // click under many GUIs except that it is generated differently
1699 // (right up under MSW, ctrl-click under Mac, right down here) and
1701 // (a) it's a command event and so is propagated to the parent
1702 // (b) under MSW it can be generated from kbd too
1703 // (c) it uses screen coords (because of (a))
1704 wxContextMenuEvent
evtCtx(wxEVT_CONTEXT_MENU
,
1706 win
->ClientToScreen(event
.GetPosition()));
1707 (void)win
->GetEventHandler()->ProcessEvent(evtCtx
);
1710 // find the correct window to send the event too: it may be a different one
1711 // from the one which got it at GTK+ level because some control don't have
1712 // their own X window and thus cannot get any events.
1713 if ( !g_captureWindow
)
1714 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1716 gs_timeLastClick
= gdk_event
->time
;
1719 if (event_type
== wxEVT_LEFT_DCLICK
)
1721 // GTK 1.2 crashes when intercepting double
1722 // click events from both wxSpinButton and
1724 if (GTK_IS_SPIN_BUTTON(win
->m_widget
))
1726 // Just disable this event for now.
1732 if (win
->GetEventHandler()->ProcessEvent( event
))
1734 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1741 //-----------------------------------------------------------------------------
1742 // "button_release_event"
1743 //-----------------------------------------------------------------------------
1745 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1746 GdkEventButton
*gdk_event
,
1752 wxapp_install_idle_handler();
1754 if (!win
->m_hasVMT
) return FALSE
;
1755 if (g_blockEventsOnDrag
) return FALSE
;
1756 if (g_blockEventsOnScroll
) return FALSE
;
1758 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1760 wxEventType event_type
= wxEVT_NULL
;
1762 switch (gdk_event
->button
)
1765 event_type
= wxEVT_LEFT_UP
;
1769 event_type
= wxEVT_MIDDLE_UP
;
1773 event_type
= wxEVT_RIGHT_UP
;
1777 // unknwon button, don't process
1781 wxMouseEvent
event( event_type
);
1782 InitMouseEvent( win
, event
, gdk_event
);
1784 AdjustEventButtonState(event
);
1786 // same wxListBox hack as above
1787 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1789 if ( !g_captureWindow
)
1790 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1792 if (win
->GetEventHandler()->ProcessEvent( event
))
1794 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1801 //-----------------------------------------------------------------------------
1802 // "motion_notify_event"
1803 //-----------------------------------------------------------------------------
1805 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1806 GdkEventMotion
*gdk_event
,
1812 wxapp_install_idle_handler();
1814 if (!win
->m_hasVMT
) return FALSE
;
1815 if (g_blockEventsOnDrag
) return FALSE
;
1816 if (g_blockEventsOnScroll
) return FALSE
;
1818 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1820 if (gdk_event
->is_hint
)
1824 GdkModifierType state
;
1825 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1831 printf( "OnMotion from " );
1832 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1833 printf( win->GetClassInfo()->GetClassName() );
1837 wxMouseEvent
event( wxEVT_MOTION
);
1838 InitMouseEvent(win
, event
, gdk_event
);
1840 if ( g_captureWindow
)
1842 // synthetize a mouse enter or leave event if needed
1843 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1844 // This seems to be necessary and actually been added to
1845 // GDK itself in version 2.0.X
1848 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1849 if ( hasMouse
!= g_captureWindowHasMouse
)
1851 // the mouse changed window
1852 g_captureWindowHasMouse
= hasMouse
;
1854 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1855 : wxEVT_LEAVE_WINDOW
);
1856 InitMouseEvent(win
, event
, gdk_event
);
1857 event
.SetEventObject(win
);
1858 win
->GetEventHandler()->ProcessEvent(event
);
1863 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1866 if (win
->GetEventHandler()->ProcessEvent( event
))
1868 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1876 //-----------------------------------------------------------------------------
1877 // "mouse_wheel_event"
1878 //-----------------------------------------------------------------------------
1880 static gint
gtk_window_wheel_callback (GtkWidget
* widget
,
1881 GdkEventScroll
* gdk_event
,
1887 wxapp_install_idle_handler();
1889 wxEventType event_type
= wxEVT_NULL
;
1890 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1891 event_type
= wxEVT_MOUSEWHEEL
;
1892 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1893 event_type
= wxEVT_MOUSEWHEEL
;
1897 wxMouseEvent
event( event_type
);
1898 // Can't use InitMouse macro because scroll events don't have button
1899 event
.SetTimestamp( gdk_event
->time
);
1900 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1901 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1902 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1903 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1904 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1905 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1906 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1907 event
.m_linesPerAction
= 3;
1908 event
.m_wheelDelta
= 120;
1909 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1910 event
.m_wheelRotation
= 120;
1912 event
.m_wheelRotation
= -120;
1914 wxPoint pt
= win
->GetClientAreaOrigin();
1915 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1916 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1918 event
.SetEventObject( win
);
1919 event
.SetId( win
->GetId() );
1920 event
.SetTimestamp( gdk_event
->time
);
1922 if (win
->GetEventHandler()->ProcessEvent( event
))
1924 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "scroll_event" );
1932 //-----------------------------------------------------------------------------
1934 //-----------------------------------------------------------------------------
1936 // send the wxChildFocusEvent and wxFocusEvent, common code of
1937 // gtk_window_focus_in_callback() and SetFocus()
1938 static bool DoSendFocusEvents(wxWindow
*win
)
1940 // Notify the parent keeping track of focus for the kbd navigation
1941 // purposes that we got it.
1942 wxChildFocusEvent
eventChildFocus(win
);
1943 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1945 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1946 eventFocus
.SetEventObject(win
);
1948 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1951 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1952 GdkEvent
*WXUNUSED(event
),
1958 wxapp_install_idle_handler();
1962 gtk_im_context_focus_in(win
->m_imData
->context
);
1966 g_focusWindow
= win
;
1968 wxLogTrace(TRACE_FOCUS
,
1969 _T("%s: focus in"), win
->GetName().c_str());
1973 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1977 // caret needs to be informed about focus change
1978 wxCaret
*caret
= win
->GetCaret();
1981 caret
->OnSetFocus();
1983 #endif // wxUSE_CARET
1985 // does the window itself think that it has the focus?
1986 if ( !win
->m_hasFocus
)
1988 // not yet, notify it
1989 win
->m_hasFocus
= TRUE
;
1991 if ( DoSendFocusEvents(win
) )
1993 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
2001 //-----------------------------------------------------------------------------
2002 // "focus_out_event"
2003 //-----------------------------------------------------------------------------
2005 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
2010 wxapp_install_idle_handler();
2014 gtk_im_context_focus_out(win
->m_imData
->context
);
2017 wxLogTrace( TRACE_FOCUS
,
2018 _T("%s: focus out"), win
->GetName().c_str() );
2021 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
2025 g_focusWindow
= (wxWindowGTK
*)NULL
;
2033 // caret needs to be informed about focus change
2034 wxCaret
*caret
= win
->GetCaret();
2037 caret
->OnKillFocus();
2039 #endif // wxUSE_CARET
2041 // don't send the window a kill focus event if it thinks that it doesn't
2042 // have focus already
2043 if ( win
->m_hasFocus
)
2045 win
->m_hasFocus
= FALSE
;
2047 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
2048 event
.SetEventObject( win
);
2050 // even if we did process the event in wx code, still let GTK itself
2051 // process it too as otherwise bad things happen, especially in GTK2
2052 // where the text control simply aborts the program if it doesn't get
2053 // the matching focus out event
2054 (void)win
->GetEventHandler()->ProcessEvent( event
);
2060 //-----------------------------------------------------------------------------
2061 // "enter_notify_event"
2062 //-----------------------------------------------------------------------------
2065 gint
gtk_window_enter_callback( GtkWidget
*widget
,
2066 GdkEventCrossing
*gdk_event
,
2072 wxapp_install_idle_handler();
2074 if (!win
->m_hasVMT
) return FALSE
;
2075 if (g_blockEventsOnDrag
) return FALSE
;
2077 // Event was emitted after a grab
2078 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2080 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2084 GdkModifierType state
= (GdkModifierType
)0;
2086 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2088 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2089 InitMouseEvent(win
, event
, gdk_event
);
2090 wxPoint pt
= win
->GetClientAreaOrigin();
2091 event
.m_x
= x
+ pt
.x
;
2092 event
.m_y
= y
+ pt
.y
;
2094 if (win
->GetEventHandler()->ProcessEvent( event
))
2096 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
2103 //-----------------------------------------------------------------------------
2104 // "leave_notify_event"
2105 //-----------------------------------------------------------------------------
2107 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
2112 wxapp_install_idle_handler();
2114 if (!win
->m_hasVMT
) return FALSE
;
2115 if (g_blockEventsOnDrag
) return FALSE
;
2117 // Event was emitted after an ungrab
2118 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2120 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2122 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2123 event
.SetTimestamp( gdk_event
->time
);
2124 event
.SetEventObject( win
);
2128 GdkModifierType state
= (GdkModifierType
)0;
2130 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2132 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2133 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2134 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2135 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2136 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2137 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2138 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2140 wxPoint pt
= win
->GetClientAreaOrigin();
2141 event
.m_x
= x
+ pt
.x
;
2142 event
.m_y
= y
+ pt
.y
;
2144 if (win
->GetEventHandler()->ProcessEvent( event
))
2146 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
2153 //-----------------------------------------------------------------------------
2154 // "value_changed" from m_vAdjust
2155 //-----------------------------------------------------------------------------
2157 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2164 wxapp_install_idle_handler();
2166 if (g_blockEventsOnDrag
) return;
2168 if (!win
->m_hasVMT
) return;
2170 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2171 if (fabs(diff
) < 0.2) return;
2173 win
->m_oldVerticalPos
= adjust
->value
;
2176 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2178 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
2180 int value
= (int)(adjust
->value
+0.5);
2182 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2183 event
.SetEventObject( win
);
2184 win
->GetEventHandler()->ProcessEvent( event
);
2187 //-----------------------------------------------------------------------------
2188 // "value_changed" from m_hAdjust
2189 //-----------------------------------------------------------------------------
2191 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2198 wxapp_install_idle_handler();
2200 if (g_blockEventsOnDrag
) return;
2201 if (!win
->m_hasVMT
) return;
2203 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2204 if (fabs(diff
) < 0.2) return;
2207 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2209 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
2211 win
->m_oldHorizontalPos
= adjust
->value
;
2213 int value
= (int)(adjust
->value
+0.5);
2215 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2216 event
.SetEventObject( win
);
2217 win
->GetEventHandler()->ProcessEvent( event
);
2220 //-----------------------------------------------------------------------------
2221 // "button_press_event" from scrollbar
2222 //-----------------------------------------------------------------------------
2224 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2225 GdkEventButton
*gdk_event
,
2231 wxapp_install_idle_handler();
2234 g_blockEventsOnScroll
= TRUE
;
2236 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2238 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2244 //-----------------------------------------------------------------------------
2245 // "button_release_event" from scrollbar
2246 //-----------------------------------------------------------------------------
2248 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2249 GdkEventButton
*WXUNUSED(gdk_event
),
2254 // don't test here as we can release the mouse while being over
2255 // a different window than the slider
2257 // if (gdk_event->window != widget->slider) return FALSE;
2259 g_blockEventsOnScroll
= FALSE
;
2261 if (win
->m_isScrolling
)
2263 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2267 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2268 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2270 value
= (int)(win
->m_hAdjust
->value
+0.5);
2273 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2275 value
= (int)(win
->m_vAdjust
->value
+0.5);
2279 wxScrollWinEvent
event( command
, value
, dir
);
2280 event
.SetEventObject( win
);
2281 win
->GetEventHandler()->ProcessEvent( event
);
2284 win
->m_isScrolling
= FALSE
;
2289 // ----------------------------------------------------------------------------
2290 // this wxWindowBase function is implemented here (in platform-specific file)
2291 // because it is static and so couldn't be made virtual
2292 // ----------------------------------------------------------------------------
2294 wxWindow
*wxWindowBase::DoFindFocus()
2296 // the cast is necessary when we compile in wxUniversal mode
2297 return (wxWindow
*)g_focusWindow
;
2301 //-----------------------------------------------------------------------------
2302 // "realize" from m_widget
2303 //-----------------------------------------------------------------------------
2305 /* We cannot set colours and fonts before the widget has
2306 been realized, so we do this directly after realization. */
2309 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2314 wxapp_install_idle_handler();
2319 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2320 gtk_im_context_set_client_window( win
->m_imData
->context
,
2321 pizza
->bin_window
);
2325 wxWindowCreateEvent
event( win
);
2326 event
.SetEventObject( win
);
2327 win
->GetEventHandler()->ProcessEvent( event
);
2332 //-----------------------------------------------------------------------------
2334 //-----------------------------------------------------------------------------
2337 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2338 GtkAllocation
*WXUNUSED(alloc
),
2342 wxapp_install_idle_handler();
2344 if (!win
->m_hasScrolling
) return;
2346 int client_width
= 0;
2347 int client_height
= 0;
2348 win
->GetClientSize( &client_width
, &client_height
);
2349 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2352 win
->m_oldClientWidth
= client_width
;
2353 win
->m_oldClientHeight
= client_height
;
2355 if (!win
->m_nativeSizeEvent
)
2357 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2358 event
.SetEventObject( win
);
2359 win
->GetEventHandler()->ProcessEvent( event
);
2365 #define WXUNUSED_UNLESS_XIM(param) param
2367 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2370 /* Resize XIM window */
2373 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2374 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2375 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2378 wxapp_install_idle_handler();
2384 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2388 gdk_window_get_size (widget
->window
, &width
, &height
);
2389 win
->m_icattr
->preedit_area
.width
= width
;
2390 win
->m_icattr
->preedit_area
.height
= height
;
2391 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2396 //-----------------------------------------------------------------------------
2397 // "realize" from m_wxwindow
2398 //-----------------------------------------------------------------------------
2400 /* Initialize XIM support */
2403 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2404 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2407 wxapp_install_idle_handler();
2410 if (win
->m_ic
) return FALSE
;
2411 if (!widget
) return FALSE
;
2412 if (!gdk_im_ready()) return FALSE
;
2414 win
->m_icattr
= gdk_ic_attr_new();
2415 if (!win
->m_icattr
) return FALSE
;
2419 GdkColormap
*colormap
;
2420 GdkICAttr
*attr
= win
->m_icattr
;
2421 unsigned attrmask
= GDK_IC_ALL_REQ
;
2423 GdkIMStyle supported_style
= (GdkIMStyle
)
2424 (GDK_IM_PREEDIT_NONE
|
2425 GDK_IM_PREEDIT_NOTHING
|
2426 GDK_IM_PREEDIT_POSITION
|
2427 GDK_IM_STATUS_NONE
|
2428 GDK_IM_STATUS_NOTHING
);
2430 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2431 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2433 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2434 attr
->client_window
= widget
->window
;
2436 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2437 gtk_widget_get_default_colormap ())
2439 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2440 attr
->preedit_colormap
= colormap
;
2443 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2444 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2445 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2446 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2448 switch (style
& GDK_IM_PREEDIT_MASK
)
2450 case GDK_IM_PREEDIT_POSITION
:
2451 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2453 g_warning ("over-the-spot style requires fontset");
2457 gdk_window_get_size (widget
->window
, &width
, &height
);
2459 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2460 attr
->spot_location
.x
= 0;
2461 attr
->spot_location
.y
= height
;
2462 attr
->preedit_area
.x
= 0;
2463 attr
->preedit_area
.y
= 0;
2464 attr
->preedit_area
.width
= width
;
2465 attr
->preedit_area
.height
= height
;
2466 attr
->preedit_fontset
= widget
->style
->font
;
2471 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2473 if (win
->m_ic
== NULL
)
2474 g_warning ("Can't create input context.");
2477 mask
= gdk_window_get_events (widget
->window
);
2478 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2479 gdk_window_set_events (widget
->window
, mask
);
2481 if (GTK_WIDGET_HAS_FOCUS(widget
))
2482 gdk_im_begin (win
->m_ic
, widget
->window
);
2489 //-----------------------------------------------------------------------------
2490 // InsertChild for wxWindowGTK.
2491 //-----------------------------------------------------------------------------
2493 /* Callback for wxWindowGTK. This very strange beast has to be used because
2494 * C++ has no virtual methods in a constructor. We have to emulate a
2495 * virtual function here as wxNotebook requires a different way to insert
2496 * a child in it. I had opted for creating a wxNotebookPage window class
2497 * which would have made this superfluous (such in the MDI window system),
2498 * but no-one was listening to me... */
2500 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2502 /* the window might have been scrolled already, do we
2503 have to adapt the position */
2504 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2505 child
->m_x
+= pizza
->xoffset
;
2506 child
->m_y
+= pizza
->yoffset
;
2508 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2509 GTK_WIDGET(child
->m_widget
),
2516 //-----------------------------------------------------------------------------
2518 //-----------------------------------------------------------------------------
2520 wxWindow
*wxGetActiveWindow()
2522 return wxWindow::FindFocus();
2525 //-----------------------------------------------------------------------------
2527 //-----------------------------------------------------------------------------
2529 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2531 #ifdef __WXUNIVERSAL__
2532 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2534 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2535 #endif // __WXUNIVERSAL__/__WXGTK__
2537 void wxWindowGTK::Init()
2540 m_widget
= (GtkWidget
*) NULL
;
2541 m_wxwindow
= (GtkWidget
*) NULL
;
2542 m_focusWidget
= (GtkWidget
*) NULL
;
2552 m_needParent
= TRUE
;
2553 m_isBeingDeleted
= FALSE
;
2556 m_nativeSizeEvent
= FALSE
;
2558 m_hasScrolling
= FALSE
;
2559 m_isScrolling
= FALSE
;
2561 m_hAdjust
= (GtkAdjustment
*) NULL
;
2562 m_vAdjust
= (GtkAdjustment
*) NULL
;
2563 m_oldHorizontalPos
=
2564 m_oldVerticalPos
= 0.0;
2566 m_oldClientHeight
= 0;
2570 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2572 m_acceptsFocus
= FALSE
;
2575 m_clipPaintRegion
= FALSE
;
2577 m_needsStyleChange
= false;
2579 m_cursor
= *wxSTANDARD_CURSOR
;
2583 m_x11Context
= NULL
;
2584 m_dirtyTabOrder
= false;
2587 m_ic
= (GdkIC
*) NULL
;
2588 m_icattr
= (GdkICAttr
*) NULL
;
2593 wxWindowGTK::wxWindowGTK()
2598 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2603 const wxString
&name
)
2607 Create( parent
, id
, pos
, size
, style
, name
);
2610 bool wxWindowGTK::Create( wxWindow
*parent
,
2615 const wxString
&name
)
2617 if (!PreCreation( parent
, pos
, size
) ||
2618 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2620 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2624 m_insertCallback
= wxInsertChildInWindow
;
2626 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2627 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2629 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2631 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2632 scroll_class
->scrollbar_spacing
= 0;
2634 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2636 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2637 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2639 m_wxwindow
= gtk_pizza_new();
2641 #ifndef __WXUNIVERSAL__
2642 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2644 if (HasFlag(wxRAISED_BORDER
))
2646 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2648 else if (HasFlag(wxSUNKEN_BORDER
))
2650 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2652 else if (HasFlag(wxSIMPLE_BORDER
))
2654 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2658 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2660 #endif // __WXUNIVERSAL__
2662 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2664 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2665 m_acceptsFocus
= TRUE
;
2667 // I _really_ don't want scrollbars in the beginning
2668 m_vAdjust
->lower
= 0.0;
2669 m_vAdjust
->upper
= 1.0;
2670 m_vAdjust
->value
= 0.0;
2671 m_vAdjust
->step_increment
= 1.0;
2672 m_vAdjust
->page_increment
= 1.0;
2673 m_vAdjust
->page_size
= 5.0;
2674 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2675 m_hAdjust
->lower
= 0.0;
2676 m_hAdjust
->upper
= 1.0;
2677 m_hAdjust
->value
= 0.0;
2678 m_hAdjust
->step_increment
= 1.0;
2679 m_hAdjust
->page_increment
= 1.0;
2680 m_hAdjust
->page_size
= 5.0;
2681 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2683 // these handlers block mouse events to any window during scrolling such as
2684 // motion events and prevent GTK and wxWidgets from fighting over where the
2687 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2688 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2690 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2691 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2693 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2694 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2696 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2697 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2699 // these handlers get notified when screen updates are required either when
2700 // scrolling or when the window size (and therefore scrollbar configuration)
2703 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2704 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2705 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2706 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2708 gtk_widget_show( m_wxwindow
);
2711 m_parent
->DoAddChild( this );
2713 m_focusWidget
= m_wxwindow
;
2720 wxWindowGTK::~wxWindowGTK()
2724 if (g_focusWindow
== this)
2725 g_focusWindow
= NULL
;
2727 if ( g_delayedFocus
== this )
2728 g_delayedFocus
= NULL
;
2730 m_isBeingDeleted
= TRUE
;
2740 gdk_ic_destroy (m_ic
);
2742 gdk_ic_attr_destroy (m_icattr
);
2747 gtk_widget_destroy( m_wxwindow
);
2748 m_wxwindow
= (GtkWidget
*) NULL
;
2753 gtk_widget_destroy( m_widget
);
2754 m_widget
= (GtkWidget
*) NULL
;
2762 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2764 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2766 // Use either the given size, or the default if -1 is given.
2767 // See wxWindowBase for these functions.
2768 m_width
= WidthDefault(size
.x
) ;
2769 m_height
= HeightDefault(size
.y
);
2777 void wxWindowGTK::PostCreation()
2779 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2785 // these get reported to wxWidgets -> wxPaintEvent
2787 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2789 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2790 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2793 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2794 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2796 if (!HasFlag(wxFULL_REPAINT_ON_RESIZE
))
2798 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2799 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2802 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2807 // Create input method handler
2808 m_imData
= new wxGtkIMData
;
2810 // Cannot handle drawing preedited text yet
2811 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2813 g_signal_connect (G_OBJECT (m_imData
->context
), "commit",
2814 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2817 // these are called when the "sunken" or "raised" borders are drawn
2818 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2819 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2822 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2823 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2829 if (!GTK_IS_WINDOW(m_widget
))
2831 if (m_focusWidget
== NULL
)
2832 m_focusWidget
= m_widget
;
2834 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2835 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2837 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2838 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2841 // connect to the various key and mouse handlers
2843 GtkWidget
*connect_widget
= GetConnectWidget();
2845 ConnectWidget( connect_widget
);
2847 /* We cannot set colours, fonts and cursors before the widget has
2848 been realized, so we do this directly after realization */
2849 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2850 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2854 // Catch native resize events
2855 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2856 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2858 // Initialize XIM support
2859 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2860 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2862 // And resize XIM window
2863 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2864 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2867 if ( !GTK_IS_COMBO(m_widget
))
2869 // This is needed if we want to add our windows into native
2870 // GTK control, such as the toolbar. With this callback, the
2871 // toolbar gets to know the correct size (the one set by the
2872 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2873 // when moving to GTK 2.0.
2874 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2875 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback
),
2879 InheritAttributes();
2883 // unless the window was created initially hidden (i.e. Hide() had been
2884 // called before Create()), we should show it at GTK+ level as well
2886 gtk_widget_show( m_widget
);
2889 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2891 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2892 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2894 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2895 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2897 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2898 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2900 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2901 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2903 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2904 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2907 gtk_signal_connect( GTK_OBJECT(widget
), "scroll_event",
2908 GTK_SIGNAL_FUNC(gtk_window_wheel_callback
), (gpointer
)this );
2911 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2912 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2914 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2915 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2918 bool wxWindowGTK::Destroy()
2920 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2924 return wxWindowBase::Destroy();
2927 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2929 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2932 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2934 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2935 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2938 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2941 if (m_resizing
) return; /* I don't like recursions */
2944 int currentX
, currentY
;
2945 GetPosition(¤tX
, ¤tY
);
2946 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2948 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2950 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2952 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2954 /* don't set the size for children of wxNotebook, just take the values. */
2962 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2963 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2965 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2966 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2970 m_x
= x
+ pizza
->xoffset
;
2971 m_y
= y
+ pizza
->yoffset
;
2974 // calculate the best size if we should auto size the window
2975 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2976 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2978 const wxSize sizeBest
= GetBestSize();
2979 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2981 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2982 height
= sizeBest
.y
;
2990 int minWidth
= GetMinWidth(),
2991 minHeight
= GetMinHeight(),
2992 maxWidth
= GetMaxWidth(),
2993 maxHeight
= GetMaxHeight();
2995 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2996 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2997 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2998 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
3001 int bottom_border
= 0;
3004 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
3006 /* the default button has a border around it */
3012 DoMoveWindow( m_x
-border
,
3015 m_height
+border
+bottom_border
);
3020 /* Sometimes the client area changes size without the
3021 whole windows's size changing, but if the whole
3022 windows's size doesn't change, no wxSizeEvent will
3023 normally be sent. Here we add an extra test if
3024 the client test has been changed and this will
3026 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
3030 wxPrintf( "OnSize sent from " );
3031 if (GetClassInfo() && GetClassInfo()->GetClassName())
3032 wxPrintf( GetClassInfo()->GetClassName() );
3033 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3036 if (!m_nativeSizeEvent
)
3038 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
3039 event
.SetEventObject( this );
3040 GetEventHandler()->ProcessEvent( event
);
3046 void wxWindowGTK::OnInternalIdle()
3049 if ( m_dirtyTabOrder
)
3052 // Update style if the window was not yet realized
3053 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
3054 if (m_needsStyleChange
)
3056 SetBackgroundStyle(GetBackgroundStyle());
3057 m_needsStyleChange
= false;
3060 // Update invalidated regions.
3063 wxCursor cursor
= m_cursor
;
3064 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3068 /* I now set the cursor anew in every OnInternalIdle call
3069 as setting the cursor in a parent window also effects the
3070 windows above so that checking for the current cursor is
3075 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3077 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3079 if (!g_globalCursor
.Ok())
3080 cursor
= *wxSTANDARD_CURSOR
;
3082 window
= m_widget
->window
;
3083 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3084 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3090 GdkWindow
*window
= m_widget
->window
;
3091 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3092 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3097 if (wxUpdateUIEvent::CanUpdate(this))
3098 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3101 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3103 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3105 if (width
) (*width
) = m_width
;
3106 if (height
) (*height
) = m_height
;
3109 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3111 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3115 SetSize( width
, height
);
3122 #ifndef __WXUNIVERSAL__
3123 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3125 /* when using GTK 1.2 we set the shadow border size to 2 */
3129 if (HasFlag(wxSIMPLE_BORDER
))
3131 /* when using GTK 1.2 we set the simple border size to 1 */
3135 #endif // __WXUNIVERSAL__
3139 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3141 GtkRequisition vscroll_req
;
3142 vscroll_req
.width
= 2;
3143 vscroll_req
.height
= 2;
3144 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3145 (scroll_window
->vscrollbar
, &vscroll_req
);
3147 GtkRequisition hscroll_req
;
3148 hscroll_req
.width
= 2;
3149 hscroll_req
.height
= 2;
3150 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3151 (scroll_window
->hscrollbar
, &hscroll_req
);
3153 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3155 if (scroll_window
->vscrollbar_visible
)
3157 dw
+= vscroll_req
.width
;
3158 dw
+= scroll_class
->scrollbar_spacing
;
3161 if (scroll_window
->hscrollbar_visible
)
3163 dh
+= hscroll_req
.height
;
3164 dh
+= scroll_class
->scrollbar_spacing
;
3168 SetSize( width
+dw
, height
+dh
);
3172 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3174 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3178 if (width
) (*width
) = m_width
;
3179 if (height
) (*height
) = m_height
;
3186 #ifndef __WXUNIVERSAL__
3187 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3189 /* when using GTK 1.2 we set the shadow border size to 2 */
3193 if (HasFlag(wxSIMPLE_BORDER
))
3195 /* when using GTK 1.2 we set the simple border size to 1 */
3199 #endif // __WXUNIVERSAL__
3203 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3205 GtkRequisition vscroll_req
;
3206 vscroll_req
.width
= 2;
3207 vscroll_req
.height
= 2;
3208 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3209 (scroll_window
->vscrollbar
, &vscroll_req
);
3211 GtkRequisition hscroll_req
;
3212 hscroll_req
.width
= 2;
3213 hscroll_req
.height
= 2;
3214 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3215 (scroll_window
->hscrollbar
, &hscroll_req
);
3217 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3219 if (scroll_window
->vscrollbar_visible
)
3221 dw
+= vscroll_req
.width
;
3222 dw
+= scroll_class
->scrollbar_spacing
;
3225 if (scroll_window
->hscrollbar_visible
)
3227 dh
+= hscroll_req
.height
;
3228 dh
+= scroll_class
->scrollbar_spacing
;
3232 if (width
) (*width
) = m_width
- dw
;
3233 if (height
) (*height
) = m_height
- dh
;
3237 printf( "GetClientSize, name %s ", GetName().c_str() );
3238 if (width) printf( " width = %d", (*width) );
3239 if (height) printf( " height = %d", (*height) );
3244 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3246 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3250 if (m_parent
&& m_parent
->m_wxwindow
)
3252 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3253 dx
= pizza
->xoffset
;
3254 dy
= pizza
->yoffset
;
3257 if (x
) (*x
) = m_x
- dx
;
3258 if (y
) (*y
) = m_y
- dy
;
3261 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3263 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3265 if (!m_widget
->window
) return;
3267 GdkWindow
*source
= (GdkWindow
*) NULL
;
3269 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3271 source
= m_widget
->window
;
3275 gdk_window_get_origin( source
, &org_x
, &org_y
);
3279 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3281 org_x
+= m_widget
->allocation
.x
;
3282 org_y
+= m_widget
->allocation
.y
;
3290 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3292 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3294 if (!m_widget
->window
) return;
3296 GdkWindow
*source
= (GdkWindow
*) NULL
;
3298 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3300 source
= m_widget
->window
;
3304 gdk_window_get_origin( source
, &org_x
, &org_y
);
3308 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3310 org_x
+= m_widget
->allocation
.x
;
3311 org_y
+= m_widget
->allocation
.y
;
3319 bool wxWindowGTK::Show( bool show
)
3321 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3323 if (!wxWindowBase::Show(show
))
3330 gtk_widget_show( m_widget
);
3332 gtk_widget_hide( m_widget
);
3334 wxShowEvent
eventShow(GetId(), show
);
3335 eventShow
.m_eventObject
= this;
3337 GetEventHandler()->ProcessEvent(eventShow
);
3342 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3344 win
->OnParentEnable(enable
);
3346 // Recurse, so that children have the opportunity to Do The Right Thing
3347 // and reset colours that have been messed up by a parent's (really ancestor's)
3349 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3351 node
= node
->GetNext() )
3353 wxWindow
*child
= node
->GetData();
3354 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3355 wxWindowNotifyEnable(child
, enable
);
3359 bool wxWindowGTK::Enable( bool enable
)
3361 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3363 if (!wxWindowBase::Enable(enable
))
3369 gtk_widget_set_sensitive( m_widget
, enable
);
3371 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3373 wxWindowNotifyEnable(this, enable
);
3378 int wxWindowGTK::GetCharHeight() const
3380 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3382 wxFont font
= GetFont();
3383 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3386 PangoContext
*context
= NULL
;
3388 context
= gtk_widget_get_pango_context( m_widget
);
3393 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3394 PangoLayout
*layout
= pango_layout_new(context
);
3395 pango_layout_set_font_description(layout
, desc
);
3396 pango_layout_set_text(layout
, "H", 1);
3397 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3399 PangoRectangle rect
;
3400 pango_layout_line_get_extents(line
, NULL
, &rect
);
3402 g_object_unref( G_OBJECT( layout
) );
3404 return (int) PANGO_PIXELS(rect
.height
);
3406 GdkFont
*gfont
= font
.GetInternalFont( 1.0 );
3408 return gfont
->ascent
+ gfont
->descent
;
3412 int wxWindowGTK::GetCharWidth() const
3414 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3416 wxFont font
= GetFont();
3417 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3420 PangoContext
*context
= NULL
;
3422 context
= gtk_widget_get_pango_context( m_widget
);
3427 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3428 PangoLayout
*layout
= pango_layout_new(context
);
3429 pango_layout_set_font_description(layout
, desc
);
3430 pango_layout_set_text(layout
, "g", 1);
3431 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3433 PangoRectangle rect
;
3434 pango_layout_line_get_extents(line
, NULL
, &rect
);
3436 g_object_unref( G_OBJECT( layout
) );
3438 return (int) PANGO_PIXELS(rect
.width
);
3440 GdkFont
*gfont
= font
.GetInternalFont( 1.0 );
3442 return gdk_string_width( gfont
, "g" );
3446 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3450 int *externalLeading
,
3451 const wxFont
*theFont
) const
3453 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3455 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3457 if (string
.IsEmpty())
3465 PangoContext
*context
= NULL
;
3467 context
= gtk_widget_get_pango_context( m_widget
);
3476 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3477 PangoLayout
*layout
= pango_layout_new(context
);
3478 pango_layout_set_font_description(layout
, desc
);
3481 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3482 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3484 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3485 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3486 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3490 PangoRectangle rect
;
3491 pango_layout_get_extents(layout
, NULL
, &rect
);
3493 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3494 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3497 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3498 int baseline
= pango_layout_iter_get_baseline(iter
);
3499 pango_layout_iter_free(iter
);
3500 *descent
= *y
- PANGO_PIXELS(baseline
);
3502 if (externalLeading
) (*externalLeading
) = 0; // ??
3504 g_object_unref( G_OBJECT( layout
) );
3506 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3507 if (x
) (*x
) = gdk_string_width( font
, wxGTK_CONV( string
) );
3508 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3509 if (descent
) (*descent
) = font
->descent
;
3510 if (externalLeading
) (*externalLeading
) = 0; // ??
3514 void wxWindowGTK::SetFocus()
3516 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3519 // don't do anything if we already have focus
3525 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3527 gtk_widget_grab_focus (m_wxwindow
);
3533 if (GTK_IS_CONTAINER(m_widget
))
3535 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3539 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3542 if (!GTK_WIDGET_REALIZED(m_widget
))
3544 // we can't set the focus to the widget now so we remember that
3545 // it should be focused and will do it later, during the idle
3546 // time, as soon as we can
3547 wxLogTrace(TRACE_FOCUS
,
3548 _T("Delaying setting focus to %s(%s)"),
3549 GetClassInfo()->GetClassName(), GetLabel().c_str());
3551 g_delayedFocus
= this;
3555 wxLogTrace(TRACE_FOCUS
,
3556 _T("Setting focus to %s(%s)"),
3557 GetClassInfo()->GetClassName(), GetLabel().c_str());
3559 gtk_widget_grab_focus (m_widget
);
3564 if (GTK_IS_CONTAINER(m_widget
))
3566 gtk_container_focus( GTK_CONTAINER(m_widget
), GTK_DIR_TAB_FORWARD
);
3571 wxLogTrace(TRACE_FOCUS
,
3572 _T("Can't set focus to %s(%s)"),
3573 GetClassInfo()->GetClassName(), GetLabel().c_str());
3578 bool wxWindowGTK::AcceptsFocus() const
3580 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3583 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3585 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3587 wxWindowGTK
*oldParent
= m_parent
,
3588 *newParent
= (wxWindowGTK
*)newParentBase
;
3590 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3592 if ( !wxWindowBase::Reparent(newParent
) )
3595 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3597 /* prevent GTK from deleting the widget arbitrarily */
3598 gtk_widget_ref( m_widget
);
3602 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3605 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3609 /* insert GTK representation */
3610 (*(newParent
->m_insertCallback
))(newParent
, this);
3613 /* reverse: prevent GTK from deleting the widget arbitrarily */
3614 gtk_widget_unref( m_widget
);
3619 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3621 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3623 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3625 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3630 /* insert GTK representation */
3631 (*m_insertCallback
)(this, child
);
3636 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3638 wxWindowBase::AddChild(child
);
3639 m_dirtyTabOrder
= true;
3641 wxapp_install_idle_handler();
3644 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3646 wxWindowBase::RemoveChild(child
);
3647 m_dirtyTabOrder
= true;
3649 wxapp_install_idle_handler();
3652 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3654 wxWindowBase::DoMoveInTabOrder(win
, move
);
3655 m_dirtyTabOrder
= true;
3657 wxapp_install_idle_handler();
3660 void wxWindowGTK::RealizeTabOrder()
3664 if (m_children
.size() > 0)
3666 GList
*chain
= NULL
;
3668 for (wxWindowList::const_iterator i
= m_children
.begin();
3669 i
!= m_children
.end(); ++i
)
3671 chain
= g_list_prepend(chain
, (*i
)->m_widget
);
3674 chain
= g_list_reverse(chain
);
3676 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3681 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3685 m_dirtyTabOrder
= false;
3688 #endif // __WXGTK20__
3690 void wxWindowGTK::Raise()
3692 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3694 if (!m_widget
->window
) return;
3696 gdk_window_raise( m_widget
->window
);
3699 void wxWindowGTK::Lower()
3701 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3703 if (!m_widget
->window
) return;
3705 gdk_window_lower( m_widget
->window
);
3708 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3710 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3712 if (cursor
== m_cursor
)
3716 wxapp_install_idle_handler();
3718 if (cursor
== wxNullCursor
)
3719 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3721 return wxWindowBase::SetCursor( cursor
);
3724 void wxWindowGTK::WarpPointer( int x
, int y
)
3726 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3728 // We provide this function ourselves as it is
3729 // missing in GDK (top of this file).
3731 GdkWindow
*window
= (GdkWindow
*) NULL
;
3733 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3735 window
= GetConnectWidget()->window
;
3738 gdk_window_warp_pointer( window
, x
, y
);
3742 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3744 if (!m_widget
) return;
3745 if (!m_widget
->window
) return;
3749 wxapp_install_idle_handler();
3751 wxRect
myRect(0,0,0,0);
3752 if (m_wxwindow
&& rect
)
3754 myRect
.SetSize(wxSize( m_wxwindow
->allocation
.width
,
3755 m_wxwindow
->allocation
.height
));
3756 myRect
.Intersect(*rect
);
3757 if (!myRect
.width
|| !myRect
.height
)
3758 // nothing to do, rectangle is empty
3763 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3767 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3768 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3772 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3773 m_clearRegion
.Clear();
3774 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3782 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3783 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3787 GdkRectangle gdk_rect
;
3788 gdk_rect
.x
= rect
->x
;
3789 gdk_rect
.y
= rect
->y
;
3790 gdk_rect
.width
= rect
->width
;
3791 gdk_rect
.height
= rect
->height
;
3792 gtk_widget_draw( m_widget
, &gdk_rect
);
3799 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3800 m_updateRegion
.Clear();
3801 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3805 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3813 GdkRectangle gdk_rect
;
3814 gdk_rect
.x
= rect
->x
;
3815 gdk_rect
.y
= rect
->y
;
3816 gdk_rect
.width
= rect
->width
;
3817 gdk_rect
.height
= rect
->height
;
3818 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3822 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3828 void wxWindowGTK::Update()
3833 void wxWindowGTK::GtkUpdate()
3836 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3837 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3839 if (!m_updateRegion
.IsEmpty())
3840 GtkSendPaintEvents();
3844 void wxWindowGTK::GtkSendPaintEvents()
3849 m_clearRegion
.Clear();
3851 m_updateRegion
.Clear();
3855 // Clip to paint region in wxClientDC
3856 m_clipPaintRegion
= TRUE
;
3858 // widget to draw on
3859 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3861 if (GetThemeEnabled() && GetBackgroundStyle() == wxBG_STYLE_SYSTEM
)
3863 // find ancestor from which to steal background
3864 wxWindow
*parent
= GetParent();
3865 while (parent
&& !parent
->IsTopLevel())
3866 parent
= parent
->GetParent();
3868 parent
= (wxWindow
*)this;
3870 wxRegionIterator
upd( m_updateRegion
);
3874 rect
.x
= upd
.GetX();
3875 rect
.y
= upd
.GetY();
3876 rect
.width
= upd
.GetWidth();
3877 rect
.height
= upd
.GetHeight();
3879 gtk_paint_flat_box( parent
->m_widget
->style
,
3881 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3895 wxWindowDC
dc( (wxWindow
*)this );
3896 dc
.SetClippingRegion( m_updateRegion
);
3898 wxEraseEvent
erase_event( GetId(), &dc
);
3899 erase_event
.SetEventObject( this );
3901 GetEventHandler()->ProcessEvent(erase_event
);
3904 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
3906 wxWindowDC
dc( (wxWindow
*)this );
3907 if (m_clearRegion
.IsEmpty())
3908 dc
.SetClippingRegion( m_updateRegion
);
3910 dc
.SetClippingRegion( m_clearRegion
);
3912 wxEraseEvent
erase_event( GetId(), &dc
);
3913 erase_event
.SetEventObject( this );
3915 if (!GetEventHandler()->ProcessEvent(erase_event
) && GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3919 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
3920 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3922 gdk_gc_set_foreground( g_eraseGC
, GetBackgroundColour().GetColor() );
3924 wxRegionIterator
upd( m_clearRegion
);
3927 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3928 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3932 m_clearRegion
.Clear();
3936 wxNcPaintEvent
nc_paint_event( GetId() );
3937 nc_paint_event
.SetEventObject( this );
3938 GetEventHandler()->ProcessEvent( nc_paint_event
);
3940 wxPaintEvent
paint_event( GetId() );
3941 paint_event
.SetEventObject( this );
3942 GetEventHandler()->ProcessEvent( paint_event
);
3944 m_clipPaintRegion
= FALSE
;
3946 #ifndef __WXUNIVERSAL__
3948 // The following code will result in all window-less widgets
3949 // being redrawn because the wxWidgets class is allowed to
3950 // paint over the window-less widgets.
3952 GList
*children
= pizza
->children
;
3955 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3956 children
= children
->next
;
3958 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3959 GTK_WIDGET_DRAWABLE (child
->widget
))
3961 // Get intersection of widget area and update region
3962 wxRegion
region( m_updateRegion
);
3964 GdkEventExpose gdk_event
;
3965 gdk_event
.type
= GDK_EXPOSE
;
3966 gdk_event
.window
= pizza
->bin_window
;
3967 gdk_event
.count
= 0;
3969 wxRegionIterator
upd( m_updateRegion
);
3973 rect
.x
= upd
.GetX();
3974 rect
.y
= upd
.GetY();
3975 rect
.width
= upd
.GetWidth();
3976 rect
.height
= upd
.GetHeight();
3978 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3980 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3990 m_updateRegion
.Clear();
3993 void wxWindowGTK::ClearBackground()
3995 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3998 if (m_wxwindow
&& m_wxwindow
->window
)
4000 m_clearRegion
.Clear();
4001 wxSize
size( GetClientSize() );
4002 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
4004 // Better do this in idle?
4011 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
4013 wxWindowBase::DoSetToolTip(tip
);
4016 m_tooltip
->Apply( (wxWindow
*)this );
4019 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
4021 wxString
tmp( tip
);
4022 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
4024 #endif // wxUSE_TOOLTIPS
4026 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
4028 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4030 if (!wxWindowBase::SetBackgroundColour(colour
))
4035 // We need the pixel value e.g. for background clearing.
4036 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
4039 // apply style change (forceStyle=true so that new style is applied
4040 // even if the bg colour changed from valid to wxNullColour)
4041 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
4042 ApplyWidgetStyle(true);
4047 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
4049 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4051 if (!wxWindowBase::SetForegroundColour(colour
))
4058 // We need the pixel value e.g. for background clearing.
4059 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
4062 // apply style change (forceStyle=true so that new style is applied
4063 // even if the bg colour changed from valid to wxNullColour):
4064 ApplyWidgetStyle(true);
4070 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
4072 return gtk_widget_get_pango_context( m_widget
);
4075 PangoContext
*wxWindowGTK::GtkGetPangoX11Context()
4078 m_x11Context
= pango_x_get_context( gdk_display
);
4080 return m_x11Context
;
4084 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
4086 // do we need to apply any changes at all?
4089 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
4094 GtkRcStyle
*style
= gtk_rc_style_new();
4100 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
4102 wxString xfontname
= m_font
.GetNativeFontInfo()->GetXFontName();
4103 style
->fontset_name
= g_strdup(xfontname
.c_str());
4107 if ( m_foregroundColour
.Ok() )
4109 GdkColor
*fg
= m_foregroundColour
.GetColor();
4111 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
4112 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
4114 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
4115 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
4117 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
4118 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
4121 if ( m_backgroundColour
.Ok() )
4123 GdkColor
*bg
= m_backgroundColour
.GetColor();
4125 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
4126 style
->base
[GTK_STATE_NORMAL
] = *bg
;
4127 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
4128 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
4130 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
4131 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
4132 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
4133 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
4135 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
4136 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
4137 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
4138 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4140 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
4141 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
4142 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
4143 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4149 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
4151 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
4154 DoApplyWidgetStyle(style
);
4155 gtk_rc_style_unref(style
);
4158 // Style change may affect GTK+'s size calculation:
4159 InvalidateBestSize();
4162 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
4165 gtk_widget_modify_style(m_wxwindow
, style
);
4166 gtk_widget_modify_style(m_widget
, style
);
4169 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
4171 wxWindowBase::SetBackgroundStyle(style
);
4173 if (style
== wxBG_STYLE_CUSTOM
)
4175 GdkWindow
*window
= (GdkWindow
*) NULL
;
4177 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4179 window
= GetConnectWidget()->window
;
4183 // Make sure GDK/X11 doesn't refresh the window
4185 gdk_window_set_back_pixmap( window
, None
, False
);
4187 Display
* display
= GDK_WINDOW_DISPLAY(window
);
4190 m_needsStyleChange
= false;
4193 // Do in OnIdle, because the window is not yet available
4194 m_needsStyleChange
= true;
4196 // Don't apply widget style, or we get a grey background
4200 // apply style change (forceStyle=true so that new style is applied
4201 // even if the bg colour changed from valid to wxNullColour):
4202 ApplyWidgetStyle(true);
4207 //-----------------------------------------------------------------------------
4208 // Pop-up menu stuff
4209 //-----------------------------------------------------------------------------
4211 #if wxUSE_MENUS_NATIVE
4214 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
4216 *is_waiting
= FALSE
;
4219 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
4221 menu
->SetInvokingWindow( win
);
4222 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
4225 wxMenuItem
*menuitem
= node
->GetData();
4226 if (menuitem
->IsSubMenu())
4228 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
4231 node
= node
->GetNext();
4235 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
4238 gboolean
* WXUNUSED(whatever
),
4240 gpointer user_data
)
4242 // ensure that the menu appears entirely on screen
4244 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
4246 wxSize sizeScreen
= wxGetDisplaySize();
4247 wxPoint
*pos
= (wxPoint
*)user_data
;
4249 gint xmax
= sizeScreen
.x
- req
.width
,
4250 ymax
= sizeScreen
.y
- req
.height
;
4252 *x
= pos
->x
< xmax
? pos
->x
: xmax
;
4253 *y
= pos
->y
< ymax
? pos
->y
: ymax
;
4256 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4258 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4260 wxCHECK_MSG( menu
!= NULL
, false, wxT("invalid popup-menu") );
4262 SetInvokingWindow( menu
, this );
4266 bool is_waiting
= true;
4268 gulong handler
= gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
4270 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
4271 (gpointer
)&is_waiting
);
4275 GtkMenuPositionFunc posfunc
;
4276 if ( x
== -1 && y
== -1 )
4278 // use GTK's default positioning algorithm
4284 pos
= ClientToScreen(wxPoint(x
, y
));
4286 posfunc
= wxPopupMenuPositionCallback
;
4290 GTK_MENU(menu
->m_menu
),
4291 (GtkWidget
*) NULL
, // parent menu shell
4292 (GtkWidget
*) NULL
, // parent menu item
4293 posfunc
, // function to position it
4294 userdata
, // client data
4295 0, // button used to activate it
4297 gtk_get_current_event_time()
4299 gs_timeLastClick
// the time of activation
4305 gtk_main_iteration();
4308 gtk_signal_disconnect(GTK_OBJECT(menu
->m_menu
), handler
);
4313 #endif // wxUSE_MENUS_NATIVE
4315 #if wxUSE_DRAG_AND_DROP
4317 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4319 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4321 GtkWidget
*dnd_widget
= GetConnectWidget();
4323 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4325 if (m_dropTarget
) delete m_dropTarget
;
4326 m_dropTarget
= dropTarget
;
4328 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4331 #endif // wxUSE_DRAG_AND_DROP
4333 GtkWidget
* wxWindowGTK::GetConnectWidget()
4335 GtkWidget
*connect_widget
= m_widget
;
4336 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4338 return connect_widget
;
4341 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4344 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4346 return (window
== m_widget
->window
);
4349 bool wxWindowGTK::SetFont( const wxFont
&font
)
4351 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4353 if (!wxWindowBase::SetFont(font
))
4356 // apply style change (forceStyle=true so that new style is applied
4357 // even if the font changed from valid to wxNullFont):
4358 ApplyWidgetStyle(true);
4363 void wxWindowGTK::DoCaptureMouse()
4365 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4367 GdkWindow
*window
= (GdkWindow
*) NULL
;
4369 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4371 window
= GetConnectWidget()->window
;
4373 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4375 wxCursor
* cursor
= & m_cursor
;
4377 cursor
= wxSTANDARD_CURSOR
;
4379 gdk_pointer_grab( window
, FALSE
,
4381 (GDK_BUTTON_PRESS_MASK
|
4382 GDK_BUTTON_RELEASE_MASK
|
4383 GDK_POINTER_MOTION_HINT_MASK
|
4384 GDK_POINTER_MOTION_MASK
),
4386 cursor
->GetCursor(),
4387 (guint32
)GDK_CURRENT_TIME
);
4388 g_captureWindow
= this;
4389 g_captureWindowHasMouse
= TRUE
;
4392 void wxWindowGTK::DoReleaseMouse()
4394 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4396 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4398 g_captureWindow
= (wxWindowGTK
*) NULL
;
4400 GdkWindow
*window
= (GdkWindow
*) NULL
;
4402 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4404 window
= GetConnectWidget()->window
;
4409 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4413 wxWindow
*wxWindowBase::GetCapture()
4415 return (wxWindow
*)g_captureWindow
;
4418 bool wxWindowGTK::IsRetained() const
4423 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4424 int range
, bool refresh
)
4426 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4428 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4430 m_hasScrolling
= TRUE
;
4432 if (orient
== wxHORIZONTAL
)
4434 float fpos
= (float)pos
;
4435 float frange
= (float)range
;
4436 float fthumb
= (float)thumbVisible
;
4437 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4438 if (fpos
< 0.0) fpos
= 0.0;
4440 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4441 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4443 SetScrollPos( orient
, pos
, refresh
);
4447 m_oldHorizontalPos
= fpos
;
4449 m_hAdjust
->lower
= 0.0;
4450 m_hAdjust
->upper
= frange
;
4451 m_hAdjust
->value
= fpos
;
4452 m_hAdjust
->step_increment
= 1.0;
4453 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4454 m_hAdjust
->page_size
= fthumb
;
4458 float fpos
= (float)pos
;
4459 float frange
= (float)range
;
4460 float fthumb
= (float)thumbVisible
;
4461 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4462 if (fpos
< 0.0) fpos
= 0.0;
4464 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4465 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4467 SetScrollPos( orient
, pos
, refresh
);
4471 m_oldVerticalPos
= fpos
;
4473 m_vAdjust
->lower
= 0.0;
4474 m_vAdjust
->upper
= frange
;
4475 m_vAdjust
->value
= fpos
;
4476 m_vAdjust
->step_increment
= 1.0;
4477 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4478 m_vAdjust
->page_size
= fthumb
;
4481 if (orient
== wxHORIZONTAL
)
4482 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4484 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4487 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4489 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4491 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4493 if (orient
== wxHORIZONTAL
)
4495 float fpos
= (float)pos
;
4496 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4497 if (fpos
< 0.0) fpos
= 0.0;
4498 m_oldHorizontalPos
= fpos
;
4500 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4501 m_hAdjust
->value
= fpos
;
4505 float fpos
= (float)pos
;
4506 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4507 if (fpos
< 0.0) fpos
= 0.0;
4508 m_oldVerticalPos
= fpos
;
4510 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4511 m_vAdjust
->value
= fpos
;
4514 if (m_wxwindow
->window
)
4516 if (orient
== wxHORIZONTAL
)
4518 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4519 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4521 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4523 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4524 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4528 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4529 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4531 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4533 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4534 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4539 int wxWindowGTK::GetScrollThumb( int orient
) const
4541 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4543 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4545 if (orient
== wxHORIZONTAL
)
4546 return (int)(m_hAdjust
->page_size
+0.5);
4548 return (int)(m_vAdjust
->page_size
+0.5);
4551 int wxWindowGTK::GetScrollPos( int orient
) const
4553 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4555 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4557 if (orient
== wxHORIZONTAL
)
4558 return (int)(m_hAdjust
->value
+0.5);
4560 return (int)(m_vAdjust
->value
+0.5);
4563 int wxWindowGTK::GetScrollRange( int orient
) const
4565 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4567 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4569 if (orient
== wxHORIZONTAL
)
4570 return (int)(m_hAdjust
->upper
+0.5);
4572 return (int)(m_vAdjust
->upper
+0.5);
4575 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4577 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4579 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4581 // No scrolling requested.
4582 if ((dx
== 0) && (dy
== 0)) return;
4585 if (!m_updateRegion
.IsEmpty())
4587 m_updateRegion
.Offset( dx
, dy
);
4591 GetClientSize( &cw
, &ch
);
4592 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4595 if (!m_clearRegion
.IsEmpty())
4597 m_clearRegion
.Offset( dx
, dy
);
4601 GetClientSize( &cw
, &ch
);
4602 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4606 m_clipPaintRegion
= TRUE
;
4608 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4610 m_clipPaintRegion
= FALSE
;
4614 // Find the wxWindow at the current mouse position, also returning the mouse
4616 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4618 pt
= wxGetMousePosition();
4619 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4623 // Get the current mouse position.
4624 wxPoint
wxGetMousePosition()
4626 /* This crashes when used within wxHelpContext,
4627 so we have to use the X-specific implementation below.
4629 GdkModifierType *mask;
4630 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4632 return wxPoint(x, y);
4636 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4638 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4639 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4640 Window rootReturn
, childReturn
;
4641 int rootX
, rootY
, winX
, winY
;
4642 unsigned int maskReturn
;
4644 XQueryPointer (display
,
4648 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4649 return wxPoint(rootX
, rootY
);
4653 // ----------------------------------------------------------------------------
4655 // ----------------------------------------------------------------------------
4657 class wxWinModule
: public wxModule
4664 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4667 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4669 bool wxWinModule::OnInit()
4671 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4672 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4677 void wxWinModule::OnExit()
4680 gdk_gc_unref( g_eraseGC
);