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 // find the correct window to send the event too: it may be a different one
1697 // from the one which got it at GTK+ level because some control don't have
1698 // their own X window and thus cannot get any events.
1699 if ( !g_captureWindow
)
1700 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1702 gs_timeLastClick
= gdk_event
->time
;
1705 if (event_type
== wxEVT_LEFT_DCLICK
)
1707 // GTK 1.2 crashes when intercepting double
1708 // click events from both wxSpinButton and
1710 if (GTK_IS_SPIN_BUTTON(win
->m_widget
))
1712 // Just disable this event for now.
1718 if (win
->GetEventHandler()->ProcessEvent( event
))
1720 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1724 if (event_type
== wxEVT_RIGHT_DOWN
)
1726 // generate a "context menu" event: this is similar to right mouse
1727 // click under many GUIs except that it is generated differently
1728 // (right up under MSW, ctrl-click under Mac, right down here) and
1730 // (a) it's a command event and so is propagated to the parent
1731 // (b) under some ports it can be generated from kbd too
1732 // (c) it uses screen coords (because of (a))
1733 wxContextMenuEvent
evtCtx(
1736 win
->ClientToScreen(event
.GetPosition()));
1737 evtCtx
.SetEventObject(win
);
1738 return win
->GetEventHandler()->ProcessEvent(evtCtx
);
1744 //-----------------------------------------------------------------------------
1745 // "button_release_event"
1746 //-----------------------------------------------------------------------------
1748 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1749 GdkEventButton
*gdk_event
,
1755 wxapp_install_idle_handler();
1757 if (!win
->m_hasVMT
) return FALSE
;
1758 if (g_blockEventsOnDrag
) return FALSE
;
1759 if (g_blockEventsOnScroll
) return FALSE
;
1761 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1763 wxEventType event_type
= wxEVT_NULL
;
1765 switch (gdk_event
->button
)
1768 event_type
= wxEVT_LEFT_UP
;
1772 event_type
= wxEVT_MIDDLE_UP
;
1776 event_type
= wxEVT_RIGHT_UP
;
1780 // unknwon button, don't process
1784 wxMouseEvent
event( event_type
);
1785 InitMouseEvent( win
, event
, gdk_event
);
1787 AdjustEventButtonState(event
);
1789 // same wxListBox hack as above
1790 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1792 if ( !g_captureWindow
)
1793 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1795 if (win
->GetEventHandler()->ProcessEvent( event
))
1797 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1804 //-----------------------------------------------------------------------------
1805 // "motion_notify_event"
1806 //-----------------------------------------------------------------------------
1808 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1809 GdkEventMotion
*gdk_event
,
1815 wxapp_install_idle_handler();
1817 if (!win
->m_hasVMT
) return FALSE
;
1818 if (g_blockEventsOnDrag
) return FALSE
;
1819 if (g_blockEventsOnScroll
) return FALSE
;
1821 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1823 if (gdk_event
->is_hint
)
1827 GdkModifierType state
;
1828 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1834 printf( "OnMotion from " );
1835 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1836 printf( win->GetClassInfo()->GetClassName() );
1840 wxMouseEvent
event( wxEVT_MOTION
);
1841 InitMouseEvent(win
, event
, gdk_event
);
1843 if ( g_captureWindow
)
1845 // synthetize a mouse enter or leave event if needed
1846 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1847 // This seems to be necessary and actually been added to
1848 // GDK itself in version 2.0.X
1851 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1852 if ( hasMouse
!= g_captureWindowHasMouse
)
1854 // the mouse changed window
1855 g_captureWindowHasMouse
= hasMouse
;
1857 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1858 : wxEVT_LEAVE_WINDOW
);
1859 InitMouseEvent(win
, event
, gdk_event
);
1860 event
.SetEventObject(win
);
1861 win
->GetEventHandler()->ProcessEvent(event
);
1866 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1869 if (win
->GetEventHandler()->ProcessEvent( event
))
1871 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1879 //-----------------------------------------------------------------------------
1880 // "mouse_wheel_event"
1881 //-----------------------------------------------------------------------------
1883 static gint
gtk_window_wheel_callback (GtkWidget
* widget
,
1884 GdkEventScroll
* gdk_event
,
1890 wxapp_install_idle_handler();
1892 wxEventType event_type
= wxEVT_NULL
;
1893 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1894 event_type
= wxEVT_MOUSEWHEEL
;
1895 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1896 event_type
= wxEVT_MOUSEWHEEL
;
1900 wxMouseEvent
event( event_type
);
1901 // Can't use InitMouse macro because scroll events don't have button
1902 event
.SetTimestamp( gdk_event
->time
);
1903 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1904 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1905 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1906 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1907 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1908 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1909 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1910 event
.m_linesPerAction
= 3;
1911 event
.m_wheelDelta
= 120;
1912 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1913 event
.m_wheelRotation
= 120;
1915 event
.m_wheelRotation
= -120;
1917 wxPoint pt
= win
->GetClientAreaOrigin();
1918 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1919 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1921 event
.SetEventObject( win
);
1922 event
.SetId( win
->GetId() );
1923 event
.SetTimestamp( gdk_event
->time
);
1925 if (win
->GetEventHandler()->ProcessEvent( event
))
1927 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "scroll_event" );
1934 //-----------------------------------------------------------------------------
1936 //-----------------------------------------------------------------------------
1937 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1939 wxContextMenuEvent
event(
1943 event
.SetEventObject(win
);
1944 return win
->GetEventHandler()->ProcessEvent(event
);
1946 #endif // __WXGTK20__
1948 //-----------------------------------------------------------------------------
1950 //-----------------------------------------------------------------------------
1952 // send the wxChildFocusEvent and wxFocusEvent, common code of
1953 // gtk_window_focus_in_callback() and SetFocus()
1954 static bool DoSendFocusEvents(wxWindow
*win
)
1956 // Notify the parent keeping track of focus for the kbd navigation
1957 // purposes that we got it.
1958 wxChildFocusEvent
eventChildFocus(win
);
1959 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1961 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1962 eventFocus
.SetEventObject(win
);
1964 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1967 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1968 GdkEvent
*WXUNUSED(event
),
1974 wxapp_install_idle_handler();
1978 gtk_im_context_focus_in(win
->m_imData
->context
);
1982 g_focusWindow
= win
;
1984 wxLogTrace(TRACE_FOCUS
,
1985 _T("%s: focus in"), win
->GetName().c_str());
1989 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1993 // caret needs to be informed about focus change
1994 wxCaret
*caret
= win
->GetCaret();
1997 caret
->OnSetFocus();
1999 #endif // wxUSE_CARET
2001 // does the window itself think that it has the focus?
2002 if ( !win
->m_hasFocus
)
2004 // not yet, notify it
2005 win
->m_hasFocus
= TRUE
;
2007 if ( DoSendFocusEvents(win
) )
2009 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
2017 //-----------------------------------------------------------------------------
2018 // "focus_out_event"
2019 //-----------------------------------------------------------------------------
2021 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
2026 wxapp_install_idle_handler();
2030 gtk_im_context_focus_out(win
->m_imData
->context
);
2033 wxLogTrace( TRACE_FOCUS
,
2034 _T("%s: focus out"), win
->GetName().c_str() );
2037 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
2041 g_focusWindow
= (wxWindowGTK
*)NULL
;
2049 // caret needs to be informed about focus change
2050 wxCaret
*caret
= win
->GetCaret();
2053 caret
->OnKillFocus();
2055 #endif // wxUSE_CARET
2057 // don't send the window a kill focus event if it thinks that it doesn't
2058 // have focus already
2059 if ( win
->m_hasFocus
)
2061 win
->m_hasFocus
= FALSE
;
2063 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
2064 event
.SetEventObject( win
);
2066 // even if we did process the event in wx code, still let GTK itself
2067 // process it too as otherwise bad things happen, especially in GTK2
2068 // where the text control simply aborts the program if it doesn't get
2069 // the matching focus out event
2070 (void)win
->GetEventHandler()->ProcessEvent( event
);
2076 //-----------------------------------------------------------------------------
2077 // "enter_notify_event"
2078 //-----------------------------------------------------------------------------
2081 gint
gtk_window_enter_callback( GtkWidget
*widget
,
2082 GdkEventCrossing
*gdk_event
,
2088 wxapp_install_idle_handler();
2090 if (!win
->m_hasVMT
) return FALSE
;
2091 if (g_blockEventsOnDrag
) return FALSE
;
2093 // Event was emitted after a grab
2094 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2096 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2100 GdkModifierType state
= (GdkModifierType
)0;
2102 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2104 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2105 InitMouseEvent(win
, event
, gdk_event
);
2106 wxPoint pt
= win
->GetClientAreaOrigin();
2107 event
.m_x
= x
+ pt
.x
;
2108 event
.m_y
= y
+ pt
.y
;
2110 if (win
->GetEventHandler()->ProcessEvent( event
))
2112 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
2119 //-----------------------------------------------------------------------------
2120 // "leave_notify_event"
2121 //-----------------------------------------------------------------------------
2123 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
2128 wxapp_install_idle_handler();
2130 if (!win
->m_hasVMT
) return FALSE
;
2131 if (g_blockEventsOnDrag
) return FALSE
;
2133 // Event was emitted after an ungrab
2134 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2136 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2138 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2139 event
.SetTimestamp( gdk_event
->time
);
2140 event
.SetEventObject( win
);
2144 GdkModifierType state
= (GdkModifierType
)0;
2146 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2148 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2149 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2150 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2151 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2152 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2153 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2154 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2156 wxPoint pt
= win
->GetClientAreaOrigin();
2157 event
.m_x
= x
+ pt
.x
;
2158 event
.m_y
= y
+ pt
.y
;
2160 if (win
->GetEventHandler()->ProcessEvent( event
))
2162 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
2169 //-----------------------------------------------------------------------------
2170 // "value_changed" from m_vAdjust
2171 //-----------------------------------------------------------------------------
2173 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2180 wxapp_install_idle_handler();
2182 if (g_blockEventsOnDrag
) return;
2184 if (!win
->m_hasVMT
) return;
2186 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2187 if (fabs(diff
) < 0.2) return;
2189 win
->m_oldVerticalPos
= adjust
->value
;
2192 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2194 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
2196 int value
= (int)(adjust
->value
+0.5);
2198 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2199 event
.SetEventObject( win
);
2200 win
->GetEventHandler()->ProcessEvent( event
);
2203 //-----------------------------------------------------------------------------
2204 // "value_changed" from m_hAdjust
2205 //-----------------------------------------------------------------------------
2207 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2214 wxapp_install_idle_handler();
2216 if (g_blockEventsOnDrag
) return;
2217 if (!win
->m_hasVMT
) return;
2219 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2220 if (fabs(diff
) < 0.2) return;
2223 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2225 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
2227 win
->m_oldHorizontalPos
= adjust
->value
;
2229 int value
= (int)(adjust
->value
+0.5);
2231 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2232 event
.SetEventObject( win
);
2233 win
->GetEventHandler()->ProcessEvent( event
);
2236 //-----------------------------------------------------------------------------
2237 // "button_press_event" from scrollbar
2238 //-----------------------------------------------------------------------------
2240 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2241 GdkEventButton
*gdk_event
,
2247 wxapp_install_idle_handler();
2250 g_blockEventsOnScroll
= TRUE
;
2252 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2254 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2260 //-----------------------------------------------------------------------------
2261 // "button_release_event" from scrollbar
2262 //-----------------------------------------------------------------------------
2264 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2265 GdkEventButton
*WXUNUSED(gdk_event
),
2270 // don't test here as we can release the mouse while being over
2271 // a different window than the slider
2273 // if (gdk_event->window != widget->slider) return FALSE;
2275 g_blockEventsOnScroll
= FALSE
;
2277 if (win
->m_isScrolling
)
2279 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2283 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2284 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2286 value
= (int)(win
->m_hAdjust
->value
+0.5);
2289 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2291 value
= (int)(win
->m_vAdjust
->value
+0.5);
2295 wxScrollWinEvent
event( command
, value
, dir
);
2296 event
.SetEventObject( win
);
2297 win
->GetEventHandler()->ProcessEvent( event
);
2300 win
->m_isScrolling
= FALSE
;
2305 // ----------------------------------------------------------------------------
2306 // this wxWindowBase function is implemented here (in platform-specific file)
2307 // because it is static and so couldn't be made virtual
2308 // ----------------------------------------------------------------------------
2310 wxWindow
*wxWindowBase::DoFindFocus()
2312 // the cast is necessary when we compile in wxUniversal mode
2313 return (wxWindow
*)g_focusWindow
;
2317 //-----------------------------------------------------------------------------
2318 // "realize" from m_widget
2319 //-----------------------------------------------------------------------------
2321 /* We cannot set colours and fonts before the widget has
2322 been realized, so we do this directly after realization. */
2325 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2330 wxapp_install_idle_handler();
2335 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2336 gtk_im_context_set_client_window( win
->m_imData
->context
,
2337 pizza
->bin_window
);
2341 wxWindowCreateEvent
event( win
);
2342 event
.SetEventObject( win
);
2343 win
->GetEventHandler()->ProcessEvent( event
);
2348 //-----------------------------------------------------------------------------
2350 //-----------------------------------------------------------------------------
2353 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2354 GtkAllocation
*WXUNUSED(alloc
),
2358 wxapp_install_idle_handler();
2360 if (!win
->m_hasScrolling
) return;
2362 int client_width
= 0;
2363 int client_height
= 0;
2364 win
->GetClientSize( &client_width
, &client_height
);
2365 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2368 win
->m_oldClientWidth
= client_width
;
2369 win
->m_oldClientHeight
= client_height
;
2371 if (!win
->m_nativeSizeEvent
)
2373 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2374 event
.SetEventObject( win
);
2375 win
->GetEventHandler()->ProcessEvent( event
);
2381 #define WXUNUSED_UNLESS_XIM(param) param
2383 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2386 /* Resize XIM window */
2389 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2390 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2391 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2394 wxapp_install_idle_handler();
2400 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2404 gdk_window_get_size (widget
->window
, &width
, &height
);
2405 win
->m_icattr
->preedit_area
.width
= width
;
2406 win
->m_icattr
->preedit_area
.height
= height
;
2407 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2412 //-----------------------------------------------------------------------------
2413 // "realize" from m_wxwindow
2414 //-----------------------------------------------------------------------------
2416 /* Initialize XIM support */
2419 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2420 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2423 wxapp_install_idle_handler();
2426 if (win
->m_ic
) return FALSE
;
2427 if (!widget
) return FALSE
;
2428 if (!gdk_im_ready()) return FALSE
;
2430 win
->m_icattr
= gdk_ic_attr_new();
2431 if (!win
->m_icattr
) return FALSE
;
2435 GdkColormap
*colormap
;
2436 GdkICAttr
*attr
= win
->m_icattr
;
2437 unsigned attrmask
= GDK_IC_ALL_REQ
;
2439 GdkIMStyle supported_style
= (GdkIMStyle
)
2440 (GDK_IM_PREEDIT_NONE
|
2441 GDK_IM_PREEDIT_NOTHING
|
2442 GDK_IM_PREEDIT_POSITION
|
2443 GDK_IM_STATUS_NONE
|
2444 GDK_IM_STATUS_NOTHING
);
2446 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2447 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2449 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2450 attr
->client_window
= widget
->window
;
2452 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2453 gtk_widget_get_default_colormap ())
2455 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2456 attr
->preedit_colormap
= colormap
;
2459 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2460 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2461 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2462 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2464 switch (style
& GDK_IM_PREEDIT_MASK
)
2466 case GDK_IM_PREEDIT_POSITION
:
2467 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2469 g_warning ("over-the-spot style requires fontset");
2473 gdk_window_get_size (widget
->window
, &width
, &height
);
2475 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2476 attr
->spot_location
.x
= 0;
2477 attr
->spot_location
.y
= height
;
2478 attr
->preedit_area
.x
= 0;
2479 attr
->preedit_area
.y
= 0;
2480 attr
->preedit_area
.width
= width
;
2481 attr
->preedit_area
.height
= height
;
2482 attr
->preedit_fontset
= widget
->style
->font
;
2487 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2489 if (win
->m_ic
== NULL
)
2490 g_warning ("Can't create input context.");
2493 mask
= gdk_window_get_events (widget
->window
);
2494 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2495 gdk_window_set_events (widget
->window
, mask
);
2497 if (GTK_WIDGET_HAS_FOCUS(widget
))
2498 gdk_im_begin (win
->m_ic
, widget
->window
);
2505 //-----------------------------------------------------------------------------
2506 // InsertChild for wxWindowGTK.
2507 //-----------------------------------------------------------------------------
2509 /* Callback for wxWindowGTK. This very strange beast has to be used because
2510 * C++ has no virtual methods in a constructor. We have to emulate a
2511 * virtual function here as wxNotebook requires a different way to insert
2512 * a child in it. I had opted for creating a wxNotebookPage window class
2513 * which would have made this superfluous (such in the MDI window system),
2514 * but no-one was listening to me... */
2516 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2518 /* the window might have been scrolled already, do we
2519 have to adapt the position */
2520 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2521 child
->m_x
+= pizza
->xoffset
;
2522 child
->m_y
+= pizza
->yoffset
;
2524 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2525 GTK_WIDGET(child
->m_widget
),
2532 //-----------------------------------------------------------------------------
2534 //-----------------------------------------------------------------------------
2536 wxWindow
*wxGetActiveWindow()
2538 return wxWindow::FindFocus();
2541 //-----------------------------------------------------------------------------
2543 //-----------------------------------------------------------------------------
2545 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2547 #ifdef __WXUNIVERSAL__
2548 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2550 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2551 #endif // __WXUNIVERSAL__/__WXGTK__
2553 void wxWindowGTK::Init()
2556 m_widget
= (GtkWidget
*) NULL
;
2557 m_wxwindow
= (GtkWidget
*) NULL
;
2558 m_focusWidget
= (GtkWidget
*) NULL
;
2568 m_needParent
= TRUE
;
2569 m_isBeingDeleted
= FALSE
;
2572 m_nativeSizeEvent
= FALSE
;
2574 m_hasScrolling
= FALSE
;
2575 m_isScrolling
= FALSE
;
2577 m_hAdjust
= (GtkAdjustment
*) NULL
;
2578 m_vAdjust
= (GtkAdjustment
*) NULL
;
2579 m_oldHorizontalPos
=
2580 m_oldVerticalPos
= 0.0;
2582 m_oldClientHeight
= 0;
2586 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2588 m_acceptsFocus
= FALSE
;
2591 m_clipPaintRegion
= FALSE
;
2593 m_needsStyleChange
= false;
2595 m_cursor
= *wxSTANDARD_CURSOR
;
2599 m_x11Context
= NULL
;
2600 m_dirtyTabOrder
= false;
2603 m_ic
= (GdkIC
*) NULL
;
2604 m_icattr
= (GdkICAttr
*) NULL
;
2609 wxWindowGTK::wxWindowGTK()
2614 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2619 const wxString
&name
)
2623 Create( parent
, id
, pos
, size
, style
, name
);
2626 bool wxWindowGTK::Create( wxWindow
*parent
,
2631 const wxString
&name
)
2633 if (!PreCreation( parent
, pos
, size
) ||
2634 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2636 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2640 m_insertCallback
= wxInsertChildInWindow
;
2642 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2643 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2645 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2647 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2648 scroll_class
->scrollbar_spacing
= 0;
2650 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2652 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2653 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2655 m_wxwindow
= gtk_pizza_new();
2657 #ifndef __WXUNIVERSAL__
2658 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2660 if (HasFlag(wxRAISED_BORDER
))
2662 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2664 else if (HasFlag(wxSUNKEN_BORDER
))
2666 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2668 else if (HasFlag(wxSIMPLE_BORDER
))
2670 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2674 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2676 #endif // __WXUNIVERSAL__
2678 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2680 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2681 m_acceptsFocus
= TRUE
;
2683 // I _really_ don't want scrollbars in the beginning
2684 m_vAdjust
->lower
= 0.0;
2685 m_vAdjust
->upper
= 1.0;
2686 m_vAdjust
->value
= 0.0;
2687 m_vAdjust
->step_increment
= 1.0;
2688 m_vAdjust
->page_increment
= 1.0;
2689 m_vAdjust
->page_size
= 5.0;
2690 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2691 m_hAdjust
->lower
= 0.0;
2692 m_hAdjust
->upper
= 1.0;
2693 m_hAdjust
->value
= 0.0;
2694 m_hAdjust
->step_increment
= 1.0;
2695 m_hAdjust
->page_increment
= 1.0;
2696 m_hAdjust
->page_size
= 5.0;
2697 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2699 // these handlers block mouse events to any window during scrolling such as
2700 // motion events and prevent GTK and wxWidgets from fighting over where the
2703 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2704 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2706 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2707 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2709 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2710 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2712 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2713 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2715 // these handlers get notified when screen updates are required either when
2716 // scrolling or when the window size (and therefore scrollbar configuration)
2719 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2720 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2721 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2722 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2724 gtk_widget_show( m_wxwindow
);
2727 m_parent
->DoAddChild( this );
2729 m_focusWidget
= m_wxwindow
;
2736 wxWindowGTK::~wxWindowGTK()
2740 if (g_focusWindow
== this)
2741 g_focusWindow
= NULL
;
2743 if ( g_delayedFocus
== this )
2744 g_delayedFocus
= NULL
;
2746 m_isBeingDeleted
= TRUE
;
2756 gdk_ic_destroy (m_ic
);
2758 gdk_ic_attr_destroy (m_icattr
);
2763 gtk_widget_destroy( m_wxwindow
);
2764 m_wxwindow
= (GtkWidget
*) NULL
;
2769 gtk_widget_destroy( m_widget
);
2770 m_widget
= (GtkWidget
*) NULL
;
2778 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2780 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2782 // Use either the given size, or the default if -1 is given.
2783 // See wxWindowBase for these functions.
2784 m_width
= WidthDefault(size
.x
) ;
2785 m_height
= HeightDefault(size
.y
);
2793 void wxWindowGTK::PostCreation()
2795 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2801 // these get reported to wxWidgets -> wxPaintEvent
2803 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2805 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2806 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2809 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2810 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2812 if (!HasFlag(wxFULL_REPAINT_ON_RESIZE
))
2814 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2815 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2818 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2823 // Create input method handler
2824 m_imData
= new wxGtkIMData
;
2826 // Cannot handle drawing preedited text yet
2827 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2829 g_signal_connect (G_OBJECT (m_imData
->context
), "commit",
2830 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2833 // these are called when the "sunken" or "raised" borders are drawn
2834 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2835 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2838 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2839 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2845 if (!GTK_IS_WINDOW(m_widget
))
2847 if (m_focusWidget
== NULL
)
2848 m_focusWidget
= m_widget
;
2850 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2851 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2853 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2854 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2857 // connect to the various key and mouse handlers
2859 GtkWidget
*connect_widget
= GetConnectWidget();
2861 ConnectWidget( connect_widget
);
2863 /* We cannot set colours, fonts and cursors before the widget has
2864 been realized, so we do this directly after realization */
2865 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2866 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2870 // Catch native resize events
2871 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2872 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2874 // Initialize XIM support
2875 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2876 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2878 // And resize XIM window
2879 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2880 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2883 if ( !GTK_IS_COMBO(m_widget
))
2885 // This is needed if we want to add our windows into native
2886 // GTK control, such as the toolbar. With this callback, the
2887 // toolbar gets to know the correct size (the one set by the
2888 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2889 // when moving to GTK 2.0.
2890 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2891 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback
),
2895 InheritAttributes();
2899 // unless the window was created initially hidden (i.e. Hide() had been
2900 // called before Create()), we should show it at GTK+ level as well
2902 gtk_widget_show( m_widget
);
2905 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2907 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2908 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2910 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2911 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2913 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2914 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2916 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2917 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2919 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2920 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2923 gtk_signal_connect( GTK_OBJECT(widget
), "scroll_event",
2924 GTK_SIGNAL_FUNC(gtk_window_wheel_callback
), (gpointer
)this );
2925 g_signal_connect(widget
, "popup_menu",
2926 G_CALLBACK(wxgtk_window_popup_menu_callback
), this);
2929 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2930 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2932 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2933 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2936 bool wxWindowGTK::Destroy()
2938 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2942 return wxWindowBase::Destroy();
2945 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2947 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2950 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2952 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2953 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2956 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2959 if (m_resizing
) return; /* I don't like recursions */
2962 int currentX
, currentY
;
2963 GetPosition(¤tX
, ¤tY
);
2964 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2966 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2968 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2970 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2972 /* don't set the size for children of wxNotebook, just take the values. */
2980 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2981 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2983 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2984 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2988 m_x
= x
+ pizza
->xoffset
;
2989 m_y
= y
+ pizza
->yoffset
;
2992 // calculate the best size if we should auto size the window
2993 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2994 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2996 const wxSize sizeBest
= GetBestSize();
2997 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2999 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
3000 height
= sizeBest
.y
;
3008 int minWidth
= GetMinWidth(),
3009 minHeight
= GetMinHeight(),
3010 maxWidth
= GetMaxWidth(),
3011 maxHeight
= GetMaxHeight();
3013 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
3014 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
3015 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
3016 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
3019 int bottom_border
= 0;
3022 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
3024 /* the default button has a border around it */
3030 DoMoveWindow( m_x
-border
,
3033 m_height
+border
+bottom_border
);
3038 /* Sometimes the client area changes size without the
3039 whole windows's size changing, but if the whole
3040 windows's size doesn't change, no wxSizeEvent will
3041 normally be sent. Here we add an extra test if
3042 the client test has been changed and this will
3044 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
3048 wxPrintf( "OnSize sent from " );
3049 if (GetClassInfo() && GetClassInfo()->GetClassName())
3050 wxPrintf( GetClassInfo()->GetClassName() );
3051 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3054 if (!m_nativeSizeEvent
)
3056 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
3057 event
.SetEventObject( this );
3058 GetEventHandler()->ProcessEvent( event
);
3064 void wxWindowGTK::OnInternalIdle()
3067 if ( m_dirtyTabOrder
)
3070 // Update style if the window was not yet realized
3071 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
3072 if (m_needsStyleChange
)
3074 SetBackgroundStyle(GetBackgroundStyle());
3075 m_needsStyleChange
= false;
3078 // Update invalidated regions.
3081 wxCursor cursor
= m_cursor
;
3082 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3086 /* I now set the cursor anew in every OnInternalIdle call
3087 as setting the cursor in a parent window also effects the
3088 windows above so that checking for the current cursor is
3093 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3095 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3097 if (!g_globalCursor
.Ok())
3098 cursor
= *wxSTANDARD_CURSOR
;
3100 window
= m_widget
->window
;
3101 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3102 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3108 GdkWindow
*window
= m_widget
->window
;
3109 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3110 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3115 if (wxUpdateUIEvent::CanUpdate(this))
3116 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3119 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3121 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3123 if (width
) (*width
) = m_width
;
3124 if (height
) (*height
) = m_height
;
3127 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3129 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3133 SetSize( width
, height
);
3140 #ifndef __WXUNIVERSAL__
3141 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3143 /* when using GTK 1.2 we set the shadow border size to 2 */
3147 if (HasFlag(wxSIMPLE_BORDER
))
3149 /* when using GTK 1.2 we set the simple border size to 1 */
3153 #endif // __WXUNIVERSAL__
3157 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3159 GtkRequisition vscroll_req
;
3160 vscroll_req
.width
= 2;
3161 vscroll_req
.height
= 2;
3162 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3163 (scroll_window
->vscrollbar
, &vscroll_req
);
3165 GtkRequisition hscroll_req
;
3166 hscroll_req
.width
= 2;
3167 hscroll_req
.height
= 2;
3168 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3169 (scroll_window
->hscrollbar
, &hscroll_req
);
3171 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3173 if (scroll_window
->vscrollbar_visible
)
3175 dw
+= vscroll_req
.width
;
3176 dw
+= scroll_class
->scrollbar_spacing
;
3179 if (scroll_window
->hscrollbar_visible
)
3181 dh
+= hscroll_req
.height
;
3182 dh
+= scroll_class
->scrollbar_spacing
;
3186 SetSize( width
+dw
, height
+dh
);
3190 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3192 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3196 if (width
) (*width
) = m_width
;
3197 if (height
) (*height
) = m_height
;
3204 #ifndef __WXUNIVERSAL__
3205 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3207 /* when using GTK 1.2 we set the shadow border size to 2 */
3211 if (HasFlag(wxSIMPLE_BORDER
))
3213 /* when using GTK 1.2 we set the simple border size to 1 */
3217 #endif // __WXUNIVERSAL__
3221 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3223 GtkRequisition vscroll_req
;
3224 vscroll_req
.width
= 2;
3225 vscroll_req
.height
= 2;
3226 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3227 (scroll_window
->vscrollbar
, &vscroll_req
);
3229 GtkRequisition hscroll_req
;
3230 hscroll_req
.width
= 2;
3231 hscroll_req
.height
= 2;
3232 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3233 (scroll_window
->hscrollbar
, &hscroll_req
);
3235 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3237 if (scroll_window
->vscrollbar_visible
)
3239 dw
+= vscroll_req
.width
;
3240 dw
+= scroll_class
->scrollbar_spacing
;
3243 if (scroll_window
->hscrollbar_visible
)
3245 dh
+= hscroll_req
.height
;
3246 dh
+= scroll_class
->scrollbar_spacing
;
3250 if (width
) (*width
) = m_width
- dw
;
3251 if (height
) (*height
) = m_height
- dh
;
3255 printf( "GetClientSize, name %s ", GetName().c_str() );
3256 if (width) printf( " width = %d", (*width) );
3257 if (height) printf( " height = %d", (*height) );
3262 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3264 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3268 if (m_parent
&& m_parent
->m_wxwindow
)
3270 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3271 dx
= pizza
->xoffset
;
3272 dy
= pizza
->yoffset
;
3275 if (x
) (*x
) = m_x
- dx
;
3276 if (y
) (*y
) = m_y
- dy
;
3279 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3281 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3283 if (!m_widget
->window
) return;
3285 GdkWindow
*source
= (GdkWindow
*) NULL
;
3287 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3289 source
= m_widget
->window
;
3293 gdk_window_get_origin( source
, &org_x
, &org_y
);
3297 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3299 org_x
+= m_widget
->allocation
.x
;
3300 org_y
+= m_widget
->allocation
.y
;
3308 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3310 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3312 if (!m_widget
->window
) return;
3314 GdkWindow
*source
= (GdkWindow
*) NULL
;
3316 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3318 source
= m_widget
->window
;
3322 gdk_window_get_origin( source
, &org_x
, &org_y
);
3326 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3328 org_x
+= m_widget
->allocation
.x
;
3329 org_y
+= m_widget
->allocation
.y
;
3337 bool wxWindowGTK::Show( bool show
)
3339 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3341 if (!wxWindowBase::Show(show
))
3348 gtk_widget_show( m_widget
);
3350 gtk_widget_hide( m_widget
);
3352 wxShowEvent
eventShow(GetId(), show
);
3353 eventShow
.SetEventObject(this);
3355 GetEventHandler()->ProcessEvent(eventShow
);
3360 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3362 win
->OnParentEnable(enable
);
3364 // Recurse, so that children have the opportunity to Do The Right Thing
3365 // and reset colours that have been messed up by a parent's (really ancestor's)
3367 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3369 node
= node
->GetNext() )
3371 wxWindow
*child
= node
->GetData();
3372 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3373 wxWindowNotifyEnable(child
, enable
);
3377 bool wxWindowGTK::Enable( bool enable
)
3379 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3381 if (!wxWindowBase::Enable(enable
))
3387 gtk_widget_set_sensitive( m_widget
, enable
);
3389 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3391 wxWindowNotifyEnable(this, enable
);
3396 int wxWindowGTK::GetCharHeight() const
3398 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3400 wxFont font
= GetFont();
3401 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3404 PangoContext
*context
= NULL
;
3406 context
= gtk_widget_get_pango_context( m_widget
);
3411 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3412 PangoLayout
*layout
= pango_layout_new(context
);
3413 pango_layout_set_font_description(layout
, desc
);
3414 pango_layout_set_text(layout
, "H", 1);
3415 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3417 PangoRectangle rect
;
3418 pango_layout_line_get_extents(line
, NULL
, &rect
);
3420 g_object_unref( G_OBJECT( layout
) );
3422 return (int) PANGO_PIXELS(rect
.height
);
3424 GdkFont
*gfont
= font
.GetInternalFont( 1.0 );
3426 return gfont
->ascent
+ gfont
->descent
;
3430 int wxWindowGTK::GetCharWidth() const
3432 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3434 wxFont font
= GetFont();
3435 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3438 PangoContext
*context
= NULL
;
3440 context
= gtk_widget_get_pango_context( m_widget
);
3445 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3446 PangoLayout
*layout
= pango_layout_new(context
);
3447 pango_layout_set_font_description(layout
, desc
);
3448 pango_layout_set_text(layout
, "g", 1);
3449 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3451 PangoRectangle rect
;
3452 pango_layout_line_get_extents(line
, NULL
, &rect
);
3454 g_object_unref( G_OBJECT( layout
) );
3456 return (int) PANGO_PIXELS(rect
.width
);
3458 GdkFont
*gfont
= font
.GetInternalFont( 1.0 );
3460 return gdk_string_width( gfont
, "g" );
3464 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3468 int *externalLeading
,
3469 const wxFont
*theFont
) const
3471 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3473 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3475 if (string
.IsEmpty())
3483 PangoContext
*context
= NULL
;
3485 context
= gtk_widget_get_pango_context( m_widget
);
3494 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3495 PangoLayout
*layout
= pango_layout_new(context
);
3496 pango_layout_set_font_description(layout
, desc
);
3499 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3500 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3502 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3503 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3504 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3508 PangoRectangle rect
;
3509 pango_layout_get_extents(layout
, NULL
, &rect
);
3511 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3512 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3515 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3516 int baseline
= pango_layout_iter_get_baseline(iter
);
3517 pango_layout_iter_free(iter
);
3518 *descent
= *y
- PANGO_PIXELS(baseline
);
3520 if (externalLeading
) (*externalLeading
) = 0; // ??
3522 g_object_unref( G_OBJECT( layout
) );
3524 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3525 if (x
) (*x
) = gdk_string_width( font
, wxGTK_CONV( string
) );
3526 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3527 if (descent
) (*descent
) = font
->descent
;
3528 if (externalLeading
) (*externalLeading
) = 0; // ??
3532 void wxWindowGTK::SetFocus()
3534 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3537 // don't do anything if we already have focus
3543 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3545 gtk_widget_grab_focus (m_wxwindow
);
3551 if (GTK_IS_CONTAINER(m_widget
))
3553 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3557 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3560 if (!GTK_WIDGET_REALIZED(m_widget
))
3562 // we can't set the focus to the widget now so we remember that
3563 // it should be focused and will do it later, during the idle
3564 // time, as soon as we can
3565 wxLogTrace(TRACE_FOCUS
,
3566 _T("Delaying setting focus to %s(%s)"),
3567 GetClassInfo()->GetClassName(), GetLabel().c_str());
3569 g_delayedFocus
= this;
3573 wxLogTrace(TRACE_FOCUS
,
3574 _T("Setting focus to %s(%s)"),
3575 GetClassInfo()->GetClassName(), GetLabel().c_str());
3577 gtk_widget_grab_focus (m_widget
);
3582 if (GTK_IS_CONTAINER(m_widget
))
3584 gtk_container_focus( GTK_CONTAINER(m_widget
), GTK_DIR_TAB_FORWARD
);
3589 wxLogTrace(TRACE_FOCUS
,
3590 _T("Can't set focus to %s(%s)"),
3591 GetClassInfo()->GetClassName(), GetLabel().c_str());
3596 bool wxWindowGTK::AcceptsFocus() const
3598 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3601 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3603 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3605 wxWindowGTK
*oldParent
= m_parent
,
3606 *newParent
= (wxWindowGTK
*)newParentBase
;
3608 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3610 if ( !wxWindowBase::Reparent(newParent
) )
3613 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3615 /* prevent GTK from deleting the widget arbitrarily */
3616 gtk_widget_ref( m_widget
);
3620 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3623 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3627 /* insert GTK representation */
3628 (*(newParent
->m_insertCallback
))(newParent
, this);
3631 /* reverse: prevent GTK from deleting the widget arbitrarily */
3632 gtk_widget_unref( m_widget
);
3637 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3639 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3641 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3643 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3648 /* insert GTK representation */
3649 (*m_insertCallback
)(this, child
);
3654 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3656 wxWindowBase::AddChild(child
);
3657 m_dirtyTabOrder
= true;
3659 wxapp_install_idle_handler();
3662 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3664 wxWindowBase::RemoveChild(child
);
3665 m_dirtyTabOrder
= true;
3667 wxapp_install_idle_handler();
3670 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3672 wxWindowBase::DoMoveInTabOrder(win
, move
);
3673 m_dirtyTabOrder
= true;
3675 wxapp_install_idle_handler();
3678 void wxWindowGTK::RealizeTabOrder()
3682 if (m_children
.size() > 0)
3684 GList
*chain
= NULL
;
3686 for (wxWindowList::const_iterator i
= m_children
.begin();
3687 i
!= m_children
.end(); ++i
)
3689 chain
= g_list_prepend(chain
, (*i
)->m_widget
);
3692 chain
= g_list_reverse(chain
);
3694 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3699 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3703 m_dirtyTabOrder
= false;
3706 #endif // __WXGTK20__
3708 void wxWindowGTK::Raise()
3710 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3712 if (!m_widget
->window
) return;
3714 gdk_window_raise( m_widget
->window
);
3717 void wxWindowGTK::Lower()
3719 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3721 if (!m_widget
->window
) return;
3723 gdk_window_lower( m_widget
->window
);
3726 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3728 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3730 if (cursor
== m_cursor
)
3734 wxapp_install_idle_handler();
3736 if (cursor
== wxNullCursor
)
3737 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3739 return wxWindowBase::SetCursor( cursor
);
3742 void wxWindowGTK::WarpPointer( int x
, int y
)
3744 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3746 // We provide this function ourselves as it is
3747 // missing in GDK (top of this file).
3749 GdkWindow
*window
= (GdkWindow
*) NULL
;
3751 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3753 window
= GetConnectWidget()->window
;
3756 gdk_window_warp_pointer( window
, x
, y
);
3760 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3762 if (!m_widget
) return;
3763 if (!m_widget
->window
) return;
3767 wxapp_install_idle_handler();
3769 wxRect
myRect(0,0,0,0);
3770 if (m_wxwindow
&& rect
)
3772 myRect
.SetSize(wxSize( m_wxwindow
->allocation
.width
,
3773 m_wxwindow
->allocation
.height
));
3774 myRect
.Intersect(*rect
);
3775 if (!myRect
.width
|| !myRect
.height
)
3776 // nothing to do, rectangle is empty
3781 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3785 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3786 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3790 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3791 m_clearRegion
.Clear();
3792 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3800 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3801 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3805 GdkRectangle gdk_rect
;
3806 gdk_rect
.x
= rect
->x
;
3807 gdk_rect
.y
= rect
->y
;
3808 gdk_rect
.width
= rect
->width
;
3809 gdk_rect
.height
= rect
->height
;
3810 gtk_widget_draw( m_widget
, &gdk_rect
);
3817 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3818 m_updateRegion
.Clear();
3819 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3823 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3831 GdkRectangle gdk_rect
;
3832 gdk_rect
.x
= rect
->x
;
3833 gdk_rect
.y
= rect
->y
;
3834 gdk_rect
.width
= rect
->width
;
3835 gdk_rect
.height
= rect
->height
;
3836 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3840 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3846 void wxWindowGTK::Update()
3851 void wxWindowGTK::GtkUpdate()
3854 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3855 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3857 if (!m_updateRegion
.IsEmpty())
3858 GtkSendPaintEvents();
3862 void wxWindowGTK::GtkSendPaintEvents()
3867 m_clearRegion
.Clear();
3869 m_updateRegion
.Clear();
3873 // Clip to paint region in wxClientDC
3874 m_clipPaintRegion
= TRUE
;
3876 // widget to draw on
3877 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3879 if (GetThemeEnabled() && GetBackgroundStyle() == wxBG_STYLE_SYSTEM
)
3881 // find ancestor from which to steal background
3882 wxWindow
*parent
= GetParent();
3883 while (parent
&& !parent
->IsTopLevel())
3884 parent
= parent
->GetParent();
3886 parent
= (wxWindow
*)this;
3888 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3890 wxRegionIterator
upd( m_updateRegion
);
3894 rect
.x
= upd
.GetX();
3895 rect
.y
= upd
.GetY();
3896 rect
.width
= upd
.GetWidth();
3897 rect
.height
= upd
.GetHeight();
3899 gtk_paint_flat_box( parent
->m_widget
->style
,
3901 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3916 wxWindowDC
dc( (wxWindow
*)this );
3917 dc
.SetClippingRegion( m_updateRegion
);
3919 wxEraseEvent
erase_event( GetId(), &dc
);
3920 erase_event
.SetEventObject( this );
3922 GetEventHandler()->ProcessEvent(erase_event
);
3925 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
3927 wxWindowDC
dc( (wxWindow
*)this );
3928 if (m_clearRegion
.IsEmpty())
3929 dc
.SetClippingRegion( m_updateRegion
);
3931 dc
.SetClippingRegion( m_clearRegion
);
3933 wxEraseEvent
erase_event( GetId(), &dc
);
3934 erase_event
.SetEventObject( this );
3936 if (!GetEventHandler()->ProcessEvent(erase_event
) && GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3940 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
3941 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3943 gdk_gc_set_foreground( g_eraseGC
, GetBackgroundColour().GetColor() );
3945 wxRegionIterator
upd( m_clearRegion
);
3948 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3949 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3953 m_clearRegion
.Clear();
3957 wxNcPaintEvent
nc_paint_event( GetId() );
3958 nc_paint_event
.SetEventObject( this );
3959 GetEventHandler()->ProcessEvent( nc_paint_event
);
3961 wxPaintEvent
paint_event( GetId() );
3962 paint_event
.SetEventObject( this );
3963 GetEventHandler()->ProcessEvent( paint_event
);
3965 m_clipPaintRegion
= FALSE
;
3967 #ifndef __WXUNIVERSAL__
3969 // The following code will result in all window-less widgets
3970 // being redrawn because the wxWidgets class is allowed to
3971 // paint over the window-less widgets.
3973 GList
*children
= pizza
->children
;
3976 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3977 children
= children
->next
;
3979 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3980 GTK_WIDGET_DRAWABLE (child
->widget
))
3982 // Get intersection of widget area and update region
3983 wxRegion
region( m_updateRegion
);
3985 GdkEventExpose gdk_event
;
3986 gdk_event
.type
= GDK_EXPOSE
;
3987 gdk_event
.window
= pizza
->bin_window
;
3988 gdk_event
.count
= 0;
3990 wxRegionIterator
upd( m_updateRegion
);
3994 rect
.x
= upd
.GetX();
3995 rect
.y
= upd
.GetY();
3996 rect
.width
= upd
.GetWidth();
3997 rect
.height
= upd
.GetHeight();
3999 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
4001 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
4011 m_updateRegion
.Clear();
4014 void wxWindowGTK::ClearBackground()
4016 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4019 if (m_wxwindow
&& m_wxwindow
->window
)
4021 m_clearRegion
.Clear();
4022 wxSize
size( GetClientSize() );
4023 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
4025 // Better do this in idle?
4032 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
4034 wxWindowBase::DoSetToolTip(tip
);
4037 m_tooltip
->Apply( (wxWindow
*)this );
4040 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
4042 wxString
tmp( tip
);
4043 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
4045 #endif // wxUSE_TOOLTIPS
4047 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
4049 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4051 if (!wxWindowBase::SetBackgroundColour(colour
))
4056 // We need the pixel value e.g. for background clearing.
4057 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
4060 // apply style change (forceStyle=true so that new style is applied
4061 // even if the bg colour changed from valid to wxNullColour)
4062 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
4063 ApplyWidgetStyle(true);
4068 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
4070 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4072 if (!wxWindowBase::SetForegroundColour(colour
))
4079 // We need the pixel value e.g. for background clearing.
4080 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
4083 // apply style change (forceStyle=true so that new style is applied
4084 // even if the bg colour changed from valid to wxNullColour):
4085 ApplyWidgetStyle(true);
4091 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
4093 return gtk_widget_get_pango_context( m_widget
);
4096 PangoContext
*wxWindowGTK::GtkGetPangoX11Context()
4099 m_x11Context
= pango_x_get_context( gdk_display
);
4101 return m_x11Context
;
4105 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
4107 // do we need to apply any changes at all?
4110 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
4115 GtkRcStyle
*style
= gtk_rc_style_new();
4121 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
4123 wxString xfontname
= m_font
.GetNativeFontInfo()->GetXFontName();
4124 style
->fontset_name
= g_strdup(xfontname
.c_str());
4128 if ( m_foregroundColour
.Ok() )
4130 GdkColor
*fg
= m_foregroundColour
.GetColor();
4132 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
4133 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
4135 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
4136 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
4138 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
4139 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
4142 if ( m_backgroundColour
.Ok() )
4144 GdkColor
*bg
= m_backgroundColour
.GetColor();
4146 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
4147 style
->base
[GTK_STATE_NORMAL
] = *bg
;
4148 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
4149 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
4151 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
4152 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
4153 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
4154 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
4156 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
4157 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
4158 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
4159 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4161 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
4162 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
4163 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
4164 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4170 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
4172 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
4175 DoApplyWidgetStyle(style
);
4176 gtk_rc_style_unref(style
);
4179 // Style change may affect GTK+'s size calculation:
4180 InvalidateBestSize();
4183 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
4186 gtk_widget_modify_style(m_wxwindow
, style
);
4187 gtk_widget_modify_style(m_widget
, style
);
4190 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
4192 wxWindowBase::SetBackgroundStyle(style
);
4194 if (style
== wxBG_STYLE_CUSTOM
)
4196 GdkWindow
*window
= (GdkWindow
*) NULL
;
4198 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4200 window
= GetConnectWidget()->window
;
4204 // Make sure GDK/X11 doesn't refresh the window
4206 gdk_window_set_back_pixmap( window
, None
, False
);
4208 Display
* display
= GDK_WINDOW_DISPLAY(window
);
4211 m_needsStyleChange
= false;
4214 // Do in OnIdle, because the window is not yet available
4215 m_needsStyleChange
= true;
4217 // Don't apply widget style, or we get a grey background
4221 // apply style change (forceStyle=true so that new style is applied
4222 // even if the bg colour changed from valid to wxNullColour):
4223 ApplyWidgetStyle(true);
4228 //-----------------------------------------------------------------------------
4229 // Pop-up menu stuff
4230 //-----------------------------------------------------------------------------
4232 #if wxUSE_MENUS_NATIVE
4235 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
4237 *is_waiting
= FALSE
;
4240 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
4242 menu
->SetInvokingWindow( win
);
4243 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
4246 wxMenuItem
*menuitem
= node
->GetData();
4247 if (menuitem
->IsSubMenu())
4249 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
4252 node
= node
->GetNext();
4256 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
4259 gboolean
* WXUNUSED(whatever
),
4261 gpointer user_data
)
4263 // ensure that the menu appears entirely on screen
4265 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
4267 wxSize sizeScreen
= wxGetDisplaySize();
4268 wxPoint
*pos
= (wxPoint
*)user_data
;
4270 gint xmax
= sizeScreen
.x
- req
.width
,
4271 ymax
= sizeScreen
.y
- req
.height
;
4273 *x
= pos
->x
< xmax
? pos
->x
: xmax
;
4274 *y
= pos
->y
< ymax
? pos
->y
: ymax
;
4277 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4279 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4281 wxCHECK_MSG( menu
!= NULL
, false, wxT("invalid popup-menu") );
4283 SetInvokingWindow( menu
, this );
4287 bool is_waiting
= true;
4289 gulong handler
= gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
4291 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
4292 (gpointer
)&is_waiting
);
4296 GtkMenuPositionFunc posfunc
;
4297 if ( x
== -1 && y
== -1 )
4299 // use GTK's default positioning algorithm
4305 pos
= ClientToScreen(wxPoint(x
, y
));
4307 posfunc
= wxPopupMenuPositionCallback
;
4311 GTK_MENU(menu
->m_menu
),
4312 (GtkWidget
*) NULL
, // parent menu shell
4313 (GtkWidget
*) NULL
, // parent menu item
4314 posfunc
, // function to position it
4315 userdata
, // client data
4316 0, // button used to activate it
4318 gtk_get_current_event_time()
4320 gs_timeLastClick
// the time of activation
4326 gtk_main_iteration();
4329 gtk_signal_disconnect(GTK_OBJECT(menu
->m_menu
), handler
);
4334 #endif // wxUSE_MENUS_NATIVE
4336 #if wxUSE_DRAG_AND_DROP
4338 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4340 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4342 GtkWidget
*dnd_widget
= GetConnectWidget();
4344 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4346 if (m_dropTarget
) delete m_dropTarget
;
4347 m_dropTarget
= dropTarget
;
4349 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4352 #endif // wxUSE_DRAG_AND_DROP
4354 GtkWidget
* wxWindowGTK::GetConnectWidget()
4356 GtkWidget
*connect_widget
= m_widget
;
4357 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4359 return connect_widget
;
4362 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4365 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4367 return (window
== m_widget
->window
);
4370 bool wxWindowGTK::SetFont( const wxFont
&font
)
4372 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4374 if (!wxWindowBase::SetFont(font
))
4377 // apply style change (forceStyle=true so that new style is applied
4378 // even if the font changed from valid to wxNullFont):
4379 ApplyWidgetStyle(true);
4384 void wxWindowGTK::DoCaptureMouse()
4386 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4388 GdkWindow
*window
= (GdkWindow
*) NULL
;
4390 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4392 window
= GetConnectWidget()->window
;
4394 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4396 wxCursor
* cursor
= & m_cursor
;
4398 cursor
= wxSTANDARD_CURSOR
;
4400 gdk_pointer_grab( window
, FALSE
,
4402 (GDK_BUTTON_PRESS_MASK
|
4403 GDK_BUTTON_RELEASE_MASK
|
4404 GDK_POINTER_MOTION_HINT_MASK
|
4405 GDK_POINTER_MOTION_MASK
),
4407 cursor
->GetCursor(),
4408 (guint32
)GDK_CURRENT_TIME
);
4409 g_captureWindow
= this;
4410 g_captureWindowHasMouse
= TRUE
;
4413 void wxWindowGTK::DoReleaseMouse()
4415 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4417 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4419 g_captureWindow
= (wxWindowGTK
*) NULL
;
4421 GdkWindow
*window
= (GdkWindow
*) NULL
;
4423 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4425 window
= GetConnectWidget()->window
;
4430 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4434 wxWindow
*wxWindowBase::GetCapture()
4436 return (wxWindow
*)g_captureWindow
;
4439 bool wxWindowGTK::IsRetained() const
4444 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4445 int range
, bool refresh
)
4447 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4449 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4451 m_hasScrolling
= TRUE
;
4453 if (orient
== wxHORIZONTAL
)
4455 float fpos
= (float)pos
;
4456 float frange
= (float)range
;
4457 float fthumb
= (float)thumbVisible
;
4458 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4459 if (fpos
< 0.0) fpos
= 0.0;
4461 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4462 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4464 SetScrollPos( orient
, pos
, refresh
);
4468 m_oldHorizontalPos
= fpos
;
4470 m_hAdjust
->lower
= 0.0;
4471 m_hAdjust
->upper
= frange
;
4472 m_hAdjust
->value
= fpos
;
4473 m_hAdjust
->step_increment
= 1.0;
4474 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4475 m_hAdjust
->page_size
= fthumb
;
4479 float fpos
= (float)pos
;
4480 float frange
= (float)range
;
4481 float fthumb
= (float)thumbVisible
;
4482 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4483 if (fpos
< 0.0) fpos
= 0.0;
4485 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4486 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4488 SetScrollPos( orient
, pos
, refresh
);
4492 m_oldVerticalPos
= fpos
;
4494 m_vAdjust
->lower
= 0.0;
4495 m_vAdjust
->upper
= frange
;
4496 m_vAdjust
->value
= fpos
;
4497 m_vAdjust
->step_increment
= 1.0;
4498 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4499 m_vAdjust
->page_size
= fthumb
;
4502 if (orient
== wxHORIZONTAL
)
4503 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4505 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4508 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4510 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4512 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4514 if (orient
== wxHORIZONTAL
)
4516 float fpos
= (float)pos
;
4517 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4518 if (fpos
< 0.0) fpos
= 0.0;
4519 m_oldHorizontalPos
= fpos
;
4521 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4522 m_hAdjust
->value
= fpos
;
4526 float fpos
= (float)pos
;
4527 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4528 if (fpos
< 0.0) fpos
= 0.0;
4529 m_oldVerticalPos
= fpos
;
4531 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4532 m_vAdjust
->value
= fpos
;
4535 if (m_wxwindow
->window
)
4537 if (orient
== wxHORIZONTAL
)
4539 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4540 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4542 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4544 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4545 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4549 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4550 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4552 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4554 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4555 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4560 int wxWindowGTK::GetScrollThumb( int orient
) const
4562 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4564 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4566 if (orient
== wxHORIZONTAL
)
4567 return (int)(m_hAdjust
->page_size
+0.5);
4569 return (int)(m_vAdjust
->page_size
+0.5);
4572 int wxWindowGTK::GetScrollPos( int orient
) const
4574 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4576 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4578 if (orient
== wxHORIZONTAL
)
4579 return (int)(m_hAdjust
->value
+0.5);
4581 return (int)(m_vAdjust
->value
+0.5);
4584 int wxWindowGTK::GetScrollRange( int orient
) const
4586 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4588 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4590 if (orient
== wxHORIZONTAL
)
4591 return (int)(m_hAdjust
->upper
+0.5);
4593 return (int)(m_vAdjust
->upper
+0.5);
4596 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4598 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4600 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4602 // No scrolling requested.
4603 if ((dx
== 0) && (dy
== 0)) return;
4606 if (!m_updateRegion
.IsEmpty())
4608 m_updateRegion
.Offset( dx
, dy
);
4612 GetClientSize( &cw
, &ch
);
4613 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4616 if (!m_clearRegion
.IsEmpty())
4618 m_clearRegion
.Offset( dx
, dy
);
4622 GetClientSize( &cw
, &ch
);
4623 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4627 m_clipPaintRegion
= TRUE
;
4629 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4631 m_clipPaintRegion
= FALSE
;
4635 // Find the wxWindow at the current mouse position, also returning the mouse
4637 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4639 pt
= wxGetMousePosition();
4640 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4644 // Get the current mouse position.
4645 wxPoint
wxGetMousePosition()
4647 /* This crashes when used within wxHelpContext,
4648 so we have to use the X-specific implementation below.
4650 GdkModifierType *mask;
4651 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4653 return wxPoint(x, y);
4657 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4659 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4660 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4661 Window rootReturn
, childReturn
;
4662 int rootX
, rootY
, winX
, winY
;
4663 unsigned int maskReturn
;
4665 XQueryPointer (display
,
4669 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4670 return wxPoint(rootX
, rootY
);
4674 // ----------------------------------------------------------------------------
4676 // ----------------------------------------------------------------------------
4678 class wxWinModule
: public wxModule
4685 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4688 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4690 bool wxWinModule::OnInit()
4692 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4693 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4698 void wxWinModule::OnExit()
4701 gdk_gc_unref( g_eraseGC
);