1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
10 // For compilers that support precompilation, includes "wx.h".
11 #include "wx/wxprec.h"
14 #define XWarpPointer XWARPPOINTER
17 #include "wx/window.h"
18 #include "wx/dcclient.h"
21 #include "wx/layout.h"
23 #include "wx/dialog.h"
24 #include "wx/msgdlg.h"
25 #include "wx/module.h"
26 #include "wx/combobox.h"
28 #if wxUSE_DRAG_AND_DROP
33 #include "wx/tooltip.h"
41 #include "wx/textctrl.h"
45 #include "wx/statusbr.h"
47 #include "wx/settings.h"
49 #include "wx/fontutil.h"
52 #include "wx/thread.h"
58 #include "wx/gtk/private.h"
59 #include <gdk/gdkprivate.h>
60 #include <gdk/gdkkeysyms.h>
64 #include <gtk/gtkprivate.h>
66 #include "wx/gtk/win_gtk.h"
69 #include <pango/pangox.h>
80 extern GtkContainerClass
*pizza_parent_class
;
83 //-----------------------------------------------------------------------------
84 // documentation on internals
85 //-----------------------------------------------------------------------------
88 I have been asked several times about writing some documentation about
89 the GTK port of wxWidgets, especially its internal structures. Obviously,
90 you cannot understand wxGTK without knowing a little about the GTK, but
91 some more information about what the wxWindow, which is the base class
92 for all other window classes, does seems required as well.
96 What does wxWindow do? It contains the common interface for the following
97 jobs of its descendants:
99 1) Define the rudimentary behaviour common to all window classes, such as
100 resizing, intercepting user input (so as to make it possible to use these
101 events for special purposes in a derived class), window names etc.
103 2) Provide the possibility to contain and manage children, if the derived
104 class is allowed to contain children, which holds true for those window
105 classes which do not display a native GTK widget. To name them, these
106 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
107 work classes are a special case and are handled a bit differently from
108 the rest. The same holds true for the wxNotebook class.
110 3) Provide the possibility to draw into a client area of a window. This,
111 too, only holds true for classes that do not display a native GTK widget
114 4) Provide the entire mechanism for scrolling widgets. This actual inter-
115 face for this is usually in wxScrolledWindow, but the GTK implementation
118 5) A multitude of helper or extra methods for special purposes, such as
119 Drag'n'Drop, managing validators etc.
121 6) Display a border (sunken, raised, simple or none).
123 Normally one might expect, that one wxWidgets window would always correspond
124 to one GTK widget. Under GTK, there is no such allround widget that has all
125 the functionality. Moreover, the GTK defines a client area as a different
126 widget from the actual widget you are handling. Last but not least some
127 special classes (e.g. wxFrame) handle different categories of widgets and
128 still have the possibility to draw something in the client area.
129 It was therefore required to write a special purpose GTK widget, that would
130 represent a client area in the sense of wxWidgets capable to do the jobs
131 2), 3) and 4). I have written this class and it resides in win_gtk.c of
134 All windows must have a widget, with which they interact with other under-
135 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
136 the wxWindow class has a member variable called m_widget which holds a
137 pointer to this widget. When the window class represents a GTK native widget,
138 this is (in most cases) the only GTK widget the class manages. E.g. the
139 wxStaticText class handles only a GtkLabel widget a pointer to which you
140 can find in m_widget (defined in wxWindow)
142 When the class has a client area for drawing into and for containing children
143 it has to handle the client area widget (of the type GtkPizza, defined in
144 win_gtk.c), but there could be any number of widgets, handled by a class
145 The common rule for all windows is only, that the widget that interacts with
146 the rest of GTK must be referenced in m_widget and all other widgets must be
147 children of this widget on the GTK level. The top-most widget, which also
148 represents the client area, must be in the m_wxwindow field and must be of
151 As I said, the window classes that display a GTK native widget only have
152 one widget, so in the case of e.g. the wxButton class m_widget holds a
153 pointer to a GtkButton widget. But windows with client areas (for drawing
154 and children) have a m_widget field that is a pointer to a GtkScrolled-
155 Window and a m_wxwindow field that is pointer to a GtkPizza and this
156 one is (in the GTK sense) a child of the GtkScrolledWindow.
158 If the m_wxwindow field is set, then all input to this widget is inter-
159 cepted and sent to the wxWidgets class. If not, all input to the widget
160 that gets pointed to by m_widget gets intercepted and sent to the class.
164 The design of scrolling in wxWidgets is markedly different from that offered
165 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
166 clicking on a scrollbar belonging to scrolled window will inevitably move
167 the window. In wxWidgets, the scrollbar will only emit an event, send this
168 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
169 which actually moves the window and its subchildren. Note that GtkPizza
170 memorizes how much it has been scrolled but that wxWidgets forgets this
171 so that the two coordinates systems have to be kept in synch. This is done
172 in various places using the pizza->xoffset and pizza->yoffset values.
176 Singularily the most broken code in GTK is the code that is supposed to
177 inform subwindows (child windows) about new positions. Very often, duplicate
178 events are sent without changes in size or position, equally often no
179 events are sent at all (All this is due to a bug in the GtkContainer code
180 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
181 GTK's own system and it simply waits for size events for toplevel windows
182 and then iterates down the respective size events to all window. This has
183 the disadvantage that windows might get size events before the GTK widget
184 actually has the reported size. This doesn't normally pose any problem, but
185 the OpenGL drawing routines rely on correct behaviour. Therefore, I have
186 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
187 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
188 window that is used for OpenGL output really has that size (as reported by
193 If someone at some point of time feels the immense desire to have a look at,
194 change or attempt to optimise the Refresh() logic, this person will need an
195 intimate understanding of what "draw" and "expose" events are and what
196 they are used for, in particular when used in connection with GTK's
197 own windowless widgets. Beware.
201 Cursors, too, have been a constant source of pleasure. The main difficulty
202 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
203 for the parent. To prevent this from doing too much harm, I use idle time
204 to set the cursor over and over again, starting from the toplevel windows
205 and ending with the youngest generation (speaking of parent and child windows).
206 Also don't forget that cursors (like much else) are connected to GdkWindows,
207 not GtkWidgets and that the "window" field of a GtkWidget might very well
208 point to the GdkWindow of the parent widget (-> "window-less widget") and
209 that the two obviously have very different meanings.
213 //-----------------------------------------------------------------------------
215 //-----------------------------------------------------------------------------
217 extern wxList wxPendingDelete
;
218 extern bool g_blockEventsOnDrag
;
219 extern bool g_blockEventsOnScroll
;
220 extern wxCursor g_globalCursor
;
222 static GdkGC
*g_eraseGC
= NULL
;
224 // mouse capture state: the window which has it and if the mouse is currently
226 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
227 static bool g_captureWindowHasMouse
= false;
229 wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
231 // the last window which had the focus - this is normally never NULL (except
232 // if we never had focus at all) as even when g_focusWindow is NULL it still
233 // keeps its previous value
234 wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
236 // If a window get the focus set but has not been realized
237 // yet, defer setting the focus to idle time.
238 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
240 // hack: we need something to pass to gtk_menu_popup, so we store the time of
241 // the last click here
243 static guint32 gs_timeLastClick
= 0;
246 extern bool g_mainThreadLocked
;
248 //-----------------------------------------------------------------------------
250 //-----------------------------------------------------------------------------
255 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
257 # define DEBUG_MAIN_THREAD
260 #define DEBUG_MAIN_THREAD
263 // the trace mask used for the focus debugging messages
264 #define TRACE_FOCUS _T("focus")
266 //-----------------------------------------------------------------------------
267 // missing gdk functions
268 //-----------------------------------------------------------------------------
271 gdk_window_warp_pointer (GdkWindow
*window
,
276 GdkWindowPrivate
*priv
;
280 window
= GDK_ROOT_PARENT();
283 if (!GDK_WINDOW_DESTROYED(window
))
285 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
286 None
, /* not source window -> move from anywhere */
287 GDK_WINDOW_XID(window
), /* dest window */
288 0, 0, 0, 0, /* not source window -> move from anywhere */
292 priv
= (GdkWindowPrivate
*) window
;
294 if (!priv
->destroyed
)
296 XWarpPointer (priv
->xdisplay
,
297 None
, /* not source window -> move from anywhere */
298 priv
->xwindow
, /* dest window */
299 0, 0, 0, 0, /* not source window -> move from anywhere */
305 //-----------------------------------------------------------------------------
307 //-----------------------------------------------------------------------------
309 extern void wxapp_install_idle_handler();
310 extern bool g_isIdle
;
312 //-----------------------------------------------------------------------------
313 // local code (see below)
314 //-----------------------------------------------------------------------------
316 // returns the child of win which currently has focus or NULL if not found
318 // Note: can't be static, needed by textctrl.cpp.
319 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
321 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
323 return (wxWindow
*)NULL
;
325 if ( winFocus
== win
)
326 return (wxWindow
*)win
;
328 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
330 node
= node
->GetNext() )
332 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
337 return (wxWindow
*)NULL
;
340 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
342 // wxUniversal widgets draw the borders and scrollbars themselves
343 #ifndef __WXUNIVERSAL__
350 if (win
->m_hasScrolling
)
352 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
354 GtkRequisition vscroll_req
;
355 vscroll_req
.width
= 2;
356 vscroll_req
.height
= 2;
357 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
358 (scroll_window
->vscrollbar
, &vscroll_req
);
360 GtkRequisition hscroll_req
;
361 hscroll_req
.width
= 2;
362 hscroll_req
.height
= 2;
363 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
364 (scroll_window
->hscrollbar
, &hscroll_req
);
366 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
368 if (scroll_window
->vscrollbar_visible
)
370 dw
+= vscroll_req
.width
;
371 dw
+= scroll_class
->scrollbar_spacing
;
374 if (scroll_window
->hscrollbar_visible
)
376 dh
+= hscroll_req
.height
;
377 dh
+= scroll_class
->scrollbar_spacing
;
383 if (GTK_WIDGET_NO_WINDOW (widget
))
385 dx
+= widget
->allocation
.x
;
386 dy
+= widget
->allocation
.y
;
389 if (win
->HasFlag(wxRAISED_BORDER
))
391 gtk_draw_shadow( widget
->style
,
396 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
400 if (win
->HasFlag(wxSUNKEN_BORDER
))
402 gtk_draw_shadow( widget
->style
,
407 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
411 if (win
->HasFlag(wxSIMPLE_BORDER
))
414 gc
= gdk_gc_new( widget
->window
);
415 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
416 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
418 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
422 #endif // __WXUNIVERSAL__
425 //-----------------------------------------------------------------------------
426 // "expose_event" of m_widget
427 //-----------------------------------------------------------------------------
430 static gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
432 if (gdk_event
->count
> 0) return FALSE
;
434 draw_frame( widget
, win
);
438 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
445 //-----------------------------------------------------------------------------
446 // "draw" of m_widget
447 //-----------------------------------------------------------------------------
452 static void gtk_window_own_draw_callback( GtkWidget
*widget
, GdkRectangle
*WXUNUSED(rect
), wxWindowGTK
*win
)
454 draw_frame( widget
, win
);
460 //-----------------------------------------------------------------------------
461 // "size_request" of m_widget
462 //-----------------------------------------------------------------------------
464 // make it extern because wxStaticText needs to disconnect this one
466 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
467 GtkRequisition
*requisition
,
471 win
->GetSize( &w
, &h
);
477 requisition
->height
= h
;
478 requisition
->width
= w
;
484 void wxgtk_combo_size_request_callback(GtkWidget
*widget
,
485 GtkRequisition
*requisition
,
488 // This callback is actually hooked into the text entry
489 // of the combo box, not the GtkHBox.
492 win
->GetSize( &w
, &h
);
498 GtkCombo
*gcombo
= GTK_COMBO(win
->m_widget
);
500 GtkRequisition entry_req
;
502 entry_req
.height
= 2;
503 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo
->button
) )->size_request
)
504 (gcombo
->button
, &entry_req
);
506 requisition
->width
= w
- entry_req
.width
;
507 requisition
->height
= entry_req
.height
;
511 //-----------------------------------------------------------------------------
512 // "expose_event" of m_wxwindow
513 //-----------------------------------------------------------------------------
516 static int gtk_window_expose_callback( GtkWidget
*widget
,
517 GdkEventExpose
*gdk_event
,
523 wxapp_install_idle_handler();
526 // This callback gets called in drawing-idle time under
527 // GTK 2.0, so we don't need to defer anything to idle
530 GtkPizza
*pizza
= GTK_PIZZA( widget
);
531 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
536 wxPrintf( wxT("OnExpose from ") );
537 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
538 wxPrintf( win
->GetClassInfo()->GetClassName() );
539 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
540 (int)gdk_event
->area
.y
,
541 (int)gdk_event
->area
.width
,
542 (int)gdk_event
->area
.height
);
547 win
->m_wxwindow
->style
,
551 (GdkRectangle
*) NULL
,
553 (char *)"button", // const_cast
558 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
560 win
->GtkSendPaintEvents();
563 // Let parent window draw window-less widgets
564 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
566 // This gets called immediately after an expose event
567 // under GTK 1.2 so we collect the calls and wait for
568 // the idle handler to pick things up.
570 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
572 gdk_event
->area
.width
,
573 gdk_event
->area
.height
);
574 win
->m_clearRegion
.Union( gdk_event
->area
.x
,
576 gdk_event
->area
.width
,
577 gdk_event
->area
.height
);
579 // Actual redrawing takes place in idle time.
587 //-----------------------------------------------------------------------------
588 // "event" of m_wxwindow
589 //-----------------------------------------------------------------------------
593 // GTK thinks it is clever and filters out a certain amount of "unneeded"
594 // expose events. We need them, of course, so we override the main event
595 // procedure in GtkWidget by giving our own handler for all system events.
596 // There, we look for expose events ourselves whereas all other events are
601 gint
gtk_window_event_event_callback( GtkWidget
*widget
,
602 GdkEventExpose
*event
,
605 if (event
->type
== GDK_EXPOSE
)
607 gint ret
= gtk_window_expose_callback( widget
, event
, win
);
617 //-----------------------------------------------------------------------------
618 // "draw" of m_wxwindow
619 //-----------------------------------------------------------------------------
623 // This callback is a complete replacement of the gtk_pizza_draw() function,
624 // which is disabled.
627 static void gtk_window_draw_callback( GtkWidget
*widget
,
634 wxapp_install_idle_handler();
636 // if there are any children we must refresh everything
639 if ( !win
->HasFlag(wxFULL_REPAINT_ON_RESIZE
) &&
640 win
->GetChildren().IsEmpty() )
648 wxPrintf( wxT("OnDraw from ") );
649 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
650 wxPrintf( win
->GetClassInfo()->GetClassName() );
651 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect
->x
,
658 #ifndef __WXUNIVERSAL__
659 GtkPizza
*pizza
= GTK_PIZZA (widget
);
661 if (win
->GetThemeEnabled() && win
->GetBackgroundStyle() == wxBG_STYLE_SYSTEM
)
663 wxWindow
*parent
= win
->GetParent();
664 while (parent
&& !parent
->IsTopLevel())
665 parent
= parent
->GetParent();
669 gtk_paint_flat_box (parent
->m_widget
->style
,
680 win
->m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
681 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
683 // Update immediately, not in idle time.
686 #ifndef __WXUNIVERSAL__
687 // Redraw child widgets
688 GList
*children
= pizza
->children
;
691 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
692 children
= children
->next
;
694 GdkRectangle child_area
;
695 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
697 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
706 //-----------------------------------------------------------------------------
707 // "key_press_event" from any window
708 //-----------------------------------------------------------------------------
710 // set WXTRACE to this to see the key event codes on the console
711 #define TRACE_KEYS _T("keyevent")
713 // translates an X key symbol to WXK_XXX value
715 // if isChar is true it means that the value returned will be used for EVT_CHAR
716 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
717 // for example, while if it is false it means that the value is going to be
718 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
720 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
726 // Shift, Control and Alt don't generate the CHAR events at all
729 key_code
= isChar
? 0 : WXK_SHIFT
;
733 key_code
= isChar
? 0 : WXK_CONTROL
;
741 key_code
= isChar
? 0 : WXK_ALT
;
744 // neither do the toggle modifies
745 case GDK_Scroll_Lock
:
746 key_code
= isChar
? 0 : WXK_SCROLL
;
750 key_code
= isChar
? 0 : WXK_CAPITAL
;
754 key_code
= isChar
? 0 : WXK_NUMLOCK
;
758 // various other special keys
771 case GDK_ISO_Left_Tab
:
778 key_code
= WXK_RETURN
;
782 key_code
= WXK_CLEAR
;
786 key_code
= WXK_PAUSE
;
790 key_code
= WXK_SELECT
;
794 key_code
= WXK_PRINT
;
798 key_code
= WXK_EXECUTE
;
802 key_code
= WXK_ESCAPE
;
805 // cursor and other extended keyboard keys
807 key_code
= WXK_DELETE
;
823 key_code
= WXK_RIGHT
;
830 case GDK_Prior
: // == GDK_Page_Up
831 key_code
= WXK_PRIOR
;
834 case GDK_Next
: // == GDK_Page_Down
847 key_code
= WXK_INSERT
;
862 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
866 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
870 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
874 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
878 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
882 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
886 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
890 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
894 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
898 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
902 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
906 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
910 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
913 case GDK_KP_Prior
: // == GDK_KP_Page_Up
914 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
917 case GDK_KP_Next
: // == GDK_KP_Page_Down
918 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
922 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
926 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
930 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
934 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
938 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
941 case GDK_KP_Multiply
:
942 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
946 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
949 case GDK_KP_Separator
:
950 // FIXME: what is this?
951 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
954 case GDK_KP_Subtract
:
955 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
959 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
963 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
980 key_code
= WXK_F1
+ keysym
- GDK_F1
;
990 static inline bool wxIsAsciiKeysym(KeySym ks
)
995 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
997 GdkEventKey
*gdk_event
)
1001 GdkModifierType state
;
1002 if (gdk_event
->window
)
1003 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1005 event
.SetTimestamp( gdk_event
->time
);
1006 event
.SetId(win
->GetId());
1007 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
1008 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
1009 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
1010 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
1011 event
.m_scanCode
= gdk_event
->keyval
;
1012 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
1013 event
.m_rawFlags
= 0;
1015 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
1017 wxGetMousePosition( &x
, &y
);
1018 win
->ScreenToClient( &x
, &y
);
1021 event
.SetEventObject( win
);
1026 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
1028 GdkEventKey
*gdk_event
)
1030 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
1031 // but only event->keyval which is quite useless to us, so remember
1032 // the last character from GDK_KEY_PRESS and reuse it as last resort
1034 // NB: should be MT-safe as we're always called from the main thread only
1039 } s_lastKeyPress
= { 0, 0 };
1041 KeySym keysym
= gdk_event
->keyval
;
1043 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
1044 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
1048 long key_code
= wxTranslateKeySymToWXKey(keysym
, false /* !isChar */);
1052 // do we have the translation or is it a plain ASCII character?
1053 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
1055 // we should use keysym if it is ASCII as X does some translations
1056 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
1057 // which we don't want here (but which we do use for OnChar())
1058 if ( !wxIsAsciiKeysym(keysym
) )
1060 keysym
= (KeySym
)gdk_event
->string
[0];
1063 // we want to always get the same key code when the same key is
1064 // pressed regardless of the state of the modifiers, i.e. on a
1065 // standard US keyboard pressing '5' or '%' ('5' key with
1066 // Shift) should result in the same key code in OnKeyDown():
1067 // '5' (although OnChar() will get either '5' or '%').
1069 // to do it we first translate keysym to keycode (== scan code)
1070 // and then back but always using the lower register
1071 Display
*dpy
= (Display
*)wxGetDisplay();
1072 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
1074 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
1076 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
1078 // use the normalized, i.e. lower register, keysym if we've
1080 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
1082 // as explained above, we want to have lower register key codes
1083 // normally but for the letter keys we want to have the upper ones
1085 // NB: don't use XConvertCase() here, we want to do it for letters
1087 key_code
= toupper(key_code
);
1089 else // non ASCII key, what to do?
1091 // by default, ignore it
1094 // but if we have cached information from the last KEY_PRESS
1095 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
1098 if ( keysym
== s_lastKeyPress
.keysym
)
1100 key_code
= s_lastKeyPress
.keycode
;
1105 if ( gdk_event
->type
== GDK_KEY_PRESS
)
1107 // remember it to be reused for KEY_UP event later
1108 s_lastKeyPress
.keysym
= keysym
;
1109 s_lastKeyPress
.keycode
= key_code
;
1113 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
1115 // sending unknown key events doesn't really make sense
1119 // now fill all the other fields
1120 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
1122 event
.m_keyCode
= key_code
;
1131 GtkIMContext
*context
;
1132 GdkEventKey
*lastKeyEvent
;
1136 context
= gtk_im_multicontext_new();
1137 lastKeyEvent
= NULL
;
1141 g_object_unref(context
);
1147 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1148 GdkEventKey
*gdk_event
,
1154 wxapp_install_idle_handler();
1158 if (g_blockEventsOnDrag
)
1162 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1164 bool return_after_IM
= false;
1166 if( wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1168 // Emit KEY_DOWN event
1169 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1173 // Return after IM processing as we cannot do
1174 // anything with it anyhow.
1175 return_after_IM
= true;
1179 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
1180 // When we get a key_press event here, it could be originate
1181 // from the current widget or its child widgets. However, only the widget
1182 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
1183 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
1184 // originated from its child widgets and shouldn't be passed to IM context.
1185 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
1186 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
1187 // widgets has both IM context and input focus, the event should be filtered
1188 // by gtk_im_context_filter_keypress().
1189 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
1190 if ((!ret
) && (win
->m_imData
!= NULL
) && ( wxWindow::FindFocus() == win
))
1192 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1193 // docs, if IM filter returns true, no further processing should be done.
1194 // we should send the key_down event anyway.
1195 bool intercepted_by_IM
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
1196 win
->m_imData
->lastKeyEvent
= NULL
;
1197 if (intercepted_by_IM
)
1199 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1204 if (return_after_IM
)
1208 // This is for GTK+ 1.2 only. The char event generatation for GTK+ 2.0 is done
1209 // in the "commit" handler.
1211 // 2005.02.02 modified by Hong Jen Yee (hzysoft@sina.com.tw).
1212 // In GTK+ 1.2, strings sent by IMs are also regarded as key_press events whose
1213 // keyCodes cannot be recognized by wxWidgets. These MBCS strings, however, are
1214 // composed of more than one character, which means gdk_event->length will always
1215 // greater than one. When gtk_event->length == 1, this may be an ASCII character
1216 // and can be translated by wx. However, when MBCS characters are sent by IM,
1217 // gdk_event->length will >= 2. So neither should we pass it to accelerator table,
1218 // nor should we pass it to controls. The following explanation was excerpted
1219 // from GDK documentation.
1220 // gint length : the length of string.
1221 // gchar *string : a null-terminated multi-byte string containing the composed
1222 // characters resulting from the key press. When text is being input, in a GtkEntry
1223 // for example, it is these characters which should be added to the input buffer.
1224 // When using Input Methods to support internationalized text input, the composed
1225 // characters appear here after the pre-editing has been completed.
1227 if ( (!ret
) && (gdk_event
->length
> 1) ) // If this event contains a pre-edited string from IM.
1229 // We should translate this key event into wxEVT_CHAR not wxEVT_KEY_DOWN.
1230 #if wxUSE_UNICODE // GTK+ 1.2 is not UTF-8 based.
1231 const wxWCharBuffer string
= wxConvLocal
.cMB2WC( gdk_event
->string
);
1235 const char* string
= gdk_event
->string
;
1238 // Implement OnCharHook by checking ancestor top level windows
1239 wxWindow
*parent
= win
;
1240 while (parent
&& !parent
->IsTopLevel())
1241 parent
= parent
->GetParent();
1243 for( const wxChar
* pstr
= string
; *pstr
; pstr
++ )
1246 event
.m_uniChar
= *pstr
;
1247 // Backward compatible for ISO-8859-1
1248 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1250 event
.m_keyCode
= *pstr
;
1254 event
.SetEventType( wxEVT_CHAR_HOOK
);
1255 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1259 event
.SetEventType(wxEVT_CHAR
);
1260 win
->GetEventHandler()->ProcessEvent( event
);
1266 #endif // #ifndef __WXGTK20__
1271 wxWindowGTK
*ancestor
= win
;
1274 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1277 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1278 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1281 if (ancestor
->IsTopLevel())
1283 ancestor
= ancestor
->GetParent();
1286 #endif // wxUSE_ACCEL
1288 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1289 // will only be sent if it is not in an accelerator table.
1293 KeySym keysym
= gdk_event
->keyval
;
1294 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1295 key_code
= wxTranslateKeySymToWXKey(keysym
, true /* isChar */);
1298 if ( wxIsAsciiKeysym(keysym
) )
1301 key_code
= (unsigned char)keysym
;
1303 // gdk_event->string is actually deprecated
1304 else if ( gdk_event
->length
== 1 )
1306 key_code
= (unsigned char)gdk_event
->string
[0];
1312 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1314 event
.m_keyCode
= key_code
;
1316 // Implement OnCharHook by checking ancestor top level windows
1317 wxWindow
*parent
= win
;
1318 while (parent
&& !parent
->IsTopLevel())
1319 parent
= parent
->GetParent();
1322 event
.SetEventType( wxEVT_CHAR_HOOK
);
1323 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1328 event
.SetEventType(wxEVT_CHAR
);
1329 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1338 // win is a control: tab can be propagated up
1340 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1341 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here - the control may
1342 // have this style, yet choose not to process this particular TAB in which
1343 // case TAB must still work as a navigational character
1344 // JS: enabling again to make consistent with other platforms
1345 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1346 // navigation behaviour)
1348 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1350 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1352 wxNavigationKeyEvent new_event
;
1353 new_event
.SetEventObject( win
->GetParent() );
1354 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1355 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1356 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1357 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1358 new_event
.SetCurrentFocus( win
);
1359 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1362 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1364 (gdk_event
->keyval
== GDK_Escape
) )
1366 // however only do it if we have a Cancel button in the dialog,
1367 // otherwise the user code may get confused by the events from a
1368 // non-existing button and, worse, a wxButton might get button event
1369 // from another button which is not really expected
1370 wxWindow
*winForCancel
= win
,
1372 while ( winForCancel
)
1374 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1377 // found a cancel button
1381 if ( winForCancel
->IsTopLevel() )
1383 // no need to look further
1387 // maybe our parent has a cancel button?
1388 winForCancel
= winForCancel
->GetParent();
1393 wxCommandEvent
eventClick(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1394 eventClick
.SetEventObject(btnCancel
);
1395 ret
= btnCancel
->GetEventHandler()->ProcessEvent(eventClick
);
1401 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1411 static void gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1415 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1417 // take modifiers, cursor position, timestamp etc. from the last
1418 // key_press_event that was fed into Input Method:
1419 if (window
->m_imData
->lastKeyEvent
)
1421 wxFillOtherKeyEventFields(event
,
1422 window
, window
->m_imData
->lastKeyEvent
);
1426 const wxWCharBuffer data
= wxConvUTF8
.cMB2WC( (char*)str
);
1428 const wxWCharBuffer wdata
= wxConvUTF8
.cMB2WC( (char*)str
);
1429 const wxCharBuffer data
= wxConvLocal
.cWC2MB( wdata
);
1430 #endif // wxUSE_UNICODE
1431 if( !(const wxChar
*)data
)
1436 // Implement OnCharHook by checking ancestor top level windows
1437 wxWindow
*parent
= window
;
1438 while (parent
&& !parent
->IsTopLevel())
1439 parent
= parent
->GetParent();
1441 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1444 event
.m_uniChar
= *pstr
;
1445 // Backward compatible for ISO-8859-1
1446 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1447 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1449 event
.m_keyCode
= *pstr
;
1450 #endif // wxUSE_UNICODE
1453 event
.SetEventType( wxEVT_CHAR_HOOK
);
1454 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1459 event
.SetEventType(wxEVT_CHAR
);
1460 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1468 //-----------------------------------------------------------------------------
1469 // "key_release_event" from any window
1470 //-----------------------------------------------------------------------------
1473 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1474 GdkEventKey
*gdk_event
,
1480 wxapp_install_idle_handler();
1485 if (g_blockEventsOnDrag
)
1488 wxKeyEvent
event( wxEVT_KEY_UP
);
1489 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1491 // unknown key pressed, ignore (the event would be useless anyhow)
1495 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1498 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1503 // ============================================================================
1505 // ============================================================================
1507 // ----------------------------------------------------------------------------
1508 // mouse event processing helpers
1509 // ----------------------------------------------------------------------------
1511 // init wxMouseEvent with the info from GdkEventXXX struct
1512 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1513 wxMouseEvent
& event
,
1516 event
.SetTimestamp( gdk_event
->time
);
1517 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1518 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1519 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1520 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1521 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1522 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1523 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1524 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1526 event
.m_linesPerAction
= 3;
1527 event
.m_wheelDelta
= 120;
1528 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1529 event
.m_wheelRotation
= 120;
1530 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1531 event
.m_wheelRotation
= -120;
1534 wxPoint pt
= win
->GetClientAreaOrigin();
1535 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1536 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1538 event
.SetEventObject( win
);
1539 event
.SetId( win
->GetId() );
1540 event
.SetTimestamp( gdk_event
->time
);
1543 static void AdjustEventButtonState(wxMouseEvent
& event
)
1545 // GDK reports the old state of the button for a button press event, but
1546 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1547 // for a LEFT_DOWN event, not FALSE, so we will invert
1548 // left/right/middleDown for the corresponding click events
1550 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1551 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1552 (event
.GetEventType() == wxEVT_LEFT_UP
))
1554 event
.m_leftDown
= !event
.m_leftDown
;
1558 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1559 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1560 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1562 event
.m_middleDown
= !event
.m_middleDown
;
1566 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1567 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1568 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1570 event
.m_rightDown
= !event
.m_rightDown
;
1575 // find the window to send the mouse event too
1577 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1582 if (win
->m_wxwindow
)
1584 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1585 xx
+= pizza
->xoffset
;
1586 yy
+= pizza
->yoffset
;
1589 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1592 wxWindowGTK
*child
= node
->GetData();
1594 node
= node
->GetNext();
1595 if (!child
->IsShown())
1598 if (child
->IsTransparentForMouse())
1600 // wxStaticBox is transparent in the box itself
1601 int xx1
= child
->m_x
;
1602 int yy1
= child
->m_y
;
1603 int xx2
= child
->m_x
+ child
->m_width
;
1604 int yy2
= child
->m_y
+ child
->m_height
;
1607 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1609 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1611 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1613 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1624 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1625 (child
->m_x
<= xx
) &&
1626 (child
->m_y
<= yy
) &&
1627 (child
->m_x
+child
->m_width
>= xx
) &&
1628 (child
->m_y
+child
->m_height
>= yy
))
1641 //-----------------------------------------------------------------------------
1642 // "button_press_event"
1643 //-----------------------------------------------------------------------------
1646 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1647 GdkEventButton
*gdk_event
,
1653 wxapp_install_idle_handler();
1656 wxPrintf( wxT("1) OnButtonPress from ") );
1657 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1658 wxPrintf( win->GetClassInfo()->GetClassName() );
1659 wxPrintf( wxT(".\n") );
1661 if (!win
->m_hasVMT
) return FALSE
;
1662 if (g_blockEventsOnDrag
) return TRUE
;
1663 if (g_blockEventsOnScroll
) return TRUE
;
1665 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1667 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1669 gtk_widget_grab_focus( win
->m_wxwindow
);
1671 wxPrintf( wxT("GrabFocus from ") );
1672 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1673 wxPrintf( win->GetClassInfo()->GetClassName() );
1674 wxPrintf( wxT(".\n") );
1678 // GDK sends surplus button down events
1679 // before a double click event. We
1680 // need to filter these out.
1681 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1683 GdkEvent
*peek_event
= gdk_event_peek();
1686 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1687 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1689 gdk_event_free( peek_event
);
1694 gdk_event_free( peek_event
);
1699 wxEventType event_type
= wxEVT_NULL
;
1701 // GdkDisplay is a GTK+ 2.2.0 thing
1702 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1703 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1704 !gtk_check_version(2,2,0) &&
1705 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1707 // Reset GDK internal timestamp variables in order to disable GDK
1708 // triple click events. GDK will then next time believe no button has
1709 // been clicked just before, and send a normal button click event.
1710 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1711 display
->button_click_time
[1] = 0;
1712 display
->button_click_time
[0] = 0;
1716 if (gdk_event
->button
== 1)
1718 // note that GDK generates triple click events which are not supported
1719 // by wxWidgets but still have to be passed to the app as otherwise
1720 // clicks would simply go missing
1721 switch (gdk_event
->type
)
1723 // we shouldn't get triple clicks at all for GTK2 because we
1724 // suppress them artificially using the code above but we still
1725 // should map them to something for GTK1 and not just ignore them
1726 // as this would lose clicks
1727 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1728 case GDK_BUTTON_PRESS
:
1729 event_type
= wxEVT_LEFT_DOWN
;
1732 case GDK_2BUTTON_PRESS
:
1733 event_type
= wxEVT_LEFT_DCLICK
;
1737 // just to silence gcc warnings
1741 else if (gdk_event
->button
== 2)
1743 switch (gdk_event
->type
)
1745 case GDK_3BUTTON_PRESS
:
1746 case GDK_BUTTON_PRESS
:
1747 event_type
= wxEVT_MIDDLE_DOWN
;
1750 case GDK_2BUTTON_PRESS
:
1751 event_type
= wxEVT_MIDDLE_DCLICK
;
1758 else if (gdk_event
->button
== 3)
1760 switch (gdk_event
->type
)
1762 case GDK_3BUTTON_PRESS
:
1763 case GDK_BUTTON_PRESS
:
1764 event_type
= wxEVT_RIGHT_DOWN
;
1767 case GDK_2BUTTON_PRESS
:
1768 event_type
= wxEVT_RIGHT_DCLICK
;
1775 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1777 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1779 event_type
= wxEVT_MOUSEWHEEL
;
1783 if ( event_type
== wxEVT_NULL
)
1785 // unknown mouse button or click type
1789 wxMouseEvent
event( event_type
);
1790 InitMouseEvent( win
, event
, gdk_event
);
1792 AdjustEventButtonState(event
);
1794 // wxListBox actually gets mouse events from the item, so we need to give it
1795 // a chance to correct this
1796 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1798 // find the correct window to send the event to: it may be a different one
1799 // from the one which got it at GTK+ level because some controls don't have
1800 // their own X window and thus cannot get any events.
1801 if ( !g_captureWindow
)
1802 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1805 gs_timeLastClick
= gdk_event
->time
;
1807 if (event_type
== wxEVT_LEFT_DCLICK
)
1809 // GTK 1.2 crashes when intercepting double
1810 // click events from both wxSpinButton and
1812 if (GTK_IS_SPIN_BUTTON(win
->m_widget
))
1814 // Just disable this event for now.
1818 #endif // !__WXGTK20__
1820 if (win
->GetEventHandler()->ProcessEvent( event
))
1822 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1826 if (event_type
== wxEVT_RIGHT_DOWN
)
1828 // generate a "context menu" event: this is similar to right mouse
1829 // click under many GUIs except that it is generated differently
1830 // (right up under MSW, ctrl-click under Mac, right down here) and
1832 // (a) it's a command event and so is propagated to the parent
1833 // (b) under some ports it can be generated from kbd too
1834 // (c) it uses screen coords (because of (a))
1835 wxContextMenuEvent
evtCtx(
1838 win
->ClientToScreen(event
.GetPosition()));
1839 evtCtx
.SetEventObject(win
);
1840 return win
->GetEventHandler()->ProcessEvent(evtCtx
);
1847 //-----------------------------------------------------------------------------
1848 // "button_release_event"
1849 //-----------------------------------------------------------------------------
1852 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1853 GdkEventButton
*gdk_event
,
1859 wxapp_install_idle_handler();
1861 if (!win
->m_hasVMT
) return FALSE
;
1862 if (g_blockEventsOnDrag
) return FALSE
;
1863 if (g_blockEventsOnScroll
) return FALSE
;
1865 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1867 wxEventType event_type
= wxEVT_NULL
;
1869 switch (gdk_event
->button
)
1872 event_type
= wxEVT_LEFT_UP
;
1876 event_type
= wxEVT_MIDDLE_UP
;
1880 event_type
= wxEVT_RIGHT_UP
;
1884 // unknwon button, don't process
1888 wxMouseEvent
event( event_type
);
1889 InitMouseEvent( win
, event
, gdk_event
);
1891 AdjustEventButtonState(event
);
1893 // same wxListBox hack as above
1894 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1896 if ( !g_captureWindow
)
1897 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1899 if (win
->GetEventHandler()->ProcessEvent( event
))
1901 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1909 //-----------------------------------------------------------------------------
1910 // "motion_notify_event"
1911 //-----------------------------------------------------------------------------
1914 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1915 GdkEventMotion
*gdk_event
,
1921 wxapp_install_idle_handler();
1923 if (!win
->m_hasVMT
) return FALSE
;
1924 if (g_blockEventsOnDrag
) return FALSE
;
1925 if (g_blockEventsOnScroll
) return FALSE
;
1927 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1929 if (gdk_event
->is_hint
)
1933 GdkModifierType state
;
1934 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1940 printf( "OnMotion from " );
1941 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1942 printf( win->GetClassInfo()->GetClassName() );
1946 wxMouseEvent
event( wxEVT_MOTION
);
1947 InitMouseEvent(win
, event
, gdk_event
);
1949 if ( g_captureWindow
)
1951 // synthetize a mouse enter or leave event if needed
1952 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1953 // This seems to be necessary and actually been added to
1954 // GDK itself in version 2.0.X
1957 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1958 if ( hasMouse
!= g_captureWindowHasMouse
)
1960 // the mouse changed window
1961 g_captureWindowHasMouse
= hasMouse
;
1963 wxMouseEvent
eventM(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1964 : wxEVT_LEAVE_WINDOW
);
1965 InitMouseEvent(win
, eventM
, gdk_event
);
1966 eventM
.SetEventObject(win
);
1967 win
->GetEventHandler()->ProcessEvent(eventM
);
1972 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1975 if (win
->GetEventHandler()->ProcessEvent( event
))
1977 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1986 //-----------------------------------------------------------------------------
1987 // "mouse_wheel_event"
1988 //-----------------------------------------------------------------------------
1991 static gint
gtk_window_wheel_callback (GtkWidget
* widget
,
1992 GdkEventScroll
* gdk_event
,
1998 wxapp_install_idle_handler();
2000 wxEventType event_type
= wxEVT_NULL
;
2001 if (gdk_event
->direction
== GDK_SCROLL_UP
)
2002 event_type
= wxEVT_MOUSEWHEEL
;
2003 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
2004 event_type
= wxEVT_MOUSEWHEEL
;
2008 wxMouseEvent
event( event_type
);
2009 // Can't use InitMouse macro because scroll events don't have button
2010 event
.SetTimestamp( gdk_event
->time
);
2011 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
2012 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
2013 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
2014 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
2015 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
2016 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
2017 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
2018 event
.m_linesPerAction
= 3;
2019 event
.m_wheelDelta
= 120;
2020 if (gdk_event
->direction
== GDK_SCROLL_UP
)
2021 event
.m_wheelRotation
= 120;
2023 event
.m_wheelRotation
= -120;
2025 wxPoint pt
= win
->GetClientAreaOrigin();
2026 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
2027 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
2029 event
.SetEventObject( win
);
2030 event
.SetId( win
->GetId() );
2031 event
.SetTimestamp( gdk_event
->time
);
2033 if (win
->GetEventHandler()->ProcessEvent( event
))
2035 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "scroll_event" );
2043 //-----------------------------------------------------------------------------
2045 //-----------------------------------------------------------------------------
2047 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
2049 wxContextMenuEvent
event(
2053 event
.SetEventObject(win
);
2054 return win
->GetEventHandler()->ProcessEvent(event
);
2057 #endif // __WXGTK20__
2059 //-----------------------------------------------------------------------------
2061 //-----------------------------------------------------------------------------
2063 // send the wxChildFocusEvent and wxFocusEvent, common code of
2064 // gtk_window_focus_in_callback() and SetFocus()
2065 static bool DoSendFocusEvents(wxWindow
*win
)
2067 // Notify the parent keeping track of focus for the kbd navigation
2068 // purposes that we got it.
2069 wxChildFocusEvent
eventChildFocus(win
);
2070 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
2072 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
2073 eventFocus
.SetEventObject(win
);
2075 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
2079 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
2080 GdkEvent
*WXUNUSED(event
),
2086 wxapp_install_idle_handler();
2090 gtk_im_context_focus_in(win
->m_imData
->context
);
2094 g_focusWindow
= win
;
2096 wxLogTrace(TRACE_FOCUS
,
2097 _T("%s: focus in"), win
->GetName().c_str());
2101 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
2105 // caret needs to be informed about focus change
2106 wxCaret
*caret
= win
->GetCaret();
2109 caret
->OnSetFocus();
2111 #endif // wxUSE_CARET
2113 // does the window itself think that it has the focus?
2114 if ( !win
->m_hasFocus
)
2116 // not yet, notify it
2117 win
->m_hasFocus
= true;
2119 if ( DoSendFocusEvents(win
) )
2121 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
2130 //-----------------------------------------------------------------------------
2131 // "focus_out_event"
2132 //-----------------------------------------------------------------------------
2135 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
2140 wxapp_install_idle_handler();
2144 gtk_im_context_focus_out(win
->m_imData
->context
);
2147 wxLogTrace( TRACE_FOCUS
,
2148 _T("%s: focus out"), win
->GetName().c_str() );
2151 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
2155 g_focusWindow
= (wxWindowGTK
*)NULL
;
2163 // caret needs to be informed about focus change
2164 wxCaret
*caret
= win
->GetCaret();
2167 caret
->OnKillFocus();
2169 #endif // wxUSE_CARET
2171 // don't send the window a kill focus event if it thinks that it doesn't
2172 // have focus already
2173 if ( win
->m_hasFocus
)
2175 win
->m_hasFocus
= false;
2177 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
2178 event
.SetEventObject( win
);
2180 // even if we did process the event in wx code, still let GTK itself
2181 // process it too as otherwise bad things happen, especially in GTK2
2182 // where the text control simply aborts the program if it doesn't get
2183 // the matching focus out event
2184 (void)win
->GetEventHandler()->ProcessEvent( event
);
2191 //-----------------------------------------------------------------------------
2192 // "enter_notify_event"
2193 //-----------------------------------------------------------------------------
2197 gint
gtk_window_enter_callback( GtkWidget
*widget
,
2198 GdkEventCrossing
*gdk_event
,
2204 wxapp_install_idle_handler();
2206 if (!win
->m_hasVMT
) return FALSE
;
2207 if (g_blockEventsOnDrag
) return FALSE
;
2209 // Event was emitted after a grab
2210 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2212 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2216 GdkModifierType state
= (GdkModifierType
)0;
2218 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2220 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2221 InitMouseEvent(win
, event
, gdk_event
);
2222 wxPoint pt
= win
->GetClientAreaOrigin();
2223 event
.m_x
= x
+ pt
.x
;
2224 event
.m_y
= y
+ pt
.y
;
2226 if (win
->GetEventHandler()->ProcessEvent( event
))
2228 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
2236 //-----------------------------------------------------------------------------
2237 // "leave_notify_event"
2238 //-----------------------------------------------------------------------------
2241 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
2246 wxapp_install_idle_handler();
2248 if (!win
->m_hasVMT
) return FALSE
;
2249 if (g_blockEventsOnDrag
) return FALSE
;
2251 // Event was emitted after an ungrab
2252 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2254 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2256 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2257 event
.SetTimestamp( gdk_event
->time
);
2258 event
.SetEventObject( win
);
2262 GdkModifierType state
= (GdkModifierType
)0;
2264 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2266 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2267 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2268 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2269 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2270 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2271 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2272 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2274 wxPoint pt
= win
->GetClientAreaOrigin();
2275 event
.m_x
= x
+ pt
.x
;
2276 event
.m_y
= y
+ pt
.y
;
2278 if (win
->GetEventHandler()->ProcessEvent( event
))
2280 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
2288 //-----------------------------------------------------------------------------
2289 // "value_changed" from m_vAdjust
2290 //-----------------------------------------------------------------------------
2293 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2300 wxapp_install_idle_handler();
2302 if (g_blockEventsOnDrag
) return;
2304 if (!win
->m_hasVMT
) return;
2306 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2307 if (fabs(diff
) < 0.2) return;
2309 win
->m_oldVerticalPos
= adjust
->value
;
2312 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2314 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
2316 int value
= (int)(adjust
->value
+0.5);
2318 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2319 event
.SetEventObject( win
);
2320 win
->GetEventHandler()->ProcessEvent( event
);
2324 //-----------------------------------------------------------------------------
2325 // "value_changed" from m_hAdjust
2326 //-----------------------------------------------------------------------------
2329 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2336 wxapp_install_idle_handler();
2338 if (g_blockEventsOnDrag
) return;
2339 if (!win
->m_hasVMT
) return;
2341 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2342 if (fabs(diff
) < 0.2) return;
2345 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2347 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
2349 win
->m_oldHorizontalPos
= adjust
->value
;
2351 int value
= (int)(adjust
->value
+0.5);
2353 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2354 event
.SetEventObject( win
);
2355 win
->GetEventHandler()->ProcessEvent( event
);
2359 //-----------------------------------------------------------------------------
2360 // "button_press_event" from scrollbar
2361 //-----------------------------------------------------------------------------
2364 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2365 GdkEventButton
*gdk_event
,
2371 wxapp_install_idle_handler();
2374 g_blockEventsOnScroll
= true;
2376 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2378 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2385 //-----------------------------------------------------------------------------
2386 // "button_release_event" from scrollbar
2387 //-----------------------------------------------------------------------------
2390 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2391 GdkEventButton
*WXUNUSED(gdk_event
),
2396 // don't test here as we can release the mouse while being over
2397 // a different window than the slider
2399 // if (gdk_event->window != widget->slider) return FALSE;
2401 g_blockEventsOnScroll
= false;
2403 if (win
->m_isScrolling
)
2405 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2409 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2410 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2412 value
= (int)(win
->m_hAdjust
->value
+0.5);
2415 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2417 value
= (int)(win
->m_vAdjust
->value
+0.5);
2421 wxScrollWinEvent
event( command
, value
, dir
);
2422 event
.SetEventObject( win
);
2423 win
->GetEventHandler()->ProcessEvent( event
);
2426 win
->m_isScrolling
= false;
2432 // ----------------------------------------------------------------------------
2433 // this wxWindowBase function is implemented here (in platform-specific file)
2434 // because it is static and so couldn't be made virtual
2435 // ----------------------------------------------------------------------------
2437 wxWindow
*wxWindowBase::DoFindFocus()
2439 // the cast is necessary when we compile in wxUniversal mode
2440 return (wxWindow
*)g_focusWindow
;
2443 //-----------------------------------------------------------------------------
2444 // "realize" from m_widget
2445 //-----------------------------------------------------------------------------
2447 /* We cannot set colours and fonts before the widget has
2448 been realized, so we do this directly after realization. */
2452 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2457 wxapp_install_idle_handler();
2462 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2463 gtk_im_context_set_client_window( win
->m_imData
->context
,
2464 pizza
->bin_window
);
2468 wxWindowCreateEvent
event( win
);
2469 event
.SetEventObject( win
);
2470 win
->GetEventHandler()->ProcessEvent( event
);
2476 //-----------------------------------------------------------------------------
2478 //-----------------------------------------------------------------------------
2482 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2483 GtkAllocation
*WXUNUSED(alloc
),
2487 wxapp_install_idle_handler();
2489 if (!win
->m_hasScrolling
) return;
2491 int client_width
= 0;
2492 int client_height
= 0;
2493 win
->GetClientSize( &client_width
, &client_height
);
2494 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2497 win
->m_oldClientWidth
= client_width
;
2498 win
->m_oldClientHeight
= client_height
;
2500 if (!win
->m_nativeSizeEvent
)
2502 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2503 event
.SetEventObject( win
);
2504 win
->GetEventHandler()->ProcessEvent( event
);
2511 #define WXUNUSED_UNLESS_XIM(param) param
2513 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2516 /* Resize XIM window */
2520 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2521 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2522 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2525 wxapp_install_idle_handler();
2531 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2535 gdk_window_get_size (widget
->window
, &width
, &height
);
2536 win
->m_icattr
->preedit_area
.width
= width
;
2537 win
->m_icattr
->preedit_area
.height
= height
;
2538 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2544 //-----------------------------------------------------------------------------
2545 // "realize" from m_wxwindow
2546 //-----------------------------------------------------------------------------
2548 /* Initialize XIM support */
2552 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2553 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2556 wxapp_install_idle_handler();
2559 if (win
->m_ic
) return FALSE
;
2560 if (!widget
) return FALSE
;
2561 if (!gdk_im_ready()) return FALSE
;
2563 win
->m_icattr
= gdk_ic_attr_new();
2564 if (!win
->m_icattr
) return FALSE
;
2568 GdkColormap
*colormap
;
2569 GdkICAttr
*attr
= win
->m_icattr
;
2570 unsigned attrmask
= GDK_IC_ALL_REQ
;
2572 GdkIMStyle supported_style
= (GdkIMStyle
)
2573 (GDK_IM_PREEDIT_NONE
|
2574 GDK_IM_PREEDIT_NOTHING
|
2575 GDK_IM_PREEDIT_POSITION
|
2576 GDK_IM_STATUS_NONE
|
2577 GDK_IM_STATUS_NOTHING
);
2579 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2580 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2582 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2583 attr
->client_window
= widget
->window
;
2585 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2586 gtk_widget_get_default_colormap ())
2588 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2589 attr
->preedit_colormap
= colormap
;
2592 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2593 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2594 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2595 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2597 switch (style
& GDK_IM_PREEDIT_MASK
)
2599 case GDK_IM_PREEDIT_POSITION
:
2600 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2602 g_warning ("over-the-spot style requires fontset");
2606 gdk_window_get_size (widget
->window
, &width
, &height
);
2608 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2609 attr
->spot_location
.x
= 0;
2610 attr
->spot_location
.y
= height
;
2611 attr
->preedit_area
.x
= 0;
2612 attr
->preedit_area
.y
= 0;
2613 attr
->preedit_area
.width
= width
;
2614 attr
->preedit_area
.height
= height
;
2615 attr
->preedit_fontset
= widget
->style
->font
;
2620 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2622 if (win
->m_ic
== NULL
)
2623 g_warning ("Can't create input context.");
2626 mask
= gdk_window_get_events (widget
->window
);
2627 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2628 gdk_window_set_events (widget
->window
, mask
);
2630 if (GTK_WIDGET_HAS_FOCUS(widget
))
2631 gdk_im_begin (win
->m_ic
, widget
->window
);
2639 //-----------------------------------------------------------------------------
2640 // InsertChild for wxWindowGTK.
2641 //-----------------------------------------------------------------------------
2643 /* Callback for wxWindowGTK. This very strange beast has to be used because
2644 * C++ has no virtual methods in a constructor. We have to emulate a
2645 * virtual function here as wxNotebook requires a different way to insert
2646 * a child in it. I had opted for creating a wxNotebookPage window class
2647 * which would have made this superfluous (such in the MDI window system),
2648 * but no-one was listening to me... */
2650 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2652 /* the window might have been scrolled already, do we
2653 have to adapt the position */
2654 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2655 child
->m_x
+= pizza
->xoffset
;
2656 child
->m_y
+= pizza
->yoffset
;
2658 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2659 GTK_WIDGET(child
->m_widget
),
2666 //-----------------------------------------------------------------------------
2668 //-----------------------------------------------------------------------------
2670 wxWindow
*wxGetActiveWindow()
2672 return wxWindow::FindFocus();
2675 //-----------------------------------------------------------------------------
2677 //-----------------------------------------------------------------------------
2679 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2681 #ifdef __WXUNIVERSAL__
2682 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2684 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2685 #endif // __WXUNIVERSAL__/__WXGTK__
2687 void wxWindowGTK::Init()
2690 m_widget
= (GtkWidget
*) NULL
;
2691 m_wxwindow
= (GtkWidget
*) NULL
;
2692 m_focusWidget
= (GtkWidget
*) NULL
;
2702 m_needParent
= true;
2703 m_isBeingDeleted
= false;
2706 m_nativeSizeEvent
= false;
2708 m_hasScrolling
= false;
2709 m_isScrolling
= false;
2711 m_hAdjust
= (GtkAdjustment
*) NULL
;
2712 m_vAdjust
= (GtkAdjustment
*) NULL
;
2713 m_oldHorizontalPos
=
2714 m_oldVerticalPos
= 0.0;
2716 m_oldClientHeight
= 0;
2720 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2722 m_acceptsFocus
= false;
2725 m_clipPaintRegion
= false;
2727 m_needsStyleChange
= false;
2729 m_cursor
= *wxSTANDARD_CURSOR
;
2733 m_dirtyTabOrder
= false;
2736 m_ic
= (GdkIC
*) NULL
;
2737 m_icattr
= (GdkICAttr
*) NULL
;
2742 wxWindowGTK::wxWindowGTK()
2747 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2752 const wxString
&name
)
2756 Create( parent
, id
, pos
, size
, style
, name
);
2759 bool wxWindowGTK::Create( wxWindow
*parent
,
2764 const wxString
&name
)
2766 if (!PreCreation( parent
, pos
, size
) ||
2767 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2769 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2773 m_insertCallback
= wxInsertChildInWindow
;
2775 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2776 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2778 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2780 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2781 scroll_class
->scrollbar_spacing
= 0;
2783 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2785 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2786 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2788 m_wxwindow
= gtk_pizza_new();
2790 #ifndef __WXUNIVERSAL__
2791 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2793 if (HasFlag(wxRAISED_BORDER
))
2795 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2797 else if (HasFlag(wxSUNKEN_BORDER
))
2799 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2801 else if (HasFlag(wxSIMPLE_BORDER
))
2803 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2807 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2809 #endif // __WXUNIVERSAL__
2811 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2813 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2814 m_acceptsFocus
= true;
2816 // I _really_ don't want scrollbars in the beginning
2817 m_vAdjust
->lower
= 0.0;
2818 m_vAdjust
->upper
= 1.0;
2819 m_vAdjust
->value
= 0.0;
2820 m_vAdjust
->step_increment
= 1.0;
2821 m_vAdjust
->page_increment
= 1.0;
2822 m_vAdjust
->page_size
= 5.0;
2823 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2824 m_hAdjust
->lower
= 0.0;
2825 m_hAdjust
->upper
= 1.0;
2826 m_hAdjust
->value
= 0.0;
2827 m_hAdjust
->step_increment
= 1.0;
2828 m_hAdjust
->page_increment
= 1.0;
2829 m_hAdjust
->page_size
= 5.0;
2830 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2832 // these handlers block mouse events to any window during scrolling such as
2833 // motion events and prevent GTK and wxWidgets from fighting over where the
2836 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2837 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2839 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2840 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2842 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2843 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2845 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2846 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2848 // these handlers get notified when screen updates are required either when
2849 // scrolling or when the window size (and therefore scrollbar configuration)
2852 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2853 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2854 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2855 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2857 gtk_widget_show( m_wxwindow
);
2860 m_parent
->DoAddChild( this );
2862 m_focusWidget
= m_wxwindow
;
2869 wxWindowGTK::~wxWindowGTK()
2873 if (g_focusWindow
== this)
2874 g_focusWindow
= NULL
;
2876 if ( g_delayedFocus
== this )
2877 g_delayedFocus
= NULL
;
2879 m_isBeingDeleted
= true;
2882 // destroy children before destroying this window itself
2885 // unhook focus handlers to prevent stray events being
2886 // propagated to this (soon to be) dead object
2887 if (m_focusWidget
!= NULL
)
2889 gtk_signal_disconnect_by_func( GTK_OBJECT(m_focusWidget
),
2890 (GtkSignalFunc
) gtk_window_focus_in_callback
, (gpointer
) this );
2891 gtk_signal_disconnect_by_func( GTK_OBJECT(m_focusWidget
),
2892 (GtkSignalFunc
) gtk_window_focus_out_callback
, (gpointer
) this );
2900 gdk_ic_destroy (m_ic
);
2902 gdk_ic_attr_destroy (m_icattr
);
2906 // delete before the widgets to avoid a crash on solaris
2912 gtk_widget_destroy( m_wxwindow
);
2913 m_wxwindow
= (GtkWidget
*) NULL
;
2918 gtk_widget_destroy( m_widget
);
2919 m_widget
= (GtkWidget
*) NULL
;
2923 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2925 wxCHECK_MSG( !m_needParent
|| parent
, false, wxT("Need complete parent.") );
2927 // Use either the given size, or the default if -1 is given.
2928 // See wxWindowBase for these functions.
2929 m_width
= WidthDefault(size
.x
) ;
2930 m_height
= HeightDefault(size
.y
);
2938 void wxWindowGTK::PostCreation()
2940 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2946 // these get reported to wxWidgets -> wxPaintEvent
2948 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2950 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2951 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2954 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2955 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2957 if (!HasFlag(wxFULL_REPAINT_ON_RESIZE
))
2959 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2960 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2963 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2968 // Create input method handler
2969 m_imData
= new wxGtkIMData
;
2971 // Cannot handle drawing preedited text yet
2972 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2974 g_signal_connect (G_OBJECT (m_imData
->context
), "commit",
2975 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2978 // these are called when the "sunken" or "raised" borders are drawn
2979 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2980 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2983 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2984 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2990 if (!GTK_IS_WINDOW(m_widget
))
2992 if (m_focusWidget
== NULL
)
2993 m_focusWidget
= m_widget
;
2995 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2996 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2998 gtk_signal_connect_after( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2999 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
3002 // connect to the various key and mouse handlers
3004 GtkWidget
*connect_widget
= GetConnectWidget();
3006 ConnectWidget( connect_widget
);
3008 /* We cannot set colours, fonts and cursors before the widget has
3009 been realized, so we do this directly after realization */
3010 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
3011 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
3015 // Catch native resize events
3016 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
3017 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
3019 // Initialize XIM support
3020 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
3021 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
3023 // And resize XIM window
3024 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
3025 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
3028 if (GTK_IS_COMBO(m_widget
))
3030 GtkCombo
*gcombo
= GTK_COMBO(m_widget
);
3032 gtk_signal_connect( GTK_OBJECT(gcombo
->entry
), "size_request",
3033 GTK_SIGNAL_FUNC(wxgtk_combo_size_request_callback
),
3038 // This is needed if we want to add our windows into native
3039 // GTK controls, such as the toolbar. With this callback, the
3040 // toolbar gets to know the correct size (the one set by the
3041 // programmer). Sadly, it misbehaves for wxComboBox.
3042 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
3043 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback
),
3047 InheritAttributes();
3051 // unless the window was created initially hidden (i.e. Hide() had been
3052 // called before Create()), we should show it at GTK+ level as well
3054 gtk_widget_show( m_widget
);
3057 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
3059 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
3060 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
3062 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
3063 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
3065 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
3066 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
3068 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
3069 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
3071 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
3072 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
3075 gtk_signal_connect( GTK_OBJECT(widget
), "scroll_event",
3076 GTK_SIGNAL_FUNC(gtk_window_wheel_callback
), (gpointer
)this );
3077 g_signal_connect(widget
, "popup_menu",
3078 G_CALLBACK(wxgtk_window_popup_menu_callback
), this);
3081 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
3082 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
3084 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
3085 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
3088 bool wxWindowGTK::Destroy()
3090 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3094 return wxWindowBase::Destroy();
3097 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
3099 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
3102 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
3104 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3105 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
3108 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
3111 if (m_resizing
) return; /* I don't like recursions */
3114 int currentX
, currentY
;
3115 GetPosition(¤tX
, ¤tY
);
3116 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
3118 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
3120 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
3122 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
3124 /* don't set the size for children of wxNotebook, just take the values. */
3132 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3133 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
3135 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
3136 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
3140 m_x
= x
+ pizza
->xoffset
;
3141 m_y
= y
+ pizza
->yoffset
;
3144 // calculate the best size if we should auto size the window
3145 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
3146 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
3148 const wxSize sizeBest
= GetBestSize();
3149 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
3151 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
3152 height
= sizeBest
.y
;
3160 int minWidth
= GetMinWidth(),
3161 minHeight
= GetMinHeight(),
3162 maxWidth
= GetMaxWidth(),
3163 maxHeight
= GetMaxHeight();
3165 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
3166 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
3167 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
3168 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
3170 int left_border
= 0;
3171 int right_border
= 0;
3173 int bottom_border
= 0;
3175 /* the default button has a border around it */
3176 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
3179 GtkBorder
*default_border
= NULL
;
3180 gtk_widget_style_get( m_widget
, "default_border", &default_border
, NULL
);
3183 left_border
+= default_border
->left
;
3184 right_border
+= default_border
->right
;
3185 top_border
+= default_border
->top
;
3186 bottom_border
+= default_border
->bottom
;
3187 g_free( default_border
);
3197 DoMoveWindow( m_x
-top_border
,
3199 m_width
+left_border
+right_border
,
3200 m_height
+top_border
+bottom_border
);
3205 /* Sometimes the client area changes size without the
3206 whole windows's size changing, but if the whole
3207 windows's size doesn't change, no wxSizeEvent will
3208 normally be sent. Here we add an extra test if
3209 the client test has been changed and this will
3211 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
3215 wxPrintf( "OnSize sent from " );
3216 if (GetClassInfo() && GetClassInfo()->GetClassName())
3217 wxPrintf( GetClassInfo()->GetClassName() );
3218 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3221 if (!m_nativeSizeEvent
)
3223 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
3224 event
.SetEventObject( this );
3225 GetEventHandler()->ProcessEvent( event
);
3231 void wxWindowGTK::OnInternalIdle()
3234 if ( m_dirtyTabOrder
)
3237 // Update style if the window was not yet realized
3238 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
3239 if (m_needsStyleChange
)
3241 SetBackgroundStyle(GetBackgroundStyle());
3242 m_needsStyleChange
= false;
3245 // Update invalidated regions.
3248 wxCursor cursor
= m_cursor
;
3249 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3253 /* I now set the cursor anew in every OnInternalIdle call
3254 as setting the cursor in a parent window also effects the
3255 windows above so that checking for the current cursor is
3260 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3262 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3264 if (!g_globalCursor
.Ok())
3265 cursor
= *wxSTANDARD_CURSOR
;
3267 window
= m_widget
->window
;
3268 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3269 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3275 GdkWindow
*window
= m_widget
->window
;
3276 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3277 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3282 if (wxUpdateUIEvent::CanUpdate(this))
3283 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3286 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3288 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3290 if (width
) (*width
) = m_width
;
3291 if (height
) (*height
) = m_height
;
3294 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3296 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3300 SetSize( width
, height
);
3307 #ifndef __WXUNIVERSAL__
3308 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3310 /* when using GTK 1.2 we set the shadow border size to 2 */
3314 if (HasFlag(wxSIMPLE_BORDER
))
3316 /* when using GTK 1.2 we set the simple border size to 1 */
3320 #endif // __WXUNIVERSAL__
3324 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3326 GtkRequisition vscroll_req
;
3327 vscroll_req
.width
= 2;
3328 vscroll_req
.height
= 2;
3329 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3330 (scroll_window
->vscrollbar
, &vscroll_req
);
3332 GtkRequisition hscroll_req
;
3333 hscroll_req
.width
= 2;
3334 hscroll_req
.height
= 2;
3335 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3336 (scroll_window
->hscrollbar
, &hscroll_req
);
3338 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3340 if (scroll_window
->vscrollbar_visible
)
3342 dw
+= vscroll_req
.width
;
3343 dw
+= scroll_class
->scrollbar_spacing
;
3346 if (scroll_window
->hscrollbar_visible
)
3348 dh
+= hscroll_req
.height
;
3349 dh
+= scroll_class
->scrollbar_spacing
;
3353 SetSize( width
+dw
, height
+dh
);
3357 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3359 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3363 if (width
) (*width
) = m_width
;
3364 if (height
) (*height
) = m_height
;
3371 #ifndef __WXUNIVERSAL__
3372 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3374 /* when using GTK 1.2 we set the shadow border size to 2 */
3378 if (HasFlag(wxSIMPLE_BORDER
))
3380 /* when using GTK 1.2 we set the simple border size to 1 */
3384 #endif // __WXUNIVERSAL__
3388 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3390 GtkRequisition vscroll_req
;
3391 vscroll_req
.width
= 2;
3392 vscroll_req
.height
= 2;
3393 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3394 (scroll_window
->vscrollbar
, &vscroll_req
);
3396 GtkRequisition hscroll_req
;
3397 hscroll_req
.width
= 2;
3398 hscroll_req
.height
= 2;
3399 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3400 (scroll_window
->hscrollbar
, &hscroll_req
);
3402 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3404 if (scroll_window
->vscrollbar_visible
)
3406 dw
+= vscroll_req
.width
;
3407 dw
+= scroll_class
->scrollbar_spacing
;
3410 if (scroll_window
->hscrollbar_visible
)
3412 dh
+= hscroll_req
.height
;
3413 dh
+= scroll_class
->scrollbar_spacing
;
3417 if (width
) (*width
) = m_width
- dw
;
3418 if (height
) (*height
) = m_height
- dh
;
3422 printf( "GetClientSize, name %s ", GetName().c_str() );
3423 if (width) printf( " width = %d", (*width) );
3424 if (height) printf( " height = %d", (*height) );
3429 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3431 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3435 if (m_parent
&& m_parent
->m_wxwindow
)
3437 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3438 dx
= pizza
->xoffset
;
3439 dy
= pizza
->yoffset
;
3442 if (x
) (*x
) = m_x
- dx
;
3443 if (y
) (*y
) = m_y
- dy
;
3446 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3448 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3450 if (!m_widget
->window
) return;
3452 GdkWindow
*source
= (GdkWindow
*) NULL
;
3454 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3456 source
= m_widget
->window
;
3460 gdk_window_get_origin( source
, &org_x
, &org_y
);
3464 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3466 org_x
+= m_widget
->allocation
.x
;
3467 org_y
+= m_widget
->allocation
.y
;
3475 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3477 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3479 if (!m_widget
->window
) return;
3481 GdkWindow
*source
= (GdkWindow
*) NULL
;
3483 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3485 source
= m_widget
->window
;
3489 gdk_window_get_origin( source
, &org_x
, &org_y
);
3493 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3495 org_x
+= m_widget
->allocation
.x
;
3496 org_y
+= m_widget
->allocation
.y
;
3504 bool wxWindowGTK::Show( bool show
)
3506 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3508 if (!wxWindowBase::Show(show
))
3515 gtk_widget_show( m_widget
);
3517 gtk_widget_hide( m_widget
);
3519 wxShowEvent
eventShow(GetId(), show
);
3520 eventShow
.SetEventObject(this);
3522 GetEventHandler()->ProcessEvent(eventShow
);
3527 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3529 win
->OnParentEnable(enable
);
3531 // Recurse, so that children have the opportunity to Do The Right Thing
3532 // and reset colours that have been messed up by a parent's (really ancestor's)
3534 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3536 node
= node
->GetNext() )
3538 wxWindow
*child
= node
->GetData();
3539 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3540 wxWindowNotifyEnable(child
, enable
);
3544 bool wxWindowGTK::Enable( bool enable
)
3546 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3548 if (!wxWindowBase::Enable(enable
))
3554 gtk_widget_set_sensitive( m_widget
, enable
);
3556 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3558 wxWindowNotifyEnable(this, enable
);
3563 int wxWindowGTK::GetCharHeight() const
3565 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3567 wxFont font
= GetFont();
3568 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3571 PangoContext
*context
= NULL
;
3573 context
= gtk_widget_get_pango_context( m_widget
);
3578 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3579 PangoLayout
*layout
= pango_layout_new(context
);
3580 pango_layout_set_font_description(layout
, desc
);
3581 pango_layout_set_text(layout
, "H", 1);
3582 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3584 PangoRectangle rect
;
3585 pango_layout_line_get_extents(line
, NULL
, &rect
);
3587 g_object_unref( G_OBJECT( layout
) );
3589 return (int) PANGO_PIXELS(rect
.height
);
3591 GdkFont
*gfont
= font
.GetInternalFont( 1.0 );
3593 return gfont
->ascent
+ gfont
->descent
;
3597 int wxWindowGTK::GetCharWidth() const
3599 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3601 wxFont font
= GetFont();
3602 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3605 PangoContext
*context
= NULL
;
3607 context
= gtk_widget_get_pango_context( m_widget
);
3612 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3613 PangoLayout
*layout
= pango_layout_new(context
);
3614 pango_layout_set_font_description(layout
, desc
);
3615 pango_layout_set_text(layout
, "g", 1);
3616 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3618 PangoRectangle rect
;
3619 pango_layout_line_get_extents(line
, NULL
, &rect
);
3621 g_object_unref( G_OBJECT( layout
) );
3623 return (int) PANGO_PIXELS(rect
.width
);
3625 GdkFont
*gfont
= font
.GetInternalFont( 1.0 );
3627 return gdk_string_width( gfont
, "g" );
3631 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3635 int *externalLeading
,
3636 const wxFont
*theFont
) const
3638 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3640 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3650 PangoContext
*context
= NULL
;
3652 context
= gtk_widget_get_pango_context( m_widget
);
3661 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3662 PangoLayout
*layout
= pango_layout_new(context
);
3663 pango_layout_set_font_description(layout
, desc
);
3666 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3667 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3669 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3670 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3671 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3675 PangoRectangle rect
;
3676 pango_layout_get_extents(layout
, NULL
, &rect
);
3678 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3679 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3682 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3683 int baseline
= pango_layout_iter_get_baseline(iter
);
3684 pango_layout_iter_free(iter
);
3685 *descent
= *y
- PANGO_PIXELS(baseline
);
3687 if (externalLeading
) (*externalLeading
) = 0; // ??
3689 g_object_unref( G_OBJECT( layout
) );
3691 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3692 if (x
) (*x
) = gdk_string_width( font
, wxGTK_CONV( string
) );
3693 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3694 if (descent
) (*descent
) = font
->descent
;
3695 if (externalLeading
) (*externalLeading
) = 0; // ??
3699 void wxWindowGTK::SetFocus()
3701 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3704 // don't do anything if we already have focus
3710 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3712 gtk_widget_grab_focus (m_wxwindow
);
3718 if (GTK_IS_CONTAINER(m_widget
))
3720 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3724 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3727 if (!GTK_WIDGET_REALIZED(m_widget
))
3729 // we can't set the focus to the widget now so we remember that
3730 // it should be focused and will do it later, during the idle
3731 // time, as soon as we can
3732 wxLogTrace(TRACE_FOCUS
,
3733 _T("Delaying setting focus to %s(%s)"),
3734 GetClassInfo()->GetClassName(), GetLabel().c_str());
3736 g_delayedFocus
= this;
3740 wxLogTrace(TRACE_FOCUS
,
3741 _T("Setting focus to %s(%s)"),
3742 GetClassInfo()->GetClassName(), GetLabel().c_str());
3744 gtk_widget_grab_focus (m_widget
);
3749 if (GTK_IS_CONTAINER(m_widget
))
3751 gtk_container_focus( GTK_CONTAINER(m_widget
), GTK_DIR_TAB_FORWARD
);
3756 wxLogTrace(TRACE_FOCUS
,
3757 _T("Can't set focus to %s(%s)"),
3758 GetClassInfo()->GetClassName(), GetLabel().c_str());
3763 bool wxWindowGTK::AcceptsFocus() const
3765 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3768 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3770 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3772 wxWindowGTK
*oldParent
= m_parent
,
3773 *newParent
= (wxWindowGTK
*)newParentBase
;
3775 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3777 if ( !wxWindowBase::Reparent(newParent
) )
3780 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3782 /* prevent GTK from deleting the widget arbitrarily */
3783 gtk_widget_ref( m_widget
);
3787 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3790 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3794 /* insert GTK representation */
3795 (*(newParent
->m_insertCallback
))(newParent
, this);
3798 /* reverse: prevent GTK from deleting the widget arbitrarily */
3799 gtk_widget_unref( m_widget
);
3804 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3806 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3808 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3810 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3815 /* insert GTK representation */
3816 (*m_insertCallback
)(this, child
);
3821 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3823 wxWindowBase::AddChild(child
);
3824 m_dirtyTabOrder
= true;
3826 wxapp_install_idle_handler();
3829 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3831 wxWindowBase::RemoveChild(child
);
3832 m_dirtyTabOrder
= true;
3834 wxapp_install_idle_handler();
3837 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3839 wxWindowBase::DoMoveInTabOrder(win
, move
);
3840 m_dirtyTabOrder
= true;
3842 wxapp_install_idle_handler();
3845 void wxWindowGTK::RealizeTabOrder()
3849 if (m_children
.size() > 0)
3851 GList
*chain
= NULL
;
3853 for (wxWindowList::const_iterator i
= m_children
.begin();
3854 i
!= m_children
.end(); ++i
)
3856 chain
= g_list_prepend(chain
, (*i
)->m_widget
);
3859 chain
= g_list_reverse(chain
);
3861 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3866 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3870 m_dirtyTabOrder
= false;
3873 #endif // __WXGTK20__
3875 void wxWindowGTK::Raise()
3877 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3879 if (m_wxwindow
&& m_wxwindow
->window
)
3881 gdk_window_raise( m_wxwindow
->window
);
3883 else if (m_widget
->window
)
3885 gdk_window_raise( m_widget
->window
);
3889 void wxWindowGTK::Lower()
3891 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3893 if (m_wxwindow
&& m_wxwindow
->window
)
3895 gdk_window_lower( m_wxwindow
->window
);
3897 else if (m_widget
->window
)
3899 gdk_window_lower( m_widget
->window
);
3903 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3905 wxCHECK_MSG( (m_widget
!= NULL
), false, wxT("invalid window") );
3907 if (cursor
== m_cursor
)
3911 wxapp_install_idle_handler();
3913 if (cursor
== wxNullCursor
)
3914 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3916 return wxWindowBase::SetCursor( cursor
);
3919 void wxWindowGTK::WarpPointer( int x
, int y
)
3921 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3923 // We provide this function ourselves as it is
3924 // missing in GDK (top of this file).
3926 GdkWindow
*window
= (GdkWindow
*) NULL
;
3928 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3930 window
= GetConnectWidget()->window
;
3933 gdk_window_warp_pointer( window
, x
, y
);
3937 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3941 if (!m_widget
->window
)
3946 wxapp_install_idle_handler();
3949 if (m_wxwindow
&& rect
)
3951 myRect
.SetSize(wxSize( m_wxwindow
->allocation
.width
,
3952 m_wxwindow
->allocation
.height
));
3953 if ( myRect
.Intersect(*rect
).IsEmpty() )
3955 // nothing to do, rectangle is empty
3962 // schedule the area for later updating in GtkUpdate()
3963 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3967 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3971 m_clearRegion
.Clear();
3972 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3980 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3984 GdkRectangle gdk_rect
;
3985 gdk_rect
.x
= rect
->x
;
3986 gdk_rect
.y
= rect
->y
;
3987 gdk_rect
.width
= rect
->width
;
3988 gdk_rect
.height
= rect
->height
;
3989 gtk_widget_draw( m_widget
, &gdk_rect
);
3996 m_updateRegion
.Clear();
3997 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
4001 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
4007 GdkRectangle gdk_rect
,
4011 gdk_rect
.x
= rect
->x
;
4012 gdk_rect
.y
= rect
->y
;
4013 gdk_rect
.width
= rect
->width
;
4014 gdk_rect
.height
= rect
->height
;
4017 else // invalidate everything
4022 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, p
, TRUE
);
4027 void wxWindowGTK::Update()
4031 // when we call Update() we really want to update the window immediately on
4032 // screen, even if it means flushing the entire queue and hence slowing down
4033 // everything -- but it should still be done, it's just that Update() should
4034 // be called very rarely
4038 void wxWindowGTK::GtkUpdate()
4041 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
4042 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
4044 if (!m_updateRegion
.IsEmpty())
4045 GtkSendPaintEvents();
4048 // for consistency with other platforms (and also because it's convenient
4049 // to be able to update an entire TLW by calling Update() only once), we
4050 // should also update all our children here
4051 for ( wxWindowList::compatibility_iterator node
= GetChildren().GetFirst();
4053 node
= node
->GetNext() )
4055 node
->GetData()->GtkUpdate();
4059 void wxWindowGTK::GtkSendPaintEvents()
4064 m_clearRegion
.Clear();
4066 m_updateRegion
.Clear();
4070 // Clip to paint region in wxClientDC
4071 m_clipPaintRegion
= true;
4073 // widget to draw on
4074 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
4076 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM
))
4078 // find ancestor from which to steal background
4079 wxWindow
*parent
= wxGetTopLevelParent((wxWindow
*)this);
4081 parent
= (wxWindow
*)this;
4083 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
4085 wxRegionIterator
upd( m_updateRegion
);
4089 rect
.x
= upd
.GetX();
4090 rect
.y
= upd
.GetY();
4091 rect
.width
= upd
.GetWidth();
4092 rect
.height
= upd
.GetHeight();
4094 gtk_paint_flat_box( parent
->m_widget
->style
,
4096 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
4111 wxWindowDC
dc( (wxWindow
*)this );
4112 dc
.SetClippingRegion( m_updateRegion
);
4114 wxEraseEvent
erase_event( GetId(), &dc
);
4115 erase_event
.SetEventObject( this );
4117 GetEventHandler()->ProcessEvent(erase_event
);
4120 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
4122 wxWindowDC
dc( (wxWindow
*)this );
4123 if (m_clearRegion
.IsEmpty())
4124 dc
.SetClippingRegion( m_updateRegion
);
4126 dc
.SetClippingRegion( m_clearRegion
);
4128 wxEraseEvent
erase_event( GetId(), &dc
);
4129 erase_event
.SetEventObject( this );
4131 if (!GetEventHandler()->ProcessEvent(erase_event
) && GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
4135 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
4136 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
4138 gdk_gc_set_foreground( g_eraseGC
, GetBackgroundColour().GetColor() );
4140 wxRegionIterator
upd( m_clearRegion
);
4143 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
4144 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
4148 m_clearRegion
.Clear();
4152 wxNcPaintEvent
nc_paint_event( GetId() );
4153 nc_paint_event
.SetEventObject( this );
4154 GetEventHandler()->ProcessEvent( nc_paint_event
);
4156 wxPaintEvent
paint_event( GetId() );
4157 paint_event
.SetEventObject( this );
4158 GetEventHandler()->ProcessEvent( paint_event
);
4160 m_clipPaintRegion
= false;
4162 #if !defined(__WXUNIVERSAL__) && !defined(__WXGTK20__)
4163 // The following code will result in all window-less widgets
4164 // being redrawn because the wxWidgets class is allowed to
4165 // paint over the window-less widgets.
4167 GList
*children
= pizza
->children
;
4170 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
4171 children
= children
->next
;
4173 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
4174 GTK_WIDGET_DRAWABLE (child
->widget
))
4176 // Get intersection of widget area and update region
4177 wxRegion
region( m_updateRegion
);
4179 GdkEventExpose gdk_event
;
4180 gdk_event
.type
= GDK_EXPOSE
;
4181 gdk_event
.window
= pizza
->bin_window
;
4182 gdk_event
.count
= 0;
4183 gdk_event
.send_event
= TRUE
;
4185 wxRegionIterator
upd( m_updateRegion
);
4189 rect
.x
= upd
.GetX();
4190 rect
.y
= upd
.GetY();
4191 rect
.width
= upd
.GetWidth();
4192 rect
.height
= upd
.GetHeight();
4194 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
4196 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
4203 #endif // native GTK 1
4205 m_updateRegion
.Clear();
4208 void wxWindowGTK::ClearBackground()
4210 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4213 if (m_wxwindow
&& m_wxwindow
->window
)
4215 m_clearRegion
.Clear();
4216 wxSize
size( GetClientSize() );
4217 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
4219 // Better do this in idle?
4226 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
4228 wxWindowBase::DoSetToolTip(tip
);
4231 m_tooltip
->Apply( (wxWindow
*)this );
4234 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
4236 wxString
tmp( tip
);
4237 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
4239 #endif // wxUSE_TOOLTIPS
4241 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
4243 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4245 if (!wxWindowBase::SetBackgroundColour(colour
))
4250 // We need the pixel value e.g. for background clearing.
4251 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
4254 // apply style change (forceStyle=true so that new style is applied
4255 // even if the bg colour changed from valid to wxNullColour)
4256 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
4257 ApplyWidgetStyle(true);
4262 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
4264 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4266 if (!wxWindowBase::SetForegroundColour(colour
))
4273 // We need the pixel value e.g. for background clearing.
4274 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
4277 // apply style change (forceStyle=true so that new style is applied
4278 // even if the bg colour changed from valid to wxNullColour):
4279 ApplyWidgetStyle(true);
4285 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
4287 return gtk_widget_get_pango_context( m_widget
);
4291 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
4293 // do we need to apply any changes at all?
4296 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
4301 GtkRcStyle
*style
= gtk_rc_style_new();
4307 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
4309 wxString xfontname
= m_font
.GetNativeFontInfo()->GetXFontName();
4310 style
->fontset_name
= g_strdup(xfontname
.c_str());
4314 if ( m_foregroundColour
.Ok() )
4316 GdkColor
*fg
= m_foregroundColour
.GetColor();
4318 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
4319 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
4321 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
4322 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
4324 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
4325 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
4328 if ( m_backgroundColour
.Ok() )
4330 GdkColor
*bg
= m_backgroundColour
.GetColor();
4332 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
4333 style
->base
[GTK_STATE_NORMAL
] = *bg
;
4334 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
4335 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
4337 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
4338 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
4339 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
4340 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
4342 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
4343 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
4344 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
4345 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4347 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
4348 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
4349 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
4350 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4356 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
4358 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
4361 DoApplyWidgetStyle(style
);
4362 gtk_rc_style_unref(style
);
4365 // Style change may affect GTK+'s size calculation:
4366 InvalidateBestSize();
4369 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
4372 gtk_widget_modify_style(m_wxwindow
, style
);
4374 gtk_widget_modify_style(m_widget
, style
);
4377 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
4379 wxWindowBase::SetBackgroundStyle(style
);
4381 if (style
== wxBG_STYLE_CUSTOM
)
4383 GdkWindow
*window
= (GdkWindow
*) NULL
;
4385 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4387 window
= GetConnectWidget()->window
;
4391 // Make sure GDK/X11 doesn't refresh the window
4393 gdk_window_set_back_pixmap( window
, None
, False
);
4395 Display
* display
= GDK_WINDOW_DISPLAY(window
);
4398 m_needsStyleChange
= false;
4401 // Do in OnIdle, because the window is not yet available
4402 m_needsStyleChange
= true;
4404 // Don't apply widget style, or we get a grey background
4408 // apply style change (forceStyle=true so that new style is applied
4409 // even if the bg colour changed from valid to wxNullColour):
4410 ApplyWidgetStyle(true);
4415 //-----------------------------------------------------------------------------
4416 // Pop-up menu stuff
4417 //-----------------------------------------------------------------------------
4419 #if wxUSE_MENUS_NATIVE
4421 extern "C" WXDLLIMPEXP_CORE
4422 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
4424 *is_waiting
= FALSE
;
4427 WXDLLIMPEXP_CORE
void SetInvokingWindow( wxMenu
*menu
, wxWindow
* win
)
4429 menu
->SetInvokingWindow( win
);
4431 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
4434 wxMenuItem
*menuitem
= node
->GetData();
4435 if (menuitem
->IsSubMenu())
4437 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
4440 node
= node
->GetNext();
4444 extern "C" WXDLLIMPEXP_CORE
4445 void wxPopupMenuPositionCallback( GtkMenu
*menu
,
4448 gboolean
* WXUNUSED(whatever
),
4450 gpointer user_data
)
4452 // ensure that the menu appears entirely on screen
4454 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
4456 wxSize sizeScreen
= wxGetDisplaySize();
4457 wxPoint
*pos
= (wxPoint
*)user_data
;
4459 gint xmax
= sizeScreen
.x
- req
.width
,
4460 ymax
= sizeScreen
.y
- req
.height
;
4462 *x
= pos
->x
< xmax
? pos
->x
: xmax
;
4463 *y
= pos
->y
< ymax
? pos
->y
: ymax
;
4466 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4468 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4470 wxCHECK_MSG( menu
!= NULL
, false, wxT("invalid popup-menu") );
4472 // NOTE: if you change this code, you need to update
4473 // the same code in taskbar.cpp as well. This
4474 // is ugly code duplication, I know.
4476 SetInvokingWindow( menu
, this );
4480 bool is_waiting
= true;
4482 gulong handler
= gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
4484 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
4485 (gpointer
)&is_waiting
);
4489 GtkMenuPositionFunc posfunc
;
4490 if ( x
== -1 && y
== -1 )
4492 // use GTK's default positioning algorithm
4498 pos
= ClientToScreen(wxPoint(x
, y
));
4500 posfunc
= wxPopupMenuPositionCallback
;
4504 GTK_MENU(menu
->m_menu
),
4505 (GtkWidget
*) NULL
, // parent menu shell
4506 (GtkWidget
*) NULL
, // parent menu item
4507 posfunc
, // function to position it
4508 userdata
, // client data
4509 0, // button used to activate it
4511 gtk_get_current_event_time()
4513 gs_timeLastClick
// the time of activation
4519 gtk_main_iteration();
4522 gtk_signal_disconnect(GTK_OBJECT(menu
->m_menu
), handler
);
4527 #endif // wxUSE_MENUS_NATIVE
4529 #if wxUSE_DRAG_AND_DROP
4531 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4533 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4535 GtkWidget
*dnd_widget
= GetConnectWidget();
4537 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4539 if (m_dropTarget
) delete m_dropTarget
;
4540 m_dropTarget
= dropTarget
;
4542 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4545 #endif // wxUSE_DRAG_AND_DROP
4547 GtkWidget
* wxWindowGTK::GetConnectWidget()
4549 GtkWidget
*connect_widget
= m_widget
;
4550 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4552 return connect_widget
;
4555 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4558 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4560 return (window
== m_widget
->window
);
4563 bool wxWindowGTK::SetFont( const wxFont
&font
)
4565 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4567 if (!wxWindowBase::SetFont(font
))
4570 // apply style change (forceStyle=true so that new style is applied
4571 // even if the font changed from valid to wxNullFont):
4572 ApplyWidgetStyle(true);
4577 void wxWindowGTK::DoCaptureMouse()
4579 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4581 GdkWindow
*window
= (GdkWindow
*) NULL
;
4583 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4585 window
= GetConnectWidget()->window
;
4587 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4589 wxCursor
* cursor
= & m_cursor
;
4591 cursor
= wxSTANDARD_CURSOR
;
4593 gdk_pointer_grab( window
, FALSE
,
4595 (GDK_BUTTON_PRESS_MASK
|
4596 GDK_BUTTON_RELEASE_MASK
|
4597 GDK_POINTER_MOTION_HINT_MASK
|
4598 GDK_POINTER_MOTION_MASK
),
4600 cursor
->GetCursor(),
4601 (guint32
)GDK_CURRENT_TIME
);
4602 g_captureWindow
= this;
4603 g_captureWindowHasMouse
= true;
4606 void wxWindowGTK::DoReleaseMouse()
4608 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4610 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4612 g_captureWindow
= (wxWindowGTK
*) NULL
;
4614 GdkWindow
*window
= (GdkWindow
*) NULL
;
4616 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4618 window
= GetConnectWidget()->window
;
4623 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4627 wxWindow
*wxWindowBase::GetCapture()
4629 return (wxWindow
*)g_captureWindow
;
4632 bool wxWindowGTK::IsRetained() const
4637 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4638 int range
, bool refresh
)
4640 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4642 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4644 m_hasScrolling
= true;
4646 if (orient
== wxHORIZONTAL
)
4648 float fpos
= (float)pos
;
4649 float frange
= (float)range
;
4650 float fthumb
= (float)thumbVisible
;
4651 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4652 if (fpos
< 0.0) fpos
= 0.0;
4654 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4655 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4657 SetScrollPos( orient
, pos
, refresh
);
4661 m_oldHorizontalPos
= fpos
;
4663 m_hAdjust
->lower
= 0.0;
4664 m_hAdjust
->upper
= frange
;
4665 m_hAdjust
->value
= fpos
;
4666 m_hAdjust
->step_increment
= 1.0;
4667 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4668 m_hAdjust
->page_size
= fthumb
;
4672 float fpos
= (float)pos
;
4673 float frange
= (float)range
;
4674 float fthumb
= (float)thumbVisible
;
4675 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4676 if (fpos
< 0.0) fpos
= 0.0;
4678 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4679 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4681 SetScrollPos( orient
, pos
, refresh
);
4685 m_oldVerticalPos
= fpos
;
4687 m_vAdjust
->lower
= 0.0;
4688 m_vAdjust
->upper
= frange
;
4689 m_vAdjust
->value
= fpos
;
4690 m_vAdjust
->step_increment
= 1.0;
4691 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4692 m_vAdjust
->page_size
= fthumb
;
4695 if (orient
== wxHORIZONTAL
)
4696 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4698 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4701 void wxWindowGTK::GtkUpdateScrollbar(int orient
)
4703 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4704 GtkSignalFunc fn
= orient
== wxHORIZONTAL
4705 ? (GtkSignalFunc
)gtk_window_hscroll_callback
4706 : (GtkSignalFunc
)gtk_window_vscroll_callback
;
4708 gtk_signal_disconnect_by_func(GTK_OBJECT(adj
), fn
, (gpointer
)this);
4709 gtk_signal_emit_by_name(GTK_OBJECT(adj
), "value_changed");
4710 gtk_signal_connect(GTK_OBJECT(adj
), "value_changed", fn
, (gpointer
)this);
4713 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4715 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4716 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4718 GtkAdjustment
*adj
= orient
== wxHORIZONTAL
? m_hAdjust
: m_vAdjust
;
4720 float fpos
= (float)pos
;
4721 if (fpos
> adj
->upper
- adj
->page_size
)
4722 fpos
= adj
->upper
- adj
->page_size
;
4725 *(orient
== wxHORIZONTAL
? &m_oldHorizontalPos
: &m_oldVerticalPos
) = fpos
;
4727 if (fabs(fpos
-adj
->value
) < 0.2)
4731 if ( m_wxwindow
->window
)
4736 int wxWindowGTK::GetScrollThumb( int orient
) const
4738 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4740 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4742 if (orient
== wxHORIZONTAL
)
4743 return (int)(m_hAdjust
->page_size
+0.5);
4745 return (int)(m_vAdjust
->page_size
+0.5);
4748 int wxWindowGTK::GetScrollPos( int orient
) const
4750 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4752 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4754 if (orient
== wxHORIZONTAL
)
4755 return (int)(m_hAdjust
->value
+0.5);
4757 return (int)(m_vAdjust
->value
+0.5);
4760 int wxWindowGTK::GetScrollRange( int orient
) const
4762 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4764 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4766 if (orient
== wxHORIZONTAL
)
4767 return (int)(m_hAdjust
->upper
+0.5);
4769 return (int)(m_vAdjust
->upper
+0.5);
4772 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4774 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4776 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4778 // No scrolling requested.
4779 if ((dx
== 0) && (dy
== 0)) return;
4782 if (!m_updateRegion
.IsEmpty())
4784 m_updateRegion
.Offset( dx
, dy
);
4788 GetClientSize( &cw
, &ch
);
4789 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4792 if (!m_clearRegion
.IsEmpty())
4794 m_clearRegion
.Offset( dx
, dy
);
4798 GetClientSize( &cw
, &ch
);
4799 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4803 m_clipPaintRegion
= true;
4805 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4807 m_clipPaintRegion
= false;
4810 void wxWindowGTK::SetWindowStyleFlag( long style
)
4812 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4813 wxWindowBase::SetWindowStyleFlag(style
);
4816 // Find the wxWindow at the current mouse position, also returning the mouse
4818 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4820 pt
= wxGetMousePosition();
4821 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4825 // Get the current mouse position.
4826 wxPoint
wxGetMousePosition()
4828 /* This crashes when used within wxHelpContext,
4829 so we have to use the X-specific implementation below.
4831 GdkModifierType *mask;
4832 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4834 return wxPoint(x, y);
4838 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4840 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4841 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4842 Window rootReturn
, childReturn
;
4843 int rootX
, rootY
, winX
, winY
;
4844 unsigned int maskReturn
;
4846 XQueryPointer (display
,
4850 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4851 return wxPoint(rootX
, rootY
);
4855 // ----------------------------------------------------------------------------
4857 // ----------------------------------------------------------------------------
4859 class wxWinModule
: public wxModule
4866 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4869 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4871 bool wxWinModule::OnInit()
4873 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4874 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4879 void wxWinModule::OnExit()
4882 gdk_gc_unref( g_eraseGC
);