1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
11 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
12 #pragma implementation "window.h"
15 // For compilers that support precompilation, includes "wx.h".
16 #include "wx/wxprec.h"
19 #define XWarpPointer XWARPPOINTER
22 #include "wx/window.h"
23 #include "wx/dcclient.h"
26 #include "wx/layout.h"
28 #include "wx/dialog.h"
29 #include "wx/msgdlg.h"
30 #include "wx/module.h"
32 #if wxUSE_DRAG_AND_DROP
37 #include "wx/tooltip.h"
45 #include "wx/textctrl.h"
49 #include "wx/statusbr.h"
51 #include "wx/settings.h"
53 #include "wx/fontutil.h"
56 #include "wx/thread.h"
62 #include "wx/gtk/private.h"
63 #include <gdk/gdkprivate.h>
64 #include <gdk/gdkkeysyms.h>
68 #include <gtk/gtkprivate.h>
70 #include "wx/gtk/win_gtk.h"
73 #include <pango/pangox.h>
84 extern GtkContainerClass
*pizza_parent_class
;
87 //-----------------------------------------------------------------------------
88 // documentation on internals
89 //-----------------------------------------------------------------------------
92 I have been asked several times about writing some documentation about
93 the GTK port of wxWidgets, especially its internal structures. Obviously,
94 you cannot understand wxGTK without knowing a little about the GTK, but
95 some more information about what the wxWindow, which is the base class
96 for all other window classes, does seems required as well.
100 What does wxWindow do? It contains the common interface for the following
101 jobs of its descendants:
103 1) Define the rudimentary behaviour common to all window classes, such as
104 resizing, intercepting user input (so as to make it possible to use these
105 events for special purposes in a derived class), window names etc.
107 2) Provide the possibility to contain and manage children, if the derived
108 class is allowed to contain children, which holds true for those window
109 classes which do not display a native GTK widget. To name them, these
110 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
111 work classes are a special case and are handled a bit differently from
112 the rest. The same holds true for the wxNotebook class.
114 3) Provide the possibility to draw into a client area of a window. This,
115 too, only holds true for classes that do not display a native GTK widget
118 4) Provide the entire mechanism for scrolling widgets. This actual inter-
119 face for this is usually in wxScrolledWindow, but the GTK implementation
122 5) A multitude of helper or extra methods for special purposes, such as
123 Drag'n'Drop, managing validators etc.
125 6) Display a border (sunken, raised, simple or none).
127 Normally one might expect, that one wxWidgets window would always correspond
128 to one GTK widget. Under GTK, there is no such allround widget that has all
129 the functionality. Moreover, the GTK defines a client area as a different
130 widget from the actual widget you are handling. Last but not least some
131 special classes (e.g. wxFrame) handle different categories of widgets and
132 still have the possibility to draw something in the client area.
133 It was therefore required to write a special purpose GTK widget, that would
134 represent a client area in the sense of wxWidgets capable to do the jobs
135 2), 3) and 4). I have written this class and it resides in win_gtk.c of
138 All windows must have a widget, with which they interact with other under-
139 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
140 thw wxWindow class has a member variable called m_widget which holds a
141 pointer to this widget. When the window class represents a GTK native widget,
142 this is (in most cases) the only GTK widget the class manages. E.g. the
143 wxStaticText class handles only a GtkLabel widget a pointer to which you
144 can find in m_widget (defined in wxWindow)
146 When the class has a client area for drawing into and for containing children
147 it has to handle the client area widget (of the type GtkPizza, defined in
148 win_gtk.c), but there could be any number of widgets, handled by a class
149 The common rule for all windows is only, that the widget that interacts with
150 the rest of GTK must be referenced in m_widget and all other widgets must be
151 children of this widget on the GTK level. The top-most widget, which also
152 represents the client area, must be in the m_wxwindow field and must be of
155 As I said, the window classes that display a GTK native widget only have
156 one widget, so in the case of e.g. the wxButton class m_widget holds a
157 pointer to a GtkButton widget. But windows with client areas (for drawing
158 and children) have a m_widget field that is a pointer to a GtkScrolled-
159 Window and a m_wxwindow field that is pointer to a GtkPizza and this
160 one is (in the GTK sense) a child of the GtkScrolledWindow.
162 If the m_wxwindow field is set, then all input to this widget is inter-
163 cepted and sent to the wxWidgets class. If not, all input to the widget
164 that gets pointed to by m_widget gets intercepted and sent to the class.
168 The design of scrolling in wxWidgets is markedly different from that offered
169 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
170 clicking on a scrollbar belonging to scrolled window will inevitably move
171 the window. In wxWidgets, the scrollbar will only emit an event, send this
172 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
173 which actually moves the window and its subchildren. Note that GtkPizza
174 memorizes how much it has been scrolled but that wxWidgets forgets this
175 so that the two coordinates systems have to be kept in synch. This is done
176 in various places using the pizza->xoffset and pizza->yoffset values.
180 Singularily the most broken code in GTK is the code that is supposes to
181 inform subwindows (child windows) about new positions. Very often, duplicate
182 events are sent without changes in size or position, equally often no
183 events are sent at all (All this is due to a bug in the GtkContainer code
184 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
185 GTK's own system and it simply waits for size events for toplevel windows
186 and then iterates down the respective size events to all window. This has
187 the disadvantage, that windows might get size events before the GTK widget
188 actually has the reported size. This doesn't normally pose any problem, but
189 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
190 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
191 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
192 window that is used for OpenGl output really has that size (as reported by
197 If someone at some point of time feels the immense desire to have a look at,
198 change or attempt to optimse the Refresh() logic, this person will need an
199 intimate understanding of what a "draw" and what an "expose" events are and
200 what there are used for, in particular when used in connection with GTK's
201 own windowless widgets. Beware.
205 Cursors, too, have been a constant source of pleasure. The main difficulty
206 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
207 for the parent. To prevent this from doing too much harm, I use idle time
208 to set the cursor over and over again, starting from the toplevel windows
209 and ending with the youngest generation (speaking of parent and child windows).
210 Also don't forget that cursors (like much else) are connected to GdkWindows,
211 not GtkWidgets and that the "window" field of a GtkWidget might very well
212 point to the GdkWindow of the parent widget (-> "window less widget") and
213 that the two obviously have very different meanings.
217 //-----------------------------------------------------------------------------
219 //-----------------------------------------------------------------------------
221 extern wxList wxPendingDelete
;
222 extern bool g_blockEventsOnDrag
;
223 extern bool g_blockEventsOnScroll
;
224 extern wxCursor g_globalCursor
;
226 static GdkGC
*g_eraseGC
= NULL
;
228 // mouse capture state: the window which has it and if the mouse is currently
230 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
231 static bool g_captureWindowHasMouse
= FALSE
;
233 wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
235 // the last window which had the focus - this is normally never NULL (except
236 // if we never had focus at all) as even when g_focusWindow is NULL it still
237 // keeps its previous value
238 wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
240 // If a window get the focus set but has not been realized
241 // yet, defer setting the focus to idle time.
242 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
244 // hack: we need something to pass to gtk_menu_popup, so we store the time of
245 // the last click here
246 static guint32 gs_timeLastClick
= 0;
248 extern bool g_mainThreadLocked
;
250 //-----------------------------------------------------------------------------
252 //-----------------------------------------------------------------------------
257 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
259 # define DEBUG_MAIN_THREAD
262 #define DEBUG_MAIN_THREAD
265 // the trace mask used for the focus debugging messages
266 #define TRACE_FOCUS _T("focus")
268 //-----------------------------------------------------------------------------
269 // missing gdk functions
270 //-----------------------------------------------------------------------------
273 gdk_window_warp_pointer (GdkWindow
*window
,
278 GdkWindowPrivate
*priv
;
282 window
= GDK_ROOT_PARENT();
285 if (!GDK_WINDOW_DESTROYED(window
))
287 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
288 None
, /* not source window -> move from anywhere */
289 GDK_WINDOW_XID(window
), /* dest window */
290 0, 0, 0, 0, /* not source window -> move from anywhere */
294 priv
= (GdkWindowPrivate
*) window
;
296 if (!priv
->destroyed
)
298 XWarpPointer (priv
->xdisplay
,
299 None
, /* not source window -> move from anywhere */
300 priv
->xwindow
, /* dest window */
301 0, 0, 0, 0, /* not source window -> move from anywhere */
307 //-----------------------------------------------------------------------------
309 //-----------------------------------------------------------------------------
311 extern void wxapp_install_idle_handler();
312 extern bool g_isIdle
;
314 //-----------------------------------------------------------------------------
315 // local code (see below)
316 //-----------------------------------------------------------------------------
318 // returns the child of win which currently has focus or NULL if not found
320 // Note: can't be static, needed by textctrl.cpp.
321 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
323 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
325 return (wxWindow
*)NULL
;
327 if ( winFocus
== win
)
328 return (wxWindow
*)win
;
330 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
332 node
= node
->GetNext() )
334 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
339 return (wxWindow
*)NULL
;
342 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
344 // wxUniversal widgets draw the borders and scrollbars themselves
345 #ifndef __WXUNIVERSAL__
352 if (win
->m_hasScrolling
)
354 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
356 GtkRequisition vscroll_req
;
357 vscroll_req
.width
= 2;
358 vscroll_req
.height
= 2;
359 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
360 (scroll_window
->vscrollbar
, &vscroll_req
);
362 GtkRequisition hscroll_req
;
363 hscroll_req
.width
= 2;
364 hscroll_req
.height
= 2;
365 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
366 (scroll_window
->hscrollbar
, &hscroll_req
);
368 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
370 if (scroll_window
->vscrollbar_visible
)
372 dw
+= vscroll_req
.width
;
373 dw
+= scroll_class
->scrollbar_spacing
;
376 if (scroll_window
->hscrollbar_visible
)
378 dh
+= hscroll_req
.height
;
379 dh
+= scroll_class
->scrollbar_spacing
;
385 if (GTK_WIDGET_NO_WINDOW (widget
))
387 dx
+= widget
->allocation
.x
;
388 dy
+= widget
->allocation
.y
;
391 if (win
->HasFlag(wxRAISED_BORDER
))
393 gtk_draw_shadow( widget
->style
,
398 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
402 if (win
->HasFlag(wxSUNKEN_BORDER
))
404 gtk_draw_shadow( widget
->style
,
409 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
413 if (win
->HasFlag(wxSIMPLE_BORDER
))
416 gc
= gdk_gc_new( widget
->window
);
417 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
418 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
420 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
424 #endif // __WXUNIVERSAL__
427 //-----------------------------------------------------------------------------
428 // "expose_event" of m_widget
429 //-----------------------------------------------------------------------------
431 gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
433 if (gdk_event
->count
> 0) return FALSE
;
435 draw_frame( widget
, win
);
439 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
445 //-----------------------------------------------------------------------------
446 // "draw" of m_widget
447 //-----------------------------------------------------------------------------
451 static void gtk_window_own_draw_callback( GtkWidget
*widget
, GdkRectangle
*WXUNUSED(rect
), wxWindowGTK
*win
)
453 draw_frame( widget
, win
);
458 //-----------------------------------------------------------------------------
459 // "size_request" of m_widget
460 //-----------------------------------------------------------------------------
462 // make it extern because wxStatitText needs to disconnect this one
464 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
465 GtkRequisition
*requisition
,
469 win
->GetSize( &w
, &h
);
475 requisition
->height
= h
;
476 requisition
->width
= w
;
479 //-----------------------------------------------------------------------------
480 // "expose_event" of m_wxwindow
481 //-----------------------------------------------------------------------------
483 static int gtk_window_expose_callback( GtkWidget
*widget
,
484 GdkEventExpose
*gdk_event
,
490 wxapp_install_idle_handler();
493 // This callback gets called in drawing-idle time under
494 // GTK 2.0, so we don't need to defer anything to idle
497 GtkPizza
*pizza
= GTK_PIZZA( widget
);
498 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
503 wxPrintf( wxT("OnExpose from ") );
504 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
505 wxPrintf( win
->GetClassInfo()->GetClassName() );
506 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
507 (int)gdk_event
->area
.y
,
508 (int)gdk_event
->area
.width
,
509 (int)gdk_event
->area
.height
);
514 win
->m_wxwindow
->style
,
518 (GdkRectangle
*) NULL
,
520 (char *)"button", // const_cast
525 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
527 win
->GtkSendPaintEvents();
530 // Let parent window draw window less widgets
531 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
533 // This gets called immediately after an expose event
534 // under GTK 1.2 so we collect the calls and wait for
535 // the idle handler to pick things up.
537 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
539 gdk_event
->area
.width
,
540 gdk_event
->area
.height
);
541 win
->m_clearRegion
.Union( gdk_event
->area
.x
,
543 gdk_event
->area
.width
,
544 gdk_event
->area
.height
);
546 // Actual redrawing takes place in idle time.
553 //-----------------------------------------------------------------------------
554 // "event" of m_wxwindow
555 //-----------------------------------------------------------------------------
557 // GTK thinks it is clever and filters out a certain amount of "unneeded"
558 // expose events. We need them, of course, so we override the main event
559 // procedure in GtkWidget by giving our own handler for all system events.
560 // There, we look for expose events ourselves whereas all other events are
563 gint
gtk_window_event_event_callback( GtkWidget
*widget
,
564 GdkEventExpose
*event
,
567 if (event
->type
== GDK_EXPOSE
)
569 gint ret
= gtk_window_expose_callback( widget
, event
, win
);
576 //-----------------------------------------------------------------------------
577 // "draw" of m_wxwindow
578 //-----------------------------------------------------------------------------
582 // This callback is a complete replacement of the gtk_pizza_draw() function,
583 // which is disabled.
585 static void gtk_window_draw_callback( GtkWidget
*widget
,
592 wxapp_install_idle_handler();
594 // if there are any children we must refresh everything
597 if ( !win
->HasFlag(wxFULL_REPAINT_ON_RESIZE
) &&
598 win
->GetChildren().IsEmpty() )
606 wxPrintf( wxT("OnDraw from ") );
607 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
608 wxPrintf( win
->GetClassInfo()->GetClassName() );
609 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect
->x
,
616 #ifndef __WXUNIVERSAL__
617 GtkPizza
*pizza
= GTK_PIZZA (widget
);
619 if (win
->GetThemeEnabled() && win
->GetBackgroundStyle() == wxBG_STYLE_SYSTEM
)
621 wxWindow
*parent
= win
->GetParent();
622 while (parent
&& !parent
->IsTopLevel())
623 parent
= parent
->GetParent();
627 gtk_paint_flat_box (parent
->m_widget
->style
,
638 win
->m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
639 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
641 // Update immediately, not in idle time.
644 #ifndef __WXUNIVERSAL__
645 // Redraw child widgets
646 GList
*children
= pizza
->children
;
649 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
650 children
= children
->next
;
652 GdkRectangle child_area
;
653 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
655 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
663 //-----------------------------------------------------------------------------
664 // "key_press_event" from any window
665 //-----------------------------------------------------------------------------
667 // set WXTRACE to this to see the key event codes on the console
668 #define TRACE_KEYS _T("keyevent")
670 // translates an X key symbol to WXK_XXX value
672 // if isChar is true it means that the value returned will be used for EVT_CHAR
673 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
674 // for example, while if it is false it means that the value is going to be
675 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
677 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
683 // Shift, Control and Alt don't generate the CHAR events at all
686 key_code
= isChar
? 0 : WXK_SHIFT
;
690 key_code
= isChar
? 0 : WXK_CONTROL
;
698 key_code
= isChar
? 0 : WXK_ALT
;
701 // neither do the toggle modifies
702 case GDK_Scroll_Lock
:
703 key_code
= isChar
? 0 : WXK_SCROLL
;
707 key_code
= isChar
? 0 : WXK_CAPITAL
;
711 key_code
= isChar
? 0 : WXK_NUMLOCK
;
715 // various other special keys
728 case GDK_ISO_Left_Tab
:
735 key_code
= WXK_RETURN
;
739 key_code
= WXK_CLEAR
;
743 key_code
= WXK_PAUSE
;
747 key_code
= WXK_SELECT
;
751 key_code
= WXK_PRINT
;
755 key_code
= WXK_EXECUTE
;
759 key_code
= WXK_ESCAPE
;
762 // cursor and other extended keyboard keys
764 key_code
= WXK_DELETE
;
780 key_code
= WXK_RIGHT
;
787 case GDK_Prior
: // == GDK_Page_Up
788 key_code
= WXK_PRIOR
;
791 case GDK_Next
: // == GDK_Page_Down
804 key_code
= WXK_INSERT
;
819 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
823 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
827 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
831 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
835 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
839 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
843 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
847 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
851 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
855 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
859 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
863 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
867 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
870 case GDK_KP_Prior
: // == GDK_KP_Page_Up
871 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
874 case GDK_KP_Next
: // == GDK_KP_Page_Down
875 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
879 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
883 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
887 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
891 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
895 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
898 case GDK_KP_Multiply
:
899 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
903 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
906 case GDK_KP_Separator
:
907 // FIXME: what is this?
908 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
911 case GDK_KP_Subtract
:
912 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
916 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
920 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
937 key_code
= WXK_F1
+ keysym
- GDK_F1
;
947 static inline bool wxIsAsciiKeysym(KeySym ks
)
952 static void wxFillOtherKeyEventFields(wxKeyEvent
& event
,
954 GdkEventKey
*gdk_event
)
958 GdkModifierType state
;
959 if (gdk_event
->window
)
960 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
962 event
.SetTimestamp( gdk_event
->time
);
963 event
.SetId(win
->GetId());
964 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
965 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
966 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
967 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
968 event
.m_scanCode
= gdk_event
->keyval
;
969 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
970 event
.m_rawFlags
= 0;
972 event
.m_uniChar
= gdk_keyval_to_unicode(gdk_event
->keyval
);
976 event
.SetEventObject( win
);
981 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
983 GdkEventKey
*gdk_event
)
985 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
986 // but only event->keyval which is quite useless to us, so remember
987 // the last character from GDK_KEY_PRESS and reuse it as last resort
989 // NB: should be MT-safe as we're always called from the main thread only
994 } s_lastKeyPress
= { 0, 0 };
996 KeySym keysym
= gdk_event
->keyval
;
998 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
999 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
1003 long key_code
= wxTranslateKeySymToWXKey(keysym
, FALSE
/* !isChar */);
1007 // do we have the translation or is it a plain ASCII character?
1008 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
1010 // we should use keysym if it is ASCII as X does some translations
1011 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
1012 // which we don't want here (but which we do use for OnChar())
1013 if ( !wxIsAsciiKeysym(keysym
) )
1015 keysym
= (KeySym
)gdk_event
->string
[0];
1018 // we want to always get the same key code when the same key is
1019 // pressed regardless of the state of the modifies, i.e. on a
1020 // standard US keyboard pressing '5' or '%' ('5' key with
1021 // Shift) should result in the same key code in OnKeyDown():
1022 // '5' (although OnChar() will get either '5' or '%').
1024 // to do it we first translate keysym to keycode (== scan code)
1025 // and then back but always using the lower register
1026 Display
*dpy
= (Display
*)wxGetDisplay();
1027 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
1029 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
1031 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
1033 // use the normalized, i.e. lower register, keysym if we've
1035 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
1037 // as explained above, we want to have lower register key codes
1038 // normally but for the letter keys we want to have the upper ones
1040 // NB: don't use XConvertCase() here, we want to do it for letters
1042 key_code
= toupper(key_code
);
1044 else // non ASCII key, what to do?
1046 // by default, ignore it
1049 // but if we have cached information from the last KEY_PRESS
1050 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
1053 if ( keysym
== s_lastKeyPress
.keysym
)
1055 key_code
= s_lastKeyPress
.keycode
;
1060 if ( gdk_event
->type
== GDK_KEY_PRESS
)
1062 // remember it to be reused for KEY_UP event later
1063 s_lastKeyPress
.keysym
= keysym
;
1064 s_lastKeyPress
.keycode
= key_code
;
1068 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
1070 // sending unknown key events doesn't really make sense
1074 // now fill all the other fields
1075 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
1077 event
.m_keyCode
= key_code
;
1086 GtkIMContext
*context
;
1087 GdkEventKey
*lastKeyEvent
;
1091 context
= gtk_im_multicontext_new();
1092 lastKeyEvent
= NULL
;
1096 g_object_unref(context
);
1101 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1102 GdkEventKey
*gdk_event
,
1108 wxapp_install_idle_handler();
1112 if (g_blockEventsOnDrag
)
1117 // We have to pass key press events through GTK+'s Input Method context
1118 // object in order to get correct characters. By doing so, we lose the
1119 // ability to let other GTK+'s handlers (namely, widgets' default signal
1120 // handlers) handle the signal by returning false from this callback.
1121 // Because GTK+ sends the events to parent widgets as well, we can't
1122 // afford losing it, otherwise native widgets inserted into wxPanel
1123 // would break in subtle ways (e.g. spacebar would no longer toggle
1124 // wxCheckButton's state). Therefore, we only pass the event to IM if it
1125 // originated in this window's widget, which we detect by checking if we've
1126 // seen the same event before (no events from children are lost this way,
1127 // because gtk_window_key_press_callback is installed for native controls
1128 // as well and the wxKeyEvent it creates propagates upwards).
1129 static GdkEventKey s_lastEvent
;
1130 bool useIM
= (win
->m_imData
!= NULL
) &&
1131 memcmp(gdk_event
, &s_lastEvent
, sizeof(GdkEventKey
)) != 0;
1132 s_lastEvent
= *gdk_event
;
1134 // 2005.01.26 modified by hzysoft@sina.com.tw:
1135 // There is no need to store lastEvent. The original code makes GTK+ IM
1136 // dysfunction. When we get a key_press event here, it could be originate
1137 // from the current widget or its child widgets. However, only the widget
1138 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
1139 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
1140 // originated from its child widgets and shouldn't be passed to IM context.
1141 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
1142 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
1143 // widgets has both IM context and input focus, the event should be filtered
1144 // by gtk_im_context_filter_keypress().
1145 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
1146 bool useIM
= (win
->m_imData
!= NULL
) && ( wxWindow::FindFocus() == win
);
1152 // 2005.01.26 modified by hzysoft@sina.com.tw:
1153 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1154 // docs, if IM filter returns true, NO FURTHER PROCESSING SHOULD BE DONE for
1155 // this keystroke. Making wxWidgets unable to receive EVT_KEY_DOWN in this
1156 // situation is resonable. In reality, when IM is activated, wxWidgets should
1157 // receive EVT_CHAR instead.
1160 // it may be useful for the input method, though:
1161 bool ret
= gtk_im_context_filter_keypress(win
->m_imData
->context
, gdk_event
);
1162 win
->m_imData
->lastKeyEvent
= NULL
;
1165 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1171 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1172 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1174 // unknown key pressed, ignore (the event would be useless anyhow)
1175 // 2005.02.22 modified by hzysoft@sina.com.tw.
1176 // In GTK+ 1.2, strings sent by IMs are also regarded as key_press events whose
1177 // keyCodes cannot be recognized by wxWidgets. These MBCS strings, however, are
1178 // composed of more than one character, which means gdk_event->length will always
1179 // greater than one.
1180 // When gtk_event->length == 1, this may be an ASCII character and can be translated
1181 // by WX. However, when MBCS characters are sent by IM, gdk_event->length will >= 2.
1182 // So when gdk_event->length >= 2, this is not an invalid key but a part of a string
1183 // sent by IM which contains user input and shouldn't be ignored.
1184 if (gdk_event
->length
<= 1) // Only ignore those keys whose gdk_event->length <=1.
1188 // Emit KEY_DOWN event
1189 bool ret
= win
->GetEventHandler()->ProcessEvent( event
);
1194 wxWindowGTK
*ancestor
= win
;
1197 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1200 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1201 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1204 if (ancestor
->IsTopLevel())
1206 ancestor
= ancestor
->GetParent();
1209 #endif // wxUSE_ACCEL
1211 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1212 // will only be sent if it is not in an accelerator table.
1216 KeySym keysym
= gdk_event
->keyval
;
1217 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1218 key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1221 if ( wxIsAsciiKeysym(keysym
) )
1224 key_code
= (unsigned char)keysym
;
1226 // gdk_event->string is actually deprecated
1227 else if ( gdk_event
->length
== 1 )
1229 key_code
= (unsigned char)gdk_event
->string
[0];
1235 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1237 event
.m_keyCode
= key_code
;
1239 // Implement OnCharHook by checking ancesteror top level windows
1240 wxWindow
*parent
= win
;
1241 while (parent
&& !parent
->IsTopLevel())
1242 parent
= parent
->GetParent();
1245 event
.SetEventType( wxEVT_CHAR_HOOK
);
1246 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1251 event
.SetEventType(wxEVT_CHAR
);
1252 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1257 // win is a control: tab can be propagated up
1259 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1260 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1261 // have this style, yet choose not to process this particular TAB in which
1262 // case TAB must still work as a navigational character
1263 // JS: enabling again to make consistent with other platforms
1264 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1265 // navigation behaviour)
1267 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1269 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1271 wxNavigationKeyEvent new_event
;
1272 new_event
.SetEventObject( win
->GetParent() );
1273 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1274 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1275 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1276 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1277 new_event
.SetCurrentFocus( win
);
1278 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1281 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1283 (gdk_event
->keyval
== GDK_Escape
) )
1285 // however only do it if we have a Cancel button in the dialog,
1286 // otherwise the user code may get confused by the events from a
1287 // non-existing button and, worse, a wxButton might get button event
1288 // from another button which is not really expected
1289 wxWindow
*winForCancel
= win
,
1291 while ( winForCancel
)
1293 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1296 // found a cancel button
1300 if ( winForCancel
->IsTopLevel() )
1302 // no need to look further
1306 // maybe our parent has a cancel button?
1307 winForCancel
= winForCancel
->GetParent();
1312 wxCommandEvent
event(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1313 event
.SetEventObject(btnCancel
);
1314 ret
= btnCancel
->GetEventHandler()->ProcessEvent(event
);
1320 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1328 static void gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1332 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1334 // take modifiers, cursor position, timestamp etc. from the last
1335 // key_press_event that was fed into Input Method:
1336 if (window
->m_imData
->lastKeyEvent
)
1338 wxFillOtherKeyEventFields(event
,
1339 window
, window
->m_imData
->lastKeyEvent
);
1343 const wxWCharBuffer data
= wxConvUTF8
.cMB2WC( (char*)str
);
1345 const wxWCharBuffer wdata
= wxConvUTF8
.cMB2WC( (char*)str
);
1346 const wxCharBuffer data
= wxConvLocal
.cWC2MB( wdata
);
1347 #endif // wxUSE_UNICODE
1348 if( !(const wxChar
*)data
)
1353 // Implement OnCharHook by checking ancestor top level windows
1354 wxWindow
*parent
= window
;
1355 while (parent
&& !parent
->IsTopLevel())
1356 parent
= parent
->GetParent();
1358 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1361 event
.m_uniChar
= *pstr
;
1362 // Backward compatible for ISO-8859-1
1363 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1364 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1366 event
.m_keyCode
= *pstr
;
1367 #endif // wxUSE_UNICODE
1370 event
.SetEventType( wxEVT_CHAR_HOOK
);
1371 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1376 event
.SetEventType(wxEVT_CHAR
);
1377 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1384 //-----------------------------------------------------------------------------
1385 // "key_release_event" from any window
1386 //-----------------------------------------------------------------------------
1388 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1389 GdkEventKey
*gdk_event
,
1395 wxapp_install_idle_handler();
1400 if (g_blockEventsOnDrag
)
1403 wxKeyEvent
event( wxEVT_KEY_UP
);
1404 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1406 // unknown key pressed, ignore (the event would be useless anyhow
1410 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1413 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1417 // ============================================================================
1419 // ============================================================================
1421 // ----------------------------------------------------------------------------
1422 // mouse event processing helpers
1423 // ----------------------------------------------------------------------------
1425 // init wxMouseEvent with the info from GdkEventXXX struct
1426 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1427 wxMouseEvent
& event
,
1430 event
.SetTimestamp( gdk_event
->time
);
1431 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1432 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1433 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1434 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1435 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1436 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1437 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1438 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1440 event
.m_linesPerAction
= 3;
1441 event
.m_wheelDelta
= 120;
1442 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1443 event
.m_wheelRotation
= 120;
1444 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1445 event
.m_wheelRotation
= -120;
1448 wxPoint pt
= win
->GetClientAreaOrigin();
1449 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1450 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1452 event
.SetEventObject( win
);
1453 event
.SetId( win
->GetId() );
1454 event
.SetTimestamp( gdk_event
->time
);
1457 static void AdjustEventButtonState(wxMouseEvent
& event
)
1459 // GDK reports the old state of the button for a button press event, but
1460 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1461 // for a LEFT_DOWN event, not FALSE, so we will invert
1462 // left/right/middleDown for the corresponding click events
1464 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1465 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1466 (event
.GetEventType() == wxEVT_LEFT_UP
))
1468 event
.m_leftDown
= !event
.m_leftDown
;
1472 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1473 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1474 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1476 event
.m_middleDown
= !event
.m_middleDown
;
1480 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1481 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1482 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1484 event
.m_rightDown
= !event
.m_rightDown
;
1489 // find the window to send the mouse event too
1491 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1496 if (win
->m_wxwindow
)
1498 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1499 xx
+= pizza
->xoffset
;
1500 yy
+= pizza
->yoffset
;
1503 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1506 wxWindowGTK
*child
= node
->GetData();
1508 node
= node
->GetNext();
1509 if (!child
->IsShown())
1512 if (child
->IsTransparentForMouse())
1514 // wxStaticBox is transparent in the box itself
1515 int xx1
= child
->m_x
;
1516 int yy1
= child
->m_y
;
1517 int xx2
= child
->m_x
+ child
->m_width
;
1518 int yy2
= child
->m_y
+ child
->m_height
;
1521 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1523 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1525 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1527 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1538 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1539 (child
->m_x
<= xx
) &&
1540 (child
->m_y
<= yy
) &&
1541 (child
->m_x
+child
->m_width
>= xx
) &&
1542 (child
->m_y
+child
->m_height
>= yy
))
1555 //-----------------------------------------------------------------------------
1556 // "button_press_event"
1557 //-----------------------------------------------------------------------------
1559 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1560 GdkEventButton
*gdk_event
,
1566 wxapp_install_idle_handler();
1569 wxPrintf( wxT("1) OnButtonPress from ") );
1570 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1571 wxPrintf( win->GetClassInfo()->GetClassName() );
1572 wxPrintf( wxT(".\n") );
1574 if (!win
->m_hasVMT
) return FALSE
;
1575 if (g_blockEventsOnDrag
) return TRUE
;
1576 if (g_blockEventsOnScroll
) return TRUE
;
1578 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1580 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1582 gtk_widget_grab_focus( win
->m_wxwindow
);
1584 wxPrintf( wxT("GrabFocus from ") );
1585 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1586 wxPrintf( win->GetClassInfo()->GetClassName() );
1587 wxPrintf( wxT(".\n") );
1591 // GDK sends surplus button down event
1592 // before a double click event. We
1593 // need to filter these out.
1594 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1596 GdkEvent
*peek_event
= gdk_event_peek();
1599 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1600 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1602 gdk_event_free( peek_event
);
1607 gdk_event_free( peek_event
);
1612 wxEventType event_type
= wxEVT_NULL
;
1614 // GdkDisplay is a GTK+ 2.2.0 thing
1615 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1616 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1617 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1619 // Reset GDK internal timestamp variables in order to disable GDK
1620 // triple click events. GDK will then next time believe no button has
1621 // been clicked just before, and send a normal button click event.
1622 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1623 display
->button_click_time
[1] = 0;
1624 display
->button_click_time
[0] = 0;
1628 if (gdk_event
->button
== 1)
1630 // note that GDK generates triple click events which are not supported
1631 // by wxWidgets but still have to be passed to the app as otherwise
1632 // clicks would simply go missing
1633 switch (gdk_event
->type
)
1635 // we shouldn't get triple clicks at all for GTK2 because we
1636 // suppress them artificially using the code above but we still
1637 // should map them to something for GTK1 and not just ignore them
1638 // as this would lose clicks
1639 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1640 case GDK_BUTTON_PRESS
:
1641 event_type
= wxEVT_LEFT_DOWN
;
1644 case GDK_2BUTTON_PRESS
:
1645 event_type
= wxEVT_LEFT_DCLICK
;
1649 // just to silence gcc warnings
1653 else if (gdk_event
->button
== 2)
1655 switch (gdk_event
->type
)
1657 case GDK_3BUTTON_PRESS
:
1658 case GDK_BUTTON_PRESS
:
1659 event_type
= wxEVT_MIDDLE_DOWN
;
1662 case GDK_2BUTTON_PRESS
:
1663 event_type
= wxEVT_MIDDLE_DCLICK
;
1670 else if (gdk_event
->button
== 3)
1672 switch (gdk_event
->type
)
1674 case GDK_3BUTTON_PRESS
:
1675 case GDK_BUTTON_PRESS
:
1676 event_type
= wxEVT_RIGHT_DOWN
;
1679 case GDK_2BUTTON_PRESS
:
1680 event_type
= wxEVT_RIGHT_DCLICK
;
1687 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1689 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1691 event_type
= wxEVT_MOUSEWHEEL
;
1695 if ( event_type
== wxEVT_NULL
)
1697 // unknown mouse button or click type
1701 wxMouseEvent
event( event_type
);
1702 InitMouseEvent( win
, event
, gdk_event
);
1704 AdjustEventButtonState(event
);
1706 // wxListBox actually get mouse events from the item, so we need to give it
1707 // a chance to correct this
1708 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1710 // find the correct window to send the event too: it may be a different one
1711 // from the one which got it at GTK+ level because some control don't have
1712 // their own X window and thus cannot get any events.
1713 if ( !g_captureWindow
)
1714 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1716 gs_timeLastClick
= gdk_event
->time
;
1719 if (event_type
== wxEVT_LEFT_DCLICK
)
1721 // GTK 1.2 crashes when intercepting double
1722 // click events from both wxSpinButton and
1724 if (GTK_IS_SPIN_BUTTON(win
->m_widget
))
1726 // Just disable this event for now.
1732 if (win
->GetEventHandler()->ProcessEvent( event
))
1734 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1738 if (event_type
== wxEVT_RIGHT_DOWN
)
1740 // generate a "context menu" event: this is similar to right mouse
1741 // click under many GUIs except that it is generated differently
1742 // (right up under MSW, ctrl-click under Mac, right down here) and
1744 // (a) it's a command event and so is propagated to the parent
1745 // (b) under some ports it can be generated from kbd too
1746 // (c) it uses screen coords (because of (a))
1747 wxContextMenuEvent
evtCtx(
1750 win
->ClientToScreen(event
.GetPosition()));
1751 evtCtx
.SetEventObject(win
);
1752 return win
->GetEventHandler()->ProcessEvent(evtCtx
);
1758 //-----------------------------------------------------------------------------
1759 // "button_release_event"
1760 //-----------------------------------------------------------------------------
1762 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1763 GdkEventButton
*gdk_event
,
1769 wxapp_install_idle_handler();
1771 if (!win
->m_hasVMT
) return FALSE
;
1772 if (g_blockEventsOnDrag
) return FALSE
;
1773 if (g_blockEventsOnScroll
) return FALSE
;
1775 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1777 wxEventType event_type
= wxEVT_NULL
;
1779 switch (gdk_event
->button
)
1782 event_type
= wxEVT_LEFT_UP
;
1786 event_type
= wxEVT_MIDDLE_UP
;
1790 event_type
= wxEVT_RIGHT_UP
;
1794 // unknwon button, don't process
1798 wxMouseEvent
event( event_type
);
1799 InitMouseEvent( win
, event
, gdk_event
);
1801 AdjustEventButtonState(event
);
1803 // same wxListBox hack as above
1804 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1806 if ( !g_captureWindow
)
1807 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1809 if (win
->GetEventHandler()->ProcessEvent( event
))
1811 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1818 //-----------------------------------------------------------------------------
1819 // "motion_notify_event"
1820 //-----------------------------------------------------------------------------
1822 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1823 GdkEventMotion
*gdk_event
,
1829 wxapp_install_idle_handler();
1831 if (!win
->m_hasVMT
) return FALSE
;
1832 if (g_blockEventsOnDrag
) return FALSE
;
1833 if (g_blockEventsOnScroll
) return FALSE
;
1835 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1837 if (gdk_event
->is_hint
)
1841 GdkModifierType state
;
1842 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1848 printf( "OnMotion from " );
1849 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1850 printf( win->GetClassInfo()->GetClassName() );
1854 wxMouseEvent
event( wxEVT_MOTION
);
1855 InitMouseEvent(win
, event
, gdk_event
);
1857 if ( g_captureWindow
)
1859 // synthetize a mouse enter or leave event if needed
1860 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1861 // This seems to be necessary and actually been added to
1862 // GDK itself in version 2.0.X
1865 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1866 if ( hasMouse
!= g_captureWindowHasMouse
)
1868 // the mouse changed window
1869 g_captureWindowHasMouse
= hasMouse
;
1871 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1872 : wxEVT_LEAVE_WINDOW
);
1873 InitMouseEvent(win
, event
, gdk_event
);
1874 event
.SetEventObject(win
);
1875 win
->GetEventHandler()->ProcessEvent(event
);
1880 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1883 if (win
->GetEventHandler()->ProcessEvent( event
))
1885 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1893 //-----------------------------------------------------------------------------
1894 // "mouse_wheel_event"
1895 //-----------------------------------------------------------------------------
1897 static gint
gtk_window_wheel_callback (GtkWidget
* widget
,
1898 GdkEventScroll
* gdk_event
,
1904 wxapp_install_idle_handler();
1906 wxEventType event_type
= wxEVT_NULL
;
1907 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1908 event_type
= wxEVT_MOUSEWHEEL
;
1909 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1910 event_type
= wxEVT_MOUSEWHEEL
;
1914 wxMouseEvent
event( event_type
);
1915 // Can't use InitMouse macro because scroll events don't have button
1916 event
.SetTimestamp( gdk_event
->time
);
1917 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1918 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1919 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1920 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1921 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1922 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1923 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1924 event
.m_linesPerAction
= 3;
1925 event
.m_wheelDelta
= 120;
1926 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1927 event
.m_wheelRotation
= 120;
1929 event
.m_wheelRotation
= -120;
1931 wxPoint pt
= win
->GetClientAreaOrigin();
1932 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1933 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1935 event
.SetEventObject( win
);
1936 event
.SetId( win
->GetId() );
1937 event
.SetTimestamp( gdk_event
->time
);
1939 if (win
->GetEventHandler()->ProcessEvent( event
))
1941 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "scroll_event" );
1948 //-----------------------------------------------------------------------------
1950 //-----------------------------------------------------------------------------
1951 static gboolean
wxgtk_window_popup_menu_callback(GtkWidget
*, wxWindowGTK
* win
)
1953 wxContextMenuEvent
event(
1957 event
.SetEventObject(win
);
1958 return win
->GetEventHandler()->ProcessEvent(event
);
1960 #endif // __WXGTK20__
1962 //-----------------------------------------------------------------------------
1964 //-----------------------------------------------------------------------------
1966 // send the wxChildFocusEvent and wxFocusEvent, common code of
1967 // gtk_window_focus_in_callback() and SetFocus()
1968 static bool DoSendFocusEvents(wxWindow
*win
)
1970 // Notify the parent keeping track of focus for the kbd navigation
1971 // purposes that we got it.
1972 wxChildFocusEvent
eventChildFocus(win
);
1973 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1975 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1976 eventFocus
.SetEventObject(win
);
1978 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1981 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1982 GdkEvent
*WXUNUSED(event
),
1988 wxapp_install_idle_handler();
1992 gtk_im_context_focus_in(win
->m_imData
->context
);
1996 g_focusWindow
= win
;
1998 wxLogTrace(TRACE_FOCUS
,
1999 _T("%s: focus in"), win
->GetName().c_str());
2003 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
2007 // caret needs to be informed about focus change
2008 wxCaret
*caret
= win
->GetCaret();
2011 caret
->OnSetFocus();
2013 #endif // wxUSE_CARET
2015 // does the window itself think that it has the focus?
2016 if ( !win
->m_hasFocus
)
2018 // not yet, notify it
2019 win
->m_hasFocus
= TRUE
;
2021 if ( DoSendFocusEvents(win
) )
2023 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
2031 //-----------------------------------------------------------------------------
2032 // "focus_out_event"
2033 //-----------------------------------------------------------------------------
2035 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
2040 wxapp_install_idle_handler();
2044 gtk_im_context_focus_out(win
->m_imData
->context
);
2047 wxLogTrace( TRACE_FOCUS
,
2048 _T("%s: focus out"), win
->GetName().c_str() );
2051 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
2055 g_focusWindow
= (wxWindowGTK
*)NULL
;
2063 // caret needs to be informed about focus change
2064 wxCaret
*caret
= win
->GetCaret();
2067 caret
->OnKillFocus();
2069 #endif // wxUSE_CARET
2071 // don't send the window a kill focus event if it thinks that it doesn't
2072 // have focus already
2073 if ( win
->m_hasFocus
)
2075 win
->m_hasFocus
= FALSE
;
2077 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
2078 event
.SetEventObject( win
);
2080 // even if we did process the event in wx code, still let GTK itself
2081 // process it too as otherwise bad things happen, especially in GTK2
2082 // where the text control simply aborts the program if it doesn't get
2083 // the matching focus out event
2084 (void)win
->GetEventHandler()->ProcessEvent( event
);
2090 //-----------------------------------------------------------------------------
2091 // "enter_notify_event"
2092 //-----------------------------------------------------------------------------
2095 gint
gtk_window_enter_callback( GtkWidget
*widget
,
2096 GdkEventCrossing
*gdk_event
,
2102 wxapp_install_idle_handler();
2104 if (!win
->m_hasVMT
) return FALSE
;
2105 if (g_blockEventsOnDrag
) return FALSE
;
2107 // Event was emitted after a grab
2108 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2110 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2114 GdkModifierType state
= (GdkModifierType
)0;
2116 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2118 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2119 InitMouseEvent(win
, event
, gdk_event
);
2120 wxPoint pt
= win
->GetClientAreaOrigin();
2121 event
.m_x
= x
+ pt
.x
;
2122 event
.m_y
= y
+ pt
.y
;
2124 if (win
->GetEventHandler()->ProcessEvent( event
))
2126 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
2133 //-----------------------------------------------------------------------------
2134 // "leave_notify_event"
2135 //-----------------------------------------------------------------------------
2137 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
2142 wxapp_install_idle_handler();
2144 if (!win
->m_hasVMT
) return FALSE
;
2145 if (g_blockEventsOnDrag
) return FALSE
;
2147 // Event was emitted after an ungrab
2148 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2150 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2152 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2153 event
.SetTimestamp( gdk_event
->time
);
2154 event
.SetEventObject( win
);
2158 GdkModifierType state
= (GdkModifierType
)0;
2160 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2162 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2163 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2164 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2165 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2166 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2167 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2168 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2170 wxPoint pt
= win
->GetClientAreaOrigin();
2171 event
.m_x
= x
+ pt
.x
;
2172 event
.m_y
= y
+ pt
.y
;
2174 if (win
->GetEventHandler()->ProcessEvent( event
))
2176 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
2183 //-----------------------------------------------------------------------------
2184 // "value_changed" from m_vAdjust
2185 //-----------------------------------------------------------------------------
2187 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2194 wxapp_install_idle_handler();
2196 if (g_blockEventsOnDrag
) return;
2198 if (!win
->m_hasVMT
) return;
2200 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2201 if (fabs(diff
) < 0.2) return;
2203 win
->m_oldVerticalPos
= adjust
->value
;
2206 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2208 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
2210 int value
= (int)(adjust
->value
+0.5);
2212 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2213 event
.SetEventObject( win
);
2214 win
->GetEventHandler()->ProcessEvent( event
);
2217 //-----------------------------------------------------------------------------
2218 // "value_changed" from m_hAdjust
2219 //-----------------------------------------------------------------------------
2221 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2228 wxapp_install_idle_handler();
2230 if (g_blockEventsOnDrag
) return;
2231 if (!win
->m_hasVMT
) return;
2233 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2234 if (fabs(diff
) < 0.2) return;
2237 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2239 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
2241 win
->m_oldHorizontalPos
= adjust
->value
;
2243 int value
= (int)(adjust
->value
+0.5);
2245 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2246 event
.SetEventObject( win
);
2247 win
->GetEventHandler()->ProcessEvent( event
);
2250 //-----------------------------------------------------------------------------
2251 // "button_press_event" from scrollbar
2252 //-----------------------------------------------------------------------------
2254 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2255 GdkEventButton
*gdk_event
,
2261 wxapp_install_idle_handler();
2264 g_blockEventsOnScroll
= TRUE
;
2266 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2268 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2274 //-----------------------------------------------------------------------------
2275 // "button_release_event" from scrollbar
2276 //-----------------------------------------------------------------------------
2278 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2279 GdkEventButton
*WXUNUSED(gdk_event
),
2284 // don't test here as we can release the mouse while being over
2285 // a different window than the slider
2287 // if (gdk_event->window != widget->slider) return FALSE;
2289 g_blockEventsOnScroll
= FALSE
;
2291 if (win
->m_isScrolling
)
2293 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2297 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2298 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2300 value
= (int)(win
->m_hAdjust
->value
+0.5);
2303 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2305 value
= (int)(win
->m_vAdjust
->value
+0.5);
2309 wxScrollWinEvent
event( command
, value
, dir
);
2310 event
.SetEventObject( win
);
2311 win
->GetEventHandler()->ProcessEvent( event
);
2314 win
->m_isScrolling
= FALSE
;
2319 // ----------------------------------------------------------------------------
2320 // this wxWindowBase function is implemented here (in platform-specific file)
2321 // because it is static and so couldn't be made virtual
2322 // ----------------------------------------------------------------------------
2324 wxWindow
*wxWindowBase::DoFindFocus()
2326 // the cast is necessary when we compile in wxUniversal mode
2327 return (wxWindow
*)g_focusWindow
;
2331 //-----------------------------------------------------------------------------
2332 // "realize" from m_widget
2333 //-----------------------------------------------------------------------------
2335 /* We cannot set colours and fonts before the widget has
2336 been realized, so we do this directly after realization. */
2339 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2344 wxapp_install_idle_handler();
2349 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2350 gtk_im_context_set_client_window( win
->m_imData
->context
,
2351 pizza
->bin_window
);
2355 wxWindowCreateEvent
event( win
);
2356 event
.SetEventObject( win
);
2357 win
->GetEventHandler()->ProcessEvent( event
);
2362 //-----------------------------------------------------------------------------
2364 //-----------------------------------------------------------------------------
2367 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2368 GtkAllocation
*WXUNUSED(alloc
),
2372 wxapp_install_idle_handler();
2374 if (!win
->m_hasScrolling
) return;
2376 int client_width
= 0;
2377 int client_height
= 0;
2378 win
->GetClientSize( &client_width
, &client_height
);
2379 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2382 win
->m_oldClientWidth
= client_width
;
2383 win
->m_oldClientHeight
= client_height
;
2385 if (!win
->m_nativeSizeEvent
)
2387 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2388 event
.SetEventObject( win
);
2389 win
->GetEventHandler()->ProcessEvent( event
);
2395 #define WXUNUSED_UNLESS_XIM(param) param
2397 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2400 /* Resize XIM window */
2403 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2404 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2405 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2408 wxapp_install_idle_handler();
2414 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2418 gdk_window_get_size (widget
->window
, &width
, &height
);
2419 win
->m_icattr
->preedit_area
.width
= width
;
2420 win
->m_icattr
->preedit_area
.height
= height
;
2421 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2426 //-----------------------------------------------------------------------------
2427 // "realize" from m_wxwindow
2428 //-----------------------------------------------------------------------------
2430 /* Initialize XIM support */
2433 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2434 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2437 wxapp_install_idle_handler();
2440 if (win
->m_ic
) return FALSE
;
2441 if (!widget
) return FALSE
;
2442 if (!gdk_im_ready()) return FALSE
;
2444 win
->m_icattr
= gdk_ic_attr_new();
2445 if (!win
->m_icattr
) return FALSE
;
2449 GdkColormap
*colormap
;
2450 GdkICAttr
*attr
= win
->m_icattr
;
2451 unsigned attrmask
= GDK_IC_ALL_REQ
;
2453 GdkIMStyle supported_style
= (GdkIMStyle
)
2454 (GDK_IM_PREEDIT_NONE
|
2455 GDK_IM_PREEDIT_NOTHING
|
2456 GDK_IM_PREEDIT_POSITION
|
2457 GDK_IM_STATUS_NONE
|
2458 GDK_IM_STATUS_NOTHING
);
2460 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2461 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2463 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2464 attr
->client_window
= widget
->window
;
2466 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2467 gtk_widget_get_default_colormap ())
2469 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2470 attr
->preedit_colormap
= colormap
;
2473 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2474 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2475 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2476 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2478 switch (style
& GDK_IM_PREEDIT_MASK
)
2480 case GDK_IM_PREEDIT_POSITION
:
2481 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2483 g_warning ("over-the-spot style requires fontset");
2487 gdk_window_get_size (widget
->window
, &width
, &height
);
2489 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2490 attr
->spot_location
.x
= 0;
2491 attr
->spot_location
.y
= height
;
2492 attr
->preedit_area
.x
= 0;
2493 attr
->preedit_area
.y
= 0;
2494 attr
->preedit_area
.width
= width
;
2495 attr
->preedit_area
.height
= height
;
2496 attr
->preedit_fontset
= widget
->style
->font
;
2501 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2503 if (win
->m_ic
== NULL
)
2504 g_warning ("Can't create input context.");
2507 mask
= gdk_window_get_events (widget
->window
);
2508 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2509 gdk_window_set_events (widget
->window
, mask
);
2511 if (GTK_WIDGET_HAS_FOCUS(widget
))
2512 gdk_im_begin (win
->m_ic
, widget
->window
);
2519 //-----------------------------------------------------------------------------
2520 // InsertChild for wxWindowGTK.
2521 //-----------------------------------------------------------------------------
2523 /* Callback for wxWindowGTK. This very strange beast has to be used because
2524 * C++ has no virtual methods in a constructor. We have to emulate a
2525 * virtual function here as wxNotebook requires a different way to insert
2526 * a child in it. I had opted for creating a wxNotebookPage window class
2527 * which would have made this superfluous (such in the MDI window system),
2528 * but no-one was listening to me... */
2530 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2532 /* the window might have been scrolled already, do we
2533 have to adapt the position */
2534 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2535 child
->m_x
+= pizza
->xoffset
;
2536 child
->m_y
+= pizza
->yoffset
;
2538 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2539 GTK_WIDGET(child
->m_widget
),
2546 //-----------------------------------------------------------------------------
2548 //-----------------------------------------------------------------------------
2550 wxWindow
*wxGetActiveWindow()
2552 return wxWindow::FindFocus();
2555 //-----------------------------------------------------------------------------
2557 //-----------------------------------------------------------------------------
2559 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2561 #ifdef __WXUNIVERSAL__
2562 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2564 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2565 #endif // __WXUNIVERSAL__/__WXGTK__
2567 void wxWindowGTK::Init()
2570 m_widget
= (GtkWidget
*) NULL
;
2571 m_wxwindow
= (GtkWidget
*) NULL
;
2572 m_focusWidget
= (GtkWidget
*) NULL
;
2582 m_needParent
= TRUE
;
2583 m_isBeingDeleted
= FALSE
;
2586 m_nativeSizeEvent
= FALSE
;
2588 m_hasScrolling
= FALSE
;
2589 m_isScrolling
= FALSE
;
2591 m_hAdjust
= (GtkAdjustment
*) NULL
;
2592 m_vAdjust
= (GtkAdjustment
*) NULL
;
2593 m_oldHorizontalPos
=
2594 m_oldVerticalPos
= 0.0;
2596 m_oldClientHeight
= 0;
2600 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2602 m_acceptsFocus
= FALSE
;
2605 m_clipPaintRegion
= FALSE
;
2607 m_needsStyleChange
= false;
2609 m_cursor
= *wxSTANDARD_CURSOR
;
2613 m_x11Context
= NULL
;
2614 m_dirtyTabOrder
= false;
2617 m_ic
= (GdkIC
*) NULL
;
2618 m_icattr
= (GdkICAttr
*) NULL
;
2623 wxWindowGTK::wxWindowGTK()
2628 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2633 const wxString
&name
)
2637 Create( parent
, id
, pos
, size
, style
, name
);
2640 bool wxWindowGTK::Create( wxWindow
*parent
,
2645 const wxString
&name
)
2647 if (!PreCreation( parent
, pos
, size
) ||
2648 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2650 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2654 m_insertCallback
= wxInsertChildInWindow
;
2656 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2657 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2659 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2661 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2662 scroll_class
->scrollbar_spacing
= 0;
2664 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2666 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2667 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2669 m_wxwindow
= gtk_pizza_new();
2671 #ifndef __WXUNIVERSAL__
2672 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2674 if (HasFlag(wxRAISED_BORDER
))
2676 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2678 else if (HasFlag(wxSUNKEN_BORDER
))
2680 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2682 else if (HasFlag(wxSIMPLE_BORDER
))
2684 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2688 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2690 #endif // __WXUNIVERSAL__
2692 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2694 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2695 m_acceptsFocus
= TRUE
;
2697 // I _really_ don't want scrollbars in the beginning
2698 m_vAdjust
->lower
= 0.0;
2699 m_vAdjust
->upper
= 1.0;
2700 m_vAdjust
->value
= 0.0;
2701 m_vAdjust
->step_increment
= 1.0;
2702 m_vAdjust
->page_increment
= 1.0;
2703 m_vAdjust
->page_size
= 5.0;
2704 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2705 m_hAdjust
->lower
= 0.0;
2706 m_hAdjust
->upper
= 1.0;
2707 m_hAdjust
->value
= 0.0;
2708 m_hAdjust
->step_increment
= 1.0;
2709 m_hAdjust
->page_increment
= 1.0;
2710 m_hAdjust
->page_size
= 5.0;
2711 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2713 // these handlers block mouse events to any window during scrolling such as
2714 // motion events and prevent GTK and wxWidgets from fighting over where the
2717 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2718 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2720 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2721 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2723 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2724 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2726 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2727 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2729 // these handlers get notified when screen updates are required either when
2730 // scrolling or when the window size (and therefore scrollbar configuration)
2733 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2734 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2735 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2736 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2738 gtk_widget_show( m_wxwindow
);
2741 m_parent
->DoAddChild( this );
2743 m_focusWidget
= m_wxwindow
;
2750 wxWindowGTK::~wxWindowGTK()
2754 if (g_focusWindow
== this)
2755 g_focusWindow
= NULL
;
2757 if ( g_delayedFocus
== this )
2758 g_delayedFocus
= NULL
;
2760 m_isBeingDeleted
= TRUE
;
2770 gdk_ic_destroy (m_ic
);
2772 gdk_ic_attr_destroy (m_icattr
);
2777 gtk_widget_destroy( m_wxwindow
);
2778 m_wxwindow
= (GtkWidget
*) NULL
;
2783 gtk_widget_destroy( m_widget
);
2784 m_widget
= (GtkWidget
*) NULL
;
2792 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2794 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2796 // Use either the given size, or the default if -1 is given.
2797 // See wxWindowBase for these functions.
2798 m_width
= WidthDefault(size
.x
) ;
2799 m_height
= HeightDefault(size
.y
);
2807 void wxWindowGTK::PostCreation()
2809 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2815 // these get reported to wxWidgets -> wxPaintEvent
2817 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2819 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2820 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2823 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2824 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2826 if (!HasFlag(wxFULL_REPAINT_ON_RESIZE
))
2828 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2829 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2832 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2837 // Create input method handler
2838 m_imData
= new wxGtkIMData
;
2840 // Cannot handle drawing preedited text yet
2841 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2843 g_signal_connect (G_OBJECT (m_imData
->context
), "commit",
2844 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2847 // these are called when the "sunken" or "raised" borders are drawn
2848 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2849 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2852 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2853 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2859 if (!GTK_IS_WINDOW(m_widget
))
2861 if (m_focusWidget
== NULL
)
2862 m_focusWidget
= m_widget
;
2864 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2865 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2867 gtk_signal_connect_after( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2868 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2871 // connect to the various key and mouse handlers
2873 GtkWidget
*connect_widget
= GetConnectWidget();
2875 ConnectWidget( connect_widget
);
2877 /* We cannot set colours, fonts and cursors before the widget has
2878 been realized, so we do this directly after realization */
2879 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2880 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2884 // Catch native resize events
2885 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2886 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2888 // Initialize XIM support
2889 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2890 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2892 // And resize XIM window
2893 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2894 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2897 if ( !GTK_IS_COMBO(m_widget
))
2899 // This is needed if we want to add our windows into native
2900 // GTK control, such as the toolbar. With this callback, the
2901 // toolbar gets to know the correct size (the one set by the
2902 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2903 // when moving to GTK 2.0.
2904 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2905 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback
),
2909 InheritAttributes();
2913 // unless the window was created initially hidden (i.e. Hide() had been
2914 // called before Create()), we should show it at GTK+ level as well
2916 gtk_widget_show( m_widget
);
2919 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2921 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2922 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2924 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2925 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2927 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2928 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2930 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2931 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2933 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2934 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2937 gtk_signal_connect( GTK_OBJECT(widget
), "scroll_event",
2938 GTK_SIGNAL_FUNC(gtk_window_wheel_callback
), (gpointer
)this );
2939 g_signal_connect(widget
, "popup_menu",
2940 G_CALLBACK(wxgtk_window_popup_menu_callback
), this);
2943 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2944 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2946 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2947 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2950 bool wxWindowGTK::Destroy()
2952 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2956 return wxWindowBase::Destroy();
2959 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2961 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2964 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2966 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2967 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2970 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2973 if (m_resizing
) return; /* I don't like recursions */
2976 int currentX
, currentY
;
2977 GetPosition(¤tX
, ¤tY
);
2978 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2980 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2982 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2984 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2986 /* don't set the size for children of wxNotebook, just take the values. */
2994 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2995 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2997 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2998 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
3002 m_x
= x
+ pizza
->xoffset
;
3003 m_y
= y
+ pizza
->yoffset
;
3006 // calculate the best size if we should auto size the window
3007 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
3008 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
3010 const wxSize sizeBest
= GetBestSize();
3011 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
3013 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
3014 height
= sizeBest
.y
;
3022 int minWidth
= GetMinWidth(),
3023 minHeight
= GetMinHeight(),
3024 maxWidth
= GetMaxWidth(),
3025 maxHeight
= GetMaxHeight();
3027 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
3028 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
3029 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
3030 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
3033 int bottom_border
= 0;
3036 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
3038 /* the default button has a border around it */
3044 DoMoveWindow( m_x
-border
,
3047 m_height
+border
+bottom_border
);
3052 /* Sometimes the client area changes size without the
3053 whole windows's size changing, but if the whole
3054 windows's size doesn't change, no wxSizeEvent will
3055 normally be sent. Here we add an extra test if
3056 the client test has been changed and this will
3058 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
3062 wxPrintf( "OnSize sent from " );
3063 if (GetClassInfo() && GetClassInfo()->GetClassName())
3064 wxPrintf( GetClassInfo()->GetClassName() );
3065 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3068 if (!m_nativeSizeEvent
)
3070 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
3071 event
.SetEventObject( this );
3072 GetEventHandler()->ProcessEvent( event
);
3078 void wxWindowGTK::OnInternalIdle()
3081 if ( m_dirtyTabOrder
)
3084 // Update style if the window was not yet realized
3085 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
3086 if (m_needsStyleChange
)
3088 SetBackgroundStyle(GetBackgroundStyle());
3089 m_needsStyleChange
= false;
3092 // Update invalidated regions.
3095 wxCursor cursor
= m_cursor
;
3096 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3100 /* I now set the cursor anew in every OnInternalIdle call
3101 as setting the cursor in a parent window also effects the
3102 windows above so that checking for the current cursor is
3107 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3109 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3111 if (!g_globalCursor
.Ok())
3112 cursor
= *wxSTANDARD_CURSOR
;
3114 window
= m_widget
->window
;
3115 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3116 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3122 GdkWindow
*window
= m_widget
->window
;
3123 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3124 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3129 if (wxUpdateUIEvent::CanUpdate(this))
3130 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3133 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3135 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3137 if (width
) (*width
) = m_width
;
3138 if (height
) (*height
) = m_height
;
3141 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3143 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3147 SetSize( width
, height
);
3154 #ifndef __WXUNIVERSAL__
3155 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3157 /* when using GTK 1.2 we set the shadow border size to 2 */
3161 if (HasFlag(wxSIMPLE_BORDER
))
3163 /* when using GTK 1.2 we set the simple border size to 1 */
3167 #endif // __WXUNIVERSAL__
3171 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3173 GtkRequisition vscroll_req
;
3174 vscroll_req
.width
= 2;
3175 vscroll_req
.height
= 2;
3176 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3177 (scroll_window
->vscrollbar
, &vscroll_req
);
3179 GtkRequisition hscroll_req
;
3180 hscroll_req
.width
= 2;
3181 hscroll_req
.height
= 2;
3182 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3183 (scroll_window
->hscrollbar
, &hscroll_req
);
3185 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3187 if (scroll_window
->vscrollbar_visible
)
3189 dw
+= vscroll_req
.width
;
3190 dw
+= scroll_class
->scrollbar_spacing
;
3193 if (scroll_window
->hscrollbar_visible
)
3195 dh
+= hscroll_req
.height
;
3196 dh
+= scroll_class
->scrollbar_spacing
;
3200 SetSize( width
+dw
, height
+dh
);
3204 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3206 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3210 if (width
) (*width
) = m_width
;
3211 if (height
) (*height
) = m_height
;
3218 #ifndef __WXUNIVERSAL__
3219 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3221 /* when using GTK 1.2 we set the shadow border size to 2 */
3225 if (HasFlag(wxSIMPLE_BORDER
))
3227 /* when using GTK 1.2 we set the simple border size to 1 */
3231 #endif // __WXUNIVERSAL__
3235 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3237 GtkRequisition vscroll_req
;
3238 vscroll_req
.width
= 2;
3239 vscroll_req
.height
= 2;
3240 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3241 (scroll_window
->vscrollbar
, &vscroll_req
);
3243 GtkRequisition hscroll_req
;
3244 hscroll_req
.width
= 2;
3245 hscroll_req
.height
= 2;
3246 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3247 (scroll_window
->hscrollbar
, &hscroll_req
);
3249 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3251 if (scroll_window
->vscrollbar_visible
)
3253 dw
+= vscroll_req
.width
;
3254 dw
+= scroll_class
->scrollbar_spacing
;
3257 if (scroll_window
->hscrollbar_visible
)
3259 dh
+= hscroll_req
.height
;
3260 dh
+= scroll_class
->scrollbar_spacing
;
3264 if (width
) (*width
) = m_width
- dw
;
3265 if (height
) (*height
) = m_height
- dh
;
3269 printf( "GetClientSize, name %s ", GetName().c_str() );
3270 if (width) printf( " width = %d", (*width) );
3271 if (height) printf( " height = %d", (*height) );
3276 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3278 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3282 if (m_parent
&& m_parent
->m_wxwindow
)
3284 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3285 dx
= pizza
->xoffset
;
3286 dy
= pizza
->yoffset
;
3289 if (x
) (*x
) = m_x
- dx
;
3290 if (y
) (*y
) = m_y
- dy
;
3293 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3295 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3297 if (!m_widget
->window
) return;
3299 GdkWindow
*source
= (GdkWindow
*) NULL
;
3301 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3303 source
= m_widget
->window
;
3307 gdk_window_get_origin( source
, &org_x
, &org_y
);
3311 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3313 org_x
+= m_widget
->allocation
.x
;
3314 org_y
+= m_widget
->allocation
.y
;
3322 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3324 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3326 if (!m_widget
->window
) return;
3328 GdkWindow
*source
= (GdkWindow
*) NULL
;
3330 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3332 source
= m_widget
->window
;
3336 gdk_window_get_origin( source
, &org_x
, &org_y
);
3340 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3342 org_x
+= m_widget
->allocation
.x
;
3343 org_y
+= m_widget
->allocation
.y
;
3351 bool wxWindowGTK::Show( bool show
)
3353 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3355 if (!wxWindowBase::Show(show
))
3362 gtk_widget_show( m_widget
);
3364 gtk_widget_hide( m_widget
);
3366 wxShowEvent
eventShow(GetId(), show
);
3367 eventShow
.SetEventObject(this);
3369 GetEventHandler()->ProcessEvent(eventShow
);
3374 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3376 win
->OnParentEnable(enable
);
3378 // Recurse, so that children have the opportunity to Do The Right Thing
3379 // and reset colours that have been messed up by a parent's (really ancestor's)
3381 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3383 node
= node
->GetNext() )
3385 wxWindow
*child
= node
->GetData();
3386 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3387 wxWindowNotifyEnable(child
, enable
);
3391 bool wxWindowGTK::Enable( bool enable
)
3393 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3395 if (!wxWindowBase::Enable(enable
))
3401 gtk_widget_set_sensitive( m_widget
, enable
);
3403 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3405 wxWindowNotifyEnable(this, enable
);
3410 int wxWindowGTK::GetCharHeight() const
3412 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3414 wxFont font
= GetFont();
3415 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3418 PangoContext
*context
= NULL
;
3420 context
= gtk_widget_get_pango_context( m_widget
);
3425 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3426 PangoLayout
*layout
= pango_layout_new(context
);
3427 pango_layout_set_font_description(layout
, desc
);
3428 pango_layout_set_text(layout
, "H", 1);
3429 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3431 PangoRectangle rect
;
3432 pango_layout_line_get_extents(line
, NULL
, &rect
);
3434 g_object_unref( G_OBJECT( layout
) );
3436 return (int) PANGO_PIXELS(rect
.height
);
3438 GdkFont
*gfont
= font
.GetInternalFont( 1.0 );
3440 return gfont
->ascent
+ gfont
->descent
;
3444 int wxWindowGTK::GetCharWidth() const
3446 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3448 wxFont font
= GetFont();
3449 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3452 PangoContext
*context
= NULL
;
3454 context
= gtk_widget_get_pango_context( m_widget
);
3459 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3460 PangoLayout
*layout
= pango_layout_new(context
);
3461 pango_layout_set_font_description(layout
, desc
);
3462 pango_layout_set_text(layout
, "g", 1);
3463 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3465 PangoRectangle rect
;
3466 pango_layout_line_get_extents(line
, NULL
, &rect
);
3468 g_object_unref( G_OBJECT( layout
) );
3470 return (int) PANGO_PIXELS(rect
.width
);
3472 GdkFont
*gfont
= font
.GetInternalFont( 1.0 );
3474 return gdk_string_width( gfont
, "g" );
3478 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3482 int *externalLeading
,
3483 const wxFont
*theFont
) const
3485 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3487 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3489 if (string
.IsEmpty())
3497 PangoContext
*context
= NULL
;
3499 context
= gtk_widget_get_pango_context( m_widget
);
3508 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3509 PangoLayout
*layout
= pango_layout_new(context
);
3510 pango_layout_set_font_description(layout
, desc
);
3513 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3514 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3516 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3517 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3518 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3522 PangoRectangle rect
;
3523 pango_layout_get_extents(layout
, NULL
, &rect
);
3525 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3526 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3529 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3530 int baseline
= pango_layout_iter_get_baseline(iter
);
3531 pango_layout_iter_free(iter
);
3532 *descent
= *y
- PANGO_PIXELS(baseline
);
3534 if (externalLeading
) (*externalLeading
) = 0; // ??
3536 g_object_unref( G_OBJECT( layout
) );
3538 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3539 if (x
) (*x
) = gdk_string_width( font
, wxGTK_CONV( string
) );
3540 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3541 if (descent
) (*descent
) = font
->descent
;
3542 if (externalLeading
) (*externalLeading
) = 0; // ??
3546 void wxWindowGTK::SetFocus()
3548 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3551 // don't do anything if we already have focus
3557 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3559 gtk_widget_grab_focus (m_wxwindow
);
3565 if (GTK_IS_CONTAINER(m_widget
))
3567 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3571 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3574 if (!GTK_WIDGET_REALIZED(m_widget
))
3576 // we can't set the focus to the widget now so we remember that
3577 // it should be focused and will do it later, during the idle
3578 // time, as soon as we can
3579 wxLogTrace(TRACE_FOCUS
,
3580 _T("Delaying setting focus to %s(%s)"),
3581 GetClassInfo()->GetClassName(), GetLabel().c_str());
3583 g_delayedFocus
= this;
3587 wxLogTrace(TRACE_FOCUS
,
3588 _T("Setting focus to %s(%s)"),
3589 GetClassInfo()->GetClassName(), GetLabel().c_str());
3591 gtk_widget_grab_focus (m_widget
);
3596 if (GTK_IS_CONTAINER(m_widget
))
3598 gtk_container_focus( GTK_CONTAINER(m_widget
), GTK_DIR_TAB_FORWARD
);
3603 wxLogTrace(TRACE_FOCUS
,
3604 _T("Can't set focus to %s(%s)"),
3605 GetClassInfo()->GetClassName(), GetLabel().c_str());
3610 bool wxWindowGTK::AcceptsFocus() const
3612 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3615 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3617 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3619 wxWindowGTK
*oldParent
= m_parent
,
3620 *newParent
= (wxWindowGTK
*)newParentBase
;
3622 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3624 if ( !wxWindowBase::Reparent(newParent
) )
3627 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3629 /* prevent GTK from deleting the widget arbitrarily */
3630 gtk_widget_ref( m_widget
);
3634 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3637 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3641 /* insert GTK representation */
3642 (*(newParent
->m_insertCallback
))(newParent
, this);
3645 /* reverse: prevent GTK from deleting the widget arbitrarily */
3646 gtk_widget_unref( m_widget
);
3651 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3653 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3655 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3657 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3662 /* insert GTK representation */
3663 (*m_insertCallback
)(this, child
);
3668 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3670 wxWindowBase::AddChild(child
);
3671 m_dirtyTabOrder
= true;
3673 wxapp_install_idle_handler();
3676 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3678 wxWindowBase::RemoveChild(child
);
3679 m_dirtyTabOrder
= true;
3681 wxapp_install_idle_handler();
3684 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3686 wxWindowBase::DoMoveInTabOrder(win
, move
);
3687 m_dirtyTabOrder
= true;
3689 wxapp_install_idle_handler();
3692 void wxWindowGTK::RealizeTabOrder()
3696 if (m_children
.size() > 0)
3698 GList
*chain
= NULL
;
3700 for (wxWindowList::const_iterator i
= m_children
.begin();
3701 i
!= m_children
.end(); ++i
)
3703 chain
= g_list_prepend(chain
, (*i
)->m_widget
);
3706 chain
= g_list_reverse(chain
);
3708 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3713 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3717 m_dirtyTabOrder
= false;
3720 #endif // __WXGTK20__
3722 void wxWindowGTK::Raise()
3724 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3726 if (!m_widget
->window
) return;
3728 gdk_window_raise( m_widget
->window
);
3731 void wxWindowGTK::Lower()
3733 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3735 if (!m_widget
->window
) return;
3737 gdk_window_lower( m_widget
->window
);
3740 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3742 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3744 if (cursor
== m_cursor
)
3748 wxapp_install_idle_handler();
3750 if (cursor
== wxNullCursor
)
3751 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3753 return wxWindowBase::SetCursor( cursor
);
3756 void wxWindowGTK::WarpPointer( int x
, int y
)
3758 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3760 // We provide this function ourselves as it is
3761 // missing in GDK (top of this file).
3763 GdkWindow
*window
= (GdkWindow
*) NULL
;
3765 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3767 window
= GetConnectWidget()->window
;
3770 gdk_window_warp_pointer( window
, x
, y
);
3774 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3776 if (!m_widget
) return;
3777 if (!m_widget
->window
) return;
3781 wxapp_install_idle_handler();
3783 wxRect
myRect(0,0,0,0);
3784 if (m_wxwindow
&& rect
)
3786 myRect
.SetSize(wxSize( m_wxwindow
->allocation
.width
,
3787 m_wxwindow
->allocation
.height
));
3788 myRect
.Intersect(*rect
);
3789 if (!myRect
.width
|| !myRect
.height
)
3790 // nothing to do, rectangle is empty
3795 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3799 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3800 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3804 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3805 m_clearRegion
.Clear();
3806 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3814 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3815 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3819 GdkRectangle gdk_rect
;
3820 gdk_rect
.x
= rect
->x
;
3821 gdk_rect
.y
= rect
->y
;
3822 gdk_rect
.width
= rect
->width
;
3823 gdk_rect
.height
= rect
->height
;
3824 gtk_widget_draw( m_widget
, &gdk_rect
);
3831 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3832 m_updateRegion
.Clear();
3833 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3837 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3845 GdkRectangle gdk_rect
;
3846 gdk_rect
.x
= rect
->x
;
3847 gdk_rect
.y
= rect
->y
;
3848 gdk_rect
.width
= rect
->width
;
3849 gdk_rect
.height
= rect
->height
;
3850 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3854 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3860 void wxWindowGTK::Update()
3865 void wxWindowGTK::GtkUpdate()
3868 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3869 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3871 if (!m_updateRegion
.IsEmpty())
3872 GtkSendPaintEvents();
3876 void wxWindowGTK::GtkSendPaintEvents()
3881 m_clearRegion
.Clear();
3883 m_updateRegion
.Clear();
3887 // Clip to paint region in wxClientDC
3888 m_clipPaintRegion
= TRUE
;
3890 // widget to draw on
3891 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3893 if (GetThemeEnabled() && GetBackgroundStyle() == wxBG_STYLE_SYSTEM
)
3895 // find ancestor from which to steal background
3896 wxWindow
*parent
= GetParent();
3897 while (parent
&& !parent
->IsTopLevel())
3898 parent
= parent
->GetParent();
3900 parent
= (wxWindow
*)this;
3902 if (GTK_WIDGET_MAPPED(parent
->m_widget
))
3904 wxRegionIterator
upd( m_updateRegion
);
3908 rect
.x
= upd
.GetX();
3909 rect
.y
= upd
.GetY();
3910 rect
.width
= upd
.GetWidth();
3911 rect
.height
= upd
.GetHeight();
3913 gtk_paint_flat_box( parent
->m_widget
->style
,
3915 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3930 wxWindowDC
dc( (wxWindow
*)this );
3931 dc
.SetClippingRegion( m_updateRegion
);
3933 wxEraseEvent
erase_event( GetId(), &dc
);
3934 erase_event
.SetEventObject( this );
3936 GetEventHandler()->ProcessEvent(erase_event
);
3939 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
3941 wxWindowDC
dc( (wxWindow
*)this );
3942 if (m_clearRegion
.IsEmpty())
3943 dc
.SetClippingRegion( m_updateRegion
);
3945 dc
.SetClippingRegion( m_clearRegion
);
3947 wxEraseEvent
erase_event( GetId(), &dc
);
3948 erase_event
.SetEventObject( this );
3950 if (!GetEventHandler()->ProcessEvent(erase_event
) && GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3954 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
3955 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3957 gdk_gc_set_foreground( g_eraseGC
, GetBackgroundColour().GetColor() );
3959 wxRegionIterator
upd( m_clearRegion
);
3962 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3963 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3967 m_clearRegion
.Clear();
3971 wxNcPaintEvent
nc_paint_event( GetId() );
3972 nc_paint_event
.SetEventObject( this );
3973 GetEventHandler()->ProcessEvent( nc_paint_event
);
3975 wxPaintEvent
paint_event( GetId() );
3976 paint_event
.SetEventObject( this );
3977 GetEventHandler()->ProcessEvent( paint_event
);
3979 m_clipPaintRegion
= FALSE
;
3981 #ifndef __WXUNIVERSAL__
3983 // The following code will result in all window-less widgets
3984 // being redrawn because the wxWidgets class is allowed to
3985 // paint over the window-less widgets.
3987 GList
*children
= pizza
->children
;
3990 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3991 children
= children
->next
;
3993 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3994 GTK_WIDGET_DRAWABLE (child
->widget
))
3996 // Get intersection of widget area and update region
3997 wxRegion
region( m_updateRegion
);
3999 GdkEventExpose gdk_event
;
4000 gdk_event
.type
= GDK_EXPOSE
;
4001 gdk_event
.window
= pizza
->bin_window
;
4002 gdk_event
.count
= 0;
4004 wxRegionIterator
upd( m_updateRegion
);
4008 rect
.x
= upd
.GetX();
4009 rect
.y
= upd
.GetY();
4010 rect
.width
= upd
.GetWidth();
4011 rect
.height
= upd
.GetHeight();
4013 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
4015 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
4025 m_updateRegion
.Clear();
4028 void wxWindowGTK::ClearBackground()
4030 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4033 if (m_wxwindow
&& m_wxwindow
->window
)
4035 m_clearRegion
.Clear();
4036 wxSize
size( GetClientSize() );
4037 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
4039 // Better do this in idle?
4046 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
4048 wxWindowBase::DoSetToolTip(tip
);
4051 m_tooltip
->Apply( (wxWindow
*)this );
4054 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
4056 wxString
tmp( tip
);
4057 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
4059 #endif // wxUSE_TOOLTIPS
4061 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
4063 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4065 if (!wxWindowBase::SetBackgroundColour(colour
))
4070 // We need the pixel value e.g. for background clearing.
4071 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
4074 // apply style change (forceStyle=true so that new style is applied
4075 // even if the bg colour changed from valid to wxNullColour)
4076 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
4077 ApplyWidgetStyle(true);
4082 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
4084 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4086 if (!wxWindowBase::SetForegroundColour(colour
))
4093 // We need the pixel value e.g. for background clearing.
4094 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
4097 // apply style change (forceStyle=true so that new style is applied
4098 // even if the bg colour changed from valid to wxNullColour):
4099 ApplyWidgetStyle(true);
4105 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
4107 return gtk_widget_get_pango_context( m_widget
);
4110 PangoContext
*wxWindowGTK::GtkGetPangoX11Context()
4113 m_x11Context
= pango_x_get_context( gdk_display
);
4115 return m_x11Context
;
4119 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
4121 // do we need to apply any changes at all?
4124 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
4129 GtkRcStyle
*style
= gtk_rc_style_new();
4135 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
4137 wxString xfontname
= m_font
.GetNativeFontInfo()->GetXFontName();
4138 style
->fontset_name
= g_strdup(xfontname
.c_str());
4142 if ( m_foregroundColour
.Ok() )
4144 GdkColor
*fg
= m_foregroundColour
.GetColor();
4146 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
4147 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
4149 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
4150 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
4152 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
4153 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
4156 if ( m_backgroundColour
.Ok() )
4158 GdkColor
*bg
= m_backgroundColour
.GetColor();
4160 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
4161 style
->base
[GTK_STATE_NORMAL
] = *bg
;
4162 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
4163 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
4165 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
4166 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
4167 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
4168 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
4170 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
4171 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
4172 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
4173 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4175 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
4176 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
4177 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
4178 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4184 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
4186 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
4189 DoApplyWidgetStyle(style
);
4190 gtk_rc_style_unref(style
);
4193 // Style change may affect GTK+'s size calculation:
4194 InvalidateBestSize();
4197 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
4200 gtk_widget_modify_style(m_wxwindow
, style
);
4201 gtk_widget_modify_style(m_widget
, style
);
4204 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
4206 wxWindowBase::SetBackgroundStyle(style
);
4208 if (style
== wxBG_STYLE_CUSTOM
)
4210 GdkWindow
*window
= (GdkWindow
*) NULL
;
4212 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4214 window
= GetConnectWidget()->window
;
4218 // Make sure GDK/X11 doesn't refresh the window
4220 gdk_window_set_back_pixmap( window
, None
, False
);
4222 Display
* display
= GDK_WINDOW_DISPLAY(window
);
4225 m_needsStyleChange
= false;
4228 // Do in OnIdle, because the window is not yet available
4229 m_needsStyleChange
= true;
4231 // Don't apply widget style, or we get a grey background
4235 // apply style change (forceStyle=true so that new style is applied
4236 // even if the bg colour changed from valid to wxNullColour):
4237 ApplyWidgetStyle(true);
4242 //-----------------------------------------------------------------------------
4243 // Pop-up menu stuff
4244 //-----------------------------------------------------------------------------
4246 #if wxUSE_MENUS_NATIVE
4249 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
4251 *is_waiting
= FALSE
;
4254 void SetInvokingWindow( wxMenu
*menu
, wxWindow
* win
)
4256 menu
->SetInvokingWindow( win
);
4258 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
4261 wxMenuItem
*menuitem
= node
->GetData();
4262 if (menuitem
->IsSubMenu())
4264 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
4267 node
= node
->GetNext();
4271 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
4274 gboolean
* WXUNUSED(whatever
),
4276 gpointer user_data
)
4278 // ensure that the menu appears entirely on screen
4280 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
4282 wxSize sizeScreen
= wxGetDisplaySize();
4283 wxPoint
*pos
= (wxPoint
*)user_data
;
4285 gint xmax
= sizeScreen
.x
- req
.width
,
4286 ymax
= sizeScreen
.y
- req
.height
;
4288 *x
= pos
->x
< xmax
? pos
->x
: xmax
;
4289 *y
= pos
->y
< ymax
? pos
->y
: ymax
;
4292 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4294 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4296 wxCHECK_MSG( menu
!= NULL
, false, wxT("invalid popup-menu") );
4298 // NOTE: if you change this code, you need to update
4299 // the same code in taskbar.cpp as well. This
4300 // is ugly code duplication, I know,
4302 SetInvokingWindow( menu
, this );
4306 bool is_waiting
= true;
4308 gulong handler
= gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
4310 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
4311 (gpointer
)&is_waiting
);
4315 GtkMenuPositionFunc posfunc
;
4316 if ( x
== -1 && y
== -1 )
4318 // use GTK's default positioning algorithm
4324 pos
= ClientToScreen(wxPoint(x
, y
));
4326 posfunc
= wxPopupMenuPositionCallback
;
4330 GTK_MENU(menu
->m_menu
),
4331 (GtkWidget
*) NULL
, // parent menu shell
4332 (GtkWidget
*) NULL
, // parent menu item
4333 posfunc
, // function to position it
4334 userdata
, // client data
4335 0, // button used to activate it
4337 gtk_get_current_event_time()
4339 gs_timeLastClick
// the time of activation
4345 gtk_main_iteration();
4348 gtk_signal_disconnect(GTK_OBJECT(menu
->m_menu
), handler
);
4353 #endif // wxUSE_MENUS_NATIVE
4355 #if wxUSE_DRAG_AND_DROP
4357 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4359 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4361 GtkWidget
*dnd_widget
= GetConnectWidget();
4363 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4365 if (m_dropTarget
) delete m_dropTarget
;
4366 m_dropTarget
= dropTarget
;
4368 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4371 #endif // wxUSE_DRAG_AND_DROP
4373 GtkWidget
* wxWindowGTK::GetConnectWidget()
4375 GtkWidget
*connect_widget
= m_widget
;
4376 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4378 return connect_widget
;
4381 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4384 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4386 return (window
== m_widget
->window
);
4389 bool wxWindowGTK::SetFont( const wxFont
&font
)
4391 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4393 if (!wxWindowBase::SetFont(font
))
4396 // apply style change (forceStyle=true so that new style is applied
4397 // even if the font changed from valid to wxNullFont):
4398 ApplyWidgetStyle(true);
4403 void wxWindowGTK::DoCaptureMouse()
4405 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4407 GdkWindow
*window
= (GdkWindow
*) NULL
;
4409 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4411 window
= GetConnectWidget()->window
;
4413 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4415 wxCursor
* cursor
= & m_cursor
;
4417 cursor
= wxSTANDARD_CURSOR
;
4419 gdk_pointer_grab( window
, FALSE
,
4421 (GDK_BUTTON_PRESS_MASK
|
4422 GDK_BUTTON_RELEASE_MASK
|
4423 GDK_POINTER_MOTION_HINT_MASK
|
4424 GDK_POINTER_MOTION_MASK
),
4426 cursor
->GetCursor(),
4427 (guint32
)GDK_CURRENT_TIME
);
4428 g_captureWindow
= this;
4429 g_captureWindowHasMouse
= TRUE
;
4432 void wxWindowGTK::DoReleaseMouse()
4434 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4436 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4438 g_captureWindow
= (wxWindowGTK
*) NULL
;
4440 GdkWindow
*window
= (GdkWindow
*) NULL
;
4442 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4444 window
= GetConnectWidget()->window
;
4449 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4453 wxWindow
*wxWindowBase::GetCapture()
4455 return (wxWindow
*)g_captureWindow
;
4458 bool wxWindowGTK::IsRetained() const
4463 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4464 int range
, bool refresh
)
4466 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4468 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4470 m_hasScrolling
= TRUE
;
4472 if (orient
== wxHORIZONTAL
)
4474 float fpos
= (float)pos
;
4475 float frange
= (float)range
;
4476 float fthumb
= (float)thumbVisible
;
4477 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4478 if (fpos
< 0.0) fpos
= 0.0;
4480 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4481 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4483 SetScrollPos( orient
, pos
, refresh
);
4487 m_oldHorizontalPos
= fpos
;
4489 m_hAdjust
->lower
= 0.0;
4490 m_hAdjust
->upper
= frange
;
4491 m_hAdjust
->value
= fpos
;
4492 m_hAdjust
->step_increment
= 1.0;
4493 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4494 m_hAdjust
->page_size
= fthumb
;
4498 float fpos
= (float)pos
;
4499 float frange
= (float)range
;
4500 float fthumb
= (float)thumbVisible
;
4501 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4502 if (fpos
< 0.0) fpos
= 0.0;
4504 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4505 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4507 SetScrollPos( orient
, pos
, refresh
);
4511 m_oldVerticalPos
= fpos
;
4513 m_vAdjust
->lower
= 0.0;
4514 m_vAdjust
->upper
= frange
;
4515 m_vAdjust
->value
= fpos
;
4516 m_vAdjust
->step_increment
= 1.0;
4517 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4518 m_vAdjust
->page_size
= fthumb
;
4521 if (orient
== wxHORIZONTAL
)
4522 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4524 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4527 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4529 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4531 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4533 if (orient
== wxHORIZONTAL
)
4535 float fpos
= (float)pos
;
4536 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4537 if (fpos
< 0.0) fpos
= 0.0;
4538 m_oldHorizontalPos
= fpos
;
4540 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4541 m_hAdjust
->value
= fpos
;
4545 float fpos
= (float)pos
;
4546 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4547 if (fpos
< 0.0) fpos
= 0.0;
4548 m_oldVerticalPos
= fpos
;
4550 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4551 m_vAdjust
->value
= fpos
;
4554 if (m_wxwindow
->window
)
4556 if (orient
== wxHORIZONTAL
)
4558 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4559 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4561 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4563 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4564 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4568 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4569 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4571 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4573 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4574 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4579 int wxWindowGTK::GetScrollThumb( int orient
) const
4581 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4583 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4585 if (orient
== wxHORIZONTAL
)
4586 return (int)(m_hAdjust
->page_size
+0.5);
4588 return (int)(m_vAdjust
->page_size
+0.5);
4591 int wxWindowGTK::GetScrollPos( int orient
) const
4593 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4595 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4597 if (orient
== wxHORIZONTAL
)
4598 return (int)(m_hAdjust
->value
+0.5);
4600 return (int)(m_vAdjust
->value
+0.5);
4603 int wxWindowGTK::GetScrollRange( int orient
) const
4605 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4607 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4609 if (orient
== wxHORIZONTAL
)
4610 return (int)(m_hAdjust
->upper
+0.5);
4612 return (int)(m_vAdjust
->upper
+0.5);
4615 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4617 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4619 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4621 // No scrolling requested.
4622 if ((dx
== 0) && (dy
== 0)) return;
4625 if (!m_updateRegion
.IsEmpty())
4627 m_updateRegion
.Offset( dx
, dy
);
4631 GetClientSize( &cw
, &ch
);
4632 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4635 if (!m_clearRegion
.IsEmpty())
4637 m_clearRegion
.Offset( dx
, dy
);
4641 GetClientSize( &cw
, &ch
);
4642 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4646 m_clipPaintRegion
= TRUE
;
4648 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4650 m_clipPaintRegion
= FALSE
;
4654 // Find the wxWindow at the current mouse position, also returning the mouse
4656 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4658 pt
= wxGetMousePosition();
4659 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4663 // Get the current mouse position.
4664 wxPoint
wxGetMousePosition()
4666 /* This crashes when used within wxHelpContext,
4667 so we have to use the X-specific implementation below.
4669 GdkModifierType *mask;
4670 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4672 return wxPoint(x, y);
4676 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4678 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4679 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4680 Window rootReturn
, childReturn
;
4681 int rootX
, rootY
, winX
, winY
;
4682 unsigned int maskReturn
;
4684 XQueryPointer (display
,
4688 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4689 return wxPoint(rootX
, rootY
);
4693 // ----------------------------------------------------------------------------
4695 // ----------------------------------------------------------------------------
4697 class wxWinModule
: public wxModule
4704 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4707 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4709 bool wxWinModule::OnInit()
4711 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4712 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4717 void wxWinModule::OnExit()
4720 gdk_gc_unref( g_eraseGC
);