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
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
964 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
965 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
966 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
967 event
.m_scanCode
= gdk_event
->keyval
;
968 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
969 event
.m_rawFlags
= 0;
972 event
.SetEventObject( win
);
977 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
979 GdkEventKey
*gdk_event
)
981 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
982 // but only event->keyval which is quite useless to us, so remember
983 // the last character from GDK_KEY_PRESS and reuse it as last resort
985 // NB: should be MT-safe as we're always called from the main thread only
990 } s_lastKeyPress
= { 0, 0 };
992 KeySym keysym
= gdk_event
->keyval
;
994 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
995 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
999 long key_code
= wxTranslateKeySymToWXKey(keysym
, FALSE
/* !isChar */);
1003 // do we have the translation or is it a plain ASCII character?
1004 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
1006 // we should use keysym if it is ASCII as X does some translations
1007 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
1008 // which we don't want here (but which we do use for OnChar())
1009 if ( !wxIsAsciiKeysym(keysym
) )
1011 keysym
= (KeySym
)gdk_event
->string
[0];
1014 // we want to always get the same key code when the same key is
1015 // pressed regardless of the state of the modifies, i.e. on a
1016 // standard US keyboard pressing '5' or '%' ('5' key with
1017 // Shift) should result in the same key code in OnKeyDown():
1018 // '5' (although OnChar() will get either '5' or '%').
1020 // to do it we first translate keysym to keycode (== scan code)
1021 // and then back but always using the lower register
1022 Display
*dpy
= (Display
*)wxGetDisplay();
1023 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
1025 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
1027 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
1029 // use the normalized, i.e. lower register, keysym if we've
1031 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
1033 // as explained above, we want to have lower register key codes
1034 // normally but for the letter keys we want to have the upper ones
1036 // NB: don't use XConvertCase() here, we want to do it for letters
1038 key_code
= toupper(key_code
);
1040 else // non ASCII key, what to do?
1042 // by default, ignore it
1045 // but if we have cached information from the last KEY_PRESS
1046 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
1049 if ( keysym
== s_lastKeyPress
.keysym
)
1051 key_code
= s_lastKeyPress
.keycode
;
1056 if ( gdk_event
->type
== GDK_KEY_PRESS
)
1058 // remember it to be reused for KEY_UP event later
1059 s_lastKeyPress
.keysym
= keysym
;
1060 s_lastKeyPress
.keycode
= key_code
;
1064 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
1066 // sending unknown key events doesn't really make sense
1070 // now fill all the other fields
1071 wxFillOtherKeyEventFields(event
, win
, gdk_event
);
1073 event
.m_keyCode
= key_code
;
1082 GtkIMContext
*context
;
1083 GdkEventKey
*lastKeyEvent
;
1087 context
= gtk_im_multicontext_new();
1088 lastKeyEvent
= NULL
;
1092 g_object_unref(context
);
1097 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1098 GdkEventKey
*gdk_event
,
1104 wxapp_install_idle_handler();
1108 if (g_blockEventsOnDrag
)
1112 // We have to pass key press events through GTK+'s Input Method context
1113 // object in order to get correct characters. By doing so, we loose the
1114 // ability to let other GTK+'s handlers (namely, widgets' default signal
1115 // handlers) handle the signal by returning false from this callback.
1116 // Because GTK+ sends the events to parent widgets as well, we can't
1117 // afford loosing it, otherwise native widgets inserted into wxPanel
1118 // would break in subtle ways (e.g. spacebar would no longer toggle
1119 // wxCheckButton's state). Therefore, we only pass the event to IM if it
1120 // originated in this window's widget, which we detect by checking if we've
1121 // seen the same event before (no events from children are lost this way,
1122 // because gtk_window_key_press_callback is installed for native controls
1123 // as well and the wxKeyEvent it creates propagates upwards).
1124 static GdkEventKey s_lastEvent
;
1126 bool useIM
= (win
->m_imData
!= NULL
) &&
1127 memcmp(gdk_event
, &s_lastEvent
, sizeof(GdkEventKey
)) != 0;
1129 s_lastEvent
= *gdk_event
;
1132 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1133 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1135 // unknown key pressed, ignore (the event would be useless anyhow)
1139 // it may be useful for the input method, though:
1140 win
->m_imData
->lastKeyEvent
= gdk_event
;
1141 bool ret
= gtk_im_context_filter_keypress(win
->m_imData
->context
,
1143 win
->m_imData
->lastKeyEvent
= NULL
;
1150 // Emit KEY_DOWN event
1151 bool ret
= win
->GetEventHandler()->ProcessEvent( event
);
1156 wxWindowGTK
*ancestor
= win
;
1159 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1162 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1163 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1166 if (ancestor
->IsTopLevel())
1168 ancestor
= ancestor
->GetParent();
1171 #endif // wxUSE_ACCEL
1173 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1174 // will only be sent if it is not in an accelerator table.
1180 // In GTK 2.0, we need to hand over the key event to an input method
1181 // and the IM will emit a "commit" event containing the actual utf8
1182 // character. In that case the EVT_CHAR events will be sent from
1184 win
->m_imData
->lastKeyEvent
= gdk_event
;
1185 if ( gtk_im_context_filter_keypress(win
->m_imData
->context
,
1188 win
->m_imData
->lastKeyEvent
= NULL
;
1189 wxLogTrace(TRACE_KEYS
, _T("Key event intercepted by IM"));
1193 win
->m_imData
->lastKeyEvent
= NULL
;
1198 KeySym keysym
= gdk_event
->keyval
;
1199 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1200 key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1203 if ( gdk_event
->length
== 1 )
1205 key_code
= (unsigned char)gdk_event
->string
[0];
1207 else if ( wxIsAsciiKeysym(keysym
) )
1210 key_code
= (unsigned char)keysym
;
1216 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1218 event
.m_keyCode
= key_code
;
1220 // Implement OnCharHook by checking ancesteror top level windows
1221 wxWindow
*parent
= win
;
1222 while (parent
&& !parent
->IsTopLevel())
1223 parent
= parent
->GetParent();
1226 event
.SetEventType( wxEVT_CHAR_HOOK
);
1227 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1232 event
.SetEventType(wxEVT_CHAR
);
1233 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1238 // win is a control: tab can be propagated up
1240 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1241 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1242 // have this style, yet choose not to process this particular TAB in which
1243 // case TAB must still work as a navigational character
1244 // JS: enabling again to make consistent with other platforms
1245 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1246 // navigation behaviour)
1248 (! (win
->HasFlag(wxTE_PROCESS_TAB
) && win
->IsKindOf(CLASSINFO(wxTextCtrl
)) )) &&
1250 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1252 wxNavigationKeyEvent new_event
;
1253 new_event
.SetEventObject( win
->GetParent() );
1254 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1255 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1256 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1257 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1258 new_event
.SetCurrentFocus( win
);
1259 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1262 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1264 (gdk_event
->keyval
== GDK_Escape
) )
1266 // however only do it if we have a Cancel button in the dialog,
1267 // otherwise the user code may get confused by the events from a
1268 // non-existing button and, worse, a wxButton might get button event
1269 // from another button which is not really expected
1270 wxWindow
*winForCancel
= win
,
1272 while ( winForCancel
)
1274 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1277 // found a cancel button
1281 if ( winForCancel
->IsTopLevel() )
1283 // no need to look further
1287 // maybe our parent has a cancel button?
1288 winForCancel
= winForCancel
->GetParent();
1293 wxCommandEvent
event(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1294 event
.SetEventObject(btnCancel
);
1295 ret
= btnCancel
->GetEventHandler()->ProcessEvent(event
);
1301 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1309 static void gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1313 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1315 // take modifiers, cursor position, timestamp etc. from the last
1316 // key_press_event that was fed into Input Method:
1317 if (window
->m_imData
->lastKeyEvent
)
1319 wxFillOtherKeyEventFields(event
,
1320 window
, window
->m_imData
->lastKeyEvent
);
1324 const wxWCharBuffer data
= wxConvUTF8
.cMB2WC( (char*)str
);
1326 const wxWCharBuffer wdata
= wxConvUTF8
.cMB2WC( (char*)str
);
1327 const wxCharBuffer data
= wxConvLocal
.cWC2MB( wdata
);
1328 #endif // wxUSE_UNICODE
1329 if( !(const wxChar
*)data
)
1334 // Implement OnCharHook by checking ancestor top level windows
1335 wxWindow
*parent
= window
;
1336 while (parent
&& !parent
->IsTopLevel())
1337 parent
= parent
->GetParent();
1339 for( const wxChar
* pstr
= data
; *pstr
; pstr
++ )
1342 event
.m_uniChar
= *pstr
;
1343 // Backward compatible for ISO-8859
1344 event
.m_keyCode
= *pstr
< 256 ? event
.m_uniChar
: 0;
1345 wxLogTrace(TRACE_KEYS
, _T("IM sent character '%c'"), event
.m_uniChar
);
1347 event
.m_keyCode
= *pstr
;
1348 #endif // wxUSE_UNICODE
1351 event
.SetEventType( wxEVT_CHAR_HOOK
);
1352 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1357 event
.SetEventType(wxEVT_CHAR
);
1358 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1365 //-----------------------------------------------------------------------------
1366 // "key_release_event" from any window
1367 //-----------------------------------------------------------------------------
1369 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1370 GdkEventKey
*gdk_event
,
1376 wxapp_install_idle_handler();
1381 if (g_blockEventsOnDrag
)
1384 wxKeyEvent
event( wxEVT_KEY_UP
);
1385 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1387 // unknown key pressed, ignore (the event would be useless anyhow
1391 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1394 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1398 // ============================================================================
1400 // ============================================================================
1402 // ----------------------------------------------------------------------------
1403 // mouse event processing helpers
1404 // ----------------------------------------------------------------------------
1406 // init wxMouseEvent with the info from GdkEventXXX struct
1407 template<typename T
> void InitMouseEvent(wxWindowGTK
*win
,
1408 wxMouseEvent
& event
,
1411 event
.SetTimestamp( gdk_event
->time
);
1412 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1413 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1414 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1415 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1416 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1417 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1418 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1419 if (event
.GetEventType() == wxEVT_MOUSEWHEEL
)
1421 event
.m_linesPerAction
= 3;
1422 event
.m_wheelDelta
= 120;
1423 if (((GdkEventButton
*)gdk_event
)->button
== 4)
1424 event
.m_wheelRotation
= 120;
1425 else if (((GdkEventButton
*)gdk_event
)->button
== 5)
1426 event
.m_wheelRotation
= -120;
1429 wxPoint pt
= win
->GetClientAreaOrigin();
1430 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1431 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1433 event
.SetEventObject( win
);
1434 event
.SetId( win
->GetId() );
1435 event
.SetTimestamp( gdk_event
->time
);
1438 static void AdjustEventButtonState(wxMouseEvent
& event
)
1440 // GDK reports the old state of the button for a button press event, but
1441 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1442 // for a LEFT_DOWN event, not FALSE, so we will invert
1443 // left/right/middleDown for the corresponding click events
1445 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1446 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1447 (event
.GetEventType() == wxEVT_LEFT_UP
))
1449 event
.m_leftDown
= !event
.m_leftDown
;
1453 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1454 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1455 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1457 event
.m_middleDown
= !event
.m_middleDown
;
1461 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1462 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1463 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1465 event
.m_rightDown
= !event
.m_rightDown
;
1470 // find the window to send the mouse event too
1472 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1477 if (win
->m_wxwindow
)
1479 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1480 xx
+= pizza
->xoffset
;
1481 yy
+= pizza
->yoffset
;
1484 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1487 wxWindowGTK
*child
= node
->GetData();
1489 node
= node
->GetNext();
1490 if (!child
->IsShown())
1493 if (child
->IsTransparentForMouse())
1495 // wxStaticBox is transparent in the box itself
1496 int xx1
= child
->m_x
;
1497 int yy1
= child
->m_y
;
1498 int xx2
= child
->m_x
+ child
->m_width
;
1499 int yy2
= child
->m_y
+ child
->m_height
;
1502 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1504 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1506 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1508 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1519 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1520 (child
->m_x
<= xx
) &&
1521 (child
->m_y
<= yy
) &&
1522 (child
->m_x
+child
->m_width
>= xx
) &&
1523 (child
->m_y
+child
->m_height
>= yy
))
1536 //-----------------------------------------------------------------------------
1537 // "button_press_event"
1538 //-----------------------------------------------------------------------------
1540 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1541 GdkEventButton
*gdk_event
,
1547 wxapp_install_idle_handler();
1550 wxPrintf( wxT("1) OnButtonPress from ") );
1551 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1552 wxPrintf( win->GetClassInfo()->GetClassName() );
1553 wxPrintf( wxT(".\n") );
1555 if (!win
->m_hasVMT
) return FALSE
;
1556 if (g_blockEventsOnDrag
) return TRUE
;
1557 if (g_blockEventsOnScroll
) return TRUE
;
1559 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1561 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1563 gtk_widget_grab_focus( win
->m_wxwindow
);
1565 wxPrintf( wxT("GrabFocus from ") );
1566 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1567 wxPrintf( win->GetClassInfo()->GetClassName() );
1568 wxPrintf( wxT(".\n") );
1572 // GDK sends surplus button down event
1573 // before a double click event. We
1574 // need to filter these out.
1575 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1577 GdkEvent
*peek_event
= gdk_event_peek();
1580 if ((peek_event
->type
== GDK_2BUTTON_PRESS
) ||
1581 (peek_event
->type
== GDK_3BUTTON_PRESS
))
1583 gdk_event_free( peek_event
);
1588 gdk_event_free( peek_event
);
1593 wxEventType event_type
= wxEVT_NULL
;
1595 // GdkDisplay is a GTK+ 2.2.0 thing
1596 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1597 if ( gdk_event
->type
== GDK_2BUTTON_PRESS
&&
1598 gdk_event
->button
>= 1 && gdk_event
->button
<= 3 )
1600 // Reset GDK internal timestamp variables in order to disable GDK
1601 // triple click events. GDK will then next time believe no button has
1602 // been clicked just before, and send a normal button click event.
1603 GdkDisplay
* display
= gtk_widget_get_display (widget
);
1604 display
->button_click_time
[1] = 0;
1605 display
->button_click_time
[0] = 0;
1609 if (gdk_event
->button
== 1)
1611 // note that GDK generates triple click events which are not supported
1612 // by wxWidgets but still have to be passed to the app as otherwise
1613 // clicks would simply go missing
1614 switch (gdk_event
->type
)
1616 // we shouldn't get triple clicks at all for GTK2 because we
1617 // suppress them artificially using the code above but we still
1618 // should map them to something for GTK1 and not just ignore them
1619 // as this would lose clicks
1620 case GDK_3BUTTON_PRESS
: // we could also map this to DCLICK...
1621 case GDK_BUTTON_PRESS
:
1622 event_type
= wxEVT_LEFT_DOWN
;
1625 case GDK_2BUTTON_PRESS
:
1626 event_type
= wxEVT_LEFT_DCLICK
;
1630 // just to silence gcc warnings
1634 else if (gdk_event
->button
== 2)
1636 switch (gdk_event
->type
)
1638 case GDK_3BUTTON_PRESS
:
1639 case GDK_BUTTON_PRESS
:
1640 event_type
= wxEVT_MIDDLE_DOWN
;
1643 case GDK_2BUTTON_PRESS
:
1644 event_type
= wxEVT_MIDDLE_DCLICK
;
1651 else if (gdk_event
->button
== 3)
1653 switch (gdk_event
->type
)
1655 case GDK_3BUTTON_PRESS
:
1656 case GDK_BUTTON_PRESS
:
1657 event_type
= wxEVT_RIGHT_DOWN
;
1660 case GDK_2BUTTON_PRESS
:
1661 event_type
= wxEVT_RIGHT_DCLICK
;
1668 else if (gdk_event
->button
== 4 || gdk_event
->button
== 5)
1670 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1672 event_type
= wxEVT_MOUSEWHEEL
;
1676 if ( event_type
== wxEVT_NULL
)
1678 // unknown mouse button or click type
1682 wxMouseEvent
event( event_type
);
1683 InitMouseEvent( win
, event
, gdk_event
);
1685 AdjustEventButtonState(event
);
1687 // wxListBox actually get mouse events from the item, so we need to give it
1688 // a chance to correct this
1689 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1691 if ( event_type
== wxEVT_RIGHT_DOWN
)
1693 // generate a "context menu" event: this is similar to right mouse
1694 // click under many GUIs except that it is generated differently
1695 // (right up under MSW, ctrl-click under Mac, right down here) and
1697 // (a) it's a command event and so is propagated to the parent
1698 // (b) under MSW it can be generated from kbd too
1699 // (c) it uses screen coords (because of (a))
1700 wxContextMenuEvent
evtCtx(wxEVT_CONTEXT_MENU
,
1702 win
->ClientToScreen(event
.GetPosition()));
1703 (void)win
->GetEventHandler()->ProcessEvent(evtCtx
);
1706 // find the correct window to send the event too: it may be a different one
1707 // from the one which got it at GTK+ level because some control don't have
1708 // their own X window and thus cannot get any events.
1709 if ( !g_captureWindow
)
1710 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1712 gs_timeLastClick
= gdk_event
->time
;
1715 if (event_type
== wxEVT_LEFT_DCLICK
)
1717 // GTK 1.2 crashes when intercepting double
1718 // click events from both wxSpinButton and
1720 if (GTK_IS_SPIN_BUTTON(win
->m_widget
))
1722 // Just disable this event for now.
1728 if (win
->GetEventHandler()->ProcessEvent( event
))
1730 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1737 //-----------------------------------------------------------------------------
1738 // "button_release_event"
1739 //-----------------------------------------------------------------------------
1741 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1742 GdkEventButton
*gdk_event
,
1748 wxapp_install_idle_handler();
1750 if (!win
->m_hasVMT
) return FALSE
;
1751 if (g_blockEventsOnDrag
) return FALSE
;
1752 if (g_blockEventsOnScroll
) return FALSE
;
1754 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1756 wxEventType event_type
= wxEVT_NULL
;
1758 switch (gdk_event
->button
)
1761 event_type
= wxEVT_LEFT_UP
;
1765 event_type
= wxEVT_MIDDLE_UP
;
1769 event_type
= wxEVT_RIGHT_UP
;
1773 // unknwon button, don't process
1777 wxMouseEvent
event( event_type
);
1778 InitMouseEvent( win
, event
, gdk_event
);
1780 AdjustEventButtonState(event
);
1782 // same wxListBox hack as above
1783 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1785 if ( !g_captureWindow
)
1786 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1788 if (win
->GetEventHandler()->ProcessEvent( event
))
1790 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1797 //-----------------------------------------------------------------------------
1798 // "motion_notify_event"
1799 //-----------------------------------------------------------------------------
1801 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1802 GdkEventMotion
*gdk_event
,
1808 wxapp_install_idle_handler();
1810 if (!win
->m_hasVMT
) return FALSE
;
1811 if (g_blockEventsOnDrag
) return FALSE
;
1812 if (g_blockEventsOnScroll
) return FALSE
;
1814 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1816 if (gdk_event
->is_hint
)
1820 GdkModifierType state
;
1821 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1827 printf( "OnMotion from " );
1828 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1829 printf( win->GetClassInfo()->GetClassName() );
1833 wxMouseEvent
event( wxEVT_MOTION
);
1834 InitMouseEvent(win
, event
, gdk_event
);
1836 if ( g_captureWindow
)
1838 // synthetize a mouse enter or leave event if needed
1839 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1840 // This seems to be necessary and actually been added to
1841 // GDK itself in version 2.0.X
1844 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1845 if ( hasMouse
!= g_captureWindowHasMouse
)
1847 // the mouse changed window
1848 g_captureWindowHasMouse
= hasMouse
;
1850 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1851 : wxEVT_LEAVE_WINDOW
);
1852 InitMouseEvent(win
, event
, gdk_event
);
1853 event
.SetEventObject(win
);
1854 win
->GetEventHandler()->ProcessEvent(event
);
1859 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1862 if (win
->GetEventHandler()->ProcessEvent( event
))
1864 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1872 //-----------------------------------------------------------------------------
1873 // "mouse_wheel_event"
1874 //-----------------------------------------------------------------------------
1876 static gint
gtk_window_wheel_callback (GtkWidget
* widget
,
1877 GdkEventScroll
* gdk_event
,
1883 wxapp_install_idle_handler();
1885 wxEventType event_type
= wxEVT_NULL
;
1886 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1887 event_type
= wxEVT_MOUSEWHEEL
;
1888 else if (gdk_event
->direction
== GDK_SCROLL_DOWN
)
1889 event_type
= wxEVT_MOUSEWHEEL
;
1893 wxMouseEvent
event( event_type
);
1894 // Can't use InitMouse macro because scroll events don't have button
1895 event
.SetTimestamp( gdk_event
->time
);
1896 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
);
1897 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
);
1898 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
);
1899 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
);
1900 event
.m_leftDown
= (gdk_event
->state
& GDK_BUTTON1_MASK
);
1901 event
.m_middleDown
= (gdk_event
->state
& GDK_BUTTON2_MASK
);
1902 event
.m_rightDown
= (gdk_event
->state
& GDK_BUTTON3_MASK
);
1903 event
.m_linesPerAction
= 3;
1904 event
.m_wheelDelta
= 120;
1905 if (gdk_event
->direction
== GDK_SCROLL_UP
)
1906 event
.m_wheelRotation
= 120;
1908 event
.m_wheelRotation
= -120;
1910 wxPoint pt
= win
->GetClientAreaOrigin();
1911 event
.m_x
= (wxCoord
)gdk_event
->x
- pt
.x
;
1912 event
.m_y
= (wxCoord
)gdk_event
->y
- pt
.y
;
1914 event
.SetEventObject( win
);
1915 event
.SetId( win
->GetId() );
1916 event
.SetTimestamp( gdk_event
->time
);
1918 if (win
->GetEventHandler()->ProcessEvent( event
))
1920 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "scroll_event" );
1928 //-----------------------------------------------------------------------------
1930 //-----------------------------------------------------------------------------
1932 // send the wxChildFocusEvent and wxFocusEvent, common code of
1933 // gtk_window_focus_in_callback() and SetFocus()
1934 static bool DoSendFocusEvents(wxWindow
*win
)
1936 // Notify the parent keeping track of focus for the kbd navigation
1937 // purposes that we got it.
1938 wxChildFocusEvent
eventChildFocus(win
);
1939 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1941 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1942 eventFocus
.SetEventObject(win
);
1944 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1947 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1948 GdkEvent
*WXUNUSED(event
),
1954 wxapp_install_idle_handler();
1958 gtk_im_context_focus_in(win
->m_imData
->context
);
1962 g_focusWindow
= win
;
1964 wxLogTrace(TRACE_FOCUS
,
1965 _T("%s: focus in"), win
->GetName().c_str());
1969 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1973 // caret needs to be informed about focus change
1974 wxCaret
*caret
= win
->GetCaret();
1977 caret
->OnSetFocus();
1979 #endif // wxUSE_CARET
1981 // does the window itself think that it has the focus?
1982 if ( !win
->m_hasFocus
)
1984 // not yet, notify it
1985 win
->m_hasFocus
= TRUE
;
1987 if ( DoSendFocusEvents(win
) )
1989 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1997 //-----------------------------------------------------------------------------
1998 // "focus_out_event"
1999 //-----------------------------------------------------------------------------
2001 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
2006 wxapp_install_idle_handler();
2010 gtk_im_context_focus_out(win
->m_imData
->context
);
2013 wxLogTrace( TRACE_FOCUS
,
2014 _T("%s: focus out"), win
->GetName().c_str() );
2017 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
2021 g_focusWindow
= (wxWindowGTK
*)NULL
;
2029 // caret needs to be informed about focus change
2030 wxCaret
*caret
= win
->GetCaret();
2033 caret
->OnKillFocus();
2035 #endif // wxUSE_CARET
2037 // don't send the window a kill focus event if it thinks that it doesn't
2038 // have focus already
2039 if ( win
->m_hasFocus
)
2041 win
->m_hasFocus
= FALSE
;
2043 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
2044 event
.SetEventObject( win
);
2046 // even if we did process the event in wx code, still let GTK itself
2047 // process it too as otherwise bad things happen, especially in GTK2
2048 // where the text control simply aborts the program if it doesn't get
2049 // the matching focus out event
2050 (void)win
->GetEventHandler()->ProcessEvent( event
);
2056 //-----------------------------------------------------------------------------
2057 // "enter_notify_event"
2058 //-----------------------------------------------------------------------------
2061 gint
gtk_window_enter_callback( GtkWidget
*widget
,
2062 GdkEventCrossing
*gdk_event
,
2068 wxapp_install_idle_handler();
2070 if (!win
->m_hasVMT
) return FALSE
;
2071 if (g_blockEventsOnDrag
) return FALSE
;
2073 // Event was emitted after a grab
2074 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2076 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2080 GdkModifierType state
= (GdkModifierType
)0;
2082 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2084 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
2085 InitMouseEvent(win
, event
, gdk_event
);
2086 wxPoint pt
= win
->GetClientAreaOrigin();
2087 event
.m_x
= x
+ pt
.x
;
2088 event
.m_y
= y
+ pt
.y
;
2090 if (win
->GetEventHandler()->ProcessEvent( event
))
2092 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
2099 //-----------------------------------------------------------------------------
2100 // "leave_notify_event"
2101 //-----------------------------------------------------------------------------
2103 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
2108 wxapp_install_idle_handler();
2110 if (!win
->m_hasVMT
) return FALSE
;
2111 if (g_blockEventsOnDrag
) return FALSE
;
2113 // Event was emitted after an ungrab
2114 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2116 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2118 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2119 event
.SetTimestamp( gdk_event
->time
);
2120 event
.SetEventObject( win
);
2124 GdkModifierType state
= (GdkModifierType
)0;
2126 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2128 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2129 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2130 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2131 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2132 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2133 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2134 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2136 wxPoint pt
= win
->GetClientAreaOrigin();
2137 event
.m_x
= x
+ pt
.x
;
2138 event
.m_y
= y
+ pt
.y
;
2140 if (win
->GetEventHandler()->ProcessEvent( event
))
2142 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
2149 //-----------------------------------------------------------------------------
2150 // "value_changed" from m_vAdjust
2151 //-----------------------------------------------------------------------------
2153 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2160 wxapp_install_idle_handler();
2162 if (g_blockEventsOnDrag
) return;
2164 if (!win
->m_hasVMT
) return;
2166 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2167 if (fabs(diff
) < 0.2) return;
2169 win
->m_oldVerticalPos
= adjust
->value
;
2172 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2174 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
2176 int value
= (int)(adjust
->value
+0.5);
2178 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2179 event
.SetEventObject( win
);
2180 win
->GetEventHandler()->ProcessEvent( event
);
2183 //-----------------------------------------------------------------------------
2184 // "value_changed" from m_hAdjust
2185 //-----------------------------------------------------------------------------
2187 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2194 wxapp_install_idle_handler();
2196 if (g_blockEventsOnDrag
) return;
2197 if (!win
->m_hasVMT
) return;
2199 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2200 if (fabs(diff
) < 0.2) return;
2203 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2205 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
2207 win
->m_oldHorizontalPos
= adjust
->value
;
2209 int value
= (int)(adjust
->value
+0.5);
2211 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2212 event
.SetEventObject( win
);
2213 win
->GetEventHandler()->ProcessEvent( event
);
2216 //-----------------------------------------------------------------------------
2217 // "button_press_event" from scrollbar
2218 //-----------------------------------------------------------------------------
2220 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2221 GdkEventButton
*gdk_event
,
2227 wxapp_install_idle_handler();
2230 g_blockEventsOnScroll
= TRUE
;
2232 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2234 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2240 //-----------------------------------------------------------------------------
2241 // "button_release_event" from scrollbar
2242 //-----------------------------------------------------------------------------
2244 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2245 GdkEventButton
*WXUNUSED(gdk_event
),
2250 // don't test here as we can release the mouse while being over
2251 // a different window than the slider
2253 // if (gdk_event->window != widget->slider) return FALSE;
2255 g_blockEventsOnScroll
= FALSE
;
2257 if (win
->m_isScrolling
)
2259 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2263 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2264 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2266 value
= (int)(win
->m_hAdjust
->value
+0.5);
2269 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2271 value
= (int)(win
->m_vAdjust
->value
+0.5);
2275 wxScrollWinEvent
event( command
, value
, dir
);
2276 event
.SetEventObject( win
);
2277 win
->GetEventHandler()->ProcessEvent( event
);
2280 win
->m_isScrolling
= FALSE
;
2285 // ----------------------------------------------------------------------------
2286 // this wxWindowBase function is implemented here (in platform-specific file)
2287 // because it is static and so couldn't be made virtual
2288 // ----------------------------------------------------------------------------
2290 wxWindow
*wxWindowBase::DoFindFocus()
2292 // the cast is necessary when we compile in wxUniversal mode
2293 return (wxWindow
*)g_focusWindow
;
2297 //-----------------------------------------------------------------------------
2298 // "realize" from m_widget
2299 //-----------------------------------------------------------------------------
2301 /* We cannot set colours and fonts before the widget has
2302 been realized, so we do this directly after realization. */
2305 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2310 wxapp_install_idle_handler();
2315 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2316 gtk_im_context_set_client_window( win
->m_imData
->context
,
2317 pizza
->bin_window
);
2321 wxWindowCreateEvent
event( win
);
2322 event
.SetEventObject( win
);
2323 win
->GetEventHandler()->ProcessEvent( event
);
2328 //-----------------------------------------------------------------------------
2330 //-----------------------------------------------------------------------------
2333 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2334 GtkAllocation
*WXUNUSED(alloc
),
2338 wxapp_install_idle_handler();
2340 if (!win
->m_hasScrolling
) return;
2342 int client_width
= 0;
2343 int client_height
= 0;
2344 win
->GetClientSize( &client_width
, &client_height
);
2345 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2348 win
->m_oldClientWidth
= client_width
;
2349 win
->m_oldClientHeight
= client_height
;
2351 if (!win
->m_nativeSizeEvent
)
2353 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2354 event
.SetEventObject( win
);
2355 win
->GetEventHandler()->ProcessEvent( event
);
2361 #define WXUNUSED_UNLESS_XIM(param) param
2363 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2366 /* Resize XIM window */
2369 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2370 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2371 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2374 wxapp_install_idle_handler();
2380 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2384 gdk_window_get_size (widget
->window
, &width
, &height
);
2385 win
->m_icattr
->preedit_area
.width
= width
;
2386 win
->m_icattr
->preedit_area
.height
= height
;
2387 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2392 //-----------------------------------------------------------------------------
2393 // "realize" from m_wxwindow
2394 //-----------------------------------------------------------------------------
2396 /* Initialize XIM support */
2399 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2400 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2403 wxapp_install_idle_handler();
2406 if (win
->m_ic
) return FALSE
;
2407 if (!widget
) return FALSE
;
2408 if (!gdk_im_ready()) return FALSE
;
2410 win
->m_icattr
= gdk_ic_attr_new();
2411 if (!win
->m_icattr
) return FALSE
;
2415 GdkColormap
*colormap
;
2416 GdkICAttr
*attr
= win
->m_icattr
;
2417 unsigned attrmask
= GDK_IC_ALL_REQ
;
2419 GdkIMStyle supported_style
= (GdkIMStyle
)
2420 (GDK_IM_PREEDIT_NONE
|
2421 GDK_IM_PREEDIT_NOTHING
|
2422 GDK_IM_PREEDIT_POSITION
|
2423 GDK_IM_STATUS_NONE
|
2424 GDK_IM_STATUS_NOTHING
);
2426 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2427 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2429 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2430 attr
->client_window
= widget
->window
;
2432 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2433 gtk_widget_get_default_colormap ())
2435 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2436 attr
->preedit_colormap
= colormap
;
2439 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2440 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2441 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2442 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2444 switch (style
& GDK_IM_PREEDIT_MASK
)
2446 case GDK_IM_PREEDIT_POSITION
:
2447 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2449 g_warning ("over-the-spot style requires fontset");
2453 gdk_window_get_size (widget
->window
, &width
, &height
);
2455 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2456 attr
->spot_location
.x
= 0;
2457 attr
->spot_location
.y
= height
;
2458 attr
->preedit_area
.x
= 0;
2459 attr
->preedit_area
.y
= 0;
2460 attr
->preedit_area
.width
= width
;
2461 attr
->preedit_area
.height
= height
;
2462 attr
->preedit_fontset
= widget
->style
->font
;
2467 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2469 if (win
->m_ic
== NULL
)
2470 g_warning ("Can't create input context.");
2473 mask
= gdk_window_get_events (widget
->window
);
2474 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2475 gdk_window_set_events (widget
->window
, mask
);
2477 if (GTK_WIDGET_HAS_FOCUS(widget
))
2478 gdk_im_begin (win
->m_ic
, widget
->window
);
2485 //-----------------------------------------------------------------------------
2486 // InsertChild for wxWindowGTK.
2487 //-----------------------------------------------------------------------------
2489 /* Callback for wxWindowGTK. This very strange beast has to be used because
2490 * C++ has no virtual methods in a constructor. We have to emulate a
2491 * virtual function here as wxNotebook requires a different way to insert
2492 * a child in it. I had opted for creating a wxNotebookPage window class
2493 * which would have made this superfluous (such in the MDI window system),
2494 * but no-one was listening to me... */
2496 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2498 /* the window might have been scrolled already, do we
2499 have to adapt the position */
2500 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2501 child
->m_x
+= pizza
->xoffset
;
2502 child
->m_y
+= pizza
->yoffset
;
2504 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2505 GTK_WIDGET(child
->m_widget
),
2512 //-----------------------------------------------------------------------------
2514 //-----------------------------------------------------------------------------
2516 wxWindow
*wxGetActiveWindow()
2518 return wxWindow::FindFocus();
2521 //-----------------------------------------------------------------------------
2523 //-----------------------------------------------------------------------------
2525 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2527 #ifdef __WXUNIVERSAL__
2528 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2530 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2531 #endif // __WXUNIVERSAL__/__WXGTK__
2533 void wxWindowGTK::Init()
2536 m_widget
= (GtkWidget
*) NULL
;
2537 m_wxwindow
= (GtkWidget
*) NULL
;
2538 m_focusWidget
= (GtkWidget
*) NULL
;
2548 m_needParent
= TRUE
;
2549 m_isBeingDeleted
= FALSE
;
2552 m_nativeSizeEvent
= FALSE
;
2554 m_hasScrolling
= FALSE
;
2555 m_isScrolling
= FALSE
;
2557 m_hAdjust
= (GtkAdjustment
*) NULL
;
2558 m_vAdjust
= (GtkAdjustment
*) NULL
;
2559 m_oldHorizontalPos
=
2560 m_oldVerticalPos
= 0.0;
2562 m_oldClientHeight
= 0;
2566 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2568 m_acceptsFocus
= FALSE
;
2571 m_clipPaintRegion
= FALSE
;
2573 m_needsStyleChange
= false;
2575 m_cursor
= *wxSTANDARD_CURSOR
;
2579 m_x11Context
= NULL
;
2580 m_dirtyTabOrder
= false;
2583 m_ic
= (GdkIC
*) NULL
;
2584 m_icattr
= (GdkICAttr
*) NULL
;
2589 wxWindowGTK::wxWindowGTK()
2594 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2599 const wxString
&name
)
2603 Create( parent
, id
, pos
, size
, style
, name
);
2606 bool wxWindowGTK::Create( wxWindow
*parent
,
2611 const wxString
&name
)
2613 if (!PreCreation( parent
, pos
, size
) ||
2614 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2616 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2620 m_insertCallback
= wxInsertChildInWindow
;
2622 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2623 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2625 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2627 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2628 scroll_class
->scrollbar_spacing
= 0;
2630 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2632 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2633 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2635 m_wxwindow
= gtk_pizza_new();
2637 #ifndef __WXUNIVERSAL__
2638 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2640 if (HasFlag(wxRAISED_BORDER
))
2642 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2644 else if (HasFlag(wxSUNKEN_BORDER
))
2646 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2648 else if (HasFlag(wxSIMPLE_BORDER
))
2650 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2654 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2656 #endif // __WXUNIVERSAL__
2658 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2660 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2661 m_acceptsFocus
= TRUE
;
2663 // I _really_ don't want scrollbars in the beginning
2664 m_vAdjust
->lower
= 0.0;
2665 m_vAdjust
->upper
= 1.0;
2666 m_vAdjust
->value
= 0.0;
2667 m_vAdjust
->step_increment
= 1.0;
2668 m_vAdjust
->page_increment
= 1.0;
2669 m_vAdjust
->page_size
= 5.0;
2670 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2671 m_hAdjust
->lower
= 0.0;
2672 m_hAdjust
->upper
= 1.0;
2673 m_hAdjust
->value
= 0.0;
2674 m_hAdjust
->step_increment
= 1.0;
2675 m_hAdjust
->page_increment
= 1.0;
2676 m_hAdjust
->page_size
= 5.0;
2677 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2679 // these handlers block mouse events to any window during scrolling such as
2680 // motion events and prevent GTK and wxWidgets from fighting over where the
2683 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2684 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2686 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2687 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2689 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2690 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2692 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2693 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2695 // these handlers get notified when screen updates are required either when
2696 // scrolling or when the window size (and therefore scrollbar configuration)
2699 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2700 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2701 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2702 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2704 gtk_widget_show( m_wxwindow
);
2707 m_parent
->DoAddChild( this );
2709 m_focusWidget
= m_wxwindow
;
2716 wxWindowGTK::~wxWindowGTK()
2720 if (g_focusWindow
== this)
2721 g_focusWindow
= NULL
;
2723 if ( g_delayedFocus
== this )
2724 g_delayedFocus
= NULL
;
2726 m_isBeingDeleted
= TRUE
;
2736 gdk_ic_destroy (m_ic
);
2738 gdk_ic_attr_destroy (m_icattr
);
2743 gtk_widget_destroy( m_wxwindow
);
2744 m_wxwindow
= (GtkWidget
*) NULL
;
2749 gtk_widget_destroy( m_widget
);
2750 m_widget
= (GtkWidget
*) NULL
;
2758 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2760 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2762 // Use either the given size, or the default if -1 is given.
2763 // See wxWindowBase for these functions.
2764 m_width
= WidthDefault(size
.x
) ;
2765 m_height
= HeightDefault(size
.y
);
2773 void wxWindowGTK::PostCreation()
2775 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2781 // these get reported to wxWidgets -> wxPaintEvent
2783 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2785 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2786 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2789 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2790 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2792 if (!HasFlag(wxFULL_REPAINT_ON_RESIZE
))
2794 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2795 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2798 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2803 // Create input method handler
2804 m_imData
= new wxGtkIMData
;
2806 // Cannot handle drawing preedited text yet
2807 gtk_im_context_set_use_preedit( m_imData
->context
, FALSE
);
2809 g_signal_connect (G_OBJECT (m_imData
->context
), "commit",
2810 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2813 // these are called when the "sunken" or "raised" borders are drawn
2814 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2815 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2818 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2819 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2825 if (!GTK_IS_WINDOW(m_widget
))
2827 if (m_focusWidget
== NULL
)
2828 m_focusWidget
= m_widget
;
2830 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2831 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2833 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2834 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2837 // connect to the various key and mouse handlers
2839 GtkWidget
*connect_widget
= GetConnectWidget();
2841 ConnectWidget( connect_widget
);
2843 /* We cannot set colours, fonts and cursors before the widget has
2844 been realized, so we do this directly after realization */
2845 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2846 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2850 // Catch native resize events
2851 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2852 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2854 // Initialize XIM support
2855 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2856 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2858 // And resize XIM window
2859 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2860 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2863 if ( !GTK_IS_COMBO(m_widget
))
2865 // This is needed if we want to add our windows into native
2866 // GTK control, such as the toolbar. With this callback, the
2867 // toolbar gets to know the correct size (the one set by the
2868 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2869 // when moving to GTK 2.0.
2870 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2871 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback
),
2875 InheritAttributes();
2879 // unless the window was created initially hidden (i.e. Hide() had been
2880 // called before Create()), we should show it at GTK+ level as well
2882 gtk_widget_show( m_widget
);
2885 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2887 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2888 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2890 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2891 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2893 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2894 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2896 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2897 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2899 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2900 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2903 gtk_signal_connect( GTK_OBJECT(widget
), "scroll_event",
2904 GTK_SIGNAL_FUNC(gtk_window_wheel_callback
), (gpointer
)this );
2907 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2908 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2910 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2911 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2914 bool wxWindowGTK::Destroy()
2916 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2920 return wxWindowBase::Destroy();
2923 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2925 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2928 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2930 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2931 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2934 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2937 if (m_resizing
) return; /* I don't like recursions */
2940 int currentX
, currentY
;
2941 GetPosition(¤tX
, ¤tY
);
2942 if (x
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2944 if (y
== -1 && !(sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
))
2946 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2948 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2950 /* don't set the size for children of wxNotebook, just take the values. */
2958 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2959 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2961 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2962 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2966 m_x
= x
+ pizza
->xoffset
;
2967 m_y
= y
+ pizza
->yoffset
;
2970 // calculate the best size if we should auto size the window
2971 if ( ((sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1) ||
2972 ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1) )
2974 const wxSize sizeBest
= GetBestSize();
2975 if ( (sizeFlags
& wxSIZE_AUTO_WIDTH
) && width
== -1 )
2977 if ( (sizeFlags
& wxSIZE_AUTO_HEIGHT
) && height
== -1 )
2978 height
= sizeBest
.y
;
2986 int minWidth
= GetMinWidth(),
2987 minHeight
= GetMinHeight(),
2988 maxWidth
= GetMaxWidth(),
2989 maxHeight
= GetMaxHeight();
2991 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2992 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2993 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2994 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2997 int bottom_border
= 0;
3000 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
3002 /* the default button has a border around it */
3008 DoMoveWindow( m_x
-border
,
3011 m_height
+border
+bottom_border
);
3016 /* Sometimes the client area changes size without the
3017 whole windows's size changing, but if the whole
3018 windows's size doesn't change, no wxSizeEvent will
3019 normally be sent. Here we add an extra test if
3020 the client test has been changed and this will
3022 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
3026 wxPrintf( "OnSize sent from " );
3027 if (GetClassInfo() && GetClassInfo()->GetClassName())
3028 wxPrintf( GetClassInfo()->GetClassName() );
3029 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3032 if (!m_nativeSizeEvent
)
3034 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
3035 event
.SetEventObject( this );
3036 GetEventHandler()->ProcessEvent( event
);
3042 void wxWindowGTK::OnInternalIdle()
3045 if ( m_dirtyTabOrder
)
3048 // Update style if the window was not yet realized
3049 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
3050 if (m_needsStyleChange
)
3052 SetBackgroundStyle(GetBackgroundStyle());
3053 m_needsStyleChange
= false;
3056 // Update invalidated regions.
3059 wxCursor cursor
= m_cursor
;
3060 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
3064 /* I now set the cursor anew in every OnInternalIdle call
3065 as setting the cursor in a parent window also effects the
3066 windows above so that checking for the current cursor is
3071 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3073 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3075 if (!g_globalCursor
.Ok())
3076 cursor
= *wxSTANDARD_CURSOR
;
3078 window
= m_widget
->window
;
3079 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3080 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3086 GdkWindow
*window
= m_widget
->window
;
3087 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3088 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3093 if (wxUpdateUIEvent::CanUpdate(this))
3094 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3097 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3099 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3101 if (width
) (*width
) = m_width
;
3102 if (height
) (*height
) = m_height
;
3105 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3107 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3111 SetSize( width
, height
);
3118 #ifndef __WXUNIVERSAL__
3119 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3121 /* when using GTK 1.2 we set the shadow border size to 2 */
3125 if (HasFlag(wxSIMPLE_BORDER
))
3127 /* when using GTK 1.2 we set the simple border size to 1 */
3131 #endif // __WXUNIVERSAL__
3135 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3137 GtkRequisition vscroll_req
;
3138 vscroll_req
.width
= 2;
3139 vscroll_req
.height
= 2;
3140 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3141 (scroll_window
->vscrollbar
, &vscroll_req
);
3143 GtkRequisition hscroll_req
;
3144 hscroll_req
.width
= 2;
3145 hscroll_req
.height
= 2;
3146 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3147 (scroll_window
->hscrollbar
, &hscroll_req
);
3149 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3151 if (scroll_window
->vscrollbar_visible
)
3153 dw
+= vscroll_req
.width
;
3154 dw
+= scroll_class
->scrollbar_spacing
;
3157 if (scroll_window
->hscrollbar_visible
)
3159 dh
+= hscroll_req
.height
;
3160 dh
+= scroll_class
->scrollbar_spacing
;
3164 SetSize( width
+dw
, height
+dh
);
3168 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3170 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3174 if (width
) (*width
) = m_width
;
3175 if (height
) (*height
) = m_height
;
3182 #ifndef __WXUNIVERSAL__
3183 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3185 /* when using GTK 1.2 we set the shadow border size to 2 */
3189 if (HasFlag(wxSIMPLE_BORDER
))
3191 /* when using GTK 1.2 we set the simple border size to 1 */
3195 #endif // __WXUNIVERSAL__
3199 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3201 GtkRequisition vscroll_req
;
3202 vscroll_req
.width
= 2;
3203 vscroll_req
.height
= 2;
3204 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3205 (scroll_window
->vscrollbar
, &vscroll_req
);
3207 GtkRequisition hscroll_req
;
3208 hscroll_req
.width
= 2;
3209 hscroll_req
.height
= 2;
3210 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3211 (scroll_window
->hscrollbar
, &hscroll_req
);
3213 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3215 if (scroll_window
->vscrollbar_visible
)
3217 dw
+= vscroll_req
.width
;
3218 dw
+= scroll_class
->scrollbar_spacing
;
3221 if (scroll_window
->hscrollbar_visible
)
3223 dh
+= hscroll_req
.height
;
3224 dh
+= scroll_class
->scrollbar_spacing
;
3228 if (width
) (*width
) = m_width
- dw
;
3229 if (height
) (*height
) = m_height
- dh
;
3233 printf( "GetClientSize, name %s ", GetName().c_str() );
3234 if (width) printf( " width = %d", (*width) );
3235 if (height) printf( " height = %d", (*height) );
3240 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3242 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3246 if (m_parent
&& m_parent
->m_wxwindow
)
3248 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3249 dx
= pizza
->xoffset
;
3250 dy
= pizza
->yoffset
;
3253 if (x
) (*x
) = m_x
- dx
;
3254 if (y
) (*y
) = m_y
- dy
;
3257 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3259 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3261 if (!m_widget
->window
) return;
3263 GdkWindow
*source
= (GdkWindow
*) NULL
;
3265 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3267 source
= m_widget
->window
;
3271 gdk_window_get_origin( source
, &org_x
, &org_y
);
3275 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3277 org_x
+= m_widget
->allocation
.x
;
3278 org_y
+= m_widget
->allocation
.y
;
3286 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3288 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3290 if (!m_widget
->window
) return;
3292 GdkWindow
*source
= (GdkWindow
*) NULL
;
3294 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3296 source
= m_widget
->window
;
3300 gdk_window_get_origin( source
, &org_x
, &org_y
);
3304 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3306 org_x
+= m_widget
->allocation
.x
;
3307 org_y
+= m_widget
->allocation
.y
;
3315 bool wxWindowGTK::Show( bool show
)
3317 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3319 if (!wxWindowBase::Show(show
))
3326 gtk_widget_show( m_widget
);
3328 gtk_widget_hide( m_widget
);
3330 wxShowEvent
eventShow(GetId(), show
);
3331 eventShow
.m_eventObject
= this;
3333 GetEventHandler()->ProcessEvent(eventShow
);
3338 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3340 win
->OnParentEnable(enable
);
3342 // Recurse, so that children have the opportunity to Do The Right Thing
3343 // and reset colours that have been messed up by a parent's (really ancestor's)
3345 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3347 node
= node
->GetNext() )
3349 wxWindow
*child
= node
->GetData();
3350 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3351 wxWindowNotifyEnable(child
, enable
);
3355 bool wxWindowGTK::Enable( bool enable
)
3357 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3359 if (!wxWindowBase::Enable(enable
))
3365 gtk_widget_set_sensitive( m_widget
, enable
);
3367 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3369 wxWindowNotifyEnable(this, enable
);
3374 int wxWindowGTK::GetCharHeight() const
3376 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3378 wxFont font
= GetFont();
3379 wxCHECK_MSG( font
.Ok(), 12, wxT("invalid font") );
3382 PangoContext
*context
= NULL
;
3384 context
= gtk_widget_get_pango_context( m_widget
);
3389 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3390 PangoLayout
*layout
= pango_layout_new(context
);
3391 pango_layout_set_font_description(layout
, desc
);
3392 pango_layout_set_text(layout
, "H", 1);
3393 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3395 PangoRectangle rect
;
3396 pango_layout_line_get_extents(line
, NULL
, &rect
);
3398 g_object_unref( G_OBJECT( layout
) );
3400 return (int) PANGO_PIXELS(rect
.height
);
3402 GdkFont
*gfont
= font
.GetInternalFont( 1.0 );
3404 return gfont
->ascent
+ gfont
->descent
;
3408 int wxWindowGTK::GetCharWidth() const
3410 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3412 wxFont font
= GetFont();
3413 wxCHECK_MSG( font
.Ok(), 8, wxT("invalid font") );
3416 PangoContext
*context
= NULL
;
3418 context
= gtk_widget_get_pango_context( m_widget
);
3423 PangoFontDescription
*desc
= font
.GetNativeFontInfo()->description
;
3424 PangoLayout
*layout
= pango_layout_new(context
);
3425 pango_layout_set_font_description(layout
, desc
);
3426 pango_layout_set_text(layout
, "g", 1);
3427 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3429 PangoRectangle rect
;
3430 pango_layout_line_get_extents(line
, NULL
, &rect
);
3432 g_object_unref( G_OBJECT( layout
) );
3434 return (int) PANGO_PIXELS(rect
.width
);
3436 GdkFont
*gfont
= font
.GetInternalFont( 1.0 );
3438 return gdk_string_width( gfont
, "g" );
3442 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3446 int *externalLeading
,
3447 const wxFont
*theFont
) const
3449 wxFont fontToUse
= theFont
? *theFont
: GetFont();
3451 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3453 if (string
.IsEmpty())
3461 PangoContext
*context
= NULL
;
3463 context
= gtk_widget_get_pango_context( m_widget
);
3472 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3473 PangoLayout
*layout
= pango_layout_new(context
);
3474 pango_layout_set_font_description(layout
, desc
);
3477 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3478 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3480 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3481 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3482 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3486 PangoRectangle rect
;
3487 pango_layout_get_extents(layout
, NULL
, &rect
);
3489 if (x
) (*x
) = (wxCoord
) PANGO_PIXELS(rect
.width
);
3490 if (y
) (*y
) = (wxCoord
) PANGO_PIXELS(rect
.height
);
3493 PangoLayoutIter
*iter
= pango_layout_get_iter(layout
);
3494 int baseline
= pango_layout_iter_get_baseline(iter
);
3495 pango_layout_iter_free(iter
);
3496 *descent
= *y
- PANGO_PIXELS(baseline
);
3498 if (externalLeading
) (*externalLeading
) = 0; // ??
3500 g_object_unref( G_OBJECT( layout
) );
3502 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3503 if (x
) (*x
) = gdk_string_width( font
, wxGTK_CONV( string
) );
3504 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3505 if (descent
) (*descent
) = font
->descent
;
3506 if (externalLeading
) (*externalLeading
) = 0; // ??
3510 void wxWindowGTK::SetFocus()
3512 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3515 // don't do anything if we already have focus
3521 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3523 gtk_widget_grab_focus (m_wxwindow
);
3529 if (GTK_IS_CONTAINER(m_widget
))
3531 gtk_widget_child_focus( m_widget
, GTK_DIR_TAB_FORWARD
);
3535 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3538 if (!GTK_WIDGET_REALIZED(m_widget
))
3540 // we can't set the focus to the widget now so we remember that
3541 // it should be focused and will do it later, during the idle
3542 // time, as soon as we can
3543 wxLogTrace(TRACE_FOCUS
,
3544 _T("Delaying setting focus to %s(%s)"),
3545 GetClassInfo()->GetClassName(), GetLabel().c_str());
3547 g_delayedFocus
= this;
3551 wxLogTrace(TRACE_FOCUS
,
3552 _T("Setting focus to %s(%s)"),
3553 GetClassInfo()->GetClassName(), GetLabel().c_str());
3555 gtk_widget_grab_focus (m_widget
);
3560 if (GTK_IS_CONTAINER(m_widget
))
3562 gtk_container_focus( GTK_CONTAINER(m_widget
), GTK_DIR_TAB_FORWARD
);
3567 wxLogTrace(TRACE_FOCUS
,
3568 _T("Can't set focus to %s(%s)"),
3569 GetClassInfo()->GetClassName(), GetLabel().c_str());
3574 bool wxWindowGTK::AcceptsFocus() const
3576 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3579 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3581 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3583 wxWindowGTK
*oldParent
= m_parent
,
3584 *newParent
= (wxWindowGTK
*)newParentBase
;
3586 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3588 if ( !wxWindowBase::Reparent(newParent
) )
3591 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3593 /* prevent GTK from deleting the widget arbitrarily */
3594 gtk_widget_ref( m_widget
);
3598 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3601 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3605 /* insert GTK representation */
3606 (*(newParent
->m_insertCallback
))(newParent
, this);
3609 /* reverse: prevent GTK from deleting the widget arbitrarily */
3610 gtk_widget_unref( m_widget
);
3615 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3617 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3619 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3621 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3626 /* insert GTK representation */
3627 (*m_insertCallback
)(this, child
);
3632 void wxWindowGTK::AddChild(wxWindowBase
*child
)
3634 wxWindowBase::AddChild(child
);
3635 m_dirtyTabOrder
= true;
3637 wxapp_install_idle_handler();
3640 void wxWindowGTK::RemoveChild(wxWindowBase
*child
)
3642 wxWindowBase::RemoveChild(child
);
3643 m_dirtyTabOrder
= true;
3645 wxapp_install_idle_handler();
3648 void wxWindowGTK::DoMoveInTabOrder(wxWindow
*win
, MoveKind move
)
3650 wxWindowBase::DoMoveInTabOrder(win
, move
);
3651 m_dirtyTabOrder
= true;
3653 wxapp_install_idle_handler();
3656 void wxWindowGTK::RealizeTabOrder()
3660 if (m_children
.size() > 0)
3662 GList
*chain
= NULL
;
3664 for (wxWindowList::const_iterator i
= m_children
.begin();
3665 i
!= m_children
.end(); ++i
)
3667 chain
= g_list_prepend(chain
, (*i
)->m_widget
);
3670 chain
= g_list_reverse(chain
);
3672 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow
), chain
);
3677 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow
));
3681 m_dirtyTabOrder
= false;
3684 #endif // __WXGTK20__
3686 void wxWindowGTK::Raise()
3688 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3690 if (!m_widget
->window
) return;
3692 gdk_window_raise( m_widget
->window
);
3695 void wxWindowGTK::Lower()
3697 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3699 if (!m_widget
->window
) return;
3701 gdk_window_lower( m_widget
->window
);
3704 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3706 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3708 if (cursor
== m_cursor
)
3712 wxapp_install_idle_handler();
3714 if (cursor
== wxNullCursor
)
3715 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3717 return wxWindowBase::SetCursor( cursor
);
3720 void wxWindowGTK::WarpPointer( int x
, int y
)
3722 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3724 // We provide this function ourselves as it is
3725 // missing in GDK (top of this file).
3727 GdkWindow
*window
= (GdkWindow
*) NULL
;
3729 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3731 window
= GetConnectWidget()->window
;
3734 gdk_window_warp_pointer( window
, x
, y
);
3738 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3740 if (!m_widget
) return;
3741 if (!m_widget
->window
) return;
3745 wxapp_install_idle_handler();
3747 wxRect
myRect(0,0,0,0);
3748 if (m_wxwindow
&& rect
)
3750 myRect
.SetSize(wxSize( m_wxwindow
->allocation
.width
,
3751 m_wxwindow
->allocation
.height
));
3752 myRect
.Intersect(*rect
);
3753 if (!myRect
.width
|| !myRect
.height
)
3754 // nothing to do, rectangle is empty
3759 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3763 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3764 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3768 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3769 m_clearRegion
.Clear();
3770 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3778 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3779 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3783 GdkRectangle gdk_rect
;
3784 gdk_rect
.x
= rect
->x
;
3785 gdk_rect
.y
= rect
->y
;
3786 gdk_rect
.width
= rect
->width
;
3787 gdk_rect
.height
= rect
->height
;
3788 gtk_widget_draw( m_widget
, &gdk_rect
);
3795 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3796 m_updateRegion
.Clear();
3797 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3801 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3809 GdkRectangle gdk_rect
;
3810 gdk_rect
.x
= rect
->x
;
3811 gdk_rect
.y
= rect
->y
;
3812 gdk_rect
.width
= rect
->width
;
3813 gdk_rect
.height
= rect
->height
;
3814 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3818 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3824 void wxWindowGTK::Update()
3829 void wxWindowGTK::GtkUpdate()
3832 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3833 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3835 if (!m_updateRegion
.IsEmpty())
3836 GtkSendPaintEvents();
3840 void wxWindowGTK::GtkSendPaintEvents()
3845 m_clearRegion
.Clear();
3847 m_updateRegion
.Clear();
3851 // Clip to paint region in wxClientDC
3852 m_clipPaintRegion
= TRUE
;
3854 // widget to draw on
3855 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3857 if (GetThemeEnabled() && GetBackgroundStyle() == wxBG_STYLE_SYSTEM
)
3859 // find ancestor from which to steal background
3860 wxWindow
*parent
= GetParent();
3861 while (parent
&& !parent
->IsTopLevel())
3862 parent
= parent
->GetParent();
3864 parent
= (wxWindow
*)this;
3866 wxRegionIterator
upd( m_updateRegion
);
3870 rect
.x
= upd
.GetX();
3871 rect
.y
= upd
.GetY();
3872 rect
.width
= upd
.GetWidth();
3873 rect
.height
= upd
.GetHeight();
3875 gtk_paint_flat_box( parent
->m_widget
->style
,
3877 (GtkStateType
)GTK_WIDGET_STATE(m_wxwindow
),
3891 wxWindowDC
dc( (wxWindow
*)this );
3892 dc
.SetClippingRegion( m_updateRegion
);
3894 wxEraseEvent
erase_event( GetId(), &dc
);
3895 erase_event
.SetEventObject( this );
3897 GetEventHandler()->ProcessEvent(erase_event
);
3900 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
3902 wxWindowDC
dc( (wxWindow
*)this );
3903 if (m_clearRegion
.IsEmpty())
3904 dc
.SetClippingRegion( m_updateRegion
);
3906 dc
.SetClippingRegion( m_clearRegion
);
3908 wxEraseEvent
erase_event( GetId(), &dc
);
3909 erase_event
.SetEventObject( this );
3911 if (!GetEventHandler()->ProcessEvent(erase_event
) && GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
3915 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
3916 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3918 gdk_gc_set_foreground( g_eraseGC
, GetBackgroundColour().GetColor() );
3920 wxRegionIterator
upd( m_clearRegion
);
3923 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3924 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3928 m_clearRegion
.Clear();
3932 wxNcPaintEvent
nc_paint_event( GetId() );
3933 nc_paint_event
.SetEventObject( this );
3934 GetEventHandler()->ProcessEvent( nc_paint_event
);
3936 wxPaintEvent
paint_event( GetId() );
3937 paint_event
.SetEventObject( this );
3938 GetEventHandler()->ProcessEvent( paint_event
);
3940 m_clipPaintRegion
= FALSE
;
3942 #ifndef __WXUNIVERSAL__
3944 // The following code will result in all window-less widgets
3945 // being redrawn because the wxWidgets class is allowed to
3946 // paint over the window-less widgets.
3948 GList
*children
= pizza
->children
;
3951 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3952 children
= children
->next
;
3954 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3955 GTK_WIDGET_DRAWABLE (child
->widget
))
3957 // Get intersection of widget area and update region
3958 wxRegion
region( m_updateRegion
);
3960 GdkEventExpose gdk_event
;
3961 gdk_event
.type
= GDK_EXPOSE
;
3962 gdk_event
.window
= pizza
->bin_window
;
3963 gdk_event
.count
= 0;
3965 wxRegionIterator
upd( m_updateRegion
);
3969 rect
.x
= upd
.GetX();
3970 rect
.y
= upd
.GetY();
3971 rect
.width
= upd
.GetWidth();
3972 rect
.height
= upd
.GetHeight();
3974 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3976 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3986 m_updateRegion
.Clear();
3989 void wxWindowGTK::ClearBackground()
3991 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3994 if (m_wxwindow
&& m_wxwindow
->window
)
3996 m_clearRegion
.Clear();
3997 wxSize
size( GetClientSize() );
3998 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
4000 // Better do this in idle?
4007 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
4009 wxWindowBase::DoSetToolTip(tip
);
4012 m_tooltip
->Apply( (wxWindow
*)this );
4015 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
4017 wxString
tmp( tip
);
4018 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxGTK_CONV(tmp
), (gchar
*) NULL
);
4020 #endif // wxUSE_TOOLTIPS
4022 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
4024 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4026 if (!wxWindowBase::SetBackgroundColour(colour
))
4031 // We need the pixel value e.g. for background clearing.
4032 m_backgroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
4035 // apply style change (forceStyle=true so that new style is applied
4036 // even if the bg colour changed from valid to wxNullColour)
4037 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM
)
4038 ApplyWidgetStyle(true);
4043 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
4045 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4047 if (!wxWindowBase::SetForegroundColour(colour
))
4054 // We need the pixel value e.g. for background clearing.
4055 m_foregroundColour
.CalcPixel(gtk_widget_get_colormap(m_widget
));
4058 // apply style change (forceStyle=true so that new style is applied
4059 // even if the bg colour changed from valid to wxNullColour):
4060 ApplyWidgetStyle(true);
4066 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
4068 return gtk_widget_get_pango_context( m_widget
);
4071 PangoContext
*wxWindowGTK::GtkGetPangoX11Context()
4074 m_x11Context
= pango_x_get_context( gdk_display
);
4076 return m_x11Context
;
4080 GtkRcStyle
*wxWindowGTK::CreateWidgetStyle(bool forceStyle
)
4082 // do we need to apply any changes at all?
4085 !m_foregroundColour
.Ok() && !m_backgroundColour
.Ok() )
4090 GtkRcStyle
*style
= gtk_rc_style_new();
4096 pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
4098 wxString xfontname
= m_font
.GetNativeFontInfo()->GetXFontName();
4099 style
->fontset_name
= g_strdup(xfontname
.c_str());
4103 if ( m_foregroundColour
.Ok() )
4105 GdkColor
*fg
= m_foregroundColour
.GetColor();
4107 style
->fg
[GTK_STATE_NORMAL
] = *fg
;
4108 style
->color_flags
[GTK_STATE_NORMAL
] = GTK_RC_FG
;
4110 style
->fg
[GTK_STATE_PRELIGHT
] = *fg
;
4111 style
->color_flags
[GTK_STATE_PRELIGHT
] = GTK_RC_FG
;
4113 style
->fg
[GTK_STATE_ACTIVE
] = *fg
;
4114 style
->color_flags
[GTK_STATE_ACTIVE
] = GTK_RC_FG
;
4117 if ( m_backgroundColour
.Ok() )
4119 GdkColor
*bg
= m_backgroundColour
.GetColor();
4121 style
->bg
[GTK_STATE_NORMAL
] = *bg
;
4122 style
->base
[GTK_STATE_NORMAL
] = *bg
;
4123 style
->color_flags
[GTK_STATE_NORMAL
] = (GtkRcFlags
)
4124 (style
->color_flags
[GTK_STATE_NORMAL
] | GTK_RC_BG
| GTK_RC_BASE
);
4126 style
->bg
[GTK_STATE_PRELIGHT
] = *bg
;
4127 style
->base
[GTK_STATE_PRELIGHT
] = *bg
;
4128 style
->color_flags
[GTK_STATE_PRELIGHT
] = (GtkRcFlags
)
4129 (style
->color_flags
[GTK_STATE_PRELIGHT
] | GTK_RC_BG
| GTK_RC_BASE
);
4131 style
->bg
[GTK_STATE_ACTIVE
] = *bg
;
4132 style
->base
[GTK_STATE_ACTIVE
] = *bg
;
4133 style
->color_flags
[GTK_STATE_ACTIVE
] = (GtkRcFlags
)
4134 (style
->color_flags
[GTK_STATE_ACTIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4136 style
->bg
[GTK_STATE_INSENSITIVE
] = *bg
;
4137 style
->base
[GTK_STATE_INSENSITIVE
] = *bg
;
4138 style
->color_flags
[GTK_STATE_INSENSITIVE
] = (GtkRcFlags
)
4139 (style
->color_flags
[GTK_STATE_INSENSITIVE
] | GTK_RC_BG
| GTK_RC_BASE
);
4145 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle
)
4147 GtkRcStyle
*style
= CreateWidgetStyle(forceStyle
);
4150 DoApplyWidgetStyle(style
);
4151 gtk_rc_style_unref(style
);
4154 // Style change may affect GTK+'s size calculation:
4155 InvalidateBestSize();
4158 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle
*style
)
4161 gtk_widget_modify_style(m_wxwindow
, style
);
4162 gtk_widget_modify_style(m_widget
, style
);
4165 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style
)
4167 wxWindowBase::SetBackgroundStyle(style
);
4169 if (style
== wxBG_STYLE_CUSTOM
)
4171 GdkWindow
*window
= (GdkWindow
*) NULL
;
4173 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4175 window
= GetConnectWidget()->window
;
4179 // Make sure GDK/X11 doesn't refresh the window
4181 gdk_window_set_back_pixmap( window
, None
, False
);
4183 Display
* display
= GDK_WINDOW_DISPLAY(window
);
4186 m_needsStyleChange
= false;
4189 // Do in OnIdle, because the window is not yet available
4190 m_needsStyleChange
= true;
4192 // Don't apply widget style, or we get a grey background
4196 // apply style change (forceStyle=true so that new style is applied
4197 // even if the bg colour changed from valid to wxNullColour):
4198 ApplyWidgetStyle(true);
4203 //-----------------------------------------------------------------------------
4204 // Pop-up menu stuff
4205 //-----------------------------------------------------------------------------
4207 #if wxUSE_MENUS_NATIVE
4210 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
4212 *is_waiting
= FALSE
;
4215 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
4217 menu
->SetInvokingWindow( win
);
4218 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
4221 wxMenuItem
*menuitem
= node
->GetData();
4222 if (menuitem
->IsSubMenu())
4224 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
4227 node
= node
->GetNext();
4231 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
4234 gboolean
* WXUNUSED(whatever
),
4236 gpointer user_data
)
4238 // ensure that the menu appears entirely on screen
4240 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
4242 wxSize sizeScreen
= wxGetDisplaySize();
4243 wxPoint
*pos
= (wxPoint
*)user_data
;
4245 gint xmax
= sizeScreen
.x
- req
.width
,
4246 ymax
= sizeScreen
.y
- req
.height
;
4248 *x
= pos
->x
< xmax
? pos
->x
: xmax
;
4249 *y
= pos
->y
< ymax
? pos
->y
: ymax
;
4252 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4254 wxCHECK_MSG( m_widget
!= NULL
, false, wxT("invalid window") );
4256 wxCHECK_MSG( menu
!= NULL
, false, wxT("invalid popup-menu") );
4258 SetInvokingWindow( menu
, this );
4262 bool is_waiting
= true;
4264 gulong handler
= gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
4266 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
4267 (gpointer
)&is_waiting
);
4271 GtkMenuPositionFunc posfunc
;
4272 if ( x
== -1 && y
== -1 )
4274 // use GTK's default positioning algorithm
4280 pos
= ClientToScreen(wxPoint(x
, y
));
4282 posfunc
= wxPopupMenuPositionCallback
;
4286 GTK_MENU(menu
->m_menu
),
4287 (GtkWidget
*) NULL
, // parent menu shell
4288 (GtkWidget
*) NULL
, // parent menu item
4289 posfunc
, // function to position it
4290 userdata
, // client data
4291 0, // button used to activate it
4293 gtk_get_current_event_time()
4295 gs_timeLastClick
// the time of activation
4301 gtk_main_iteration();
4304 gtk_signal_disconnect(GTK_OBJECT(menu
->m_menu
), handler
);
4309 #endif // wxUSE_MENUS_NATIVE
4311 #if wxUSE_DRAG_AND_DROP
4313 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4315 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4317 GtkWidget
*dnd_widget
= GetConnectWidget();
4319 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4321 if (m_dropTarget
) delete m_dropTarget
;
4322 m_dropTarget
= dropTarget
;
4324 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4327 #endif // wxUSE_DRAG_AND_DROP
4329 GtkWidget
* wxWindowGTK::GetConnectWidget()
4331 GtkWidget
*connect_widget
= m_widget
;
4332 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4334 return connect_widget
;
4337 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4340 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4342 return (window
== m_widget
->window
);
4345 bool wxWindowGTK::SetFont( const wxFont
&font
)
4347 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4349 if (!wxWindowBase::SetFont(font
))
4352 // apply style change (forceStyle=true so that new style is applied
4353 // even if the font changed from valid to wxNullFont):
4354 ApplyWidgetStyle(true);
4359 void wxWindowGTK::DoCaptureMouse()
4361 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4363 GdkWindow
*window
= (GdkWindow
*) NULL
;
4365 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4367 window
= GetConnectWidget()->window
;
4369 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4371 wxCursor
* cursor
= & m_cursor
;
4373 cursor
= wxSTANDARD_CURSOR
;
4375 gdk_pointer_grab( window
, FALSE
,
4377 (GDK_BUTTON_PRESS_MASK
|
4378 GDK_BUTTON_RELEASE_MASK
|
4379 GDK_POINTER_MOTION_HINT_MASK
|
4380 GDK_POINTER_MOTION_MASK
),
4382 cursor
->GetCursor(),
4383 (guint32
)GDK_CURRENT_TIME
);
4384 g_captureWindow
= this;
4385 g_captureWindowHasMouse
= TRUE
;
4388 void wxWindowGTK::DoReleaseMouse()
4390 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4392 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4394 g_captureWindow
= (wxWindowGTK
*) NULL
;
4396 GdkWindow
*window
= (GdkWindow
*) NULL
;
4398 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4400 window
= GetConnectWidget()->window
;
4405 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4409 wxWindow
*wxWindowBase::GetCapture()
4411 return (wxWindow
*)g_captureWindow
;
4414 bool wxWindowGTK::IsRetained() const
4419 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4420 int range
, bool refresh
)
4422 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4424 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4426 m_hasScrolling
= TRUE
;
4428 if (orient
== wxHORIZONTAL
)
4430 float fpos
= (float)pos
;
4431 float frange
= (float)range
;
4432 float fthumb
= (float)thumbVisible
;
4433 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4434 if (fpos
< 0.0) fpos
= 0.0;
4436 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4437 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4439 SetScrollPos( orient
, pos
, refresh
);
4443 m_oldHorizontalPos
= fpos
;
4445 m_hAdjust
->lower
= 0.0;
4446 m_hAdjust
->upper
= frange
;
4447 m_hAdjust
->value
= fpos
;
4448 m_hAdjust
->step_increment
= 1.0;
4449 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4450 m_hAdjust
->page_size
= fthumb
;
4454 float fpos
= (float)pos
;
4455 float frange
= (float)range
;
4456 float fthumb
= (float)thumbVisible
;
4457 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4458 if (fpos
< 0.0) fpos
= 0.0;
4460 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4461 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4463 SetScrollPos( orient
, pos
, refresh
);
4467 m_oldVerticalPos
= fpos
;
4469 m_vAdjust
->lower
= 0.0;
4470 m_vAdjust
->upper
= frange
;
4471 m_vAdjust
->value
= fpos
;
4472 m_vAdjust
->step_increment
= 1.0;
4473 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4474 m_vAdjust
->page_size
= fthumb
;
4477 if (orient
== wxHORIZONTAL
)
4478 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4480 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4483 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4485 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4487 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4489 if (orient
== wxHORIZONTAL
)
4491 float fpos
= (float)pos
;
4492 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4493 if (fpos
< 0.0) fpos
= 0.0;
4494 m_oldHorizontalPos
= fpos
;
4496 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4497 m_hAdjust
->value
= fpos
;
4501 float fpos
= (float)pos
;
4502 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4503 if (fpos
< 0.0) fpos
= 0.0;
4504 m_oldVerticalPos
= fpos
;
4506 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4507 m_vAdjust
->value
= fpos
;
4510 if (m_wxwindow
->window
)
4512 if (orient
== wxHORIZONTAL
)
4514 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4515 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4517 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4519 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4520 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4524 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4525 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4527 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4529 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4530 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4535 int wxWindowGTK::GetScrollThumb( int orient
) const
4537 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4539 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4541 if (orient
== wxHORIZONTAL
)
4542 return (int)(m_hAdjust
->page_size
+0.5);
4544 return (int)(m_vAdjust
->page_size
+0.5);
4547 int wxWindowGTK::GetScrollPos( int orient
) const
4549 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4551 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4553 if (orient
== wxHORIZONTAL
)
4554 return (int)(m_hAdjust
->value
+0.5);
4556 return (int)(m_vAdjust
->value
+0.5);
4559 int wxWindowGTK::GetScrollRange( int orient
) const
4561 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4563 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4565 if (orient
== wxHORIZONTAL
)
4566 return (int)(m_hAdjust
->upper
+0.5);
4568 return (int)(m_vAdjust
->upper
+0.5);
4571 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4573 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4575 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4577 // No scrolling requested.
4578 if ((dx
== 0) && (dy
== 0)) return;
4581 if (!m_updateRegion
.IsEmpty())
4583 m_updateRegion
.Offset( dx
, dy
);
4587 GetClientSize( &cw
, &ch
);
4588 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4591 if (!m_clearRegion
.IsEmpty())
4593 m_clearRegion
.Offset( dx
, dy
);
4597 GetClientSize( &cw
, &ch
);
4598 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4602 m_clipPaintRegion
= TRUE
;
4604 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4606 m_clipPaintRegion
= FALSE
;
4610 // Find the wxWindow at the current mouse position, also returning the mouse
4612 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4614 pt
= wxGetMousePosition();
4615 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4619 // Get the current mouse position.
4620 wxPoint
wxGetMousePosition()
4622 /* This crashes when used within wxHelpContext,
4623 so we have to use the X-specific implementation below.
4625 GdkModifierType *mask;
4626 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4628 return wxPoint(x, y);
4632 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4634 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4635 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4636 Window rootReturn
, childReturn
;
4637 int rootX
, rootY
, winX
, winY
;
4638 unsigned int maskReturn
;
4640 XQueryPointer (display
,
4644 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4645 return wxPoint(rootX
, rootY
);
4649 // ----------------------------------------------------------------------------
4651 // ----------------------------------------------------------------------------
4653 class wxWinModule
: public wxModule
4660 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4663 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4665 bool wxWinModule::OnInit()
4667 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4668 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4673 void wxWinModule::OnExit()
4676 gdk_gc_unref( g_eraseGC
);