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
)
1117 // We have to pass key press events through GTK+'s Input Method context
1118 // object in order to get correct characters. By doing so, we lose the
1119 // ability to let other GTK+'s handlers (namely, widgets' default signal
1120 // handlers) handle the signal by returning false from this callback.
1121 // Because GTK+ sends the events to parent widgets as well, we can't
1122 // afford losing it, otherwise native widgets inserted into wxPanel
1123 // would break in subtle ways (e.g. spacebar would no longer toggle
1124 // wxCheckButton's state). Therefore, we only pass the event to IM if it
1125 // originated in this window's widget, which we detect by checking if we've
1126 // seen the same event before (no events from children are lost this way,
1127 // because gtk_window_key_press_callback is installed for native controls
1128 // as well and the wxKeyEvent it creates propagates upwards).
1129 static GdkEventKey s_lastEvent
;
1130 bool useIM
= (win
->m_imData
!= NULL
) &&
1131 memcmp(gdk_event
, &s_lastEvent
, sizeof(GdkEventKey
)) != 0;
1132 s_lastEvent
= *gdk_event
;
1134 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
1135 // There is no need to store lastEvent. The original code makes GTK+ IM
1136 // dysfunction. When we get a key_press event here, it could be originate
1137 // from the current widget or its child widgets. However, only the widget
1138 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
1139 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
1140 // originated from its child widgets and shouldn't be passed to IM context.
1141 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
1142 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
1143 // widgets has both IM context and input focus, the event should be filtered
1144 // by gtk_im_context_filter_keypress().
1145 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
1146 bool useIM
= (win
->m_imData
!= NULL
) && ( wxWindow::FindFocus() == win
);
1151 bool IM_ret
= FALSE
;
1153 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
1154 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1155 // docs, if IM filter returns true, no further processing should be done.
1156 // wWe should send the key_down event anyway.
1159 // it may be useful for the input method, though:
1160 IM_ret
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
1161 win
->m_imData
->lastKeyEvent
= NULL
;
1163 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1167 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1170 // 2005.02.02 modified by Hong Jen Yee (hzysoft@sina.com.tw).
1171 // In GTK+ 1.2, strings sent by IMs are also regarded as key_press events whose
1172 // keyCodes cannot be recognized by wxWidgets. These MBCS strings, however, are
1173 // composed of more than one character, which means gdk_event->length will always
1174 // greater than one. When gtk_event->length == 1, this may be an ASCII character
1175 // and can be translated by wx. However, when MBCS characters are sent by IM,
1176 // gdk_event->length will >= 2. So neither should we pass it to accelerator table,
1177 // nor should we pass it to controls. The following explanation was excerpted
1178 // from GDK documentation.
1179 // gint length : the length of string.
1180 // gchar *string : a null-terminated multi-byte string containing the composed
1181 // characters resulting from the key press. When text is being input, in a GtkEntry
1182 // for example, it is these characters which should be added to the input buffer.
1183 // When using Input Methods to support internationalized text input, the composed
1184 // characters appear here after the pre-editing has been completed.
1187 // This is for GTK+ 1.2 only. The char event generatation for
1188 // GTK+ 2.0 is done in the emit handler.
1190 if ( (!ret
) && (gdk_event
->length
> 1) ) // If this event contains a pre-edited string from IM.
1192 // We should translate this key event into wxEVT_CHAR not wxEVT_KEY_DOWN.
1193 #if wxUSE_UNICODE // GTK+ 1.2 is not UTF-8 based.
1194 const wxWCharBuffer string
= wxConvLocal
.cMB2WC( gdk_event
->string
);
1198 const char* string
= gdk_event
->string
;
1201 // Implement OnCharHook by checking ancesteror top level windows
1202 wxWindow
*parent
= window
;
1203 while (parent
&& !parent
->IsTopLevel())
1204 parent
= parent
->GetParent();
1206 for( wxChar
* pstr
= string
; *pstr
; pstr
++ )
1209 event
.m_uniChar
= *pstr
;
1210 // Backward compatible for ISO-8859-1
1211 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1213 event
.m_keyCode
= *pstr
;
1217 event
.SetEventType( wxEVT_CHAR_HOOK
);
1218 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1222 event
.SetEventType(wxEVT_CHAR
);
1223 window
->GetEventHandler()->ProcessEvent( event
);
1228 // Only translate the key event when it's not sent with a pre-edited string.
1230 #endif // #ifndef __WXGTK20__
1232 if( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1234 // unknown key pressed, ignore (the event would be useless anyhow)
1237 else // This event doesn't contain a pre-edited string and is not an invalid key either.
1239 // Emit KEY_DOWN event
1240 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1248 wxWindowGTK
*ancestor
= win
;
1251 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1254 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1255 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1258 if (ancestor
->IsTopLevel())
1260 ancestor
= ancestor
->GetParent();
1263 #endif // wxUSE_ACCEL
1265 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1266 // will only be sent if it is not in an accelerator table.
1270 KeySym keysym
= gdk_event
->keyval
;
1271 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1272 key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1275 if ( wxIsAsciiKeysym(keysym
) )
1278 key_code
= (unsigned char)keysym
;
1280 // gdk_event->string is actually deprecated
1281 else if ( gdk_event
->length
== 1 )
1283 key_code
= (unsigned char)gdk_event
->string
[0];
1289 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1291 event
.m_keyCode
= key_code
;
1293 // Implement OnCharHook by checking ancesteror top level windows
1294 wxWindow
*parent
= win
;
1295 while (parent
&& !parent
->IsTopLevel())
1296 parent
= parent
->GetParent();
1299 event
.SetEventType( wxEVT_CHAR_HOOK
);
1300 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1305 event
.SetEventType(wxEVT_CHAR
);
1306 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1311 // win is a control: tab can be propagated up
1313 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1314 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1315 // have this style, yet choose not to process this particular TAB in which
1316 // case TAB must still work as a navigational character
1317 // JS: enabling again to make consistent with other platforms
1318 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1319 // navigation behaviour)
1321 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1323 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1325 wxNavigationKeyEvent new_event
;
1326 new_event
.SetEventObject( win
->GetParent() );
1327 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1328 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1329 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1330 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1331 new_event
.SetCurrentFocus( win
);
1332 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1335 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1337 (gdk_event
->keyval
== GDK_Escape
) )
1339 // however only do it if we have a Cancel button in the dialog,
1340 // otherwise the user code may get confused by the events from a
1341 // non-existing button and, worse, a wxButton might get button event
1342 // from another button which is not really expected
1343 wxWindow
*winForCancel
= win
,
1345 while ( winForCancel
)
1347 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1350 // found a cancel button
1354 if ( winForCancel
->IsTopLevel() )
1356 // no need to look further
1360 // maybe our parent has a cancel button?
1361 winForCancel
= winForCancel
->GetParent();
1366 wxCommandEvent
event(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1367 event
.SetEventObject(btnCancel
);
1368 ret
= btnCancel
->GetEventHandler()->ProcessEvent(event
);
1374 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1382 static void gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1386 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1388 // take modifiers, cursor position, timestamp etc. from the last
1389 // key_press_event that was fed into Input Method:
1390 if (window
->m_imData
->lastKeyEvent
)
1392 wxFillOtherKeyEventFields(event
,
1393 window
, window
->m_imData
->lastKeyEvent
);
1397 const wxWCharBuffer data
= wxConvUTF8
.cMB2WC( (char*)str
);
1399 const wxWCharBuffer wdata
= wxConvUTF8
.cMB2WC( (char*)str
);
1400 const wxCharBuffer data
= wxConvLocal
.cWC2MB( wdata
);
1401 #endif // wxUSE_UNICODE
1402 if( !(const wxChar
*)data
)
1407 // Implement OnCharHook by checking ancestor top level windows
1408 wxWindow
*parent
= window
;
1409 while (parent
&& !parent
->IsTopLevel())
1410 parent
= parent
->GetParent();
1412 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1415 event
.m_uniChar
= *pstr
;
1416 // Backward compatible for ISO-8859-1
1417 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1418 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1420 event
.m_keyCode
= *pstr
;
1421 #endif // wxUSE_UNICODE
1424 event
.SetEventType( wxEVT_CHAR_HOOK
);
1425 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1430 event
.SetEventType(wxEVT_CHAR
);
1431 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1438 //-----------------------------------------------------------------------------
1439 // "key_release_event" from any window
1440 //-----------------------------------------------------------------------------
1442 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1443 GdkEventKey
*gdk_event
,
1449 wxapp_install_idle_handler();
1454 if (g_blockEventsOnDrag
)
1457 wxKeyEvent
event( wxEVT_KEY_UP
);
1458 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1460 // unknown key pressed, ignore (the event would be useless anyhow
1464 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1467 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1471 // ============================================================================
1473 // ============================================================================
1475 // ----------------------------------------------------------------------------
1476 // mouse event processing helpers
1477 // ----------------------------------------------------------------------------
1479 // init wxMouseEvent with the info from GdkEventXXX struct
1480 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1481 wxMouseEvent
& event
,
1484 event
.SetTimestamp( gdk_event
->time
);
1485 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1486 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1487 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1488 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1489 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1490 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1491 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1492 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1494 event
.m_linesPerAction
= 3;
1495 event
.m_wheelDelta
= 120;
1496 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1497 event
.m_wheelRotation
= 120;
1498 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1499 event
.m_wheelRotation
= -120;
1502 wxPoint pt
= win
->GetClientAreaOrigin();
1503 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1504 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1506 event
.SetEventObject( win
);
1507 event
.SetId( win
->GetId() );
1508 event
.SetTimestamp( gdk_event
->time
);
1511 static void AdjustEventButtonState(wxMouseEvent
& event
)
1513 // GDK reports the old state of the button for a button press event, but
1514 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1515 // for a LEFT_DOWN event, not FALSE, so we will invert
1516 // left/right/middleDown for the corresponding click events
1518 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1519 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1520 (event
.GetEventType() == wxEVT_LEFT_UP
))
1522 event
.m_leftDown
= !event
.m_leftDown
;
1526 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1527 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1528 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1530 event
.m_middleDown
= !event
.m_middleDown
;
1534 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1535 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1536 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1538 event
.m_rightDown
= !event
.m_rightDown
;
1543 // find the window to send the mouse event too
1545 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1550 if (win
->m_wxwindow
)
1552 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1553 xx
+= pizza
->xoffset
;
1554 yy
+= pizza
->yoffset
;
1557 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1560 wxWindowGTK
*child
= node
->GetData();
1562 node
= node
->GetNext();
1563 if (!child
->IsShown())
1566 if (child
->IsTransparentForMouse())
1568 // wxStaticBox is transparent in the box itself
1569 int xx1
= child
->m_x
;
1570 int yy1
= child
->m_y
;
1571 int xx2
= child
->m_x
+ child
->m_width
;
1572 int yy2
= child
->m_y
+ child
->m_height
;
1575 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1577 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1579 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1581 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1592 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1593 (child
->m_x
<= xx
) &&
1594 (child
->m_y
<= yy
) &&
1595 (child
->m_x
+child
->m_width
>= xx
) &&
1596 (child
->m_y
+child
->m_height
>= yy
))
1609 //-----------------------------------------------------------------------------
1610 // "button_press_event"
1611 //-----------------------------------------------------------------------------
1613 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1614 GdkEventButton
*gdk_event
,
1620 wxapp_install_idle_handler();
1623 wxPrintf( wxT("1) OnButtonPress from ") );
1624 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1625 wxPrintf( win->GetClassInfo()->GetClassName() );
1626 wxPrintf( wxT(".\n") );
1628 if (!win
->m_hasVMT
) return FALSE
;
1629 if (g_blockEventsOnDrag
) return TRUE
;
1630 if (g_blockEventsOnScroll
) return TRUE
;
1632 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1634 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1636 gtk_widget_grab_focus( win
->m_wxwindow
);
1638 wxPrintf( wxT("GrabFocus from ") );
1639 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1640 wxPrintf( win->GetClassInfo()->GetClassName() );
1641 wxPrintf( wxT(".\n") );
1645 // GDK sends surplus button down event
1646 // before a double click event. We
1647 // need to filter these out.
1648 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1650 GdkEvent
*peek_event
= gdk_event_peek();
1653 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1654 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1656 gdk_event_free( peek_event
);
1661 gdk_event_free( peek_event
);
1666 wxEventType event_type
= wxEVT_NULL
;
1668 // GdkDisplay is a GTK+ 2.2.0 thing
1669 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1670 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1671 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1673 // Reset GDK internal timestamp variables in order to disable GDK
1674 // triple click events. GDK will then next time believe no button has
1675 // been clicked just before, and send a normal button click event.
1676 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1677 display
->button_click_time
[1] = 0;
1678 display
->button_click_time
[0] = 0;
1682 if (gdk_event
->button
== 1)
1684 // note that GDK generates triple click events which are not supported
1685 // by wxWidgets but still have to be passed to the app as otherwise
1686 // clicks would simply go missing
1687 switch (gdk_event
->type
)
1689 // we shouldn't get triple clicks at all for GTK2 because we
1690 // suppress them artificially using the code above but we still
1691 // should map them to something for GTK1 and not just ignore them
1692 // as this would lose clicks
1693 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1694 case GDK_BUTTON_PRESS
:
1695 event_type
= wxEVT_LEFT_DOWN
;
1698 case GDK_2BUTTON_PRESS
:
1699 event_type
= wxEVT_LEFT_DCLICK
;
1703 // just to silence gcc warnings
1707 else if (gdk_event
->button
== 2)
1709 switch (gdk_event
->type
)
1711 case GDK_3BUTTON_PRESS
:
1712 case GDK_BUTTON_PRESS
:
1713 event_type
= wxEVT_MIDDLE_DOWN
;
1716 case GDK_2BUTTON_PRESS
:
1717 event_type
= wxEVT_MIDDLE_DCLICK
;
1724 else if (gdk_event
->button
== 3)
1726 switch (gdk_event
->type
)
1728 case GDK_3BUTTON_PRESS
:
1729 case GDK_BUTTON_PRESS
:
1730 event_type
= wxEVT_RIGHT_DOWN
;
1733 case GDK_2BUTTON_PRESS
:
1734 event_type
= wxEVT_RIGHT_DCLICK
;
1741 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1743 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1745 event_type
= wxEVT_MOUSEWHEEL
;
1749 if ( event_type
== wxEVT_NULL
)
1751 // unknown mouse button or click type
1755 wxMouseEvent
event( event_type
);
1756 InitMouseEvent( win
, event
, gdk_event
);
1758 AdjustEventButtonState(event
);
1760 // wxListBox actually get mouse events from the item, so we need to give it
1761 // a chance to correct this
1762 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1764 // find the correct window to send the event too: it may be a different one
1765 // from the one which got it at GTK+ level because some control don't have
1766 // their own X window and thus cannot get any events.
1767 if ( !g_captureWindow
)
1768 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1770 gs_timeLastClick
= gdk_event
->time
;
1773 if (event_type
== wxEVT_LEFT_DCLICK
)
1775 // GTK 1.2 crashes when intercepting double
1776 // click events from both wxSpinButton and
1778 if (GTK_IS_SPIN_BUTTON(win
->m_widget
))
1780 // Just disable this event for now.
1786 if (win
->GetEventHandler()->ProcessEvent( event
))
1788 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1792 if (event_type
== wxEVT_RIGHT_DOWN
)
1794 // generate a "context menu" event: this is similar to right mouse
1795 // click under many GUIs except that it is generated differently
1796 // (right up under MSW, ctrl-click under Mac, right down here) and
1798 // (a) it's a command event and so is propagated to the parent
1799 // (b) under some ports it can be generated from kbd too
1800 // (c) it uses screen coords (because of (a))
1801 wxContextMenuEvent
evtCtx(
1804 win
->ClientToScreen(event
.GetPosition()));
1805 evtCtx
.SetEventObject(win
);
1806 return win
->GetEventHandler()->ProcessEvent(evtCtx
);
1812 //-----------------------------------------------------------------------------
1813 // "button_release_event"
1814 //-----------------------------------------------------------------------------
1816 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1817 GdkEventButton
*gdk_event
,
1823 wxapp_install_idle_handler();
1825 if (!win
->m_hasVMT
) return FALSE
;
1826 if (g_blockEventsOnDrag
) return FALSE
;
1827 if (g_blockEventsOnScroll
) return FALSE
;
1829 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1831 wxEventType event_type
= wxEVT_NULL
;
1833 switch (gdk_event
->button
)
1836 event_type
= wxEVT_LEFT_UP
;
1840 event_type
= wxEVT_MIDDLE_UP
;
1844 event_type
= wxEVT_RIGHT_UP
;
1848 // unknwon button, don't process
1852 wxMouseEvent
event( event_type
);
1853 InitMouseEvent( win
, event
, gdk_event
);
1855 AdjustEventButtonState(event
);
1857 // same wxListBox hack as above
1858 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1860 if ( !g_captureWindow
)
1861 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1863 if (win
->GetEventHandler()->ProcessEvent( event
))
1865 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1872 //-----------------------------------------------------------------------------
1873 // "motion_notify_event"
1874 //-----------------------------------------------------------------------------
1876 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1877 GdkEventMotion
*gdk_event
,
1883 wxapp_install_idle_handler();
1885 if (!win
->m_hasVMT
) return FALSE
;
1886 if (g_blockEventsOnDrag
) return FALSE
;
1887 if (g_blockEventsOnScroll
) return FALSE
;
1889 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1891 if (gdk_event
->is_hint
)
1895 GdkModifierType state
;
1896 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1902 printf( "OnMotion from " );
1903 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1904 printf( win->GetClassInfo()->GetClassName() );
1908 wxMouseEvent
event( wxEVT_MOTION
);
1909 InitMouseEvent(win
, event
, gdk_event
);
1911 if ( g_captureWindow
)
1913 // synthetize a mouse enter or leave event if needed
1914 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1915 // This seems to be necessary and actually been added to
1916 // GDK itself in version 2.0.X
1919 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1920 if ( hasMouse
!= g_captureWindowHasMouse
)
1922 // the mouse changed window
1923 g_captureWindowHasMouse
= hasMouse
;
1925 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1926 : wxEVT_LEAVE_WINDOW
);
1927 InitMouseEvent(win
, event
, gdk_event
);
1928 event
.SetEventObject(win
);
1929 win
->GetEventHandler()->ProcessEvent(event
);
1934 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1937 if (win
->GetEventHandler()->ProcessEvent( event
))
1939 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1947 //-----------------------------------------------------------------------------
1948 // "mouse_wheel_event"
1949 //-----------------------------------------------------------------------------
1951 static gint
gtk_window_wheel_callback (GtkWidget
* widget
,
1952 GdkEventScroll
* gdk_event
,
1958 wxapp_install_idle_handler();
1960 wxEventType event_type
= wxEVT_NULL
;
1961 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1962 event_type
= wxEVT_MOUSEWHEEL
;
1963 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1964 event_type
= wxEVT_MOUSEWHEEL
;
1968 wxMouseEvent
event( event_type
);
1969 // Can't use InitMouse macro because scroll events don't have button
1970 event
.SetTimestamp( gdk_event
->time
);
1971 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1972 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1973 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1974 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1975 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1976 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1977 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1978 event
.m_linesPerAction
= 3;
1979 event
.m_wheelDelta
= 120;
1980 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1981 event
.m_wheelRotation
= 120;
1983 event
.m_wheelRotation
= -120;
1985 wxPoint pt
= win
->GetClientAreaOrigin();
1986 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1987 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1989 event
.SetEventObject( win
);
1990 event
.SetId( win
->GetId() );
1991 event
.SetTimestamp( gdk_event
->time
);
1993 if (win
->GetEventHandler()->ProcessEvent( event
))
1995 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "scroll_event" );
2002 //-----------------------------------------------------------------------------
2004 //-----------------------------------------------------------------------------
2005 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
2007 wxContextMenuEvent
event(
2011 event
.SetEventObject(win
);
2012 return win
->GetEventHandler()->ProcessEvent(event
);
2014 #endif // __WXGTK20__
2016 //-----------------------------------------------------------------------------
2018 //-----------------------------------------------------------------------------
2020 // send the wxChildFocusEvent and wxFocusEvent, common code of
2021 // gtk_window_focus_in_callback() and SetFocus()
2022 static bool DoSendFocusEvents(wxWindow
*win
)
2024 // Notify the parent keeping track of focus for the kbd navigation
2025 // purposes that we got it.
2026 wxChildFocusEvent
eventChildFocus(win
);
2027 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
2029 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
2030 eventFocus
.SetEventObject(win
);
2032 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
2035 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
2036 GdkEvent
*WXUNUSED(event
),
2042 wxapp_install_idle_handler();
2046 gtk_im_context_focus_in(win
->m_imData
->context
);
2050 g_focusWindow
= win
;
2052 wxLogTrace(TRACE_FOCUS
,
2053 _T("%s: focus in"), win
->GetName().c_str());
2057 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
2061 // caret needs to be informed about focus change
2062 wxCaret
*caret
= win
->GetCaret();
2065 caret
->OnSetFocus();
2067 #endif // wxUSE_CARET
2069 // does the window itself think that it has the focus?
2070 if ( !win
->m_hasFocus
)
2072 // not yet, notify it
2073 win
->m_hasFocus
= TRUE
;
2075 if ( DoSendFocusEvents(win
) )
2077 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
2085 //-----------------------------------------------------------------------------
2086 // "focus_out_event"
2087 //-----------------------------------------------------------------------------
2089 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
2094 wxapp_install_idle_handler();
2098 gtk_im_context_focus_out(win
->m_imData
->context
);
2101 wxLogTrace( TRACE_FOCUS
,
2102 _T("%s: focus out"), win
->GetName().c_str() );
2105 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
2109 g_focusWindow
= (wxWindowGTK
*)NULL
;
2117 // caret needs to be informed about focus change
2118 wxCaret
*caret
= win
->GetCaret();
2121 caret
->OnKillFocus();
2123 #endif // wxUSE_CARET
2125 // don't send the window a kill focus event if it thinks that it doesn't
2126 // have focus already
2127 if ( win
->m_hasFocus
)
2129 win
->m_hasFocus
= FALSE
;
2131 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
2132 event
.SetEventObject( win
);
2134 // even if we did process the event in wx code, still let GTK itself
2135 // process it too as otherwise bad things happen, especially in GTK2
2136 // where the text control simply aborts the program if it doesn't get
2137 // the matching focus out event
2138 (void)win
->GetEventHandler()->ProcessEvent( event
);
2144 //-----------------------------------------------------------------------------
2145 // "enter_notify_event"
2146 //-----------------------------------------------------------------------------
2149 gint
gtk_window_enter_callback( GtkWidget
*widget
,
2150 GdkEventCrossing
*gdk_event
,
2156 wxapp_install_idle_handler();
2158 if (!win
->m_hasVMT
) return FALSE
;
2159 if (g_blockEventsOnDrag
) return FALSE
;
2161 // Event was emitted after a grab
2162 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2164 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2168 GdkModifierType state
= (GdkModifierType
)0;
2170 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2172 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2173 InitMouseEvent(win
, event
, gdk_event
);
2174 wxPoint pt
= win
->GetClientAreaOrigin();
2175 event
.m_x
= x
+ pt
.x
;
2176 event
.m_y
= y
+ pt
.y
;
2178 if (win
->GetEventHandler()->ProcessEvent( event
))
2180 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
2187 //-----------------------------------------------------------------------------
2188 // "leave_notify_event"
2189 //-----------------------------------------------------------------------------
2191 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
2196 wxapp_install_idle_handler();
2198 if (!win
->m_hasVMT
) return FALSE
;
2199 if (g_blockEventsOnDrag
) return FALSE
;
2201 // Event was emitted after an ungrab
2202 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2204 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2206 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2207 event
.SetTimestamp( gdk_event
->time
);
2208 event
.SetEventObject( win
);
2212 GdkModifierType state
= (GdkModifierType
)0;
2214 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2216 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2217 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2218 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2219 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2220 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2221 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2222 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2224 wxPoint pt
= win
->GetClientAreaOrigin();
2225 event
.m_x
= x
+ pt
.x
;
2226 event
.m_y
= y
+ pt
.y
;
2228 if (win
->GetEventHandler()->ProcessEvent( event
))
2230 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
2237 //-----------------------------------------------------------------------------
2238 // "value_changed" from m_vAdjust
2239 //-----------------------------------------------------------------------------
2241 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2248 wxapp_install_idle_handler();
2250 if (g_blockEventsOnDrag
) return;
2252 if (!win
->m_hasVMT
) return;
2254 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2255 if (fabs(diff
) < 0.2) return;
2257 win
->m_oldVerticalPos
= adjust
->value
;
2260 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2262 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
2264 int value
= (int)(adjust
->value
+0.5);
2266 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2267 event
.SetEventObject( win
);
2268 win
->GetEventHandler()->ProcessEvent( event
);
2271 //-----------------------------------------------------------------------------
2272 // "value_changed" from m_hAdjust
2273 //-----------------------------------------------------------------------------
2275 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2282 wxapp_install_idle_handler();
2284 if (g_blockEventsOnDrag
) return;
2285 if (!win
->m_hasVMT
) return;
2287 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2288 if (fabs(diff
) < 0.2) return;
2291 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2293 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
2295 win
->m_oldHorizontalPos
= adjust
->value
;
2297 int value
= (int)(adjust
->value
+0.5);
2299 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2300 event
.SetEventObject( win
);
2301 win
->GetEventHandler()->ProcessEvent( event
);
2304 //-----------------------------------------------------------------------------
2305 // "button_press_event" from scrollbar
2306 //-----------------------------------------------------------------------------
2308 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2309 GdkEventButton
*gdk_event
,
2315 wxapp_install_idle_handler();
2318 g_blockEventsOnScroll
= TRUE
;
2320 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2322 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2328 //-----------------------------------------------------------------------------
2329 // "button_release_event" from scrollbar
2330 //-----------------------------------------------------------------------------
2332 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2333 GdkEventButton
*WXUNUSED(gdk_event
),
2338 // don't test here as we can release the mouse while being over
2339 // a different window than the slider
2341 // if (gdk_event->window != widget->slider) return FALSE;
2343 g_blockEventsOnScroll
= FALSE
;
2345 if (win
->m_isScrolling
)
2347 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2351 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2352 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2354 value
= (int)(win
->m_hAdjust
->value
+0.5);
2357 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2359 value
= (int)(win
->m_vAdjust
->value
+0.5);
2363 wxScrollWinEvent
event( command
, value
, dir
);
2364 event
.SetEventObject( win
);
2365 win
->GetEventHandler()->ProcessEvent( event
);
2368 win
->m_isScrolling
= FALSE
;
2373 // ----------------------------------------------------------------------------
2374 // this wxWindowBase function is implemented here (in platform-specific file)
2375 // because it is static and so couldn't be made virtual
2376 // ----------------------------------------------------------------------------
2378 wxWindow
*wxWindowBase::DoFindFocus()
2380 // the cast is necessary when we compile in wxUniversal mode
2381 return (wxWindow
*)g_focusWindow
;
2385 //-----------------------------------------------------------------------------
2386 // "realize" from m_widget
2387 //-----------------------------------------------------------------------------
2389 /* We cannot set colours and fonts before the widget has
2390 been realized, so we do this directly after realization. */
2393 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2398 wxapp_install_idle_handler();
2403 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2404 gtk_im_context_set_client_window( win
->m_imData
->context
,
2405 pizza
->bin_window
);
2409 wxWindowCreateEvent
event( win
);
2410 event
.SetEventObject( win
);
2411 win
->GetEventHandler()->ProcessEvent( event
);
2416 //-----------------------------------------------------------------------------
2418 //-----------------------------------------------------------------------------
2421 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2422 GtkAllocation
*WXUNUSED(alloc
),
2426 wxapp_install_idle_handler();
2428 if (!win
->m_hasScrolling
) return;
2430 int client_width
= 0;
2431 int client_height
= 0;
2432 win
->GetClientSize( &client_width
, &client_height
);
2433 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2436 win
->m_oldClientWidth
= client_width
;
2437 win
->m_oldClientHeight
= client_height
;
2439 if (!win
->m_nativeSizeEvent
)
2441 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2442 event
.SetEventObject( win
);
2443 win
->GetEventHandler()->ProcessEvent( event
);
2449 #define WXUNUSED_UNLESS_XIM(param) param
2451 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2454 /* Resize XIM window */
2457 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2458 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2459 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2462 wxapp_install_idle_handler();
2468 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2472 gdk_window_get_size (widget
->window
, &width
, &height
);
2473 win
->m_icattr
->preedit_area
.width
= width
;
2474 win
->m_icattr
->preedit_area
.height
= height
;
2475 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2480 //-----------------------------------------------------------------------------
2481 // "realize" from m_wxwindow
2482 //-----------------------------------------------------------------------------
2484 /* Initialize XIM support */
2487 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2488 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2491 wxapp_install_idle_handler();
2494 if (win
->m_ic
) return FALSE
;
2495 if (!widget
) return FALSE
;
2496 if (!gdk_im_ready()) return FALSE
;
2498 win
->m_icattr
= gdk_ic_attr_new();
2499 if (!win
->m_icattr
) return FALSE
;
2503 GdkColormap
*colormap
;
2504 GdkICAttr
*attr
= win
->m_icattr
;
2505 unsigned attrmask
= GDK_IC_ALL_REQ
;
2507 GdkIMStyle supported_style
= (GdkIMStyle
)
2508 (GDK_IM_PREEDIT_NONE
|
2509 GDK_IM_PREEDIT_NOTHING
|
2510 GDK_IM_PREEDIT_POSITION
|
2511 GDK_IM_STATUS_NONE
|
2512 GDK_IM_STATUS_NOTHING
);
2514 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2515 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2517 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2518 attr
->client_window
= widget
->window
;
2520 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2521 gtk_widget_get_default_colormap ())
2523 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2524 attr
->preedit_colormap
= colormap
;
2527 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2528 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2529 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2530 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2532 switch (style
& GDK_IM_PREEDIT_MASK
)
2534 case GDK_IM_PREEDIT_POSITION
:
2535 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2537 g_warning ("over-the-spot style requires fontset");
2541 gdk_window_get_size (widget
->window
, &width
, &height
);
2543 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2544 attr
->spot_location
.x
= 0;
2545 attr
->spot_location
.y
= height
;
2546 attr
->preedit_area
.x
= 0;
2547 attr
->preedit_area
.y
= 0;
2548 attr
->preedit_area
.width
= width
;
2549 attr
->preedit_area
.height
= height
;
2550 attr
->preedit_fontset
= widget
->style
->font
;
2555 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2557 if (win
->m_ic
== NULL
)
2558 g_warning ("Can't create input context.");
2561 mask
= gdk_window_get_events (widget
->window
);
2562 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2563 gdk_window_set_events (widget
->window
, mask
);
2565 if (GTK_WIDGET_HAS_FOCUS(widget
))
2566 gdk_im_begin (win
->m_ic
, widget
->window
);
2573 //-----------------------------------------------------------------------------
2574 // InsertChild for wxWindowGTK.
2575 //-----------------------------------------------------------------------------
2577 /* Callback for wxWindowGTK. This very strange beast has to be used because
2578 * C++ has no virtual methods in a constructor. We have to emulate a
2579 * virtual function here as wxNotebook requires a different way to insert
2580 * a child in it. I had opted for creating a wxNotebookPage window class
2581 * which would have made this superfluous (such in the MDI window system),
2582 * but no-one was listening to me... */
2584 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2586 /* the window might have been scrolled already, do we
2587 have to adapt the position */
2588 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2589 child
->m_x
+= pizza
->xoffset
;
2590 child
->m_y
+= pizza
->yoffset
;
2592 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2593 GTK_WIDGET(child
->m_widget
),
2600 //-----------------------------------------------------------------------------
2602 //-----------------------------------------------------------------------------
2604 wxWindow
*wxGetActiveWindow()
2606 return wxWindow::FindFocus();
2609 //-----------------------------------------------------------------------------
2611 //-----------------------------------------------------------------------------
2613 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2615 #ifdef __WXUNIVERSAL__
2616 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2618 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2619 #endif // __WXUNIVERSAL__/__WXGTK__
2621 void wxWindowGTK::Init()
2624 m_widget
= (GtkWidget
*) NULL
;
2625 m_wxwindow
= (GtkWidget
*) NULL
;
2626 m_focusWidget
= (GtkWidget
*) NULL
;
2636 m_needParent
= TRUE
;
2637 m_isBeingDeleted
= FALSE
;
2640 m_nativeSizeEvent
= FALSE
;
2642 m_hasScrolling
= FALSE
;
2643 m_isScrolling
= FALSE
;
2645 m_hAdjust
= (GtkAdjustment
*) NULL
;
2646 m_vAdjust
= (GtkAdjustment
*) NULL
;
2647 m_oldHorizontalPos
=
2648 m_oldVerticalPos
= 0.0;
2650 m_oldClientHeight
= 0;
2654 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2656 m_acceptsFocus
= FALSE
;
2659 m_clipPaintRegion
= FALSE
;
2661 m_needsStyleChange
= false;
2663 m_cursor
= *wxSTANDARD_CURSOR
;
2667 m_x11Context
= NULL
;
2668 m_dirtyTabOrder
= false;
2671 m_ic
= (GdkIC
*) NULL
;
2672 m_icattr
= (GdkICAttr
*) NULL
;
2677 wxWindowGTK::wxWindowGTK()
2682 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2687 const wxString
&name
)
2691 Create( parent
, id
, pos
, size
, style
, name
);
2694 bool wxWindowGTK::Create( wxWindow
*parent
,
2699 const wxString
&name
)
2701 if (!PreCreation( parent
, pos
, size
) ||
2702 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2704 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2708 m_insertCallback
= wxInsertChildInWindow
;
2710 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2711 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2713 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2715 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2716 scroll_class
->scrollbar_spacing
= 0;
2718 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2720 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2721 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2723 m_wxwindow
= gtk_pizza_new();
2725 #ifndef __WXUNIVERSAL__
2726 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2728 if (HasFlag(wxRAISED_BORDER
))
2730 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2732 else if (HasFlag(wxSUNKEN_BORDER
))
2734 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2736 else if (HasFlag(wxSIMPLE_BORDER
))
2738 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2742 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2744 #endif // __WXUNIVERSAL__
2746 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2748 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2749 m_acceptsFocus
= TRUE
;
2751 // I _really_ don't want scrollbars in the beginning
2752 m_vAdjust
->lower
= 0.0;
2753 m_vAdjust
->upper
= 1.0;
2754 m_vAdjust
->value
= 0.0;
2755 m_vAdjust
->step_increment
= 1.0;
2756 m_vAdjust
->page_increment
= 1.0;
2757 m_vAdjust
->page_size
= 5.0;
2758 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2759 m_hAdjust
->lower
= 0.0;
2760 m_hAdjust
->upper
= 1.0;
2761 m_hAdjust
->value
= 0.0;
2762 m_hAdjust
->step_increment
= 1.0;
2763 m_hAdjust
->page_increment
= 1.0;
2764 m_hAdjust
->page_size
= 5.0;
2765 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2767 // these handlers block mouse events to any window during scrolling such as
2768 // motion events and prevent GTK and wxWidgets from fighting over where the
2771 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2772 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2774 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2775 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2777 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2778 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2780 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2781 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2783 // these handlers get notified when screen updates are required either when
2784 // scrolling or when the window size (and therefore scrollbar configuration)
2787 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2788 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2789 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2790 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2792 gtk_widget_show( m_wxwindow
);
2795 m_parent
->DoAddChild( this );
2797 m_focusWidget
= m_wxwindow
;
2804 wxWindowGTK::~wxWindowGTK()
2808 if (g_focusWindow
== this)
2809 g_focusWindow
= NULL
;
2811 if ( g_delayedFocus
== this )
2812 g_delayedFocus
= NULL
;
2814 m_isBeingDeleted
= TRUE
;
2824 gdk_ic_destroy (m_ic
);
2826 gdk_ic_attr_destroy (m_icattr
);
2831 gtk_widget_destroy( m_wxwindow
);
2832 m_wxwindow
= (GtkWidget
*) NULL
;
2837 gtk_widget_destroy( m_widget
);
2838 m_widget
= (GtkWidget
*) NULL
;
2846 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2848 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2850 // Use either the given size, or the default if -1 is given.
2851 // See wxWindowBase for these functions.
2852 m_width
= WidthDefault(size
.x
) ;
2853 m_height
= HeightDefault(size
.y
);
2861 void wxWindowGTK::PostCreation()
2863 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2869 // these get reported to wxWidgets -> wxPaintEvent
2871 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2873 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2874 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2877 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2878 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2880 if (!HasFlag(wxFULL_REPAINT_ON_RESIZE
))
2882 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2883 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2886 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2891 // Create input method handler
2892 m_imData
= new wxGtkIMData
;
2894 // Cannot handle drawing preedited text yet
2895 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2897 g_signal_connect (G_OBJECT (m_imData
->context
), "commit",
2898 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2901 // these are called when the "sunken" or "raised" borders are drawn
2902 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2903 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2906 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2907 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2913 if (!GTK_IS_WINDOW(m_widget
))
2915 if (m_focusWidget
== NULL
)
2916 m_focusWidget
= m_widget
;
2918 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2919 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2921 gtk_signal_connect_after( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2922 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2925 // connect to the various key and mouse handlers
2927 GtkWidget
*connect_widget
= GetConnectWidget();
2929 ConnectWidget( connect_widget
);
2931 /* We cannot set colours, fonts and cursors before the widget has
2932 been realized, so we do this directly after realization */
2933 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2934 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2938 // Catch native resize events
2939 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2940 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2942 // Initialize XIM support
2943 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2944 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2946 // And resize XIM window
2947 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2948 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2951 if ( !GTK_IS_COMBO(m_widget
))
2953 // This is needed if we want to add our windows into native
2954 // GTK control, such as the toolbar. With this callback, the
2955 // toolbar gets to know the correct size (the one set by the
2956 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2957 // when moving to GTK 2.0.
2958 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2959 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback
),
2963 InheritAttributes();
2967 // unless the window was created initially hidden (i.e. Hide() had been
2968 // called before Create()), we should show it at GTK+ level as well
2970 gtk_widget_show( m_widget
);
2973 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2975 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2976 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2978 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2979 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2981 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2982 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2984 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2985 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2987 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2988 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2991 gtk_signal_connect( GTK_OBJECT(widget
), "scroll_event",
2992 GTK_SIGNAL_FUNC(gtk_window_wheel_callback
), (gpointer
)this );
2993 g_signal_connect(widget
, "popup_menu",
2994 G_CALLBACK(wxgtk_window_popup_menu_callback
), this);
2997 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2998 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
3000 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
3001 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
3004 bool wxWindowGTK::Destroy()
3006 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3010 return wxWindowBase::Destroy();
3013 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
3015 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
3018 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
3020 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3021 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
3024 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
3027 if (m_resizing
) return; /* I don't like recursions */
3030 int currentX
, currentY
;
3031 GetPosition(¤tX
, ¤tY
);
3032 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
3034 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
3036 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
3038 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
3040 /* don't set the size for children of wxNotebook, just take the values. */
3048 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3049 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
3051 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
3052 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
3056 m_x
= x
+ pizza
->xoffset
;
3057 m_y
= y
+ pizza
->yoffset
;
3060 // calculate the best size if we should auto size the window
3061 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
3062 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
3064 const wxSize sizeBest
= GetBestSize();
3065 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
3067 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
3068 height
= sizeBest
.y
;
3076 int minWidth
= GetMinWidth(),
3077 minHeight
= GetMinHeight(),
3078 maxWidth
= GetMaxWidth(),
3079 maxHeight
= GetMaxHeight();
3081 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
3082 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
3083 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
3084 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
3087 int bottom_border
= 0;
3090 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
3092 /* the default button has a border around it */
3098 DoMoveWindow( m_x
-border
,
3101 m_height
+border
+bottom_border
);
3106 /* Sometimes the client area changes size without the
3107 whole windows's size changing, but if the whole
3108 windows's size doesn't change, no wxSizeEvent will
3109 normally be sent. Here we add an extra test if
3110 the client test has been changed and this will
3112 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
3116 wxPrintf( "OnSize sent from " );
3117 if (GetClassInfo() && GetClassInfo()->GetClassName())
3118 wxPrintf( GetClassInfo()->GetClassName() );
3119 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3122 if (!m_nativeSizeEvent
)
3124 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
3125 event
.SetEventObject( this );
3126 GetEventHandler()->ProcessEvent( event
);
3132 void wxWindowGTK::OnInternalIdle()
3135 if ( m_dirtyTabOrder
)
3138 // Update style if the window was not yet realized
3139 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
3140 if (m_needsStyleChange
)
3142 SetBackgroundStyle(GetBackgroundStyle());
3143 m_needsStyleChange
= false;
3146 // Update invalidated regions.
3149 wxCursor cursor
= m_cursor
;
3150 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3154 /* I now set the cursor anew in every OnInternalIdle call
3155 as setting the cursor in a parent window also effects the
3156 windows above so that checking for the current cursor is
3161 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3163 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3165 if (!g_globalCursor
.Ok())
3166 cursor
= *wxSTANDARD_CURSOR
;
3168 window
= m_widget
->window
;
3169 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3170 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3176 GdkWindow
*window
= m_widget
->window
;
3177 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3178 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3183 if (wxUpdateUIEvent::CanUpdate(this))
3184 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3187 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3189 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3191 if (width
) (*width
) = m_width
;
3192 if (height
) (*height
) = m_height
;
3195 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3197 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3201 SetSize( width
, height
);
3208 #ifndef __WXUNIVERSAL__
3209 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3211 /* when using GTK 1.2 we set the shadow border size to 2 */
3215 if (HasFlag(wxSIMPLE_BORDER
))
3217 /* when using GTK 1.2 we set the simple border size to 1 */
3221 #endif // __WXUNIVERSAL__
3225 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3227 GtkRequisition vscroll_req
;
3228 vscroll_req
.width
= 2;
3229 vscroll_req
.height
= 2;
3230 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3231 (scroll_window
->vscrollbar
, &vscroll_req
);
3233 GtkRequisition hscroll_req
;
3234 hscroll_req
.width
= 2;
3235 hscroll_req
.height
= 2;
3236 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3237 (scroll_window
->hscrollbar
, &hscroll_req
);
3239 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3241 if (scroll_window
->vscrollbar_visible
)
3243 dw
+= vscroll_req
.width
;
3244 dw
+= scroll_class
->scrollbar_spacing
;
3247 if (scroll_window
->hscrollbar_visible
)
3249 dh
+= hscroll_req
.height
;
3250 dh
+= scroll_class
->scrollbar_spacing
;
3254 SetSize( width
+dw
, height
+dh
);
3258 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3260 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3264 if (width
) (*width
) = m_width
;
3265 if (height
) (*height
) = m_height
;
3272 #ifndef __WXUNIVERSAL__
3273 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3275 /* when using GTK 1.2 we set the shadow border size to 2 */
3279 if (HasFlag(wxSIMPLE_BORDER
))
3281 /* when using GTK 1.2 we set the simple border size to 1 */
3285 #endif // __WXUNIVERSAL__
3289 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3291 GtkRequisition vscroll_req
;
3292 vscroll_req
.width
= 2;
3293 vscroll_req
.height
= 2;
3294 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3295 (scroll_window
->vscrollbar
, &vscroll_req
);
3297 GtkRequisition hscroll_req
;
3298 hscroll_req
.width
= 2;
3299 hscroll_req
.height
= 2;
3300 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3301 (scroll_window
->hscrollbar
, &hscroll_req
);
3303 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3305 if (scroll_window
->vscrollbar_visible
)
3307 dw
+= vscroll_req
.width
;
3308 dw
+= scroll_class
->scrollbar_spacing
;
3311 if (scroll_window
->hscrollbar_visible
)
3313 dh
+= hscroll_req
.height
;
3314 dh
+= scroll_class
->scrollbar_spacing
;
3318 if (width
) (*width
) = m_width
- dw
;
3319 if (height
) (*height
) = m_height
- dh
;
3323 printf( "GetClientSize, name %s ", GetName().c_str() );
3324 if (width) printf( " width = %d", (*width) );
3325 if (height) printf( " height = %d", (*height) );
3330 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3332 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3336 if (m_parent
&& m_parent
->m_wxwindow
)
3338 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3339 dx
= pizza
->xoffset
;
3340 dy
= pizza
->yoffset
;
3343 if (x
) (*x
) = m_x
- dx
;
3344 if (y
) (*y
) = m_y
- dy
;
3347 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3349 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3351 if (!m_widget
->window
) return;
3353 GdkWindow
*source
= (GdkWindow
*) NULL
;
3355 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3357 source
= m_widget
->window
;
3361 gdk_window_get_origin( source
, &org_x
, &org_y
);
3365 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3367 org_x
+= m_widget
->allocation
.x
;
3368 org_y
+= m_widget
->allocation
.y
;
3376 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3378 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3380 if (!m_widget
->window
) return;
3382 GdkWindow
*source
= (GdkWindow
*) NULL
;
3384 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3386 source
= m_widget
->window
;
3390 gdk_window_get_origin( source
, &org_x
, &org_y
);
3394 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3396 org_x
+= m_widget
->allocation
.x
;
3397 org_y
+= m_widget
->allocation
.y
;
3405 bool wxWindowGTK::Show( bool show
)
3407 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3409 if (!wxWindowBase::Show(show
))
3416 gtk_widget_show( m_widget
);
3418 gtk_widget_hide( m_widget
);
3420 wxShowEvent
eventShow(GetId(), show
);
3421 eventShow
.SetEventObject(this);
3423 GetEventHandler()->ProcessEvent(eventShow
);
3428 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3430 win
->OnParentEnable(enable
);
3432 // Recurse, so that children have the opportunity to Do The Right Thing
3433 // and reset colours that have been messed up by a parent's (really ancestor's)
3435 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3437 node
= node
->GetNext() )
3439 wxWindow
*child
= node
->GetData();
3440 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3441 wxWindowNotifyEnable(child
, enable
);
3445 bool wxWindowGTK::Enable( bool enable
)
3447 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3449 if (!wxWindowBase::Enable(enable
))
3455 gtk_widget_set_sensitive( m_widget
, enable
);
3457 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3459 wxWindowNotifyEnable(this, enable
);
3464 int wxWindowGTK::GetCharHeight() const
3466 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3468 wxFont font
= GetFont();
3469 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3472 PangoContext
*context
= NULL
;
3474 context
= gtk_widget_get_pango_context( m_widget
);
3479 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3480 PangoLayout
*layout
= pango_layout_new(context
);
3481 pango_layout_set_font_description(layout
, desc
);
3482 pango_layout_set_text(layout
, "H", 1);
3483 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3485 PangoRectangle rect
;
3486 pango_layout_line_get_extents(line
, NULL
, &rect
);
3488 g_object_unref( G_OBJECT( layout
) );
3490 return (int) PANGO_PIXELS(rect
.height
);
3492 GdkFont
*gfont
= font
.GetInternalFont( 1.0 );
3494 return gfont
->ascent
+ gfont
->descent
;
3498 int wxWindowGTK::GetCharWidth() const
3500 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3502 wxFont font
= GetFont();
3503 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3506 PangoContext
*context
= NULL
;
3508 context
= gtk_widget_get_pango_context( m_widget
);
3513 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3514 PangoLayout
*layout
= pango_layout_new(context
);
3515 pango_layout_set_font_description(layout
, desc
);
3516 pango_layout_set_text(layout
, "g", 1);
3517 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3519 PangoRectangle rect
;
3520 pango_layout_line_get_extents(line
, NULL
, &rect
);
3522 g_object_unref( G_OBJECT( layout
) );
3524 return (int) PANGO_PIXELS(rect
.width
);
3526 GdkFont
*gfont
= font
.GetInternalFont( 1.0 );
3528 return gdk_string_width( gfont
, "g" );
3532 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3536 int *externalLeading
,
3537 const wxFont
*theFont
) const
3539 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3541 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3543 if (string
.IsEmpty())
3551 PangoContext
*context
= NULL
;
3553 context
= gtk_widget_get_pango_context( m_widget
);
3562 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3563 PangoLayout
*layout
= pango_layout_new(context
);
3564 pango_layout_set_font_description(layout
, desc
);
3567 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3568 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3570 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3571 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3572 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3576 PangoRectangle rect
;
3577 pango_layout_get_extents(layout
, NULL
, &rect
);
3579 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3580 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3583 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3584 int baseline
= pango_layout_iter_get_baseline(iter
);
3585 pango_layout_iter_free(iter
);
3586 *descent
= *y
- PANGO_PIXELS(baseline
);
3588 if (externalLeading
) (*externalLeading
) = 0; // ??
3590 g_object_unref( G_OBJECT( layout
) );
3592 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3593 if (x
) (*x
) = gdk_string_width( font
, wxGTK_CONV( string
) );
3594 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3595 if (descent
) (*descent
) = font
->descent
;
3596 if (externalLeading
) (*externalLeading
) = 0; // ??
3600 void wxWindowGTK::SetFocus()
3602 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3605 // don't do anything if we already have focus
3611 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3613 gtk_widget_grab_focus (m_wxwindow
);
3619 if (GTK_IS_CONTAINER(m_widget
))
3621 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3625 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3628 if (!GTK_WIDGET_REALIZED(m_widget
))
3630 // we can't set the focus to the widget now so we remember that
3631 // it should be focused and will do it later, during the idle
3632 // time, as soon as we can
3633 wxLogTrace(TRACE_FOCUS
,
3634 _T("Delaying setting focus to %s(%s)"),
3635 GetClassInfo()->GetClassName(), GetLabel().c_str());
3637 g_delayedFocus
= this;
3641 wxLogTrace(TRACE_FOCUS
,
3642 _T("Setting focus to %s(%s)"),
3643 GetClassInfo()->GetClassName(), GetLabel().c_str());
3645 gtk_widget_grab_focus (m_widget
);
3650 if (GTK_IS_CONTAINER(m_widget
))
3652 gtk_container_focus( GTK_CONTAINER(m_widget
), GTK_DIR_TAB_FORWARD
);
3657 wxLogTrace(TRACE_FOCUS
,
3658 _T("Can't set focus to %s(%s)"),
3659 GetClassInfo()->GetClassName(), GetLabel().c_str());
3664 bool wxWindowGTK::AcceptsFocus() const
3666 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3669 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3671 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3673 wxWindowGTK
*oldParent
= m_parent
,
3674 *newParent
= (wxWindowGTK
*)newParentBase
;
3676 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3678 if ( !wxWindowBase::Reparent(newParent
) )
3681 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3683 /* prevent GTK from deleting the widget arbitrarily */
3684 gtk_widget_ref( m_widget
);
3688 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3691 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3695 /* insert GTK representation */
3696 (*(newParent
->m_insertCallback
))(newParent
, this);
3699 /* reverse: prevent GTK from deleting the widget arbitrarily */
3700 gtk_widget_unref( m_widget
);
3705 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3707 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3709 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3711 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3716 /* insert GTK representation */
3717 (*m_insertCallback
)(this, child
);
3722 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3724 wxWindowBase::AddChild(child
);
3725 m_dirtyTabOrder
= true;
3727 wxapp_install_idle_handler();
3730 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3732 wxWindowBase::RemoveChild(child
);
3733 m_dirtyTabOrder
= true;
3735 wxapp_install_idle_handler();
3738 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3740 wxWindowBase::DoMoveInTabOrder(win
, move
);
3741 m_dirtyTabOrder
= true;
3743 wxapp_install_idle_handler();
3746 void wxWindowGTK::RealizeTabOrder()
3750 if (m_children
.size() > 0)
3752 GList
*chain
= NULL
;
3754 for (wxWindowList::const_iterator i
= m_children
.begin();
3755 i
!= m_children
.end(); ++i
)
3757 chain
= g_list_prepend(chain
, (*i
)->m_widget
);
3760 chain
= g_list_reverse(chain
);
3762 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3767 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3771 m_dirtyTabOrder
= false;
3774 #endif // __WXGTK20__
3776 void wxWindowGTK::Raise()
3778 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3780 if (m_wxwindow
&& m_wxwindow
->window
)
3782 gdk_window_raise( m_wxwindow
->window
);
3784 else if (m_widget
->window
)
3786 gdk_window_raise( m_widget
->window
);
3790 void wxWindowGTK::Lower()
3792 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3794 if (m_wxwindow
&& m_wxwindow
->window
)
3796 gdk_window_lower( m_wxwindow
->window
);
3798 else if (m_widget
->window
)
3800 gdk_window_lower( m_widget
->window
);
3804 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3806 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3808 if (cursor
== m_cursor
)
3812 wxapp_install_idle_handler();
3814 if (cursor
== wxNullCursor
)
3815 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3817 return wxWindowBase::SetCursor( cursor
);
3820 void wxWindowGTK::WarpPointer( int x
, int y
)
3822 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3824 // We provide this function ourselves as it is
3825 // missing in GDK (top of this file).
3827 GdkWindow
*window
= (GdkWindow
*) NULL
;
3829 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3831 window
= GetConnectWidget()->window
;
3834 gdk_window_warp_pointer( window
, x
, y
);
3838 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3840 if (!m_widget
) return;
3841 if (!m_widget
->window
) return;
3845 wxapp_install_idle_handler();
3847 wxRect
myRect(0,0,0,0);
3848 if (m_wxwindow
&& rect
)
3850 myRect
.SetSize(wxSize( m_wxwindow
->allocation
.width
,
3851 m_wxwindow
->allocation
.height
));
3852 myRect
.Intersect(*rect
);
3853 if (!myRect
.width
|| !myRect
.height
)
3854 // nothing to do, rectangle is empty
3859 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3863 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3864 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3868 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3869 m_clearRegion
.Clear();
3870 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3878 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3879 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3883 GdkRectangle gdk_rect
;
3884 gdk_rect
.x
= rect
->x
;
3885 gdk_rect
.y
= rect
->y
;
3886 gdk_rect
.width
= rect
->width
;
3887 gdk_rect
.height
= rect
->height
;
3888 gtk_widget_draw( m_widget
, &gdk_rect
);
3895 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3896 m_updateRegion
.Clear();
3897 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3901 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3909 GdkRectangle gdk_rect
;
3910 gdk_rect
.x
= rect
->x
;
3911 gdk_rect
.y
= rect
->y
;
3912 gdk_rect
.width
= rect
->width
;
3913 gdk_rect
.height
= rect
->height
;
3914 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3918 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3924 void wxWindowGTK::Update()
3929 void wxWindowGTK::GtkUpdate()
3932 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3933 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3935 if (!m_updateRegion
.IsEmpty())
3936 GtkSendPaintEvents();
3940 void wxWindowGTK::GtkSendPaintEvents()
3945 m_clearRegion
.Clear();
3947 m_updateRegion
.Clear();
3951 // Clip to paint region in wxClientDC
3952 m_clipPaintRegion
= TRUE
;
3954 // widget to draw on
3955 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3957 if (GetThemeEnabled() && GetBackgroundStyle() == wxBG_STYLE_SYSTEM
)
3959 // find ancestor from which to steal background
3960 wxWindow
*parent
= GetParent();
3961 while (parent
&& !parent
->IsTopLevel())
3962 parent
= parent
->GetParent();
3964 parent
= (wxWindow
*)this;
3966 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3968 wxRegionIterator
upd( m_updateRegion
);
3972 rect
.x
= upd
.GetX();
3973 rect
.y
= upd
.GetY();
3974 rect
.width
= upd
.GetWidth();
3975 rect
.height
= upd
.GetHeight();
3977 gtk_paint_flat_box( parent
->m_widget
->style
,
3979 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3994 wxWindowDC
dc( (wxWindow
*)this );
3995 dc
.SetClippingRegion( m_updateRegion
);
3997 wxEraseEvent
erase_event( GetId(), &dc
);
3998 erase_event
.SetEventObject( this );
4000 GetEventHandler()->ProcessEvent(erase_event
);
4003 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
4005 wxWindowDC
dc( (wxWindow
*)this );
4006 if (m_clearRegion
.IsEmpty())
4007 dc
.SetClippingRegion( m_updateRegion
);
4009 dc
.SetClippingRegion( m_clearRegion
);
4011 wxEraseEvent
erase_event( GetId(), &dc
);
4012 erase_event
.SetEventObject( this );
4014 if (!GetEventHandler()->ProcessEvent(erase_event
) && GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
4018 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
4019 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
4021 gdk_gc_set_foreground( g_eraseGC
, GetBackgroundColour().GetColor() );
4023 wxRegionIterator
upd( m_clearRegion
);
4026 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
4027 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
4031 m_clearRegion
.Clear();
4035 wxNcPaintEvent
nc_paint_event( GetId() );
4036 nc_paint_event
.SetEventObject( this );
4037 GetEventHandler()->ProcessEvent( nc_paint_event
);
4039 wxPaintEvent
paint_event( GetId() );
4040 paint_event
.SetEventObject( this );
4041 GetEventHandler()->ProcessEvent( paint_event
);
4043 m_clipPaintRegion
= FALSE
;
4045 #ifndef __WXUNIVERSAL__
4047 // The following code will result in all window-less widgets
4048 // being redrawn because the wxWidgets class is allowed to
4049 // paint over the window-less widgets.
4051 GList
*children
= pizza
->children
;
4054 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
4055 children
= children
->next
;
4057 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
4058 GTK_WIDGET_DRAWABLE (child
->widget
))
4060 // Get intersection of widget area and update region
4061 wxRegion
region( m_updateRegion
);
4063 GdkEventExpose gdk_event
;
4064 gdk_event
.type
= GDK_EXPOSE
;
4065 gdk_event
.window
= pizza
->bin_window
;
4066 gdk_event
.count
= 0;
4068 wxRegionIterator
upd( m_updateRegion
);
4072 rect
.x
= upd
.GetX();
4073 rect
.y
= upd
.GetY();
4074 rect
.width
= upd
.GetWidth();
4075 rect
.height
= upd
.GetHeight();
4077 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
4079 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
4089 m_updateRegion
.Clear();
4092 void wxWindowGTK::ClearBackground()
4094 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4097 if (m_wxwindow
&& m_wxwindow
->window
)
4099 m_clearRegion
.Clear();
4100 wxSize
size( GetClientSize() );
4101 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
4103 // Better do this in idle?
4110 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
4112 wxWindowBase::DoSetToolTip(tip
);
4115 m_tooltip
->Apply( (wxWindow
*)this );
4118 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
4120 wxString
tmp( tip
);
4121 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
4123 #endif // wxUSE_TOOLTIPS
4125 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
4127 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4129 if (!wxWindowBase::SetBackgroundColour(colour
))
4134 // We need the pixel value e.g. for background clearing.
4135 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
4138 // apply style change (forceStyle=true so that new style is applied
4139 // even if the bg colour changed from valid to wxNullColour)
4140 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
4141 ApplyWidgetStyle(true);
4146 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
4148 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4150 if (!wxWindowBase::SetForegroundColour(colour
))
4157 // We need the pixel value e.g. for background clearing.
4158 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
4161 // apply style change (forceStyle=true so that new style is applied
4162 // even if the bg colour changed from valid to wxNullColour):
4163 ApplyWidgetStyle(true);
4169 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
4171 return gtk_widget_get_pango_context( m_widget
);
4174 PangoContext
*wxWindowGTK::GtkGetPangoX11Context()
4177 m_x11Context
= pango_x_get_context( gdk_display
);
4179 return m_x11Context
;
4183 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
4185 // do we need to apply any changes at all?
4188 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
4193 GtkRcStyle
*style
= gtk_rc_style_new();
4199 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
4201 wxString xfontname
= m_font
.GetNativeFontInfo()->GetXFontName();
4202 style
->fontset_name
= g_strdup(xfontname
.c_str());
4206 if ( m_foregroundColour
.Ok() )
4208 GdkColor
*fg
= m_foregroundColour
.GetColor();
4210 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
4211 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
4213 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
4214 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
4216 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
4217 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
4220 if ( m_backgroundColour
.Ok() )
4222 GdkColor
*bg
= m_backgroundColour
.GetColor();
4224 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
4225 style
->base
[GTK_STATE_NORMAL
] = *bg
;
4226 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
4227 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
4229 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
4230 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
4231 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
4232 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
4234 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
4235 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
4236 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
4237 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4239 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
4240 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
4241 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
4242 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4248 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
4250 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
4253 DoApplyWidgetStyle(style
);
4254 gtk_rc_style_unref(style
);
4257 // Style change may affect GTK+'s size calculation:
4258 InvalidateBestSize();
4261 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
4264 gtk_widget_modify_style(m_wxwindow
, style
);
4265 gtk_widget_modify_style(m_widget
, style
);
4268 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
4270 wxWindowBase::SetBackgroundStyle(style
);
4272 if (style
== wxBG_STYLE_CUSTOM
)
4274 GdkWindow
*window
= (GdkWindow
*) NULL
;
4276 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4278 window
= GetConnectWidget()->window
;
4282 // Make sure GDK/X11 doesn't refresh the window
4284 gdk_window_set_back_pixmap( window
, None
, False
);
4286 Display
* display
= GDK_WINDOW_DISPLAY(window
);
4289 m_needsStyleChange
= false;
4292 // Do in OnIdle, because the window is not yet available
4293 m_needsStyleChange
= true;
4295 // Don't apply widget style, or we get a grey background
4299 // apply style change (forceStyle=true so that new style is applied
4300 // even if the bg colour changed from valid to wxNullColour):
4301 ApplyWidgetStyle(true);
4306 //-----------------------------------------------------------------------------
4307 // Pop-up menu stuff
4308 //-----------------------------------------------------------------------------
4310 #if wxUSE_MENUS_NATIVE
4313 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
4315 *is_waiting
= FALSE
;
4318 void SetInvokingWindow( wxMenu
*menu
, wxWindow
* win
)
4320 menu
->SetInvokingWindow( win
);
4322 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
4325 wxMenuItem
*menuitem
= node
->GetData();
4326 if (menuitem
->IsSubMenu())
4328 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
4331 node
= node
->GetNext();
4335 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
4338 gboolean
* WXUNUSED(whatever
),
4340 gpointer user_data
)
4342 // ensure that the menu appears entirely on screen
4344 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
4346 wxSize sizeScreen
= wxGetDisplaySize();
4347 wxPoint
*pos
= (wxPoint
*)user_data
;
4349 gint xmax
= sizeScreen
.x
- req
.width
,
4350 ymax
= sizeScreen
.y
- req
.height
;
4352 *x
= pos
->x
< xmax
? pos
->x
: xmax
;
4353 *y
= pos
->y
< ymax
? pos
->y
: ymax
;
4356 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4358 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4360 wxCHECK_MSG( menu
!= NULL
, false, wxT("invalid popup-menu") );
4362 // NOTE: if you change this code, you need to update
4363 // the same code in taskbar.cpp as well. This
4364 // is ugly code duplication, I know,
4366 SetInvokingWindow( menu
, this );
4370 bool is_waiting
= true;
4372 gulong handler
= gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
4374 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
4375 (gpointer
)&is_waiting
);
4379 GtkMenuPositionFunc posfunc
;
4380 if ( x
== -1 && y
== -1 )
4382 // use GTK's default positioning algorithm
4388 pos
= ClientToScreen(wxPoint(x
, y
));
4390 posfunc
= wxPopupMenuPositionCallback
;
4394 GTK_MENU(menu
->m_menu
),
4395 (GtkWidget
*) NULL
, // parent menu shell
4396 (GtkWidget
*) NULL
, // parent menu item
4397 posfunc
, // function to position it
4398 userdata
, // client data
4399 0, // button used to activate it
4401 gtk_get_current_event_time()
4403 gs_timeLastClick
// the time of activation
4409 gtk_main_iteration();
4412 gtk_signal_disconnect(GTK_OBJECT(menu
->m_menu
), handler
);
4417 #endif // wxUSE_MENUS_NATIVE
4419 #if wxUSE_DRAG_AND_DROP
4421 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4423 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4425 GtkWidget
*dnd_widget
= GetConnectWidget();
4427 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4429 if (m_dropTarget
) delete m_dropTarget
;
4430 m_dropTarget
= dropTarget
;
4432 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4435 #endif // wxUSE_DRAG_AND_DROP
4437 GtkWidget
* wxWindowGTK::GetConnectWidget()
4439 GtkWidget
*connect_widget
= m_widget
;
4440 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4442 return connect_widget
;
4445 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4448 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4450 return (window
== m_widget
->window
);
4453 bool wxWindowGTK::SetFont( const wxFont
&font
)
4455 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4457 if (!wxWindowBase::SetFont(font
))
4460 // apply style change (forceStyle=true so that new style is applied
4461 // even if the font changed from valid to wxNullFont):
4462 ApplyWidgetStyle(true);
4467 void wxWindowGTK::DoCaptureMouse()
4469 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4471 GdkWindow
*window
= (GdkWindow
*) NULL
;
4473 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4475 window
= GetConnectWidget()->window
;
4477 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4479 wxCursor
* cursor
= & m_cursor
;
4481 cursor
= wxSTANDARD_CURSOR
;
4483 gdk_pointer_grab( window
, FALSE
,
4485 (GDK_BUTTON_PRESS_MASK
|
4486 GDK_BUTTON_RELEASE_MASK
|
4487 GDK_POINTER_MOTION_HINT_MASK
|
4488 GDK_POINTER_MOTION_MASK
),
4490 cursor
->GetCursor(),
4491 (guint32
)GDK_CURRENT_TIME
);
4492 g_captureWindow
= this;
4493 g_captureWindowHasMouse
= TRUE
;
4496 void wxWindowGTK::DoReleaseMouse()
4498 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4500 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4502 g_captureWindow
= (wxWindowGTK
*) NULL
;
4504 GdkWindow
*window
= (GdkWindow
*) NULL
;
4506 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4508 window
= GetConnectWidget()->window
;
4513 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4517 wxWindow
*wxWindowBase::GetCapture()
4519 return (wxWindow
*)g_captureWindow
;
4522 bool wxWindowGTK::IsRetained() const
4527 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4528 int range
, bool refresh
)
4530 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4532 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4534 m_hasScrolling
= TRUE
;
4536 if (orient
== wxHORIZONTAL
)
4538 float fpos
= (float)pos
;
4539 float frange
= (float)range
;
4540 float fthumb
= (float)thumbVisible
;
4541 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4542 if (fpos
< 0.0) fpos
= 0.0;
4544 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4545 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4547 SetScrollPos( orient
, pos
, refresh
);
4551 m_oldHorizontalPos
= fpos
;
4553 m_hAdjust
->lower
= 0.0;
4554 m_hAdjust
->upper
= frange
;
4555 m_hAdjust
->value
= fpos
;
4556 m_hAdjust
->step_increment
= 1.0;
4557 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4558 m_hAdjust
->page_size
= fthumb
;
4562 float fpos
= (float)pos
;
4563 float frange
= (float)range
;
4564 float fthumb
= (float)thumbVisible
;
4565 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4566 if (fpos
< 0.0) fpos
= 0.0;
4568 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4569 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4571 SetScrollPos( orient
, pos
, refresh
);
4575 m_oldVerticalPos
= fpos
;
4577 m_vAdjust
->lower
= 0.0;
4578 m_vAdjust
->upper
= frange
;
4579 m_vAdjust
->value
= fpos
;
4580 m_vAdjust
->step_increment
= 1.0;
4581 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4582 m_vAdjust
->page_size
= fthumb
;
4585 if (orient
== wxHORIZONTAL
)
4586 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4588 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4591 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4593 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4595 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4597 if (orient
== wxHORIZONTAL
)
4599 float fpos
= (float)pos
;
4600 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4601 if (fpos
< 0.0) fpos
= 0.0;
4602 m_oldHorizontalPos
= fpos
;
4604 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4605 m_hAdjust
->value
= fpos
;
4609 float fpos
= (float)pos
;
4610 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4611 if (fpos
< 0.0) fpos
= 0.0;
4612 m_oldVerticalPos
= fpos
;
4614 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4615 m_vAdjust
->value
= fpos
;
4618 if (m_wxwindow
->window
)
4620 if (orient
== wxHORIZONTAL
)
4622 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4623 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4625 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4627 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4628 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4632 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4633 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4635 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4637 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4638 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4643 int wxWindowGTK::GetScrollThumb( int orient
) const
4645 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4647 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4649 if (orient
== wxHORIZONTAL
)
4650 return (int)(m_hAdjust
->page_size
+0.5);
4652 return (int)(m_vAdjust
->page_size
+0.5);
4655 int wxWindowGTK::GetScrollPos( int orient
) const
4657 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4659 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4661 if (orient
== wxHORIZONTAL
)
4662 return (int)(m_hAdjust
->value
+0.5);
4664 return (int)(m_vAdjust
->value
+0.5);
4667 int wxWindowGTK::GetScrollRange( int orient
) const
4669 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4671 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4673 if (orient
== wxHORIZONTAL
)
4674 return (int)(m_hAdjust
->upper
+0.5);
4676 return (int)(m_vAdjust
->upper
+0.5);
4679 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4681 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4683 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4685 // No scrolling requested.
4686 if ((dx
== 0) && (dy
== 0)) return;
4689 if (!m_updateRegion
.IsEmpty())
4691 m_updateRegion
.Offset( dx
, dy
);
4695 GetClientSize( &cw
, &ch
);
4696 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4699 if (!m_clearRegion
.IsEmpty())
4701 m_clearRegion
.Offset( dx
, dy
);
4705 GetClientSize( &cw
, &ch
);
4706 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4710 m_clipPaintRegion
= TRUE
;
4712 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4714 m_clipPaintRegion
= FALSE
;
4718 // Find the wxWindow at the current mouse position, also returning the mouse
4720 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4722 pt
= wxGetMousePosition();
4723 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4727 // Get the current mouse position.
4728 wxPoint
wxGetMousePosition()
4730 /* This crashes when used within wxHelpContext,
4731 so we have to use the X-specific implementation below.
4733 GdkModifierType *mask;
4734 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4736 return wxPoint(x, y);
4740 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4742 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4743 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4744 Window rootReturn
, childReturn
;
4745 int rootX
, rootY
, winX
, winY
;
4746 unsigned int maskReturn
;
4748 XQueryPointer (display
,
4752 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4753 return wxPoint(rootX
, rootY
);
4757 // ----------------------------------------------------------------------------
4759 // ----------------------------------------------------------------------------
4761 class wxWinModule
: public wxModule
4768 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4771 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4773 bool wxWinModule::OnInit()
4775 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4776 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4781 void wxWinModule::OnExit()
4784 gdk_gc_unref( g_eraseGC
);