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 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1118 bool return_after_IM
= false;
1120 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1122 // Emit KEY_DOWN event
1123 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1127 // Return after IM processing as we cannot do
1128 // anything with it anyhow.
1129 return_after_IM
= true;
1133 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
1134 // When we get a key_press event here, it could be originate
1135 // from the current widget or its child widgets. However, only the widget
1136 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
1137 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
1138 // originated from its child widgets and shouldn't be passed to IM context.
1139 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
1140 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
1141 // widgets has both IM context and input focus, the event should be filtered
1142 // by gtk_im_context_filter_keypress().
1143 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
1144 if ((!ret
) && (win
->m_imData
!= NULL
) && ( wxWindow::FindFocus() == win
))
1146 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1147 // docs, if IM filter returns true, no further processing should be done.
1148 // we should send the key_down event anyway.
1149 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
1150 win
->m_imData
->lastKeyEvent
= NULL
;
1151 if (intercepted_by_IM
)
1153 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1158 if (return_after_IM
)
1162 // This is for GTK+ 1.2 only. The char event generatation for GTK+ 2.0 is done
1163 // in the "commit" handler.
1165 // 2005.02.02 modified by Hong Jen Yee (hzysoft@sina.com.tw).
1166 // In GTK+ 1.2, strings sent by IMs are also regarded as key_press events whose
1167 // keyCodes cannot be recognized by wxWidgets. These MBCS strings, however, are
1168 // composed of more than one character, which means gdk_event->length will always
1169 // greater than one. When gtk_event->length == 1, this may be an ASCII character
1170 // and can be translated by wx. However, when MBCS characters are sent by IM,
1171 // gdk_event->length will >= 2. So neither should we pass it to accelerator table,
1172 // nor should we pass it to controls. The following explanation was excerpted
1173 // from GDK documentation.
1174 // gint length : the length of string.
1175 // gchar *string : a null-terminated multi-byte string containing the composed
1176 // characters resulting from the key press. When text is being input, in a GtkEntry
1177 // for example, it is these characters which should be added to the input buffer.
1178 // When using Input Methods to support internationalized text input, the composed
1179 // characters appear here after the pre-editing has been completed.
1181 if ( (!ret
) && (gdk_event
->length
> 1) ) // If this event contains a pre-edited string from IM.
1183 // We should translate this key event into wxEVT_CHAR not wxEVT_KEY_DOWN.
1184 #if wxUSE_UNICODE // GTK+ 1.2 is not UTF-8 based.
1185 const wxWCharBuffer string
= wxConvLocal
.cMB2WC( gdk_event
->string
);
1189 const char* string
= gdk_event
->string
;
1192 // Implement OnCharHook by checking ancesteror top level windows
1193 wxWindow
*parent
= win
;
1194 while (parent
&& !parent
->IsTopLevel())
1195 parent
= parent
->GetParent();
1197 for( const wxChar
* pstr
= string
; *pstr
; pstr
++ )
1200 event
.m_uniChar
= *pstr
;
1201 // Backward compatible for ISO-8859-1
1202 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1204 event
.m_keyCode
= *pstr
;
1208 event
.SetEventType( wxEVT_CHAR_HOOK
);
1209 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1213 event
.SetEventType(wxEVT_CHAR
);
1214 win
->GetEventHandler()->ProcessEvent( event
);
1220 #endif // #ifndef __WXGTK20__
1225 wxWindowGTK
*ancestor
= win
;
1228 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1231 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1232 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1235 if (ancestor
->IsTopLevel())
1237 ancestor
= ancestor
->GetParent();
1240 #endif // wxUSE_ACCEL
1242 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1243 // will only be sent if it is not in an accelerator table.
1247 KeySym keysym
= gdk_event
->keyval
;
1248 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1249 key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1252 if ( wxIsAsciiKeysym(keysym
) )
1255 key_code
= (unsigned char)keysym
;
1257 // gdk_event->string is actually deprecated
1258 else if ( gdk_event
->length
== 1 )
1260 key_code
= (unsigned char)gdk_event
->string
[0];
1266 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1268 event
.m_keyCode
= key_code
;
1270 // Implement OnCharHook by checking ancesteror top level windows
1271 wxWindow
*parent
= win
;
1272 while (parent
&& !parent
->IsTopLevel())
1273 parent
= parent
->GetParent();
1276 event
.SetEventType( wxEVT_CHAR_HOOK
);
1277 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1282 event
.SetEventType(wxEVT_CHAR
);
1283 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1292 // win is a control: tab can be propagated up
1294 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1295 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1296 // have this style, yet choose not to process this particular TAB in which
1297 // case TAB must still work as a navigational character
1298 // JS: enabling again to make consistent with other platforms
1299 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1300 // navigation behaviour)
1302 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1304 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1306 wxNavigationKeyEvent new_event
;
1307 new_event
.SetEventObject( win
->GetParent() );
1308 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1309 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1310 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1311 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1312 new_event
.SetCurrentFocus( win
);
1313 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1316 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1318 (gdk_event
->keyval
== GDK_Escape
) )
1320 // however only do it if we have a Cancel button in the dialog,
1321 // otherwise the user code may get confused by the events from a
1322 // non-existing button and, worse, a wxButton might get button event
1323 // from another button which is not really expected
1324 wxWindow
*winForCancel
= win
,
1326 while ( winForCancel
)
1328 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1331 // found a cancel button
1335 if ( winForCancel
->IsTopLevel() )
1337 // no need to look further
1341 // maybe our parent has a cancel button?
1342 winForCancel
= winForCancel
->GetParent();
1347 wxCommandEvent
event(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1348 event
.SetEventObject(btnCancel
);
1349 ret
= btnCancel
->GetEventHandler()->ProcessEvent(event
);
1355 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1363 static void gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1367 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1369 // take modifiers, cursor position, timestamp etc. from the last
1370 // key_press_event that was fed into Input Method:
1371 if (window
->m_imData
->lastKeyEvent
)
1373 wxFillOtherKeyEventFields(event
,
1374 window
, window
->m_imData
->lastKeyEvent
);
1378 const wxWCharBuffer data
= wxConvUTF8
.cMB2WC( (char*)str
);
1380 const wxWCharBuffer wdata
= wxConvUTF8
.cMB2WC( (char*)str
);
1381 const wxCharBuffer data
= wxConvLocal
.cWC2MB( wdata
);
1382 #endif // wxUSE_UNICODE
1383 if( !(const wxChar
*)data
)
1388 // Implement OnCharHook by checking ancestor top level windows
1389 wxWindow
*parent
= window
;
1390 while (parent
&& !parent
->IsTopLevel())
1391 parent
= parent
->GetParent();
1393 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1396 event
.m_uniChar
= *pstr
;
1397 // Backward compatible for ISO-8859-1
1398 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1399 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1401 event
.m_keyCode
= *pstr
;
1402 #endif // wxUSE_UNICODE
1405 event
.SetEventType( wxEVT_CHAR_HOOK
);
1406 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1411 event
.SetEventType(wxEVT_CHAR
);
1412 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1419 //-----------------------------------------------------------------------------
1420 // "key_release_event" from any window
1421 //-----------------------------------------------------------------------------
1423 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1424 GdkEventKey
*gdk_event
,
1430 wxapp_install_idle_handler();
1435 if (g_blockEventsOnDrag
)
1438 wxKeyEvent
event( wxEVT_KEY_UP
);
1439 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1441 // unknown key pressed, ignore (the event would be useless anyhow
1445 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1448 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1452 // ============================================================================
1454 // ============================================================================
1456 // ----------------------------------------------------------------------------
1457 // mouse event processing helpers
1458 // ----------------------------------------------------------------------------
1460 // init wxMouseEvent with the info from GdkEventXXX struct
1461 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1462 wxMouseEvent
& event
,
1465 event
.SetTimestamp( gdk_event
->time
);
1466 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1467 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1468 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1469 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1470 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1471 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1472 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1473 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1475 event
.m_linesPerAction
= 3;
1476 event
.m_wheelDelta
= 120;
1477 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1478 event
.m_wheelRotation
= 120;
1479 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1480 event
.m_wheelRotation
= -120;
1483 wxPoint pt
= win
->GetClientAreaOrigin();
1484 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1485 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1487 event
.SetEventObject( win
);
1488 event
.SetId( win
->GetId() );
1489 event
.SetTimestamp( gdk_event
->time
);
1492 static void AdjustEventButtonState(wxMouseEvent
& event
)
1494 // GDK reports the old state of the button for a button press event, but
1495 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1496 // for a LEFT_DOWN event, not FALSE, so we will invert
1497 // left/right/middleDown for the corresponding click events
1499 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1500 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1501 (event
.GetEventType() == wxEVT_LEFT_UP
))
1503 event
.m_leftDown
= !event
.m_leftDown
;
1507 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1508 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1509 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1511 event
.m_middleDown
= !event
.m_middleDown
;
1515 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1516 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1517 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1519 event
.m_rightDown
= !event
.m_rightDown
;
1524 // find the window to send the mouse event too
1526 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1531 if (win
->m_wxwindow
)
1533 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1534 xx
+= pizza
->xoffset
;
1535 yy
+= pizza
->yoffset
;
1538 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1541 wxWindowGTK
*child
= node
->GetData();
1543 node
= node
->GetNext();
1544 if (!child
->IsShown())
1547 if (child
->IsTransparentForMouse())
1549 // wxStaticBox is transparent in the box itself
1550 int xx1
= child
->m_x
;
1551 int yy1
= child
->m_y
;
1552 int xx2
= child
->m_x
+ child
->m_width
;
1553 int yy2
= child
->m_y
+ child
->m_height
;
1556 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1558 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1560 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1562 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1573 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1574 (child
->m_x
<= xx
) &&
1575 (child
->m_y
<= yy
) &&
1576 (child
->m_x
+child
->m_width
>= xx
) &&
1577 (child
->m_y
+child
->m_height
>= yy
))
1590 //-----------------------------------------------------------------------------
1591 // "button_press_event"
1592 //-----------------------------------------------------------------------------
1594 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1595 GdkEventButton
*gdk_event
,
1601 wxapp_install_idle_handler();
1604 wxPrintf( wxT("1) OnButtonPress from ") );
1605 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1606 wxPrintf( win->GetClassInfo()->GetClassName() );
1607 wxPrintf( wxT(".\n") );
1609 if (!win
->m_hasVMT
) return FALSE
;
1610 if (g_blockEventsOnDrag
) return TRUE
;
1611 if (g_blockEventsOnScroll
) return TRUE
;
1613 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1615 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1617 gtk_widget_grab_focus( win
->m_wxwindow
);
1619 wxPrintf( wxT("GrabFocus from ") );
1620 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1621 wxPrintf( win->GetClassInfo()->GetClassName() );
1622 wxPrintf( wxT(".\n") );
1626 // GDK sends surplus button down event
1627 // before a double click event. We
1628 // need to filter these out.
1629 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1631 GdkEvent
*peek_event
= gdk_event_peek();
1634 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1635 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1637 gdk_event_free( peek_event
);
1642 gdk_event_free( peek_event
);
1647 wxEventType event_type
= wxEVT_NULL
;
1649 // GdkDisplay is a GTK+ 2.2.0 thing
1650 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1651 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1652 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1654 // Reset GDK internal timestamp variables in order to disable GDK
1655 // triple click events. GDK will then next time believe no button has
1656 // been clicked just before, and send a normal button click event.
1657 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1658 display
->button_click_time
[1] = 0;
1659 display
->button_click_time
[0] = 0;
1663 if (gdk_event
->button
== 1)
1665 // note that GDK generates triple click events which are not supported
1666 // by wxWidgets but still have to be passed to the app as otherwise
1667 // clicks would simply go missing
1668 switch (gdk_event
->type
)
1670 // we shouldn't get triple clicks at all for GTK2 because we
1671 // suppress them artificially using the code above but we still
1672 // should map them to something for GTK1 and not just ignore them
1673 // as this would lose clicks
1674 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1675 case GDK_BUTTON_PRESS
:
1676 event_type
= wxEVT_LEFT_DOWN
;
1679 case GDK_2BUTTON_PRESS
:
1680 event_type
= wxEVT_LEFT_DCLICK
;
1684 // just to silence gcc warnings
1688 else if (gdk_event
->button
== 2)
1690 switch (gdk_event
->type
)
1692 case GDK_3BUTTON_PRESS
:
1693 case GDK_BUTTON_PRESS
:
1694 event_type
= wxEVT_MIDDLE_DOWN
;
1697 case GDK_2BUTTON_PRESS
:
1698 event_type
= wxEVT_MIDDLE_DCLICK
;
1705 else if (gdk_event
->button
== 3)
1707 switch (gdk_event
->type
)
1709 case GDK_3BUTTON_PRESS
:
1710 case GDK_BUTTON_PRESS
:
1711 event_type
= wxEVT_RIGHT_DOWN
;
1714 case GDK_2BUTTON_PRESS
:
1715 event_type
= wxEVT_RIGHT_DCLICK
;
1722 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1724 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1726 event_type
= wxEVT_MOUSEWHEEL
;
1730 if ( event_type
== wxEVT_NULL
)
1732 // unknown mouse button or click type
1736 wxMouseEvent
event( event_type
);
1737 InitMouseEvent( win
, event
, gdk_event
);
1739 AdjustEventButtonState(event
);
1741 // wxListBox actually get mouse events from the item, so we need to give it
1742 // a chance to correct this
1743 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1745 // find the correct window to send the event too: it may be a different one
1746 // from the one which got it at GTK+ level because some control don't have
1747 // their own X window and thus cannot get any events.
1748 if ( !g_captureWindow
)
1749 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1751 gs_timeLastClick
= gdk_event
->time
;
1754 if (event_type
== wxEVT_LEFT_DCLICK
)
1756 // GTK 1.2 crashes when intercepting double
1757 // click events from both wxSpinButton and
1759 if (GTK_IS_SPIN_BUTTON(win
->m_widget
))
1761 // Just disable this event for now.
1767 if (win
->GetEventHandler()->ProcessEvent( event
))
1769 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1773 if (event_type
== wxEVT_RIGHT_DOWN
)
1775 // generate a "context menu" event: this is similar to right mouse
1776 // click under many GUIs except that it is generated differently
1777 // (right up under MSW, ctrl-click under Mac, right down here) and
1779 // (a) it's a command event and so is propagated to the parent
1780 // (b) under some ports it can be generated from kbd too
1781 // (c) it uses screen coords (because of (a))
1782 wxContextMenuEvent
evtCtx(
1785 win
->ClientToScreen(event
.GetPosition()));
1786 evtCtx
.SetEventObject(win
);
1787 return win
->GetEventHandler()->ProcessEvent(evtCtx
);
1793 //-----------------------------------------------------------------------------
1794 // "button_release_event"
1795 //-----------------------------------------------------------------------------
1797 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1798 GdkEventButton
*gdk_event
,
1804 wxapp_install_idle_handler();
1806 if (!win
->m_hasVMT
) return FALSE
;
1807 if (g_blockEventsOnDrag
) return FALSE
;
1808 if (g_blockEventsOnScroll
) return FALSE
;
1810 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1812 wxEventType event_type
= wxEVT_NULL
;
1814 switch (gdk_event
->button
)
1817 event_type
= wxEVT_LEFT_UP
;
1821 event_type
= wxEVT_MIDDLE_UP
;
1825 event_type
= wxEVT_RIGHT_UP
;
1829 // unknwon button, don't process
1833 wxMouseEvent
event( event_type
);
1834 InitMouseEvent( win
, event
, gdk_event
);
1836 AdjustEventButtonState(event
);
1838 // same wxListBox hack as above
1839 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1841 if ( !g_captureWindow
)
1842 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1844 if (win
->GetEventHandler()->ProcessEvent( event
))
1846 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1853 //-----------------------------------------------------------------------------
1854 // "motion_notify_event"
1855 //-----------------------------------------------------------------------------
1857 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1858 GdkEventMotion
*gdk_event
,
1864 wxapp_install_idle_handler();
1866 if (!win
->m_hasVMT
) return FALSE
;
1867 if (g_blockEventsOnDrag
) return FALSE
;
1868 if (g_blockEventsOnScroll
) return FALSE
;
1870 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1872 if (gdk_event
->is_hint
)
1876 GdkModifierType state
;
1877 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1883 printf( "OnMotion from " );
1884 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1885 printf( win->GetClassInfo()->GetClassName() );
1889 wxMouseEvent
event( wxEVT_MOTION
);
1890 InitMouseEvent(win
, event
, gdk_event
);
1892 if ( g_captureWindow
)
1894 // synthetize a mouse enter or leave event if needed
1895 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1896 // This seems to be necessary and actually been added to
1897 // GDK itself in version 2.0.X
1900 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1901 if ( hasMouse
!= g_captureWindowHasMouse
)
1903 // the mouse changed window
1904 g_captureWindowHasMouse
= hasMouse
;
1906 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1907 : wxEVT_LEAVE_WINDOW
);
1908 InitMouseEvent(win
, event
, gdk_event
);
1909 event
.SetEventObject(win
);
1910 win
->GetEventHandler()->ProcessEvent(event
);
1915 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1918 if (win
->GetEventHandler()->ProcessEvent( event
))
1920 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1928 //-----------------------------------------------------------------------------
1929 // "mouse_wheel_event"
1930 //-----------------------------------------------------------------------------
1932 static gint
gtk_window_wheel_callback (GtkWidget
* widget
,
1933 GdkEventScroll
* gdk_event
,
1939 wxapp_install_idle_handler();
1941 wxEventType event_type
= wxEVT_NULL
;
1942 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1943 event_type
= wxEVT_MOUSEWHEEL
;
1944 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1945 event_type
= wxEVT_MOUSEWHEEL
;
1949 wxMouseEvent
event( event_type
);
1950 // Can't use InitMouse macro because scroll events don't have button
1951 event
.SetTimestamp( gdk_event
->time
);
1952 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1953 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1954 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1955 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1956 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1957 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1958 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1959 event
.m_linesPerAction
= 3;
1960 event
.m_wheelDelta
= 120;
1961 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1962 event
.m_wheelRotation
= 120;
1964 event
.m_wheelRotation
= -120;
1966 wxPoint pt
= win
->GetClientAreaOrigin();
1967 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1968 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1970 event
.SetEventObject( win
);
1971 event
.SetId( win
->GetId() );
1972 event
.SetTimestamp( gdk_event
->time
);
1974 if (win
->GetEventHandler()->ProcessEvent( event
))
1976 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "scroll_event" );
1983 //-----------------------------------------------------------------------------
1985 //-----------------------------------------------------------------------------
1986 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1988 wxContextMenuEvent
event(
1992 event
.SetEventObject(win
);
1993 return win
->GetEventHandler()->ProcessEvent(event
);
1995 #endif // __WXGTK20__
1997 //-----------------------------------------------------------------------------
1999 //-----------------------------------------------------------------------------
2001 // send the wxChildFocusEvent and wxFocusEvent, common code of
2002 // gtk_window_focus_in_callback() and SetFocus()
2003 static bool DoSendFocusEvents(wxWindow
*win
)
2005 // Notify the parent keeping track of focus for the kbd navigation
2006 // purposes that we got it.
2007 wxChildFocusEvent
eventChildFocus(win
);
2008 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
2010 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
2011 eventFocus
.SetEventObject(win
);
2013 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
2016 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
2017 GdkEvent
*WXUNUSED(event
),
2023 wxapp_install_idle_handler();
2027 gtk_im_context_focus_in(win
->m_imData
->context
);
2031 g_focusWindow
= win
;
2033 wxLogTrace(TRACE_FOCUS
,
2034 _T("%s: focus in"), win
->GetName().c_str());
2038 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
2042 // caret needs to be informed about focus change
2043 wxCaret
*caret
= win
->GetCaret();
2046 caret
->OnSetFocus();
2048 #endif // wxUSE_CARET
2050 // does the window itself think that it has the focus?
2051 if ( !win
->m_hasFocus
)
2053 // not yet, notify it
2054 win
->m_hasFocus
= TRUE
;
2056 if ( DoSendFocusEvents(win
) )
2058 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
2066 //-----------------------------------------------------------------------------
2067 // "focus_out_event"
2068 //-----------------------------------------------------------------------------
2070 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
2075 wxapp_install_idle_handler();
2079 gtk_im_context_focus_out(win
->m_imData
->context
);
2082 wxLogTrace( TRACE_FOCUS
,
2083 _T("%s: focus out"), win
->GetName().c_str() );
2086 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
2090 g_focusWindow
= (wxWindowGTK
*)NULL
;
2098 // caret needs to be informed about focus change
2099 wxCaret
*caret
= win
->GetCaret();
2102 caret
->OnKillFocus();
2104 #endif // wxUSE_CARET
2106 // don't send the window a kill focus event if it thinks that it doesn't
2107 // have focus already
2108 if ( win
->m_hasFocus
)
2110 win
->m_hasFocus
= FALSE
;
2112 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
2113 event
.SetEventObject( win
);
2115 // even if we did process the event in wx code, still let GTK itself
2116 // process it too as otherwise bad things happen, especially in GTK2
2117 // where the text control simply aborts the program if it doesn't get
2118 // the matching focus out event
2119 (void)win
->GetEventHandler()->ProcessEvent( event
);
2125 //-----------------------------------------------------------------------------
2126 // "enter_notify_event"
2127 //-----------------------------------------------------------------------------
2130 gint
gtk_window_enter_callback( GtkWidget
*widget
,
2131 GdkEventCrossing
*gdk_event
,
2137 wxapp_install_idle_handler();
2139 if (!win
->m_hasVMT
) return FALSE
;
2140 if (g_blockEventsOnDrag
) return FALSE
;
2142 // Event was emitted after a grab
2143 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2145 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2149 GdkModifierType state
= (GdkModifierType
)0;
2151 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2153 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2154 InitMouseEvent(win
, event
, gdk_event
);
2155 wxPoint pt
= win
->GetClientAreaOrigin();
2156 event
.m_x
= x
+ pt
.x
;
2157 event
.m_y
= y
+ pt
.y
;
2159 if (win
->GetEventHandler()->ProcessEvent( event
))
2161 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
2168 //-----------------------------------------------------------------------------
2169 // "leave_notify_event"
2170 //-----------------------------------------------------------------------------
2172 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
2177 wxapp_install_idle_handler();
2179 if (!win
->m_hasVMT
) return FALSE
;
2180 if (g_blockEventsOnDrag
) return FALSE
;
2182 // Event was emitted after an ungrab
2183 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2185 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2187 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2188 event
.SetTimestamp( gdk_event
->time
);
2189 event
.SetEventObject( win
);
2193 GdkModifierType state
= (GdkModifierType
)0;
2195 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2197 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2198 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2199 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2200 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2201 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2202 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2203 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2205 wxPoint pt
= win
->GetClientAreaOrigin();
2206 event
.m_x
= x
+ pt
.x
;
2207 event
.m_y
= y
+ pt
.y
;
2209 if (win
->GetEventHandler()->ProcessEvent( event
))
2211 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
2218 //-----------------------------------------------------------------------------
2219 // "value_changed" from m_vAdjust
2220 //-----------------------------------------------------------------------------
2222 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2229 wxapp_install_idle_handler();
2231 if (g_blockEventsOnDrag
) return;
2233 if (!win
->m_hasVMT
) return;
2235 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2236 if (fabs(diff
) < 0.2) return;
2238 win
->m_oldVerticalPos
= adjust
->value
;
2241 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2243 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
2245 int value
= (int)(adjust
->value
+0.5);
2247 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2248 event
.SetEventObject( win
);
2249 win
->GetEventHandler()->ProcessEvent( event
);
2252 //-----------------------------------------------------------------------------
2253 // "value_changed" from m_hAdjust
2254 //-----------------------------------------------------------------------------
2256 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2263 wxapp_install_idle_handler();
2265 if (g_blockEventsOnDrag
) return;
2266 if (!win
->m_hasVMT
) return;
2268 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2269 if (fabs(diff
) < 0.2) return;
2272 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2274 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
2276 win
->m_oldHorizontalPos
= adjust
->value
;
2278 int value
= (int)(adjust
->value
+0.5);
2280 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2281 event
.SetEventObject( win
);
2282 win
->GetEventHandler()->ProcessEvent( event
);
2285 //-----------------------------------------------------------------------------
2286 // "button_press_event" from scrollbar
2287 //-----------------------------------------------------------------------------
2289 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2290 GdkEventButton
*gdk_event
,
2296 wxapp_install_idle_handler();
2299 g_blockEventsOnScroll
= TRUE
;
2301 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2303 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2309 //-----------------------------------------------------------------------------
2310 // "button_release_event" from scrollbar
2311 //-----------------------------------------------------------------------------
2313 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2314 GdkEventButton
*WXUNUSED(gdk_event
),
2319 // don't test here as we can release the mouse while being over
2320 // a different window than the slider
2322 // if (gdk_event->window != widget->slider) return FALSE;
2324 g_blockEventsOnScroll
= FALSE
;
2326 if (win
->m_isScrolling
)
2328 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2332 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2333 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2335 value
= (int)(win
->m_hAdjust
->value
+0.5);
2338 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2340 value
= (int)(win
->m_vAdjust
->value
+0.5);
2344 wxScrollWinEvent
event( command
, value
, dir
);
2345 event
.SetEventObject( win
);
2346 win
->GetEventHandler()->ProcessEvent( event
);
2349 win
->m_isScrolling
= FALSE
;
2354 // ----------------------------------------------------------------------------
2355 // this wxWindowBase function is implemented here (in platform-specific file)
2356 // because it is static and so couldn't be made virtual
2357 // ----------------------------------------------------------------------------
2359 wxWindow
*wxWindowBase::DoFindFocus()
2361 // the cast is necessary when we compile in wxUniversal mode
2362 return (wxWindow
*)g_focusWindow
;
2366 //-----------------------------------------------------------------------------
2367 // "realize" from m_widget
2368 //-----------------------------------------------------------------------------
2370 /* We cannot set colours and fonts before the widget has
2371 been realized, so we do this directly after realization. */
2374 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2379 wxapp_install_idle_handler();
2384 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2385 gtk_im_context_set_client_window( win
->m_imData
->context
,
2386 pizza
->bin_window
);
2390 wxWindowCreateEvent
event( win
);
2391 event
.SetEventObject( win
);
2392 win
->GetEventHandler()->ProcessEvent( event
);
2397 //-----------------------------------------------------------------------------
2399 //-----------------------------------------------------------------------------
2402 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2403 GtkAllocation
*WXUNUSED(alloc
),
2407 wxapp_install_idle_handler();
2409 if (!win
->m_hasScrolling
) return;
2411 int client_width
= 0;
2412 int client_height
= 0;
2413 win
->GetClientSize( &client_width
, &client_height
);
2414 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2417 win
->m_oldClientWidth
= client_width
;
2418 win
->m_oldClientHeight
= client_height
;
2420 if (!win
->m_nativeSizeEvent
)
2422 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2423 event
.SetEventObject( win
);
2424 win
->GetEventHandler()->ProcessEvent( event
);
2430 #define WXUNUSED_UNLESS_XIM(param) param
2432 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2435 /* Resize XIM window */
2438 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2439 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2440 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2443 wxapp_install_idle_handler();
2449 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2453 gdk_window_get_size (widget
->window
, &width
, &height
);
2454 win
->m_icattr
->preedit_area
.width
= width
;
2455 win
->m_icattr
->preedit_area
.height
= height
;
2456 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2461 //-----------------------------------------------------------------------------
2462 // "realize" from m_wxwindow
2463 //-----------------------------------------------------------------------------
2465 /* Initialize XIM support */
2468 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2469 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2472 wxapp_install_idle_handler();
2475 if (win
->m_ic
) return FALSE
;
2476 if (!widget
) return FALSE
;
2477 if (!gdk_im_ready()) return FALSE
;
2479 win
->m_icattr
= gdk_ic_attr_new();
2480 if (!win
->m_icattr
) return FALSE
;
2484 GdkColormap
*colormap
;
2485 GdkICAttr
*attr
= win
->m_icattr
;
2486 unsigned attrmask
= GDK_IC_ALL_REQ
;
2488 GdkIMStyle supported_style
= (GdkIMStyle
)
2489 (GDK_IM_PREEDIT_NONE
|
2490 GDK_IM_PREEDIT_NOTHING
|
2491 GDK_IM_PREEDIT_POSITION
|
2492 GDK_IM_STATUS_NONE
|
2493 GDK_IM_STATUS_NOTHING
);
2495 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2496 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2498 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2499 attr
->client_window
= widget
->window
;
2501 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2502 gtk_widget_get_default_colormap ())
2504 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2505 attr
->preedit_colormap
= colormap
;
2508 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2509 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2510 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2511 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2513 switch (style
& GDK_IM_PREEDIT_MASK
)
2515 case GDK_IM_PREEDIT_POSITION
:
2516 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2518 g_warning ("over-the-spot style requires fontset");
2522 gdk_window_get_size (widget
->window
, &width
, &height
);
2524 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2525 attr
->spot_location
.x
= 0;
2526 attr
->spot_location
.y
= height
;
2527 attr
->preedit_area
.x
= 0;
2528 attr
->preedit_area
.y
= 0;
2529 attr
->preedit_area
.width
= width
;
2530 attr
->preedit_area
.height
= height
;
2531 attr
->preedit_fontset
= widget
->style
->font
;
2536 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2538 if (win
->m_ic
== NULL
)
2539 g_warning ("Can't create input context.");
2542 mask
= gdk_window_get_events (widget
->window
);
2543 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2544 gdk_window_set_events (widget
->window
, mask
);
2546 if (GTK_WIDGET_HAS_FOCUS(widget
))
2547 gdk_im_begin (win
->m_ic
, widget
->window
);
2554 //-----------------------------------------------------------------------------
2555 // InsertChild for wxWindowGTK.
2556 //-----------------------------------------------------------------------------
2558 /* Callback for wxWindowGTK. This very strange beast has to be used because
2559 * C++ has no virtual methods in a constructor. We have to emulate a
2560 * virtual function here as wxNotebook requires a different way to insert
2561 * a child in it. I had opted for creating a wxNotebookPage window class
2562 * which would have made this superfluous (such in the MDI window system),
2563 * but no-one was listening to me... */
2565 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2567 /* the window might have been scrolled already, do we
2568 have to adapt the position */
2569 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2570 child
->m_x
+= pizza
->xoffset
;
2571 child
->m_y
+= pizza
->yoffset
;
2573 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2574 GTK_WIDGET(child
->m_widget
),
2581 //-----------------------------------------------------------------------------
2583 //-----------------------------------------------------------------------------
2585 wxWindow
*wxGetActiveWindow()
2587 return wxWindow::FindFocus();
2590 //-----------------------------------------------------------------------------
2592 //-----------------------------------------------------------------------------
2594 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2596 #ifdef __WXUNIVERSAL__
2597 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2599 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2600 #endif // __WXUNIVERSAL__/__WXGTK__
2602 void wxWindowGTK::Init()
2605 m_widget
= (GtkWidget
*) NULL
;
2606 m_wxwindow
= (GtkWidget
*) NULL
;
2607 m_focusWidget
= (GtkWidget
*) NULL
;
2617 m_needParent
= TRUE
;
2618 m_isBeingDeleted
= FALSE
;
2621 m_nativeSizeEvent
= FALSE
;
2623 m_hasScrolling
= FALSE
;
2624 m_isScrolling
= FALSE
;
2626 m_hAdjust
= (GtkAdjustment
*) NULL
;
2627 m_vAdjust
= (GtkAdjustment
*) NULL
;
2628 m_oldHorizontalPos
=
2629 m_oldVerticalPos
= 0.0;
2631 m_oldClientHeight
= 0;
2635 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2637 m_acceptsFocus
= FALSE
;
2640 m_clipPaintRegion
= FALSE
;
2642 m_needsStyleChange
= false;
2644 m_cursor
= *wxSTANDARD_CURSOR
;
2648 m_x11Context
= NULL
;
2649 m_dirtyTabOrder
= false;
2652 m_ic
= (GdkIC
*) NULL
;
2653 m_icattr
= (GdkICAttr
*) NULL
;
2658 wxWindowGTK::wxWindowGTK()
2663 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2668 const wxString
&name
)
2672 Create( parent
, id
, pos
, size
, style
, name
);
2675 bool wxWindowGTK::Create( wxWindow
*parent
,
2680 const wxString
&name
)
2682 if (!PreCreation( parent
, pos
, size
) ||
2683 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2685 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2689 m_insertCallback
= wxInsertChildInWindow
;
2691 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2692 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2694 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2696 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2697 scroll_class
->scrollbar_spacing
= 0;
2699 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2701 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2702 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2704 m_wxwindow
= gtk_pizza_new();
2706 #ifndef __WXUNIVERSAL__
2707 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2709 if (HasFlag(wxRAISED_BORDER
))
2711 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2713 else if (HasFlag(wxSUNKEN_BORDER
))
2715 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2717 else if (HasFlag(wxSIMPLE_BORDER
))
2719 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2723 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2725 #endif // __WXUNIVERSAL__
2727 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2729 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2730 m_acceptsFocus
= TRUE
;
2732 // I _really_ don't want scrollbars in the beginning
2733 m_vAdjust
->lower
= 0.0;
2734 m_vAdjust
->upper
= 1.0;
2735 m_vAdjust
->value
= 0.0;
2736 m_vAdjust
->step_increment
= 1.0;
2737 m_vAdjust
->page_increment
= 1.0;
2738 m_vAdjust
->page_size
= 5.0;
2739 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2740 m_hAdjust
->lower
= 0.0;
2741 m_hAdjust
->upper
= 1.0;
2742 m_hAdjust
->value
= 0.0;
2743 m_hAdjust
->step_increment
= 1.0;
2744 m_hAdjust
->page_increment
= 1.0;
2745 m_hAdjust
->page_size
= 5.0;
2746 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2748 // these handlers block mouse events to any window during scrolling such as
2749 // motion events and prevent GTK and wxWidgets from fighting over where the
2752 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2753 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2755 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2756 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2758 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2759 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2761 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2762 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2764 // these handlers get notified when screen updates are required either when
2765 // scrolling or when the window size (and therefore scrollbar configuration)
2768 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2769 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2770 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2771 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2773 gtk_widget_show( m_wxwindow
);
2776 m_parent
->DoAddChild( this );
2778 m_focusWidget
= m_wxwindow
;
2785 wxWindowGTK::~wxWindowGTK()
2789 if (g_focusWindow
== this)
2790 g_focusWindow
= NULL
;
2792 if ( g_delayedFocus
== this )
2793 g_delayedFocus
= NULL
;
2795 m_isBeingDeleted
= TRUE
;
2805 gdk_ic_destroy (m_ic
);
2807 gdk_ic_attr_destroy (m_icattr
);
2812 gtk_widget_destroy( m_wxwindow
);
2813 m_wxwindow
= (GtkWidget
*) NULL
;
2818 gtk_widget_destroy( m_widget
);
2819 m_widget
= (GtkWidget
*) NULL
;
2827 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2829 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2831 // Use either the given size, or the default if -1 is given.
2832 // See wxWindowBase for these functions.
2833 m_width
= WidthDefault(size
.x
) ;
2834 m_height
= HeightDefault(size
.y
);
2842 void wxWindowGTK::PostCreation()
2844 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2850 // these get reported to wxWidgets -> wxPaintEvent
2852 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2854 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2855 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2858 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2859 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2861 if (!HasFlag(wxFULL_REPAINT_ON_RESIZE
))
2863 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2864 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2867 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2872 // Create input method handler
2873 m_imData
= new wxGtkIMData
;
2875 // Cannot handle drawing preedited text yet
2876 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2878 g_signal_connect (G_OBJECT (m_imData
->context
), "commit",
2879 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2882 // these are called when the "sunken" or "raised" borders are drawn
2883 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2884 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2887 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2888 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2894 if (!GTK_IS_WINDOW(m_widget
))
2896 if (m_focusWidget
== NULL
)
2897 m_focusWidget
= m_widget
;
2899 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2900 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2902 gtk_signal_connect_after( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2903 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2906 // connect to the various key and mouse handlers
2908 GtkWidget
*connect_widget
= GetConnectWidget();
2910 ConnectWidget( connect_widget
);
2912 /* We cannot set colours, fonts and cursors before the widget has
2913 been realized, so we do this directly after realization */
2914 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2915 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2919 // Catch native resize events
2920 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2921 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2923 // Initialize XIM support
2924 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2925 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2927 // And resize XIM window
2928 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2929 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2932 if ( !GTK_IS_COMBO(m_widget
))
2934 // This is needed if we want to add our windows into native
2935 // GTK control, such as the toolbar. With this callback, the
2936 // toolbar gets to know the correct size (the one set by the
2937 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2938 // when moving to GTK 2.0.
2939 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2940 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback
),
2944 InheritAttributes();
2948 // unless the window was created initially hidden (i.e. Hide() had been
2949 // called before Create()), we should show it at GTK+ level as well
2951 gtk_widget_show( m_widget
);
2954 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2956 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2957 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2959 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2960 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2962 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2963 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2965 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2966 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2968 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2969 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2972 gtk_signal_connect( GTK_OBJECT(widget
), "scroll_event",
2973 GTK_SIGNAL_FUNC(gtk_window_wheel_callback
), (gpointer
)this );
2974 g_signal_connect(widget
, "popup_menu",
2975 G_CALLBACK(wxgtk_window_popup_menu_callback
), this);
2978 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2979 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2981 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2982 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2985 bool wxWindowGTK::Destroy()
2987 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2991 return wxWindowBase::Destroy();
2994 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2996 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2999 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
3001 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3002 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
3005 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
3008 if (m_resizing
) return; /* I don't like recursions */
3011 int currentX
, currentY
;
3012 GetPosition(¤tX
, ¤tY
);
3013 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
3015 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
3017 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
3019 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
3021 /* don't set the size for children of wxNotebook, just take the values. */
3029 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3030 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
3032 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
3033 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
3037 m_x
= x
+ pizza
->xoffset
;
3038 m_y
= y
+ pizza
->yoffset
;
3041 // calculate the best size if we should auto size the window
3042 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
3043 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
3045 const wxSize sizeBest
= GetBestSize();
3046 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
3048 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
3049 height
= sizeBest
.y
;
3057 int minWidth
= GetMinWidth(),
3058 minHeight
= GetMinHeight(),
3059 maxWidth
= GetMaxWidth(),
3060 maxHeight
= GetMaxHeight();
3062 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
3063 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
3064 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
3065 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
3068 int bottom_border
= 0;
3071 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
3073 /* the default button has a border around it */
3079 DoMoveWindow( m_x
-border
,
3082 m_height
+border
+bottom_border
);
3087 /* Sometimes the client area changes size without the
3088 whole windows's size changing, but if the whole
3089 windows's size doesn't change, no wxSizeEvent will
3090 normally be sent. Here we add an extra test if
3091 the client test has been changed and this will
3093 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
3097 wxPrintf( "OnSize sent from " );
3098 if (GetClassInfo() && GetClassInfo()->GetClassName())
3099 wxPrintf( GetClassInfo()->GetClassName() );
3100 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3103 if (!m_nativeSizeEvent
)
3105 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
3106 event
.SetEventObject( this );
3107 GetEventHandler()->ProcessEvent( event
);
3113 void wxWindowGTK::OnInternalIdle()
3116 if ( m_dirtyTabOrder
)
3119 // Update style if the window was not yet realized
3120 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
3121 if (m_needsStyleChange
)
3123 SetBackgroundStyle(GetBackgroundStyle());
3124 m_needsStyleChange
= false;
3127 // Update invalidated regions.
3130 wxCursor cursor
= m_cursor
;
3131 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3135 /* I now set the cursor anew in every OnInternalIdle call
3136 as setting the cursor in a parent window also effects the
3137 windows above so that checking for the current cursor is
3142 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3144 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3146 if (!g_globalCursor
.Ok())
3147 cursor
= *wxSTANDARD_CURSOR
;
3149 window
= m_widget
->window
;
3150 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3151 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3157 GdkWindow
*window
= m_widget
->window
;
3158 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3159 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3164 if (wxUpdateUIEvent::CanUpdate(this))
3165 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3168 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3170 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3172 if (width
) (*width
) = m_width
;
3173 if (height
) (*height
) = m_height
;
3176 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3178 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3182 SetSize( width
, height
);
3189 #ifndef __WXUNIVERSAL__
3190 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3192 /* when using GTK 1.2 we set the shadow border size to 2 */
3196 if (HasFlag(wxSIMPLE_BORDER
))
3198 /* when using GTK 1.2 we set the simple border size to 1 */
3202 #endif // __WXUNIVERSAL__
3206 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3208 GtkRequisition vscroll_req
;
3209 vscroll_req
.width
= 2;
3210 vscroll_req
.height
= 2;
3211 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3212 (scroll_window
->vscrollbar
, &vscroll_req
);
3214 GtkRequisition hscroll_req
;
3215 hscroll_req
.width
= 2;
3216 hscroll_req
.height
= 2;
3217 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3218 (scroll_window
->hscrollbar
, &hscroll_req
);
3220 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3222 if (scroll_window
->vscrollbar_visible
)
3224 dw
+= vscroll_req
.width
;
3225 dw
+= scroll_class
->scrollbar_spacing
;
3228 if (scroll_window
->hscrollbar_visible
)
3230 dh
+= hscroll_req
.height
;
3231 dh
+= scroll_class
->scrollbar_spacing
;
3235 SetSize( width
+dw
, height
+dh
);
3239 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3241 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3245 if (width
) (*width
) = m_width
;
3246 if (height
) (*height
) = m_height
;
3253 #ifndef __WXUNIVERSAL__
3254 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3256 /* when using GTK 1.2 we set the shadow border size to 2 */
3260 if (HasFlag(wxSIMPLE_BORDER
))
3262 /* when using GTK 1.2 we set the simple border size to 1 */
3266 #endif // __WXUNIVERSAL__
3270 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3272 GtkRequisition vscroll_req
;
3273 vscroll_req
.width
= 2;
3274 vscroll_req
.height
= 2;
3275 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3276 (scroll_window
->vscrollbar
, &vscroll_req
);
3278 GtkRequisition hscroll_req
;
3279 hscroll_req
.width
= 2;
3280 hscroll_req
.height
= 2;
3281 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3282 (scroll_window
->hscrollbar
, &hscroll_req
);
3284 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3286 if (scroll_window
->vscrollbar_visible
)
3288 dw
+= vscroll_req
.width
;
3289 dw
+= scroll_class
->scrollbar_spacing
;
3292 if (scroll_window
->hscrollbar_visible
)
3294 dh
+= hscroll_req
.height
;
3295 dh
+= scroll_class
->scrollbar_spacing
;
3299 if (width
) (*width
) = m_width
- dw
;
3300 if (height
) (*height
) = m_height
- dh
;
3304 printf( "GetClientSize, name %s ", GetName().c_str() );
3305 if (width) printf( " width = %d", (*width) );
3306 if (height) printf( " height = %d", (*height) );
3311 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3313 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3317 if (m_parent
&& m_parent
->m_wxwindow
)
3319 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3320 dx
= pizza
->xoffset
;
3321 dy
= pizza
->yoffset
;
3324 if (x
) (*x
) = m_x
- dx
;
3325 if (y
) (*y
) = m_y
- dy
;
3328 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3330 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3332 if (!m_widget
->window
) return;
3334 GdkWindow
*source
= (GdkWindow
*) NULL
;
3336 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3338 source
= m_widget
->window
;
3342 gdk_window_get_origin( source
, &org_x
, &org_y
);
3346 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3348 org_x
+= m_widget
->allocation
.x
;
3349 org_y
+= m_widget
->allocation
.y
;
3357 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3359 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3361 if (!m_widget
->window
) return;
3363 GdkWindow
*source
= (GdkWindow
*) NULL
;
3365 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3367 source
= m_widget
->window
;
3371 gdk_window_get_origin( source
, &org_x
, &org_y
);
3375 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3377 org_x
+= m_widget
->allocation
.x
;
3378 org_y
+= m_widget
->allocation
.y
;
3386 bool wxWindowGTK::Show( bool show
)
3388 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3390 if (!wxWindowBase::Show(show
))
3397 gtk_widget_show( m_widget
);
3399 gtk_widget_hide( m_widget
);
3401 wxShowEvent
eventShow(GetId(), show
);
3402 eventShow
.SetEventObject(this);
3404 GetEventHandler()->ProcessEvent(eventShow
);
3409 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3411 win
->OnParentEnable(enable
);
3413 // Recurse, so that children have the opportunity to Do The Right Thing
3414 // and reset colours that have been messed up by a parent's (really ancestor's)
3416 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3418 node
= node
->GetNext() )
3420 wxWindow
*child
= node
->GetData();
3421 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3422 wxWindowNotifyEnable(child
, enable
);
3426 bool wxWindowGTK::Enable( bool enable
)
3428 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3430 if (!wxWindowBase::Enable(enable
))
3436 gtk_widget_set_sensitive( m_widget
, enable
);
3438 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3440 wxWindowNotifyEnable(this, enable
);
3445 int wxWindowGTK::GetCharHeight() const
3447 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3449 wxFont font
= GetFont();
3450 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3453 PangoContext
*context
= NULL
;
3455 context
= gtk_widget_get_pango_context( m_widget
);
3460 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3461 PangoLayout
*layout
= pango_layout_new(context
);
3462 pango_layout_set_font_description(layout
, desc
);
3463 pango_layout_set_text(layout
, "H", 1);
3464 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3466 PangoRectangle rect
;
3467 pango_layout_line_get_extents(line
, NULL
, &rect
);
3469 g_object_unref( G_OBJECT( layout
) );
3471 return (int) PANGO_PIXELS(rect
.height
);
3473 GdkFont
*gfont
= font
.GetInternalFont( 1.0 );
3475 return gfont
->ascent
+ gfont
->descent
;
3479 int wxWindowGTK::GetCharWidth() const
3481 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3483 wxFont font
= GetFont();
3484 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3487 PangoContext
*context
= NULL
;
3489 context
= gtk_widget_get_pango_context( m_widget
);
3494 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3495 PangoLayout
*layout
= pango_layout_new(context
);
3496 pango_layout_set_font_description(layout
, desc
);
3497 pango_layout_set_text(layout
, "g", 1);
3498 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3500 PangoRectangle rect
;
3501 pango_layout_line_get_extents(line
, NULL
, &rect
);
3503 g_object_unref( G_OBJECT( layout
) );
3505 return (int) PANGO_PIXELS(rect
.width
);
3507 GdkFont
*gfont
= font
.GetInternalFont( 1.0 );
3509 return gdk_string_width( gfont
, "g" );
3513 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3517 int *externalLeading
,
3518 const wxFont
*theFont
) const
3520 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3522 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3524 if (string
.IsEmpty())
3532 PangoContext
*context
= NULL
;
3534 context
= gtk_widget_get_pango_context( m_widget
);
3543 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3544 PangoLayout
*layout
= pango_layout_new(context
);
3545 pango_layout_set_font_description(layout
, desc
);
3548 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3549 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3551 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3552 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3553 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3557 PangoRectangle rect
;
3558 pango_layout_get_extents(layout
, NULL
, &rect
);
3560 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3561 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3564 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3565 int baseline
= pango_layout_iter_get_baseline(iter
);
3566 pango_layout_iter_free(iter
);
3567 *descent
= *y
- PANGO_PIXELS(baseline
);
3569 if (externalLeading
) (*externalLeading
) = 0; // ??
3571 g_object_unref( G_OBJECT( layout
) );
3573 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3574 if (x
) (*x
) = gdk_string_width( font
, wxGTK_CONV( string
) );
3575 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3576 if (descent
) (*descent
) = font
->descent
;
3577 if (externalLeading
) (*externalLeading
) = 0; // ??
3581 void wxWindowGTK::SetFocus()
3583 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3586 // don't do anything if we already have focus
3592 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3594 gtk_widget_grab_focus (m_wxwindow
);
3600 if (GTK_IS_CONTAINER(m_widget
))
3602 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3606 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3609 if (!GTK_WIDGET_REALIZED(m_widget
))
3611 // we can't set the focus to the widget now so we remember that
3612 // it should be focused and will do it later, during the idle
3613 // time, as soon as we can
3614 wxLogTrace(TRACE_FOCUS
,
3615 _T("Delaying setting focus to %s(%s)"),
3616 GetClassInfo()->GetClassName(), GetLabel().c_str());
3618 g_delayedFocus
= this;
3622 wxLogTrace(TRACE_FOCUS
,
3623 _T("Setting focus to %s(%s)"),
3624 GetClassInfo()->GetClassName(), GetLabel().c_str());
3626 gtk_widget_grab_focus (m_widget
);
3631 if (GTK_IS_CONTAINER(m_widget
))
3633 gtk_container_focus( GTK_CONTAINER(m_widget
), GTK_DIR_TAB_FORWARD
);
3638 wxLogTrace(TRACE_FOCUS
,
3639 _T("Can't set focus to %s(%s)"),
3640 GetClassInfo()->GetClassName(), GetLabel().c_str());
3645 bool wxWindowGTK::AcceptsFocus() const
3647 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3650 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3652 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3654 wxWindowGTK
*oldParent
= m_parent
,
3655 *newParent
= (wxWindowGTK
*)newParentBase
;
3657 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3659 if ( !wxWindowBase::Reparent(newParent
) )
3662 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3664 /* prevent GTK from deleting the widget arbitrarily */
3665 gtk_widget_ref( m_widget
);
3669 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3672 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3676 /* insert GTK representation */
3677 (*(newParent
->m_insertCallback
))(newParent
, this);
3680 /* reverse: prevent GTK from deleting the widget arbitrarily */
3681 gtk_widget_unref( m_widget
);
3686 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3688 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3690 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3692 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3697 /* insert GTK representation */
3698 (*m_insertCallback
)(this, child
);
3703 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3705 wxWindowBase::AddChild(child
);
3706 m_dirtyTabOrder
= true;
3708 wxapp_install_idle_handler();
3711 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3713 wxWindowBase::RemoveChild(child
);
3714 m_dirtyTabOrder
= true;
3716 wxapp_install_idle_handler();
3719 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3721 wxWindowBase::DoMoveInTabOrder(win
, move
);
3722 m_dirtyTabOrder
= true;
3724 wxapp_install_idle_handler();
3727 void wxWindowGTK::RealizeTabOrder()
3731 if (m_children
.size() > 0)
3733 GList
*chain
= NULL
;
3735 for (wxWindowList::const_iterator i
= m_children
.begin();
3736 i
!= m_children
.end(); ++i
)
3738 chain
= g_list_prepend(chain
, (*i
)->m_widget
);
3741 chain
= g_list_reverse(chain
);
3743 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3748 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3752 m_dirtyTabOrder
= false;
3755 #endif // __WXGTK20__
3757 void wxWindowGTK::Raise()
3759 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3761 if (m_wxwindow
&& m_wxwindow
->window
)
3763 gdk_window_raise( m_wxwindow
->window
);
3765 else if (m_widget
->window
)
3767 gdk_window_raise( m_widget
->window
);
3771 void wxWindowGTK::Lower()
3773 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3775 if (m_wxwindow
&& m_wxwindow
->window
)
3777 gdk_window_lower( m_wxwindow
->window
);
3779 else if (m_widget
->window
)
3781 gdk_window_lower( m_widget
->window
);
3785 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3787 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3789 if (cursor
== m_cursor
)
3793 wxapp_install_idle_handler();
3795 if (cursor
== wxNullCursor
)
3796 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3798 return wxWindowBase::SetCursor( cursor
);
3801 void wxWindowGTK::WarpPointer( int x
, int y
)
3803 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3805 // We provide this function ourselves as it is
3806 // missing in GDK (top of this file).
3808 GdkWindow
*window
= (GdkWindow
*) NULL
;
3810 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3812 window
= GetConnectWidget()->window
;
3815 gdk_window_warp_pointer( window
, x
, y
);
3819 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3821 if (!m_widget
) return;
3822 if (!m_widget
->window
) return;
3826 wxapp_install_idle_handler();
3828 wxRect
myRect(0,0,0,0);
3829 if (m_wxwindow
&& rect
)
3831 myRect
.SetSize(wxSize( m_wxwindow
->allocation
.width
,
3832 m_wxwindow
->allocation
.height
));
3833 myRect
.Intersect(*rect
);
3834 if (!myRect
.width
|| !myRect
.height
)
3835 // nothing to do, rectangle is empty
3840 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3844 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3845 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3849 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3850 m_clearRegion
.Clear();
3851 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3859 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3860 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3864 GdkRectangle gdk_rect
;
3865 gdk_rect
.x
= rect
->x
;
3866 gdk_rect
.y
= rect
->y
;
3867 gdk_rect
.width
= rect
->width
;
3868 gdk_rect
.height
= rect
->height
;
3869 gtk_widget_draw( m_widget
, &gdk_rect
);
3876 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3877 m_updateRegion
.Clear();
3878 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3882 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3890 GdkRectangle gdk_rect
;
3891 gdk_rect
.x
= rect
->x
;
3892 gdk_rect
.y
= rect
->y
;
3893 gdk_rect
.width
= rect
->width
;
3894 gdk_rect
.height
= rect
->height
;
3895 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3899 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3905 void wxWindowGTK::Update()
3910 void wxWindowGTK::GtkUpdate()
3913 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3914 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3916 if (!m_updateRegion
.IsEmpty())
3917 GtkSendPaintEvents();
3921 void wxWindowGTK::GtkSendPaintEvents()
3926 m_clearRegion
.Clear();
3928 m_updateRegion
.Clear();
3932 // Clip to paint region in wxClientDC
3933 m_clipPaintRegion
= TRUE
;
3935 // widget to draw on
3936 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3938 if (GetThemeEnabled() && GetBackgroundStyle() == wxBG_STYLE_SYSTEM
)
3940 // find ancestor from which to steal background
3941 wxWindow
*parent
= GetParent();
3942 while (parent
&& !parent
->IsTopLevel())
3943 parent
= parent
->GetParent();
3945 parent
= (wxWindow
*)this;
3947 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3949 wxRegionIterator
upd( m_updateRegion
);
3953 rect
.x
= upd
.GetX();
3954 rect
.y
= upd
.GetY();
3955 rect
.width
= upd
.GetWidth();
3956 rect
.height
= upd
.GetHeight();
3958 gtk_paint_flat_box( parent
->m_widget
->style
,
3960 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3975 wxWindowDC
dc( (wxWindow
*)this );
3976 dc
.SetClippingRegion( m_updateRegion
);
3978 wxEraseEvent
erase_event( GetId(), &dc
);
3979 erase_event
.SetEventObject( this );
3981 GetEventHandler()->ProcessEvent(erase_event
);
3984 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
3986 wxWindowDC
dc( (wxWindow
*)this );
3987 if (m_clearRegion
.IsEmpty())
3988 dc
.SetClippingRegion( m_updateRegion
);
3990 dc
.SetClippingRegion( m_clearRegion
);
3992 wxEraseEvent
erase_event( GetId(), &dc
);
3993 erase_event
.SetEventObject( this );
3995 if (!GetEventHandler()->ProcessEvent(erase_event
) && GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3999 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
4000 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
4002 gdk_gc_set_foreground( g_eraseGC
, GetBackgroundColour().GetColor() );
4004 wxRegionIterator
upd( m_clearRegion
);
4007 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
4008 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
4012 m_clearRegion
.Clear();
4016 wxNcPaintEvent
nc_paint_event( GetId() );
4017 nc_paint_event
.SetEventObject( this );
4018 GetEventHandler()->ProcessEvent( nc_paint_event
);
4020 wxPaintEvent
paint_event( GetId() );
4021 paint_event
.SetEventObject( this );
4022 GetEventHandler()->ProcessEvent( paint_event
);
4024 m_clipPaintRegion
= FALSE
;
4026 #ifndef __WXUNIVERSAL__
4028 // The following code will result in all window-less widgets
4029 // being redrawn because the wxWidgets class is allowed to
4030 // paint over the window-less widgets.
4032 GList
*children
= pizza
->children
;
4035 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
4036 children
= children
->next
;
4038 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
4039 GTK_WIDGET_DRAWABLE (child
->widget
))
4041 // Get intersection of widget area and update region
4042 wxRegion
region( m_updateRegion
);
4044 GdkEventExpose gdk_event
;
4045 gdk_event
.type
= GDK_EXPOSE
;
4046 gdk_event
.window
= pizza
->bin_window
;
4047 gdk_event
.count
= 0;
4049 wxRegionIterator
upd( m_updateRegion
);
4053 rect
.x
= upd
.GetX();
4054 rect
.y
= upd
.GetY();
4055 rect
.width
= upd
.GetWidth();
4056 rect
.height
= upd
.GetHeight();
4058 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
4060 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
4070 m_updateRegion
.Clear();
4073 void wxWindowGTK::ClearBackground()
4075 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4078 if (m_wxwindow
&& m_wxwindow
->window
)
4080 m_clearRegion
.Clear();
4081 wxSize
size( GetClientSize() );
4082 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
4084 // Better do this in idle?
4091 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
4093 wxWindowBase::DoSetToolTip(tip
);
4096 m_tooltip
->Apply( (wxWindow
*)this );
4099 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
4101 wxString
tmp( tip
);
4102 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
4104 #endif // wxUSE_TOOLTIPS
4106 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
4108 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4110 if (!wxWindowBase::SetBackgroundColour(colour
))
4115 // We need the pixel value e.g. for background clearing.
4116 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
4119 // apply style change (forceStyle=true so that new style is applied
4120 // even if the bg colour changed from valid to wxNullColour)
4121 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
4122 ApplyWidgetStyle(true);
4127 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
4129 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4131 if (!wxWindowBase::SetForegroundColour(colour
))
4138 // We need the pixel value e.g. for background clearing.
4139 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
4142 // apply style change (forceStyle=true so that new style is applied
4143 // even if the bg colour changed from valid to wxNullColour):
4144 ApplyWidgetStyle(true);
4150 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
4152 return gtk_widget_get_pango_context( m_widget
);
4155 PangoContext
*wxWindowGTK::GtkGetPangoX11Context()
4158 m_x11Context
= pango_x_get_context( gdk_display
);
4160 return m_x11Context
;
4164 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
4166 // do we need to apply any changes at all?
4169 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
4174 GtkRcStyle
*style
= gtk_rc_style_new();
4180 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
4182 wxString xfontname
= m_font
.GetNativeFontInfo()->GetXFontName();
4183 style
->fontset_name
= g_strdup(xfontname
.c_str());
4187 if ( m_foregroundColour
.Ok() )
4189 GdkColor
*fg
= m_foregroundColour
.GetColor();
4191 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
4192 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
4194 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
4195 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
4197 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
4198 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
4201 if ( m_backgroundColour
.Ok() )
4203 GdkColor
*bg
= m_backgroundColour
.GetColor();
4205 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
4206 style
->base
[GTK_STATE_NORMAL
] = *bg
;
4207 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
4208 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
4210 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
4211 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
4212 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
4213 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
4215 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
4216 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
4217 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
4218 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4220 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
4221 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
4222 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
4223 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4229 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
4231 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
4234 DoApplyWidgetStyle(style
);
4235 gtk_rc_style_unref(style
);
4238 // Style change may affect GTK+'s size calculation:
4239 InvalidateBestSize();
4242 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
4245 gtk_widget_modify_style(m_wxwindow
, style
);
4246 gtk_widget_modify_style(m_widget
, style
);
4249 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
4251 wxWindowBase::SetBackgroundStyle(style
);
4253 if (style
== wxBG_STYLE_CUSTOM
)
4255 GdkWindow
*window
= (GdkWindow
*) NULL
;
4257 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4259 window
= GetConnectWidget()->window
;
4263 // Make sure GDK/X11 doesn't refresh the window
4265 gdk_window_set_back_pixmap( window
, None
, False
);
4267 Display
* display
= GDK_WINDOW_DISPLAY(window
);
4270 m_needsStyleChange
= false;
4273 // Do in OnIdle, because the window is not yet available
4274 m_needsStyleChange
= true;
4276 // Don't apply widget style, or we get a grey background
4280 // apply style change (forceStyle=true so that new style is applied
4281 // even if the bg colour changed from valid to wxNullColour):
4282 ApplyWidgetStyle(true);
4287 //-----------------------------------------------------------------------------
4288 // Pop-up menu stuff
4289 //-----------------------------------------------------------------------------
4291 #if wxUSE_MENUS_NATIVE
4294 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
4296 *is_waiting
= FALSE
;
4299 void SetInvokingWindow( wxMenu
*menu
, wxWindow
* win
)
4301 menu
->SetInvokingWindow( win
);
4303 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
4306 wxMenuItem
*menuitem
= node
->GetData();
4307 if (menuitem
->IsSubMenu())
4309 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
4312 node
= node
->GetNext();
4316 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
4319 gboolean
* WXUNUSED(whatever
),
4321 gpointer user_data
)
4323 // ensure that the menu appears entirely on screen
4325 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
4327 wxSize sizeScreen
= wxGetDisplaySize();
4328 wxPoint
*pos
= (wxPoint
*)user_data
;
4330 gint xmax
= sizeScreen
.x
- req
.width
,
4331 ymax
= sizeScreen
.y
- req
.height
;
4333 *x
= pos
->x
< xmax
? pos
->x
: xmax
;
4334 *y
= pos
->y
< ymax
? pos
->y
: ymax
;
4337 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4339 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4341 wxCHECK_MSG( menu
!= NULL
, false, wxT("invalid popup-menu") );
4343 // NOTE: if you change this code, you need to update
4344 // the same code in taskbar.cpp as well. This
4345 // is ugly code duplication, I know,
4347 SetInvokingWindow( menu
, this );
4351 bool is_waiting
= true;
4353 gulong handler
= gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
4355 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
4356 (gpointer
)&is_waiting
);
4360 GtkMenuPositionFunc posfunc
;
4361 if ( x
== -1 && y
== -1 )
4363 // use GTK's default positioning algorithm
4369 pos
= ClientToScreen(wxPoint(x
, y
));
4371 posfunc
= wxPopupMenuPositionCallback
;
4375 GTK_MENU(menu
->m_menu
),
4376 (GtkWidget
*) NULL
, // parent menu shell
4377 (GtkWidget
*) NULL
, // parent menu item
4378 posfunc
, // function to position it
4379 userdata
, // client data
4380 0, // button used to activate it
4382 gtk_get_current_event_time()
4384 gs_timeLastClick
// the time of activation
4390 gtk_main_iteration();
4393 gtk_signal_disconnect(GTK_OBJECT(menu
->m_menu
), handler
);
4398 #endif // wxUSE_MENUS_NATIVE
4400 #if wxUSE_DRAG_AND_DROP
4402 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4404 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4406 GtkWidget
*dnd_widget
= GetConnectWidget();
4408 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4410 if (m_dropTarget
) delete m_dropTarget
;
4411 m_dropTarget
= dropTarget
;
4413 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4416 #endif // wxUSE_DRAG_AND_DROP
4418 GtkWidget
* wxWindowGTK::GetConnectWidget()
4420 GtkWidget
*connect_widget
= m_widget
;
4421 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4423 return connect_widget
;
4426 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4429 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4431 return (window
== m_widget
->window
);
4434 bool wxWindowGTK::SetFont( const wxFont
&font
)
4436 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4438 if (!wxWindowBase::SetFont(font
))
4441 // apply style change (forceStyle=true so that new style is applied
4442 // even if the font changed from valid to wxNullFont):
4443 ApplyWidgetStyle(true);
4448 void wxWindowGTK::DoCaptureMouse()
4450 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4452 GdkWindow
*window
= (GdkWindow
*) NULL
;
4454 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4456 window
= GetConnectWidget()->window
;
4458 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4460 wxCursor
* cursor
= & m_cursor
;
4462 cursor
= wxSTANDARD_CURSOR
;
4464 gdk_pointer_grab( window
, FALSE
,
4466 (GDK_BUTTON_PRESS_MASK
|
4467 GDK_BUTTON_RELEASE_MASK
|
4468 GDK_POINTER_MOTION_HINT_MASK
|
4469 GDK_POINTER_MOTION_MASK
),
4471 cursor
->GetCursor(),
4472 (guint32
)GDK_CURRENT_TIME
);
4473 g_captureWindow
= this;
4474 g_captureWindowHasMouse
= TRUE
;
4477 void wxWindowGTK::DoReleaseMouse()
4479 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4481 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4483 g_captureWindow
= (wxWindowGTK
*) NULL
;
4485 GdkWindow
*window
= (GdkWindow
*) NULL
;
4487 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4489 window
= GetConnectWidget()->window
;
4494 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4498 wxWindow
*wxWindowBase::GetCapture()
4500 return (wxWindow
*)g_captureWindow
;
4503 bool wxWindowGTK::IsRetained() const
4508 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4509 int range
, bool refresh
)
4511 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4513 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4515 m_hasScrolling
= TRUE
;
4517 if (orient
== wxHORIZONTAL
)
4519 float fpos
= (float)pos
;
4520 float frange
= (float)range
;
4521 float fthumb
= (float)thumbVisible
;
4522 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4523 if (fpos
< 0.0) fpos
= 0.0;
4525 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4526 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4528 SetScrollPos( orient
, pos
, refresh
);
4532 m_oldHorizontalPos
= fpos
;
4534 m_hAdjust
->lower
= 0.0;
4535 m_hAdjust
->upper
= frange
;
4536 m_hAdjust
->value
= fpos
;
4537 m_hAdjust
->step_increment
= 1.0;
4538 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4539 m_hAdjust
->page_size
= fthumb
;
4543 float fpos
= (float)pos
;
4544 float frange
= (float)range
;
4545 float fthumb
= (float)thumbVisible
;
4546 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4547 if (fpos
< 0.0) fpos
= 0.0;
4549 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4550 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4552 SetScrollPos( orient
, pos
, refresh
);
4556 m_oldVerticalPos
= fpos
;
4558 m_vAdjust
->lower
= 0.0;
4559 m_vAdjust
->upper
= frange
;
4560 m_vAdjust
->value
= fpos
;
4561 m_vAdjust
->step_increment
= 1.0;
4562 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4563 m_vAdjust
->page_size
= fthumb
;
4566 if (orient
== wxHORIZONTAL
)
4567 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4569 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4572 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4574 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4576 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4578 if (orient
== wxHORIZONTAL
)
4580 float fpos
= (float)pos
;
4581 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4582 if (fpos
< 0.0) fpos
= 0.0;
4583 m_oldHorizontalPos
= fpos
;
4585 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4586 m_hAdjust
->value
= fpos
;
4590 float fpos
= (float)pos
;
4591 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4592 if (fpos
< 0.0) fpos
= 0.0;
4593 m_oldVerticalPos
= fpos
;
4595 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4596 m_vAdjust
->value
= fpos
;
4599 if (m_wxwindow
->window
)
4601 if (orient
== wxHORIZONTAL
)
4603 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4604 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4606 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4608 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4609 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4613 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4614 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4616 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4618 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4619 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4624 int wxWindowGTK::GetScrollThumb( int orient
) const
4626 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4628 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4630 if (orient
== wxHORIZONTAL
)
4631 return (int)(m_hAdjust
->page_size
+0.5);
4633 return (int)(m_vAdjust
->page_size
+0.5);
4636 int wxWindowGTK::GetScrollPos( int orient
) const
4638 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4640 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4642 if (orient
== wxHORIZONTAL
)
4643 return (int)(m_hAdjust
->value
+0.5);
4645 return (int)(m_vAdjust
->value
+0.5);
4648 int wxWindowGTK::GetScrollRange( int orient
) const
4650 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4652 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4654 if (orient
== wxHORIZONTAL
)
4655 return (int)(m_hAdjust
->upper
+0.5);
4657 return (int)(m_vAdjust
->upper
+0.5);
4660 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4662 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4664 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4666 // No scrolling requested.
4667 if ((dx
== 0) && (dy
== 0)) return;
4670 if (!m_updateRegion
.IsEmpty())
4672 m_updateRegion
.Offset( dx
, dy
);
4676 GetClientSize( &cw
, &ch
);
4677 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4680 if (!m_clearRegion
.IsEmpty())
4682 m_clearRegion
.Offset( dx
, dy
);
4686 GetClientSize( &cw
, &ch
);
4687 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4691 m_clipPaintRegion
= TRUE
;
4693 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4695 m_clipPaintRegion
= FALSE
;
4699 // Find the wxWindow at the current mouse position, also returning the mouse
4701 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4703 pt
= wxGetMousePosition();
4704 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4708 // Get the current mouse position.
4709 wxPoint
wxGetMousePosition()
4711 /* This crashes when used within wxHelpContext,
4712 so we have to use the X-specific implementation below.
4714 GdkModifierType *mask;
4715 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4717 return wxPoint(x, y);
4721 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4723 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4724 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4725 Window rootReturn
, childReturn
;
4726 int rootX
, rootY
, winX
, winY
;
4727 unsigned int maskReturn
;
4729 XQueryPointer (display
,
4733 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4734 return wxPoint(rootX
, rootY
);
4738 // ----------------------------------------------------------------------------
4740 // ----------------------------------------------------------------------------
4742 class wxWinModule
: public wxModule
4749 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4752 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4754 bool wxWinModule::OnInit()
4756 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4757 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4762 void wxWinModule::OnExit()
4765 gdk_gc_unref( g_eraseGC
);