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
.SetId(win
->GetId());
964 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
965 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
966 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
967 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
968 event
.m_scanCode
= gdk_event
->keyval
;
969 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
970 event
.m_rawFlags
= 0;
972 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
976 event
.SetEventObject( win
);
981 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
983 GdkEventKey
*gdk_event
)
985 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
986 // but only event->keyval which is quite useless to us, so remember
987 // the last character from GDK_KEY_PRESS and reuse it as last resort
989 // NB: should be MT-safe as we're always called from the main thread only
994 } s_lastKeyPress
= { 0, 0 };
996 KeySym keysym
= gdk_event
->keyval
;
998 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
999 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
1003 long key_code
= wxTranslateKeySymToWXKey(keysym
, FALSE
/* !isChar */);
1007 // do we have the translation or is it a plain ASCII character?
1008 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
1010 // we should use keysym if it is ASCII as X does some translations
1011 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
1012 // which we don't want here (but which we do use for OnChar())
1013 if ( !wxIsAsciiKeysym(keysym
) )
1015 keysym
= (KeySym
)gdk_event
->string
[0];
1018 // we want to always get the same key code when the same key is
1019 // pressed regardless of the state of the modifies, i.e. on a
1020 // standard US keyboard pressing '5' or '%' ('5' key with
1021 // Shift) should result in the same key code in OnKeyDown():
1022 // '5' (although OnChar() will get either '5' or '%').
1024 // to do it we first translate keysym to keycode (== scan code)
1025 // and then back but always using the lower register
1026 Display
*dpy
= (Display
*)wxGetDisplay();
1027 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
1029 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
1031 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
1033 // use the normalized, i.e. lower register, keysym if we've
1035 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
1037 // as explained above, we want to have lower register key codes
1038 // normally but for the letter keys we want to have the upper ones
1040 // NB: don't use XConvertCase() here, we want to do it for letters
1042 key_code
= toupper(key_code
);
1044 else // non ASCII key, what to do?
1046 // by default, ignore it
1049 // but if we have cached information from the last KEY_PRESS
1050 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
1053 if ( keysym
== s_lastKeyPress
.keysym
)
1055 key_code
= s_lastKeyPress
.keycode
;
1060 if ( gdk_event
->type
== GDK_KEY_PRESS
)
1062 // remember it to be reused for KEY_UP event later
1063 s_lastKeyPress
.keysym
= keysym
;
1064 s_lastKeyPress
.keycode
= key_code
;
1068 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
1070 // sending unknown key events doesn't really make sense
1074 // now fill all the other fields
1075 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
1077 event
.m_keyCode
= key_code
;
1086 GtkIMContext
*context
;
1087 GdkEventKey
*lastKeyEvent
;
1091 context
= gtk_im_multicontext_new();
1092 lastKeyEvent
= NULL
;
1096 g_object_unref(context
);
1101 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1102 GdkEventKey
*gdk_event
,
1108 wxapp_install_idle_handler();
1112 if (g_blockEventsOnDrag
)
1116 // We have to pass key press events through GTK+'s Input Method context
1117 // object in order to get correct characters. By doing so, we loose the
1118 // ability to let other GTK+'s handlers (namely, widgets' default signal
1119 // handlers) handle the signal by returning false from this callback.
1120 // Because GTK+ sends the events to parent widgets as well, we can't
1121 // afford loosing it, otherwise native widgets inserted into wxPanel
1122 // would break in subtle ways (e.g. spacebar would no longer toggle
1123 // wxCheckButton's state). Therefore, we only pass the event to IM if it
1124 // originated in this window's widget, which we detect by checking if we've
1125 // seen the same event before (no events from children are lost this way,
1126 // because gtk_window_key_press_callback is installed for native controls
1127 // as well and the wxKeyEvent it creates propagates upwards).
1128 static GdkEventKey s_lastEvent
;
1130 bool useIM
= (win
->m_imData
!= NULL
) &&
1131 memcmp(gdk_event
, &s_lastEvent
, sizeof(GdkEventKey
)) != 0;
1133 s_lastEvent
= *gdk_event
;
1136 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1137 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1139 // unknown key pressed, ignore (the event would be useless anyhow)
1143 // it may be useful for the input method, though:
1144 win
->m_imData
->lastKeyEvent
= gdk_event
;
1145 bool ret
= gtk_im_context_filter_keypress(win
->m_imData
->context
,
1147 win
->m_imData
->lastKeyEvent
= NULL
;
1154 // Emit KEY_DOWN event
1155 bool ret
= win
->GetEventHandler()->ProcessEvent( event
);
1160 wxWindowGTK
*ancestor
= win
;
1163 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1166 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1167 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1170 if (ancestor
->IsTopLevel())
1172 ancestor
= ancestor
->GetParent();
1175 #endif // wxUSE_ACCEL
1177 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1178 // will only be sent if it is not in an accelerator table.
1184 // In GTK 2.0, we need to hand over the key event to an input method
1185 // and the IM will emit a "commit" event containing the actual utf8
1186 // character. In that case the EVT_CHAR events will be sent from
1188 win
->m_imData
->lastKeyEvent
= gdk_event
;
1189 if ( gtk_im_context_filter_keypress(win
->m_imData
->context
,
1192 win
->m_imData
->lastKeyEvent
= NULL
;
1193 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1197 win
->m_imData
->lastKeyEvent
= NULL
;
1202 KeySym keysym
= gdk_event
->keyval
;
1203 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1204 key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1207 if ( wxIsAsciiKeysym(keysym
) )
1210 key_code
= (unsigned char)keysym
;
1212 // gdk_event->string is actually deprecated
1213 else if ( gdk_event
->length
== 1 )
1215 key_code
= (unsigned char)gdk_event
->string
[0];
1221 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1223 event
.m_keyCode
= key_code
;
1225 // Implement OnCharHook by checking ancesteror top level windows
1226 wxWindow
*parent
= win
;
1227 while (parent
&& !parent
->IsTopLevel())
1228 parent
= parent
->GetParent();
1231 event
.SetEventType( wxEVT_CHAR_HOOK
);
1232 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1237 event
.SetEventType(wxEVT_CHAR
);
1238 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1243 // win is a control: tab can be propagated up
1245 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1246 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1247 // have this style, yet choose not to process this particular TAB in which
1248 // case TAB must still work as a navigational character
1249 // JS: enabling again to make consistent with other platforms
1250 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1251 // navigation behaviour)
1253 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1255 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1257 wxNavigationKeyEvent new_event
;
1258 new_event
.SetEventObject( win
->GetParent() );
1259 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1260 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1261 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1262 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1263 new_event
.SetCurrentFocus( win
);
1264 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1267 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1269 (gdk_event
->keyval
== GDK_Escape
) )
1271 // however only do it if we have a Cancel button in the dialog,
1272 // otherwise the user code may get confused by the events from a
1273 // non-existing button and, worse, a wxButton might get button event
1274 // from another button which is not really expected
1275 wxWindow
*winForCancel
= win
,
1277 while ( winForCancel
)
1279 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1282 // found a cancel button
1286 if ( winForCancel
->IsTopLevel() )
1288 // no need to look further
1292 // maybe our parent has a cancel button?
1293 winForCancel
= winForCancel
->GetParent();
1298 wxCommandEvent
event(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1299 event
.SetEventObject(btnCancel
);
1300 ret
= btnCancel
->GetEventHandler()->ProcessEvent(event
);
1306 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1314 static void gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1318 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1320 // take modifiers, cursor position, timestamp etc. from the last
1321 // key_press_event that was fed into Input Method:
1322 if (window
->m_imData
->lastKeyEvent
)
1324 wxFillOtherKeyEventFields(event
,
1325 window
, window
->m_imData
->lastKeyEvent
);
1329 const wxWCharBuffer data
= wxConvUTF8
.cMB2WC( (char*)str
);
1331 const wxWCharBuffer wdata
= wxConvUTF8
.cMB2WC( (char*)str
);
1332 const wxCharBuffer data
= wxConvLocal
.cWC2MB( wdata
);
1333 #endif // wxUSE_UNICODE
1334 if( !(const wxChar
*)data
)
1339 // Implement OnCharHook by checking ancestor top level windows
1340 wxWindow
*parent
= window
;
1341 while (parent
&& !parent
->IsTopLevel())
1342 parent
= parent
->GetParent();
1344 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1347 event
.m_uniChar
= *pstr
;
1348 // Backward compatible for ISO-8859
1349 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1350 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1352 event
.m_keyCode
= *pstr
;
1353 #endif // wxUSE_UNICODE
1356 event
.SetEventType( wxEVT_CHAR_HOOK
);
1357 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1362 event
.SetEventType(wxEVT_CHAR
);
1363 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1370 //-----------------------------------------------------------------------------
1371 // "key_release_event" from any window
1372 //-----------------------------------------------------------------------------
1374 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1375 GdkEventKey
*gdk_event
,
1381 wxapp_install_idle_handler();
1386 if (g_blockEventsOnDrag
)
1389 wxKeyEvent
event( wxEVT_KEY_UP
);
1390 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1392 // unknown key pressed, ignore (the event would be useless anyhow
1396 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1399 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1403 // ============================================================================
1405 // ============================================================================
1407 // ----------------------------------------------------------------------------
1408 // mouse event processing helpers
1409 // ----------------------------------------------------------------------------
1411 // init wxMouseEvent with the info from GdkEventXXX struct
1412 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1413 wxMouseEvent
& event
,
1416 event
.SetTimestamp( gdk_event
->time
);
1417 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1418 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1419 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1420 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1421 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1422 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1423 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1424 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1426 event
.m_linesPerAction
= 3;
1427 event
.m_wheelDelta
= 120;
1428 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1429 event
.m_wheelRotation
= 120;
1430 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1431 event
.m_wheelRotation
= -120;
1434 wxPoint pt
= win
->GetClientAreaOrigin();
1435 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1436 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1438 event
.SetEventObject( win
);
1439 event
.SetId( win
->GetId() );
1440 event
.SetTimestamp( gdk_event
->time
);
1443 static void AdjustEventButtonState(wxMouseEvent
& event
)
1445 // GDK reports the old state of the button for a button press event, but
1446 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1447 // for a LEFT_DOWN event, not FALSE, so we will invert
1448 // left/right/middleDown for the corresponding click events
1450 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1451 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1452 (event
.GetEventType() == wxEVT_LEFT_UP
))
1454 event
.m_leftDown
= !event
.m_leftDown
;
1458 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1459 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1460 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1462 event
.m_middleDown
= !event
.m_middleDown
;
1466 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1467 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1468 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1470 event
.m_rightDown
= !event
.m_rightDown
;
1475 // find the window to send the mouse event too
1477 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1482 if (win
->m_wxwindow
)
1484 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1485 xx
+= pizza
->xoffset
;
1486 yy
+= pizza
->yoffset
;
1489 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1492 wxWindowGTK
*child
= node
->GetData();
1494 node
= node
->GetNext();
1495 if (!child
->IsShown())
1498 if (child
->IsTransparentForMouse())
1500 // wxStaticBox is transparent in the box itself
1501 int xx1
= child
->m_x
;
1502 int yy1
= child
->m_y
;
1503 int xx2
= child
->m_x
+ child
->m_width
;
1504 int yy2
= child
->m_y
+ child
->m_height
;
1507 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1509 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1511 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1513 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1524 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1525 (child
->m_x
<= xx
) &&
1526 (child
->m_y
<= yy
) &&
1527 (child
->m_x
+child
->m_width
>= xx
) &&
1528 (child
->m_y
+child
->m_height
>= yy
))
1541 //-----------------------------------------------------------------------------
1542 // "button_press_event"
1543 //-----------------------------------------------------------------------------
1545 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1546 GdkEventButton
*gdk_event
,
1552 wxapp_install_idle_handler();
1555 wxPrintf( wxT("1) OnButtonPress from ") );
1556 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1557 wxPrintf( win->GetClassInfo()->GetClassName() );
1558 wxPrintf( wxT(".\n") );
1560 if (!win
->m_hasVMT
) return FALSE
;
1561 if (g_blockEventsOnDrag
) return TRUE
;
1562 if (g_blockEventsOnScroll
) return TRUE
;
1564 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1566 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1568 gtk_widget_grab_focus( win
->m_wxwindow
);
1570 wxPrintf( wxT("GrabFocus from ") );
1571 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1572 wxPrintf( win->GetClassInfo()->GetClassName() );
1573 wxPrintf( wxT(".\n") );
1577 // GDK sends surplus button down event
1578 // before a double click event. We
1579 // need to filter these out.
1580 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1582 GdkEvent
*peek_event
= gdk_event_peek();
1585 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1586 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1588 gdk_event_free( peek_event
);
1593 gdk_event_free( peek_event
);
1598 wxEventType event_type
= wxEVT_NULL
;
1600 // GdkDisplay is a GTK+ 2.2.0 thing
1601 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1602 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1603 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1605 // Reset GDK internal timestamp variables in order to disable GDK
1606 // triple click events. GDK will then next time believe no button has
1607 // been clicked just before, and send a normal button click event.
1608 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1609 display
->button_click_time
[1] = 0;
1610 display
->button_click_time
[0] = 0;
1614 if (gdk_event
->button
== 1)
1616 // note that GDK generates triple click events which are not supported
1617 // by wxWidgets but still have to be passed to the app as otherwise
1618 // clicks would simply go missing
1619 switch (gdk_event
->type
)
1621 // we shouldn't get triple clicks at all for GTK2 because we
1622 // suppress them artificially using the code above but we still
1623 // should map them to something for GTK1 and not just ignore them
1624 // as this would lose clicks
1625 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1626 case GDK_BUTTON_PRESS
:
1627 event_type
= wxEVT_LEFT_DOWN
;
1630 case GDK_2BUTTON_PRESS
:
1631 event_type
= wxEVT_LEFT_DCLICK
;
1635 // just to silence gcc warnings
1639 else if (gdk_event
->button
== 2)
1641 switch (gdk_event
->type
)
1643 case GDK_3BUTTON_PRESS
:
1644 case GDK_BUTTON_PRESS
:
1645 event_type
= wxEVT_MIDDLE_DOWN
;
1648 case GDK_2BUTTON_PRESS
:
1649 event_type
= wxEVT_MIDDLE_DCLICK
;
1656 else if (gdk_event
->button
== 3)
1658 switch (gdk_event
->type
)
1660 case GDK_3BUTTON_PRESS
:
1661 case GDK_BUTTON_PRESS
:
1662 event_type
= wxEVT_RIGHT_DOWN
;
1665 case GDK_2BUTTON_PRESS
:
1666 event_type
= wxEVT_RIGHT_DCLICK
;
1673 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1675 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1677 event_type
= wxEVT_MOUSEWHEEL
;
1681 if ( event_type
== wxEVT_NULL
)
1683 // unknown mouse button or click type
1687 wxMouseEvent
event( event_type
);
1688 InitMouseEvent( win
, event
, gdk_event
);
1690 AdjustEventButtonState(event
);
1692 // wxListBox actually get mouse events from the item, so we need to give it
1693 // a chance to correct this
1694 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1696 if ( event_type
== wxEVT_RIGHT_DOWN
)
1698 // generate a "context menu" event: this is similar to right mouse
1699 // click under many GUIs except that it is generated differently
1700 // (right up under MSW, ctrl-click under Mac, right down here) and
1702 // (a) it's a command event and so is propagated to the parent
1703 // (b) under MSW it can be generated from kbd too
1704 // (c) it uses screen coords (because of (a))
1705 wxContextMenuEvent
evtCtx(wxEVT_CONTEXT_MENU
,
1707 win
->ClientToScreen(event
.GetPosition()));
1708 (void)win
->GetEventHandler()->ProcessEvent(evtCtx
);
1711 // find the correct window to send the event too: it may be a different one
1712 // from the one which got it at GTK+ level because some control don't have
1713 // their own X window and thus cannot get any events.
1714 if ( !g_captureWindow
)
1715 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1717 gs_timeLastClick
= gdk_event
->time
;
1720 if (event_type
== wxEVT_LEFT_DCLICK
)
1722 // GTK 1.2 crashes when intercepting double
1723 // click events from both wxSpinButton and
1725 if (GTK_IS_SPIN_BUTTON(win
->m_widget
))
1727 // Just disable this event for now.
1733 if (win
->GetEventHandler()->ProcessEvent( event
))
1735 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1742 //-----------------------------------------------------------------------------
1743 // "button_release_event"
1744 //-----------------------------------------------------------------------------
1746 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1747 GdkEventButton
*gdk_event
,
1753 wxapp_install_idle_handler();
1755 if (!win
->m_hasVMT
) return FALSE
;
1756 if (g_blockEventsOnDrag
) return FALSE
;
1757 if (g_blockEventsOnScroll
) return FALSE
;
1759 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1761 wxEventType event_type
= wxEVT_NULL
;
1763 switch (gdk_event
->button
)
1766 event_type
= wxEVT_LEFT_UP
;
1770 event_type
= wxEVT_MIDDLE_UP
;
1774 event_type
= wxEVT_RIGHT_UP
;
1778 // unknwon button, don't process
1782 wxMouseEvent
event( event_type
);
1783 InitMouseEvent( win
, event
, gdk_event
);
1785 AdjustEventButtonState(event
);
1787 // same wxListBox hack as above
1788 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1790 if ( !g_captureWindow
)
1791 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1793 if (win
->GetEventHandler()->ProcessEvent( event
))
1795 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1802 //-----------------------------------------------------------------------------
1803 // "motion_notify_event"
1804 //-----------------------------------------------------------------------------
1806 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1807 GdkEventMotion
*gdk_event
,
1813 wxapp_install_idle_handler();
1815 if (!win
->m_hasVMT
) return FALSE
;
1816 if (g_blockEventsOnDrag
) return FALSE
;
1817 if (g_blockEventsOnScroll
) return FALSE
;
1819 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1821 if (gdk_event
->is_hint
)
1825 GdkModifierType state
;
1826 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1832 printf( "OnMotion from " );
1833 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1834 printf( win->GetClassInfo()->GetClassName() );
1838 wxMouseEvent
event( wxEVT_MOTION
);
1839 InitMouseEvent(win
, event
, gdk_event
);
1841 if ( g_captureWindow
)
1843 // synthetize a mouse enter or leave event if needed
1844 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1845 // This seems to be necessary and actually been added to
1846 // GDK itself in version 2.0.X
1849 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1850 if ( hasMouse
!= g_captureWindowHasMouse
)
1852 // the mouse changed window
1853 g_captureWindowHasMouse
= hasMouse
;
1855 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1856 : wxEVT_LEAVE_WINDOW
);
1857 InitMouseEvent(win
, event
, gdk_event
);
1858 event
.SetEventObject(win
);
1859 win
->GetEventHandler()->ProcessEvent(event
);
1864 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1867 if (win
->GetEventHandler()->ProcessEvent( event
))
1869 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1877 //-----------------------------------------------------------------------------
1878 // "mouse_wheel_event"
1879 //-----------------------------------------------------------------------------
1881 static gint
gtk_window_wheel_callback (GtkWidget
* widget
,
1882 GdkEventScroll
* gdk_event
,
1888 wxapp_install_idle_handler();
1890 wxEventType event_type
= wxEVT_NULL
;
1891 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1892 event_type
= wxEVT_MOUSEWHEEL
;
1893 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1894 event_type
= wxEVT_MOUSEWHEEL
;
1898 wxMouseEvent
event( event_type
);
1899 // Can't use InitMouse macro because scroll events don't have button
1900 event
.SetTimestamp( gdk_event
->time
);
1901 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1902 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1903 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1904 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1905 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1906 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1907 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1908 event
.m_linesPerAction
= 3;
1909 event
.m_wheelDelta
= 120;
1910 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1911 event
.m_wheelRotation
= 120;
1913 event
.m_wheelRotation
= -120;
1915 wxPoint pt
= win
->GetClientAreaOrigin();
1916 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1917 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1919 event
.SetEventObject( win
);
1920 event
.SetId( win
->GetId() );
1921 event
.SetTimestamp( gdk_event
->time
);
1923 if (win
->GetEventHandler()->ProcessEvent( event
))
1925 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "scroll_event" );
1933 //-----------------------------------------------------------------------------
1935 //-----------------------------------------------------------------------------
1937 // send the wxChildFocusEvent and wxFocusEvent, common code of
1938 // gtk_window_focus_in_callback() and SetFocus()
1939 static bool DoSendFocusEvents(wxWindow
*win
)
1941 // Notify the parent keeping track of focus for the kbd navigation
1942 // purposes that we got it.
1943 wxChildFocusEvent
eventChildFocus(win
);
1944 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1946 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1947 eventFocus
.SetEventObject(win
);
1949 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1952 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1953 GdkEvent
*WXUNUSED(event
),
1959 wxapp_install_idle_handler();
1963 gtk_im_context_focus_in(win
->m_imData
->context
);
1967 g_focusWindow
= win
;
1969 wxLogTrace(TRACE_FOCUS
,
1970 _T("%s: focus in"), win
->GetName().c_str());
1974 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1978 // caret needs to be informed about focus change
1979 wxCaret
*caret
= win
->GetCaret();
1982 caret
->OnSetFocus();
1984 #endif // wxUSE_CARET
1986 // does the window itself think that it has the focus?
1987 if ( !win
->m_hasFocus
)
1989 // not yet, notify it
1990 win
->m_hasFocus
= TRUE
;
1992 if ( DoSendFocusEvents(win
) )
1994 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
2002 //-----------------------------------------------------------------------------
2003 // "focus_out_event"
2004 //-----------------------------------------------------------------------------
2006 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
2011 wxapp_install_idle_handler();
2015 gtk_im_context_focus_out(win
->m_imData
->context
);
2018 wxLogTrace( TRACE_FOCUS
,
2019 _T("%s: focus out"), win
->GetName().c_str() );
2022 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
2026 g_focusWindow
= (wxWindowGTK
*)NULL
;
2034 // caret needs to be informed about focus change
2035 wxCaret
*caret
= win
->GetCaret();
2038 caret
->OnKillFocus();
2040 #endif // wxUSE_CARET
2042 // don't send the window a kill focus event if it thinks that it doesn't
2043 // have focus already
2044 if ( win
->m_hasFocus
)
2046 win
->m_hasFocus
= FALSE
;
2048 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
2049 event
.SetEventObject( win
);
2051 // even if we did process the event in wx code, still let GTK itself
2052 // process it too as otherwise bad things happen, especially in GTK2
2053 // where the text control simply aborts the program if it doesn't get
2054 // the matching focus out event
2055 (void)win
->GetEventHandler()->ProcessEvent( event
);
2061 //-----------------------------------------------------------------------------
2062 // "enter_notify_event"
2063 //-----------------------------------------------------------------------------
2066 gint
gtk_window_enter_callback( GtkWidget
*widget
,
2067 GdkEventCrossing
*gdk_event
,
2073 wxapp_install_idle_handler();
2075 if (!win
->m_hasVMT
) return FALSE
;
2076 if (g_blockEventsOnDrag
) return FALSE
;
2078 // Event was emitted after a grab
2079 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2081 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2085 GdkModifierType state
= (GdkModifierType
)0;
2087 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2089 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2090 InitMouseEvent(win
, event
, gdk_event
);
2091 wxPoint pt
= win
->GetClientAreaOrigin();
2092 event
.m_x
= x
+ pt
.x
;
2093 event
.m_y
= y
+ pt
.y
;
2095 if (win
->GetEventHandler()->ProcessEvent( event
))
2097 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
2104 //-----------------------------------------------------------------------------
2105 // "leave_notify_event"
2106 //-----------------------------------------------------------------------------
2108 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
2113 wxapp_install_idle_handler();
2115 if (!win
->m_hasVMT
) return FALSE
;
2116 if (g_blockEventsOnDrag
) return FALSE
;
2118 // Event was emitted after an ungrab
2119 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2121 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2123 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2124 event
.SetTimestamp( gdk_event
->time
);
2125 event
.SetEventObject( win
);
2129 GdkModifierType state
= (GdkModifierType
)0;
2131 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2133 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2134 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2135 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2136 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2137 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2138 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2139 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2141 wxPoint pt
= win
->GetClientAreaOrigin();
2142 event
.m_x
= x
+ pt
.x
;
2143 event
.m_y
= y
+ pt
.y
;
2145 if (win
->GetEventHandler()->ProcessEvent( event
))
2147 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
2154 //-----------------------------------------------------------------------------
2155 // "value_changed" from m_vAdjust
2156 //-----------------------------------------------------------------------------
2158 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2165 wxapp_install_idle_handler();
2167 if (g_blockEventsOnDrag
) return;
2169 if (!win
->m_hasVMT
) return;
2171 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2172 if (fabs(diff
) < 0.2) return;
2174 win
->m_oldVerticalPos
= adjust
->value
;
2177 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2179 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
2181 int value
= (int)(adjust
->value
+0.5);
2183 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2184 event
.SetEventObject( win
);
2185 win
->GetEventHandler()->ProcessEvent( event
);
2188 //-----------------------------------------------------------------------------
2189 // "value_changed" from m_hAdjust
2190 //-----------------------------------------------------------------------------
2192 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2199 wxapp_install_idle_handler();
2201 if (g_blockEventsOnDrag
) return;
2202 if (!win
->m_hasVMT
) return;
2204 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2205 if (fabs(diff
) < 0.2) return;
2208 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2210 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
2212 win
->m_oldHorizontalPos
= adjust
->value
;
2214 int value
= (int)(adjust
->value
+0.5);
2216 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2217 event
.SetEventObject( win
);
2218 win
->GetEventHandler()->ProcessEvent( event
);
2221 //-----------------------------------------------------------------------------
2222 // "button_press_event" from scrollbar
2223 //-----------------------------------------------------------------------------
2225 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2226 GdkEventButton
*gdk_event
,
2232 wxapp_install_idle_handler();
2235 g_blockEventsOnScroll
= TRUE
;
2237 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2239 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2245 //-----------------------------------------------------------------------------
2246 // "button_release_event" from scrollbar
2247 //-----------------------------------------------------------------------------
2249 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2250 GdkEventButton
*WXUNUSED(gdk_event
),
2255 // don't test here as we can release the mouse while being over
2256 // a different window than the slider
2258 // if (gdk_event->window != widget->slider) return FALSE;
2260 g_blockEventsOnScroll
= FALSE
;
2262 if (win
->m_isScrolling
)
2264 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2268 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2269 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2271 value
= (int)(win
->m_hAdjust
->value
+0.5);
2274 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2276 value
= (int)(win
->m_vAdjust
->value
+0.5);
2280 wxScrollWinEvent
event( command
, value
, dir
);
2281 event
.SetEventObject( win
);
2282 win
->GetEventHandler()->ProcessEvent( event
);
2285 win
->m_isScrolling
= FALSE
;
2290 // ----------------------------------------------------------------------------
2291 // this wxWindowBase function is implemented here (in platform-specific file)
2292 // because it is static and so couldn't be made virtual
2293 // ----------------------------------------------------------------------------
2295 wxWindow
*wxWindowBase::DoFindFocus()
2297 // the cast is necessary when we compile in wxUniversal mode
2298 return (wxWindow
*)g_focusWindow
;
2302 //-----------------------------------------------------------------------------
2303 // "realize" from m_widget
2304 //-----------------------------------------------------------------------------
2306 /* We cannot set colours and fonts before the widget has
2307 been realized, so we do this directly after realization. */
2310 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2315 wxapp_install_idle_handler();
2320 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2321 gtk_im_context_set_client_window( win
->m_imData
->context
,
2322 pizza
->bin_window
);
2326 wxWindowCreateEvent
event( win
);
2327 event
.SetEventObject( win
);
2328 win
->GetEventHandler()->ProcessEvent( event
);
2333 //-----------------------------------------------------------------------------
2335 //-----------------------------------------------------------------------------
2338 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2339 GtkAllocation
*WXUNUSED(alloc
),
2343 wxapp_install_idle_handler();
2345 if (!win
->m_hasScrolling
) return;
2347 int client_width
= 0;
2348 int client_height
= 0;
2349 win
->GetClientSize( &client_width
, &client_height
);
2350 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2353 win
->m_oldClientWidth
= client_width
;
2354 win
->m_oldClientHeight
= client_height
;
2356 if (!win
->m_nativeSizeEvent
)
2358 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2359 event
.SetEventObject( win
);
2360 win
->GetEventHandler()->ProcessEvent( event
);
2366 #define WXUNUSED_UNLESS_XIM(param) param
2368 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2371 /* Resize XIM window */
2374 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2375 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2376 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2379 wxapp_install_idle_handler();
2385 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2389 gdk_window_get_size (widget
->window
, &width
, &height
);
2390 win
->m_icattr
->preedit_area
.width
= width
;
2391 win
->m_icattr
->preedit_area
.height
= height
;
2392 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2397 //-----------------------------------------------------------------------------
2398 // "realize" from m_wxwindow
2399 //-----------------------------------------------------------------------------
2401 /* Initialize XIM support */
2404 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2405 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2408 wxapp_install_idle_handler();
2411 if (win
->m_ic
) return FALSE
;
2412 if (!widget
) return FALSE
;
2413 if (!gdk_im_ready()) return FALSE
;
2415 win
->m_icattr
= gdk_ic_attr_new();
2416 if (!win
->m_icattr
) return FALSE
;
2420 GdkColormap
*colormap
;
2421 GdkICAttr
*attr
= win
->m_icattr
;
2422 unsigned attrmask
= GDK_IC_ALL_REQ
;
2424 GdkIMStyle supported_style
= (GdkIMStyle
)
2425 (GDK_IM_PREEDIT_NONE
|
2426 GDK_IM_PREEDIT_NOTHING
|
2427 GDK_IM_PREEDIT_POSITION
|
2428 GDK_IM_STATUS_NONE
|
2429 GDK_IM_STATUS_NOTHING
);
2431 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2432 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2434 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2435 attr
->client_window
= widget
->window
;
2437 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2438 gtk_widget_get_default_colormap ())
2440 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2441 attr
->preedit_colormap
= colormap
;
2444 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2445 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2446 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2447 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2449 switch (style
& GDK_IM_PREEDIT_MASK
)
2451 case GDK_IM_PREEDIT_POSITION
:
2452 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2454 g_warning ("over-the-spot style requires fontset");
2458 gdk_window_get_size (widget
->window
, &width
, &height
);
2460 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2461 attr
->spot_location
.x
= 0;
2462 attr
->spot_location
.y
= height
;
2463 attr
->preedit_area
.x
= 0;
2464 attr
->preedit_area
.y
= 0;
2465 attr
->preedit_area
.width
= width
;
2466 attr
->preedit_area
.height
= height
;
2467 attr
->preedit_fontset
= widget
->style
->font
;
2472 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2474 if (win
->m_ic
== NULL
)
2475 g_warning ("Can't create input context.");
2478 mask
= gdk_window_get_events (widget
->window
);
2479 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2480 gdk_window_set_events (widget
->window
, mask
);
2482 if (GTK_WIDGET_HAS_FOCUS(widget
))
2483 gdk_im_begin (win
->m_ic
, widget
->window
);
2490 //-----------------------------------------------------------------------------
2491 // InsertChild for wxWindowGTK.
2492 //-----------------------------------------------------------------------------
2494 /* Callback for wxWindowGTK. This very strange beast has to be used because
2495 * C++ has no virtual methods in a constructor. We have to emulate a
2496 * virtual function here as wxNotebook requires a different way to insert
2497 * a child in it. I had opted for creating a wxNotebookPage window class
2498 * which would have made this superfluous (such in the MDI window system),
2499 * but no-one was listening to me... */
2501 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2503 /* the window might have been scrolled already, do we
2504 have to adapt the position */
2505 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2506 child
->m_x
+= pizza
->xoffset
;
2507 child
->m_y
+= pizza
->yoffset
;
2509 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2510 GTK_WIDGET(child
->m_widget
),
2517 //-----------------------------------------------------------------------------
2519 //-----------------------------------------------------------------------------
2521 wxWindow
*wxGetActiveWindow()
2523 return wxWindow::FindFocus();
2526 //-----------------------------------------------------------------------------
2528 //-----------------------------------------------------------------------------
2530 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2532 #ifdef __WXUNIVERSAL__
2533 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2535 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2536 #endif // __WXUNIVERSAL__/__WXGTK__
2538 void wxWindowGTK::Init()
2541 m_widget
= (GtkWidget
*) NULL
;
2542 m_wxwindow
= (GtkWidget
*) NULL
;
2543 m_focusWidget
= (GtkWidget
*) NULL
;
2553 m_needParent
= TRUE
;
2554 m_isBeingDeleted
= FALSE
;
2557 m_nativeSizeEvent
= FALSE
;
2559 m_hasScrolling
= FALSE
;
2560 m_isScrolling
= FALSE
;
2562 m_hAdjust
= (GtkAdjustment
*) NULL
;
2563 m_vAdjust
= (GtkAdjustment
*) NULL
;
2564 m_oldHorizontalPos
=
2565 m_oldVerticalPos
= 0.0;
2567 m_oldClientHeight
= 0;
2571 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2573 m_acceptsFocus
= FALSE
;
2576 m_clipPaintRegion
= FALSE
;
2578 m_needsStyleChange
= false;
2580 m_cursor
= *wxSTANDARD_CURSOR
;
2584 m_x11Context
= NULL
;
2585 m_dirtyTabOrder
= false;
2588 m_ic
= (GdkIC
*) NULL
;
2589 m_icattr
= (GdkICAttr
*) NULL
;
2594 wxWindowGTK::wxWindowGTK()
2599 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2604 const wxString
&name
)
2608 Create( parent
, id
, pos
, size
, style
, name
);
2611 bool wxWindowGTK::Create( wxWindow
*parent
,
2616 const wxString
&name
)
2618 if (!PreCreation( parent
, pos
, size
) ||
2619 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2621 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2625 m_insertCallback
= wxInsertChildInWindow
;
2627 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2628 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2630 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2632 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2633 scroll_class
->scrollbar_spacing
= 0;
2635 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2637 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2638 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2640 m_wxwindow
= gtk_pizza_new();
2642 #ifndef __WXUNIVERSAL__
2643 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2645 if (HasFlag(wxRAISED_BORDER
))
2647 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2649 else if (HasFlag(wxSUNKEN_BORDER
))
2651 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2653 else if (HasFlag(wxSIMPLE_BORDER
))
2655 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2659 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2661 #endif // __WXUNIVERSAL__
2663 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2665 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2666 m_acceptsFocus
= TRUE
;
2668 // I _really_ don't want scrollbars in the beginning
2669 m_vAdjust
->lower
= 0.0;
2670 m_vAdjust
->upper
= 1.0;
2671 m_vAdjust
->value
= 0.0;
2672 m_vAdjust
->step_increment
= 1.0;
2673 m_vAdjust
->page_increment
= 1.0;
2674 m_vAdjust
->page_size
= 5.0;
2675 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2676 m_hAdjust
->lower
= 0.0;
2677 m_hAdjust
->upper
= 1.0;
2678 m_hAdjust
->value
= 0.0;
2679 m_hAdjust
->step_increment
= 1.0;
2680 m_hAdjust
->page_increment
= 1.0;
2681 m_hAdjust
->page_size
= 5.0;
2682 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2684 // these handlers block mouse events to any window during scrolling such as
2685 // motion events and prevent GTK and wxWidgets from fighting over where the
2688 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2689 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2691 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2692 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2694 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2695 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2697 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2698 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2700 // these handlers get notified when screen updates are required either when
2701 // scrolling or when the window size (and therefore scrollbar configuration)
2704 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2705 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2706 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2707 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2709 gtk_widget_show( m_wxwindow
);
2712 m_parent
->DoAddChild( this );
2714 m_focusWidget
= m_wxwindow
;
2721 wxWindowGTK::~wxWindowGTK()
2725 if (g_focusWindow
== this)
2726 g_focusWindow
= NULL
;
2728 if ( g_delayedFocus
== this )
2729 g_delayedFocus
= NULL
;
2731 m_isBeingDeleted
= TRUE
;
2741 gdk_ic_destroy (m_ic
);
2743 gdk_ic_attr_destroy (m_icattr
);
2748 gtk_widget_destroy( m_wxwindow
);
2749 m_wxwindow
= (GtkWidget
*) NULL
;
2754 gtk_widget_destroy( m_widget
);
2755 m_widget
= (GtkWidget
*) NULL
;
2763 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2765 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2767 // Use either the given size, or the default if -1 is given.
2768 // See wxWindowBase for these functions.
2769 m_width
= WidthDefault(size
.x
) ;
2770 m_height
= HeightDefault(size
.y
);
2778 void wxWindowGTK::PostCreation()
2780 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2786 // these get reported to wxWidgets -> wxPaintEvent
2788 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2790 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2791 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2794 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2795 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2797 if (!HasFlag(wxFULL_REPAINT_ON_RESIZE
))
2799 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2800 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2803 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2808 // Create input method handler
2809 m_imData
= new wxGtkIMData
;
2811 // Cannot handle drawing preedited text yet
2812 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2814 g_signal_connect (G_OBJECT (m_imData
->context
), "commit",
2815 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2818 // these are called when the "sunken" or "raised" borders are drawn
2819 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2820 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2823 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2824 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2830 if (!GTK_IS_WINDOW(m_widget
))
2832 if (m_focusWidget
== NULL
)
2833 m_focusWidget
= m_widget
;
2835 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2836 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2838 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2839 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2842 // connect to the various key and mouse handlers
2844 GtkWidget
*connect_widget
= GetConnectWidget();
2846 ConnectWidget( connect_widget
);
2848 /* We cannot set colours, fonts and cursors before the widget has
2849 been realized, so we do this directly after realization */
2850 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2851 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2855 // Catch native resize events
2856 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2857 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2859 // Initialize XIM support
2860 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2861 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2863 // And resize XIM window
2864 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2865 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2868 if ( !GTK_IS_COMBO(m_widget
))
2870 // This is needed if we want to add our windows into native
2871 // GTK control, such as the toolbar. With this callback, the
2872 // toolbar gets to know the correct size (the one set by the
2873 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2874 // when moving to GTK 2.0.
2875 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2876 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback
),
2880 InheritAttributes();
2884 // unless the window was created initially hidden (i.e. Hide() had been
2885 // called before Create()), we should show it at GTK+ level as well
2887 gtk_widget_show( m_widget
);
2890 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2892 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2893 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2895 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2896 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2898 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2899 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2901 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2902 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2904 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2905 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2908 gtk_signal_connect( GTK_OBJECT(widget
), "scroll_event",
2909 GTK_SIGNAL_FUNC(gtk_window_wheel_callback
), (gpointer
)this );
2912 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2913 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2915 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2916 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2919 bool wxWindowGTK::Destroy()
2921 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2925 return wxWindowBase::Destroy();
2928 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2930 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2933 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2935 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2936 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2939 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2942 if (m_resizing
) return; /* I don't like recursions */
2945 int currentX
, currentY
;
2946 GetPosition(¤tX
, ¤tY
);
2947 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2949 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2951 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2953 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2955 /* don't set the size for children of wxNotebook, just take the values. */
2963 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2964 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2966 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2967 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2971 m_x
= x
+ pizza
->xoffset
;
2972 m_y
= y
+ pizza
->yoffset
;
2975 // calculate the best size if we should auto size the window
2976 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2977 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2979 const wxSize sizeBest
= GetBestSize();
2980 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2982 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2983 height
= sizeBest
.y
;
2991 int minWidth
= GetMinWidth(),
2992 minHeight
= GetMinHeight(),
2993 maxWidth
= GetMaxWidth(),
2994 maxHeight
= GetMaxHeight();
2996 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2997 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2998 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2999 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
3002 int bottom_border
= 0;
3005 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
3007 /* the default button has a border around it */
3013 DoMoveWindow( m_x
-border
,
3016 m_height
+border
+bottom_border
);
3021 /* Sometimes the client area changes size without the
3022 whole windows's size changing, but if the whole
3023 windows's size doesn't change, no wxSizeEvent will
3024 normally be sent. Here we add an extra test if
3025 the client test has been changed and this will
3027 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
3031 wxPrintf( "OnSize sent from " );
3032 if (GetClassInfo() && GetClassInfo()->GetClassName())
3033 wxPrintf( GetClassInfo()->GetClassName() );
3034 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3037 if (!m_nativeSizeEvent
)
3039 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
3040 event
.SetEventObject( this );
3041 GetEventHandler()->ProcessEvent( event
);
3047 void wxWindowGTK::OnInternalIdle()
3050 if ( m_dirtyTabOrder
)
3053 // Update style if the window was not yet realized
3054 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
3055 if (m_needsStyleChange
)
3057 SetBackgroundStyle(GetBackgroundStyle());
3058 m_needsStyleChange
= false;
3061 // Update invalidated regions.
3064 wxCursor cursor
= m_cursor
;
3065 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3069 /* I now set the cursor anew in every OnInternalIdle call
3070 as setting the cursor in a parent window also effects the
3071 windows above so that checking for the current cursor is
3076 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3078 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3080 if (!g_globalCursor
.Ok())
3081 cursor
= *wxSTANDARD_CURSOR
;
3083 window
= m_widget
->window
;
3084 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3085 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3091 GdkWindow
*window
= m_widget
->window
;
3092 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3093 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3098 if (wxUpdateUIEvent::CanUpdate(this))
3099 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3102 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3104 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3106 if (width
) (*width
) = m_width
;
3107 if (height
) (*height
) = m_height
;
3110 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3112 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3116 SetSize( width
, height
);
3123 #ifndef __WXUNIVERSAL__
3124 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3126 /* when using GTK 1.2 we set the shadow border size to 2 */
3130 if (HasFlag(wxSIMPLE_BORDER
))
3132 /* when using GTK 1.2 we set the simple border size to 1 */
3136 #endif // __WXUNIVERSAL__
3140 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3142 GtkRequisition vscroll_req
;
3143 vscroll_req
.width
= 2;
3144 vscroll_req
.height
= 2;
3145 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3146 (scroll_window
->vscrollbar
, &vscroll_req
);
3148 GtkRequisition hscroll_req
;
3149 hscroll_req
.width
= 2;
3150 hscroll_req
.height
= 2;
3151 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3152 (scroll_window
->hscrollbar
, &hscroll_req
);
3154 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3156 if (scroll_window
->vscrollbar_visible
)
3158 dw
+= vscroll_req
.width
;
3159 dw
+= scroll_class
->scrollbar_spacing
;
3162 if (scroll_window
->hscrollbar_visible
)
3164 dh
+= hscroll_req
.height
;
3165 dh
+= scroll_class
->scrollbar_spacing
;
3169 SetSize( width
+dw
, height
+dh
);
3173 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3175 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3179 if (width
) (*width
) = m_width
;
3180 if (height
) (*height
) = m_height
;
3187 #ifndef __WXUNIVERSAL__
3188 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3190 /* when using GTK 1.2 we set the shadow border size to 2 */
3194 if (HasFlag(wxSIMPLE_BORDER
))
3196 /* when using GTK 1.2 we set the simple border size to 1 */
3200 #endif // __WXUNIVERSAL__
3204 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3206 GtkRequisition vscroll_req
;
3207 vscroll_req
.width
= 2;
3208 vscroll_req
.height
= 2;
3209 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3210 (scroll_window
->vscrollbar
, &vscroll_req
);
3212 GtkRequisition hscroll_req
;
3213 hscroll_req
.width
= 2;
3214 hscroll_req
.height
= 2;
3215 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3216 (scroll_window
->hscrollbar
, &hscroll_req
);
3218 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3220 if (scroll_window
->vscrollbar_visible
)
3222 dw
+= vscroll_req
.width
;
3223 dw
+= scroll_class
->scrollbar_spacing
;
3226 if (scroll_window
->hscrollbar_visible
)
3228 dh
+= hscroll_req
.height
;
3229 dh
+= scroll_class
->scrollbar_spacing
;
3233 if (width
) (*width
) = m_width
- dw
;
3234 if (height
) (*height
) = m_height
- dh
;
3238 printf( "GetClientSize, name %s ", GetName().c_str() );
3239 if (width) printf( " width = %d", (*width) );
3240 if (height) printf( " height = %d", (*height) );
3245 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3247 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3251 if (m_parent
&& m_parent
->m_wxwindow
)
3253 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3254 dx
= pizza
->xoffset
;
3255 dy
= pizza
->yoffset
;
3258 if (x
) (*x
) = m_x
- dx
;
3259 if (y
) (*y
) = m_y
- dy
;
3262 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3264 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3266 if (!m_widget
->window
) return;
3268 GdkWindow
*source
= (GdkWindow
*) NULL
;
3270 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3272 source
= m_widget
->window
;
3276 gdk_window_get_origin( source
, &org_x
, &org_y
);
3280 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3282 org_x
+= m_widget
->allocation
.x
;
3283 org_y
+= m_widget
->allocation
.y
;
3291 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3293 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3295 if (!m_widget
->window
) return;
3297 GdkWindow
*source
= (GdkWindow
*) NULL
;
3299 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3301 source
= m_widget
->window
;
3305 gdk_window_get_origin( source
, &org_x
, &org_y
);
3309 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3311 org_x
+= m_widget
->allocation
.x
;
3312 org_y
+= m_widget
->allocation
.y
;
3320 bool wxWindowGTK::Show( bool show
)
3322 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3324 if (!wxWindowBase::Show(show
))
3331 gtk_widget_show( m_widget
);
3333 gtk_widget_hide( m_widget
);
3335 wxShowEvent
eventShow(GetId(), show
);
3336 eventShow
.m_eventObject
= this;
3338 GetEventHandler()->ProcessEvent(eventShow
);
3343 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3345 win
->OnParentEnable(enable
);
3347 // Recurse, so that children have the opportunity to Do The Right Thing
3348 // and reset colours that have been messed up by a parent's (really ancestor's)
3350 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3352 node
= node
->GetNext() )
3354 wxWindow
*child
= node
->GetData();
3355 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3356 wxWindowNotifyEnable(child
, enable
);
3360 bool wxWindowGTK::Enable( bool enable
)
3362 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3364 if (!wxWindowBase::Enable(enable
))
3370 gtk_widget_set_sensitive( m_widget
, enable
);
3372 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3374 wxWindowNotifyEnable(this, enable
);
3379 int wxWindowGTK::GetCharHeight() const
3381 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3383 wxFont font
= GetFont();
3384 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3387 PangoContext
*context
= NULL
;
3389 context
= gtk_widget_get_pango_context( m_widget
);
3394 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3395 PangoLayout
*layout
= pango_layout_new(context
);
3396 pango_layout_set_font_description(layout
, desc
);
3397 pango_layout_set_text(layout
, "H", 1);
3398 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3400 PangoRectangle rect
;
3401 pango_layout_line_get_extents(line
, NULL
, &rect
);
3403 g_object_unref( G_OBJECT( layout
) );
3405 return (int) PANGO_PIXELS(rect
.height
);
3407 GdkFont
*gfont
= font
.GetInternalFont( 1.0 );
3409 return gfont
->ascent
+ gfont
->descent
;
3413 int wxWindowGTK::GetCharWidth() const
3415 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3417 wxFont font
= GetFont();
3418 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3421 PangoContext
*context
= NULL
;
3423 context
= gtk_widget_get_pango_context( m_widget
);
3428 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3429 PangoLayout
*layout
= pango_layout_new(context
);
3430 pango_layout_set_font_description(layout
, desc
);
3431 pango_layout_set_text(layout
, "g", 1);
3432 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3434 PangoRectangle rect
;
3435 pango_layout_line_get_extents(line
, NULL
, &rect
);
3437 g_object_unref( G_OBJECT( layout
) );
3439 return (int) PANGO_PIXELS(rect
.width
);
3441 GdkFont
*gfont
= font
.GetInternalFont( 1.0 );
3443 return gdk_string_width( gfont
, "g" );
3447 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3451 int *externalLeading
,
3452 const wxFont
*theFont
) const
3454 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3456 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3458 if (string
.IsEmpty())
3466 PangoContext
*context
= NULL
;
3468 context
= gtk_widget_get_pango_context( m_widget
);
3477 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3478 PangoLayout
*layout
= pango_layout_new(context
);
3479 pango_layout_set_font_description(layout
, desc
);
3482 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3483 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3485 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3486 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3487 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3491 PangoRectangle rect
;
3492 pango_layout_get_extents(layout
, NULL
, &rect
);
3494 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3495 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3498 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3499 int baseline
= pango_layout_iter_get_baseline(iter
);
3500 pango_layout_iter_free(iter
);
3501 *descent
= *y
- PANGO_PIXELS(baseline
);
3503 if (externalLeading
) (*externalLeading
) = 0; // ??
3505 g_object_unref( G_OBJECT( layout
) );
3507 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3508 if (x
) (*x
) = gdk_string_width( font
, wxGTK_CONV( string
) );
3509 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3510 if (descent
) (*descent
) = font
->descent
;
3511 if (externalLeading
) (*externalLeading
) = 0; // ??
3515 void wxWindowGTK::SetFocus()
3517 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3520 // don't do anything if we already have focus
3526 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3528 gtk_widget_grab_focus (m_wxwindow
);
3534 if (GTK_IS_CONTAINER(m_widget
))
3536 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3540 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3543 if (!GTK_WIDGET_REALIZED(m_widget
))
3545 // we can't set the focus to the widget now so we remember that
3546 // it should be focused and will do it later, during the idle
3547 // time, as soon as we can
3548 wxLogTrace(TRACE_FOCUS
,
3549 _T("Delaying setting focus to %s(%s)"),
3550 GetClassInfo()->GetClassName(), GetLabel().c_str());
3552 g_delayedFocus
= this;
3556 wxLogTrace(TRACE_FOCUS
,
3557 _T("Setting focus to %s(%s)"),
3558 GetClassInfo()->GetClassName(), GetLabel().c_str());
3560 gtk_widget_grab_focus (m_widget
);
3565 if (GTK_IS_CONTAINER(m_widget
))
3567 gtk_container_focus( GTK_CONTAINER(m_widget
), GTK_DIR_TAB_FORWARD
);
3572 wxLogTrace(TRACE_FOCUS
,
3573 _T("Can't set focus to %s(%s)"),
3574 GetClassInfo()->GetClassName(), GetLabel().c_str());
3579 bool wxWindowGTK::AcceptsFocus() const
3581 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3584 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3586 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3588 wxWindowGTK
*oldParent
= m_parent
,
3589 *newParent
= (wxWindowGTK
*)newParentBase
;
3591 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3593 if ( !wxWindowBase::Reparent(newParent
) )
3596 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3598 /* prevent GTK from deleting the widget arbitrarily */
3599 gtk_widget_ref( m_widget
);
3603 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3606 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3610 /* insert GTK representation */
3611 (*(newParent
->m_insertCallback
))(newParent
, this);
3614 /* reverse: prevent GTK from deleting the widget arbitrarily */
3615 gtk_widget_unref( m_widget
);
3620 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3622 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3624 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3626 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3631 /* insert GTK representation */
3632 (*m_insertCallback
)(this, child
);
3637 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3639 wxWindowBase::AddChild(child
);
3640 m_dirtyTabOrder
= true;
3642 wxapp_install_idle_handler();
3645 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3647 wxWindowBase::RemoveChild(child
);
3648 m_dirtyTabOrder
= true;
3650 wxapp_install_idle_handler();
3653 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3655 wxWindowBase::DoMoveInTabOrder(win
, move
);
3656 m_dirtyTabOrder
= true;
3658 wxapp_install_idle_handler();
3661 void wxWindowGTK::RealizeTabOrder()
3665 if (m_children
.size() > 0)
3667 GList
*chain
= NULL
;
3669 for (wxWindowList::const_iterator i
= m_children
.begin();
3670 i
!= m_children
.end(); ++i
)
3672 chain
= g_list_prepend(chain
, (*i
)->m_widget
);
3675 chain
= g_list_reverse(chain
);
3677 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3682 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3686 m_dirtyTabOrder
= false;
3689 #endif // __WXGTK20__
3691 void wxWindowGTK::Raise()
3693 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3695 if (!m_widget
->window
) return;
3697 gdk_window_raise( m_widget
->window
);
3700 void wxWindowGTK::Lower()
3702 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3704 if (!m_widget
->window
) return;
3706 gdk_window_lower( m_widget
->window
);
3709 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3711 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3713 if (cursor
== m_cursor
)
3717 wxapp_install_idle_handler();
3719 if (cursor
== wxNullCursor
)
3720 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3722 return wxWindowBase::SetCursor( cursor
);
3725 void wxWindowGTK::WarpPointer( int x
, int y
)
3727 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3729 // We provide this function ourselves as it is
3730 // missing in GDK (top of this file).
3732 GdkWindow
*window
= (GdkWindow
*) NULL
;
3734 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3736 window
= GetConnectWidget()->window
;
3739 gdk_window_warp_pointer( window
, x
, y
);
3743 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3745 if (!m_widget
) return;
3746 if (!m_widget
->window
) return;
3750 wxapp_install_idle_handler();
3752 wxRect
myRect(0,0,0,0);
3753 if (m_wxwindow
&& rect
)
3755 myRect
.SetSize(wxSize( m_wxwindow
->allocation
.width
,
3756 m_wxwindow
->allocation
.height
));
3757 myRect
.Intersect(*rect
);
3758 if (!myRect
.width
|| !myRect
.height
)
3759 // nothing to do, rectangle is empty
3764 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3768 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3769 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3773 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3774 m_clearRegion
.Clear();
3775 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3783 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3784 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3788 GdkRectangle gdk_rect
;
3789 gdk_rect
.x
= rect
->x
;
3790 gdk_rect
.y
= rect
->y
;
3791 gdk_rect
.width
= rect
->width
;
3792 gdk_rect
.height
= rect
->height
;
3793 gtk_widget_draw( m_widget
, &gdk_rect
);
3800 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3801 m_updateRegion
.Clear();
3802 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3806 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3814 GdkRectangle gdk_rect
;
3815 gdk_rect
.x
= rect
->x
;
3816 gdk_rect
.y
= rect
->y
;
3817 gdk_rect
.width
= rect
->width
;
3818 gdk_rect
.height
= rect
->height
;
3819 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3823 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3829 void wxWindowGTK::Update()
3834 void wxWindowGTK::GtkUpdate()
3837 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3838 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3840 if (!m_updateRegion
.IsEmpty())
3841 GtkSendPaintEvents();
3845 void wxWindowGTK::GtkSendPaintEvents()
3850 m_clearRegion
.Clear();
3852 m_updateRegion
.Clear();
3856 // Clip to paint region in wxClientDC
3857 m_clipPaintRegion
= TRUE
;
3859 // widget to draw on
3860 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3862 if (GetThemeEnabled() && GetBackgroundStyle() == wxBG_STYLE_SYSTEM
)
3864 // find ancestor from which to steal background
3865 wxWindow
*parent
= GetParent();
3866 while (parent
&& !parent
->IsTopLevel())
3867 parent
= parent
->GetParent();
3869 parent
= (wxWindow
*)this;
3871 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3873 wxRegionIterator
upd( m_updateRegion
);
3877 rect
.x
= upd
.GetX();
3878 rect
.y
= upd
.GetY();
3879 rect
.width
= upd
.GetWidth();
3880 rect
.height
= upd
.GetHeight();
3882 gtk_paint_flat_box( parent
->m_widget
->style
,
3884 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3899 wxWindowDC
dc( (wxWindow
*)this );
3900 dc
.SetClippingRegion( m_updateRegion
);
3902 wxEraseEvent
erase_event( GetId(), &dc
);
3903 erase_event
.SetEventObject( this );
3905 GetEventHandler()->ProcessEvent(erase_event
);
3908 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
3910 wxWindowDC
dc( (wxWindow
*)this );
3911 if (m_clearRegion
.IsEmpty())
3912 dc
.SetClippingRegion( m_updateRegion
);
3914 dc
.SetClippingRegion( m_clearRegion
);
3916 wxEraseEvent
erase_event( GetId(), &dc
);
3917 erase_event
.SetEventObject( this );
3919 if (!GetEventHandler()->ProcessEvent(erase_event
) && GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3923 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
3924 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3926 gdk_gc_set_foreground( g_eraseGC
, GetBackgroundColour().GetColor() );
3928 wxRegionIterator
upd( m_clearRegion
);
3931 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3932 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3936 m_clearRegion
.Clear();
3940 wxNcPaintEvent
nc_paint_event( GetId() );
3941 nc_paint_event
.SetEventObject( this );
3942 GetEventHandler()->ProcessEvent( nc_paint_event
);
3944 wxPaintEvent
paint_event( GetId() );
3945 paint_event
.SetEventObject( this );
3946 GetEventHandler()->ProcessEvent( paint_event
);
3948 m_clipPaintRegion
= FALSE
;
3950 #ifndef __WXUNIVERSAL__
3952 // The following code will result in all window-less widgets
3953 // being redrawn because the wxWidgets class is allowed to
3954 // paint over the window-less widgets.
3956 GList
*children
= pizza
->children
;
3959 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3960 children
= children
->next
;
3962 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3963 GTK_WIDGET_DRAWABLE (child
->widget
))
3965 // Get intersection of widget area and update region
3966 wxRegion
region( m_updateRegion
);
3968 GdkEventExpose gdk_event
;
3969 gdk_event
.type
= GDK_EXPOSE
;
3970 gdk_event
.window
= pizza
->bin_window
;
3971 gdk_event
.count
= 0;
3973 wxRegionIterator
upd( m_updateRegion
);
3977 rect
.x
= upd
.GetX();
3978 rect
.y
= upd
.GetY();
3979 rect
.width
= upd
.GetWidth();
3980 rect
.height
= upd
.GetHeight();
3982 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3984 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3994 m_updateRegion
.Clear();
3997 void wxWindowGTK::ClearBackground()
3999 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4002 if (m_wxwindow
&& m_wxwindow
->window
)
4004 m_clearRegion
.Clear();
4005 wxSize
size( GetClientSize() );
4006 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
4008 // Better do this in idle?
4015 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
4017 wxWindowBase::DoSetToolTip(tip
);
4020 m_tooltip
->Apply( (wxWindow
*)this );
4023 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
4025 wxString
tmp( tip
);
4026 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
4028 #endif // wxUSE_TOOLTIPS
4030 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
4032 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4034 if (!wxWindowBase::SetBackgroundColour(colour
))
4039 // We need the pixel value e.g. for background clearing.
4040 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
4043 // apply style change (forceStyle=true so that new style is applied
4044 // even if the bg colour changed from valid to wxNullColour)
4045 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
4046 ApplyWidgetStyle(true);
4051 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
4053 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4055 if (!wxWindowBase::SetForegroundColour(colour
))
4062 // We need the pixel value e.g. for background clearing.
4063 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
4066 // apply style change (forceStyle=true so that new style is applied
4067 // even if the bg colour changed from valid to wxNullColour):
4068 ApplyWidgetStyle(true);
4074 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
4076 return gtk_widget_get_pango_context( m_widget
);
4079 PangoContext
*wxWindowGTK::GtkGetPangoX11Context()
4082 m_x11Context
= pango_x_get_context( gdk_display
);
4084 return m_x11Context
;
4088 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
4090 // do we need to apply any changes at all?
4093 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
4098 GtkRcStyle
*style
= gtk_rc_style_new();
4104 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
4106 wxString xfontname
= m_font
.GetNativeFontInfo()->GetXFontName();
4107 style
->fontset_name
= g_strdup(xfontname
.c_str());
4111 if ( m_foregroundColour
.Ok() )
4113 GdkColor
*fg
= m_foregroundColour
.GetColor();
4115 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
4116 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
4118 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
4119 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
4121 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
4122 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
4125 if ( m_backgroundColour
.Ok() )
4127 GdkColor
*bg
= m_backgroundColour
.GetColor();
4129 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
4130 style
->base
[GTK_STATE_NORMAL
] = *bg
;
4131 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
4132 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
4134 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
4135 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
4136 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
4137 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
4139 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
4140 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
4141 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
4142 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4144 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
4145 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
4146 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
4147 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4153 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
4155 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
4158 DoApplyWidgetStyle(style
);
4159 gtk_rc_style_unref(style
);
4162 // Style change may affect GTK+'s size calculation:
4163 InvalidateBestSize();
4166 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
4169 gtk_widget_modify_style(m_wxwindow
, style
);
4170 gtk_widget_modify_style(m_widget
, style
);
4173 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
4175 wxWindowBase::SetBackgroundStyle(style
);
4177 if (style
== wxBG_STYLE_CUSTOM
)
4179 GdkWindow
*window
= (GdkWindow
*) NULL
;
4181 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4183 window
= GetConnectWidget()->window
;
4187 // Make sure GDK/X11 doesn't refresh the window
4189 gdk_window_set_back_pixmap( window
, None
, False
);
4191 Display
* display
= GDK_WINDOW_DISPLAY(window
);
4194 m_needsStyleChange
= false;
4197 // Do in OnIdle, because the window is not yet available
4198 m_needsStyleChange
= true;
4200 // Don't apply widget style, or we get a grey background
4204 // apply style change (forceStyle=true so that new style is applied
4205 // even if the bg colour changed from valid to wxNullColour):
4206 ApplyWidgetStyle(true);
4211 //-----------------------------------------------------------------------------
4212 // Pop-up menu stuff
4213 //-----------------------------------------------------------------------------
4215 #if wxUSE_MENUS_NATIVE
4218 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
4220 *is_waiting
= FALSE
;
4223 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
4225 menu
->SetInvokingWindow( win
);
4226 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
4229 wxMenuItem
*menuitem
= node
->GetData();
4230 if (menuitem
->IsSubMenu())
4232 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
4235 node
= node
->GetNext();
4239 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
4242 gboolean
* WXUNUSED(whatever
),
4244 gpointer user_data
)
4246 // ensure that the menu appears entirely on screen
4248 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
4250 wxSize sizeScreen
= wxGetDisplaySize();
4251 wxPoint
*pos
= (wxPoint
*)user_data
;
4253 gint xmax
= sizeScreen
.x
- req
.width
,
4254 ymax
= sizeScreen
.y
- req
.height
;
4256 *x
= pos
->x
< xmax
? pos
->x
: xmax
;
4257 *y
= pos
->y
< ymax
? pos
->y
: ymax
;
4260 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4262 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4264 wxCHECK_MSG( menu
!= NULL
, false, wxT("invalid popup-menu") );
4266 SetInvokingWindow( menu
, this );
4270 bool is_waiting
= true;
4272 gulong handler
= gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
4274 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
4275 (gpointer
)&is_waiting
);
4279 GtkMenuPositionFunc posfunc
;
4280 if ( x
== -1 && y
== -1 )
4282 // use GTK's default positioning algorithm
4288 pos
= ClientToScreen(wxPoint(x
, y
));
4290 posfunc
= wxPopupMenuPositionCallback
;
4294 GTK_MENU(menu
->m_menu
),
4295 (GtkWidget
*) NULL
, // parent menu shell
4296 (GtkWidget
*) NULL
, // parent menu item
4297 posfunc
, // function to position it
4298 userdata
, // client data
4299 0, // button used to activate it
4301 gtk_get_current_event_time()
4303 gs_timeLastClick
// the time of activation
4309 gtk_main_iteration();
4312 gtk_signal_disconnect(GTK_OBJECT(menu
->m_menu
), handler
);
4317 #endif // wxUSE_MENUS_NATIVE
4319 #if wxUSE_DRAG_AND_DROP
4321 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4323 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4325 GtkWidget
*dnd_widget
= GetConnectWidget();
4327 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4329 if (m_dropTarget
) delete m_dropTarget
;
4330 m_dropTarget
= dropTarget
;
4332 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4335 #endif // wxUSE_DRAG_AND_DROP
4337 GtkWidget
* wxWindowGTK::GetConnectWidget()
4339 GtkWidget
*connect_widget
= m_widget
;
4340 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4342 return connect_widget
;
4345 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4348 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4350 return (window
== m_widget
->window
);
4353 bool wxWindowGTK::SetFont( const wxFont
&font
)
4355 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4357 if (!wxWindowBase::SetFont(font
))
4360 // apply style change (forceStyle=true so that new style is applied
4361 // even if the font changed from valid to wxNullFont):
4362 ApplyWidgetStyle(true);
4367 void wxWindowGTK::DoCaptureMouse()
4369 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4371 GdkWindow
*window
= (GdkWindow
*) NULL
;
4373 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4375 window
= GetConnectWidget()->window
;
4377 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4379 wxCursor
* cursor
= & m_cursor
;
4381 cursor
= wxSTANDARD_CURSOR
;
4383 gdk_pointer_grab( window
, FALSE
,
4385 (GDK_BUTTON_PRESS_MASK
|
4386 GDK_BUTTON_RELEASE_MASK
|
4387 GDK_POINTER_MOTION_HINT_MASK
|
4388 GDK_POINTER_MOTION_MASK
),
4390 cursor
->GetCursor(),
4391 (guint32
)GDK_CURRENT_TIME
);
4392 g_captureWindow
= this;
4393 g_captureWindowHasMouse
= TRUE
;
4396 void wxWindowGTK::DoReleaseMouse()
4398 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4400 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4402 g_captureWindow
= (wxWindowGTK
*) NULL
;
4404 GdkWindow
*window
= (GdkWindow
*) NULL
;
4406 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4408 window
= GetConnectWidget()->window
;
4413 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4417 wxWindow
*wxWindowBase::GetCapture()
4419 return (wxWindow
*)g_captureWindow
;
4422 bool wxWindowGTK::IsRetained() const
4427 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4428 int range
, bool refresh
)
4430 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4432 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4434 m_hasScrolling
= TRUE
;
4436 if (orient
== wxHORIZONTAL
)
4438 float fpos
= (float)pos
;
4439 float frange
= (float)range
;
4440 float fthumb
= (float)thumbVisible
;
4441 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4442 if (fpos
< 0.0) fpos
= 0.0;
4444 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4445 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4447 SetScrollPos( orient
, pos
, refresh
);
4451 m_oldHorizontalPos
= fpos
;
4453 m_hAdjust
->lower
= 0.0;
4454 m_hAdjust
->upper
= frange
;
4455 m_hAdjust
->value
= fpos
;
4456 m_hAdjust
->step_increment
= 1.0;
4457 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4458 m_hAdjust
->page_size
= fthumb
;
4462 float fpos
= (float)pos
;
4463 float frange
= (float)range
;
4464 float fthumb
= (float)thumbVisible
;
4465 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4466 if (fpos
< 0.0) fpos
= 0.0;
4468 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4469 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4471 SetScrollPos( orient
, pos
, refresh
);
4475 m_oldVerticalPos
= fpos
;
4477 m_vAdjust
->lower
= 0.0;
4478 m_vAdjust
->upper
= frange
;
4479 m_vAdjust
->value
= fpos
;
4480 m_vAdjust
->step_increment
= 1.0;
4481 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4482 m_vAdjust
->page_size
= fthumb
;
4485 if (orient
== wxHORIZONTAL
)
4486 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4488 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4491 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4493 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4495 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4497 if (orient
== wxHORIZONTAL
)
4499 float fpos
= (float)pos
;
4500 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4501 if (fpos
< 0.0) fpos
= 0.0;
4502 m_oldHorizontalPos
= fpos
;
4504 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4505 m_hAdjust
->value
= fpos
;
4509 float fpos
= (float)pos
;
4510 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4511 if (fpos
< 0.0) fpos
= 0.0;
4512 m_oldVerticalPos
= fpos
;
4514 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4515 m_vAdjust
->value
= fpos
;
4518 if (m_wxwindow
->window
)
4520 if (orient
== wxHORIZONTAL
)
4522 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4523 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4525 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4527 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4528 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4532 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4533 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4535 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4537 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4538 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4543 int wxWindowGTK::GetScrollThumb( int orient
) const
4545 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4547 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4549 if (orient
== wxHORIZONTAL
)
4550 return (int)(m_hAdjust
->page_size
+0.5);
4552 return (int)(m_vAdjust
->page_size
+0.5);
4555 int wxWindowGTK::GetScrollPos( int orient
) const
4557 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4559 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4561 if (orient
== wxHORIZONTAL
)
4562 return (int)(m_hAdjust
->value
+0.5);
4564 return (int)(m_vAdjust
->value
+0.5);
4567 int wxWindowGTK::GetScrollRange( int orient
) const
4569 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4571 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4573 if (orient
== wxHORIZONTAL
)
4574 return (int)(m_hAdjust
->upper
+0.5);
4576 return (int)(m_vAdjust
->upper
+0.5);
4579 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4581 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4583 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4585 // No scrolling requested.
4586 if ((dx
== 0) && (dy
== 0)) return;
4589 if (!m_updateRegion
.IsEmpty())
4591 m_updateRegion
.Offset( dx
, dy
);
4595 GetClientSize( &cw
, &ch
);
4596 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4599 if (!m_clearRegion
.IsEmpty())
4601 m_clearRegion
.Offset( dx
, dy
);
4605 GetClientSize( &cw
, &ch
);
4606 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4610 m_clipPaintRegion
= TRUE
;
4612 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4614 m_clipPaintRegion
= FALSE
;
4618 // Find the wxWindow at the current mouse position, also returning the mouse
4620 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4622 pt
= wxGetMousePosition();
4623 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4627 // Get the current mouse position.
4628 wxPoint
wxGetMousePosition()
4630 /* This crashes when used within wxHelpContext,
4631 so we have to use the X-specific implementation below.
4633 GdkModifierType *mask;
4634 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4636 return wxPoint(x, y);
4640 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4642 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4643 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4644 Window rootReturn
, childReturn
;
4645 int rootX
, rootY
, winX
, winY
;
4646 unsigned int maskReturn
;
4648 XQueryPointer (display
,
4652 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4653 return wxPoint(rootX
, rootY
);
4657 // ----------------------------------------------------------------------------
4659 // ----------------------------------------------------------------------------
4661 class wxWinModule
: public wxModule
4668 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4671 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4673 bool wxWinModule::OnInit()
4675 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4676 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4681 void wxWinModule::OnExit()
4684 gdk_gc_unref( g_eraseGC
);