1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
4 // Author: Robert Roebling
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
12 #pragma implementation "window.h"
16 #define XWarpPointer XWARPPOINTER
20 #include "wx/window.h"
21 #include "wx/dcclient.h"
24 #include "wx/layout.h"
26 #include "wx/dialog.h"
27 #include "wx/msgdlg.h"
28 #include "wx/module.h"
30 #if wxUSE_DRAG_AND_DROP
35 #include "wx/tooltip.h"
43 #include "wx/textctrl.h"
47 #include "wx/statusbr.h"
49 #include "wx/settings.h"
51 #include "wx/fontutil.h"
54 #include "wx/thread.h"
60 #include "wx/gtk/private.h"
61 #include <gdk/gdkprivate.h>
62 #include <gdk/gdkkeysyms.h>
66 #include <gtk/gtkprivate.h>
68 #include "wx/gtk/win_gtk.h"
71 #include <pango/pangox.h>
75 #define SET_CONTAINER_FOCUS(w, d) gtk_widget_child_focus((w), (d))
77 #define SET_CONTAINER_FOCUS(w, d) gtk_container_focus(GTK_CONTAINER(w), (d))
87 extern GtkContainerClass
*pizza_parent_class
;
90 //-----------------------------------------------------------------------------
91 // documentation on internals
92 //-----------------------------------------------------------------------------
95 I have been asked several times about writing some documentation about
96 the GTK port of wxWindows, especially its internal structures. Obviously,
97 you cannot understand wxGTK without knowing a little about the GTK, but
98 some more information about what the wxWindow, which is the base class
99 for all other window classes, does seems required as well.
103 What does wxWindow do? It contains the common interface for the following
104 jobs of its descendants:
106 1) Define the rudimentary behaviour common to all window classes, such as
107 resizing, intercepting user input (so as to make it possible to use these
108 events for special purposes in a derived class), window names etc.
110 2) Provide the possibility to contain and manage children, if the derived
111 class is allowed to contain children, which holds true for those window
112 classes which do not display a native GTK widget. To name them, these
113 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
114 work classes are a special case and are handled a bit differently from
115 the rest. The same holds true for the wxNotebook class.
117 3) Provide the possibility to draw into a client area of a window. This,
118 too, only holds true for classes that do not display a native GTK widget
121 4) Provide the entire mechanism for scrolling widgets. This actual inter-
122 face for this is usually in wxScrolledWindow, but the GTK implementation
125 5) A multitude of helper or extra methods for special purposes, such as
126 Drag'n'Drop, managing validators etc.
128 6) Display a border (sunken, raised, simple or none).
130 Normally one might expect, that one wxWindows window would always correspond
131 to one GTK widget. Under GTK, there is no such allround widget that has all
132 the functionality. Moreover, the GTK defines a client area as a different
133 widget from the actual widget you are handling. Last but not least some
134 special classes (e.g. wxFrame) handle different categories of widgets and
135 still have the possibility to draw something in the client area.
136 It was therefore required to write a special purpose GTK widget, that would
137 represent a client area in the sense of wxWindows capable to do the jobs
138 2), 3) and 4). I have written this class and it resides in win_gtk.c of
141 All windows must have a widget, with which they interact with other under-
142 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
143 thw wxWindow class has a member variable called m_widget which holds a
144 pointer to this widget. When the window class represents a GTK native widget,
145 this is (in most cases) the only GTK widget the class manages. E.g. the
146 wxStatitText class handles only a GtkLabel widget a pointer to which you
147 can find in m_widget (defined in wxWindow)
149 When the class has a client area for drawing into and for containing children
150 it has to handle the client area widget (of the type GtkPizza, defined in
151 win_gtk.c), but there could be any number of widgets, handled by a class
152 The common rule for all windows is only, that the widget that interacts with
153 the rest of GTK must be referenced in m_widget and all other widgets must be
154 children of this widget on the GTK level. The top-most widget, which also
155 represents the client area, must be in the m_wxwindow field and must be of
158 As I said, the window classes that display a GTK native widget only have
159 one widget, so in the case of e.g. the wxButton class m_widget holds a
160 pointer to a GtkButton widget. But windows with client areas (for drawing
161 and children) have a m_widget field that is a pointer to a GtkScrolled-
162 Window and a m_wxwindow field that is pointer to a GtkPizza and this
163 one is (in the GTK sense) a child of the GtkScrolledWindow.
165 If the m_wxwindow field is set, then all input to this widget is inter-
166 cepted and sent to the wxWindows class. If not, all input to the widget
167 that gets pointed to by m_widget gets intercepted and sent to the class.
171 The design of scrolling in wxWindows is markedly different from that offered
172 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
173 clicking on a scrollbar belonging to scrolled window will inevitably move
174 the window. In wxWindows, the scrollbar will only emit an event, send this
175 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
176 which actually moves the window and its subchildren. Note that GtkPizza
177 memorizes how much it has been scrolled but that wxWindows forgets this
178 so that the two coordinates systems have to be kept in synch. This is done
179 in various places using the pizza->xoffset and pizza->yoffset values.
183 Singularily the most broken code in GTK is the code that is supposes to
184 inform subwindows (child windows) about new positions. Very often, duplicate
185 events are sent without changes in size or position, equally often no
186 events are sent at all (All this is due to a bug in the GtkContainer code
187 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
188 GTK's own system and it simply waits for size events for toplevel windows
189 and then iterates down the respective size events to all window. This has
190 the disadvantage, that windows might get size events before the GTK widget
191 actually has the reported size. This doesn't normally pose any problem, but
192 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
193 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
194 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
195 window that is used for OpenGl output really has that size (as reported by
200 If someone at some point of time feels the immense desire to have a look at,
201 change or attempt to optimse the Refresh() logic, this person will need an
202 intimate understanding of what a "draw" and what an "expose" events are and
203 what there are used for, in particular when used in connection with GTK's
204 own windowless widgets. Beware.
208 Cursors, too, have been a constant source of pleasure. The main difficulty
209 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
210 for the parent. To prevent this from doing too much harm, I use idle time
211 to set the cursor over and over again, starting from the toplevel windows
212 and ending with the youngest generation (speaking of parent and child windows).
213 Also don't forget that cursors (like much else) are connected to GdkWindows,
214 not GtkWidgets and that the "window" field of a GtkWidget might very well
215 point to the GdkWindow of the parent widget (-> "window less widget") and
216 that the two obviously have very different meanings.
220 //-----------------------------------------------------------------------------
222 //-----------------------------------------------------------------------------
224 extern wxList wxPendingDelete
;
225 extern bool g_blockEventsOnDrag
;
226 extern bool g_blockEventsOnScroll
;
227 extern wxCursor g_globalCursor
;
229 static GdkGC
*g_eraseGC
= NULL
;
231 // mouse capture state: the window which has it and if the mouse is currently
233 static wxWindowGTK
*g_captureWindow
= (wxWindowGTK
*) NULL
;
234 static bool g_captureWindowHasMouse
= FALSE
;
236 /* extern */ wxWindowGTK
*g_focusWindow
= (wxWindowGTK
*) NULL
;
238 // the last window which had the focus - this is normally never NULL (except
239 // if we never had focus at all) as even when g_focusWindow is NULL it still
240 // keeps its previous value
241 static wxWindowGTK
*g_focusWindowLast
= (wxWindowGTK
*) NULL
;
243 // the frame that is currently active (i.e. its child has focus). It is
244 // used to generate wxActivateEvents
245 static wxWindowGTK
*g_activeFrame
= (wxWindowGTK
*) NULL
;
246 static bool g_activeFrameLostFocus
= FALSE
;
248 // If a window get the focus set but has not been realized
249 // yet, defer setting the focus to idle time.
250 wxWindowGTK
*g_delayedFocus
= (wxWindowGTK
*) NULL
;
252 // if we detect that the app has got/lost the focus, we set this variable to
253 // either TRUE or FALSE and an activate event will be sent during the next
254 // OnIdle() call and it is reset to -1: this value means that we shouldn't
255 // send any activate events at all
256 static int g_sendActivateEvent
= -1;
258 extern bool g_mainThreadLocked
;
260 //-----------------------------------------------------------------------------
262 //-----------------------------------------------------------------------------
265 #define DISABLE_STYLE_IF_BROKEN_THEME 0
271 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
273 # define DEBUG_MAIN_THREAD
276 #define DEBUG_MAIN_THREAD
279 // the trace mask used for the focus debugging messages
280 #define TRACE_FOCUS _T("focus")
282 //-----------------------------------------------------------------------------
283 // missing gdk functions
284 //-----------------------------------------------------------------------------
287 gdk_window_warp_pointer (GdkWindow
*window
,
292 GdkWindowPrivate
*priv
;
296 window
= GDK_ROOT_PARENT();
299 if (!GDK_WINDOW_DESTROYED(window
))
301 XWarpPointer (GDK_WINDOW_XDISPLAY(window
),
302 None
, /* not source window -> move from anywhere */
303 GDK_WINDOW_XID(window
), /* dest window */
304 0, 0, 0, 0, /* not source window -> move from anywhere */
308 priv
= (GdkWindowPrivate
*) window
;
310 if (!priv
->destroyed
)
312 XWarpPointer (priv
->xdisplay
,
313 None
, /* not source window -> move from anywhere */
314 priv
->xwindow
, /* dest window */
315 0, 0, 0, 0, /* not source window -> move from anywhere */
321 //-----------------------------------------------------------------------------
323 //-----------------------------------------------------------------------------
325 extern void wxapp_install_idle_handler();
326 extern bool g_isIdle
;
328 //-----------------------------------------------------------------------------
329 // local code (see below)
330 //-----------------------------------------------------------------------------
332 // returns the child of win which currently has focus or NULL if not found
334 // Note: can't be static, needed by textctrl.cpp.
335 wxWindow
*wxFindFocusedChild(wxWindowGTK
*win
)
337 wxWindow
*winFocus
= wxWindowGTK::FindFocus();
339 return (wxWindow
*)NULL
;
341 if ( winFocus
== win
)
342 return (wxWindow
*)win
;
344 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
346 node
= node
->GetNext() )
348 wxWindow
*child
= wxFindFocusedChild(node
->GetData());
353 return (wxWindow
*)NULL
;
356 static void draw_frame( GtkWidget
*widget
, wxWindowGTK
*win
)
358 // wxUniversal widgets draw the borders and scrollbars themselves
359 #ifndef __WXUNIVERSAL__
366 if (win
->m_hasScrolling
)
368 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(widget
);
370 GtkRequisition vscroll_req
;
371 vscroll_req
.width
= 2;
372 vscroll_req
.height
= 2;
373 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
374 (scroll_window
->vscrollbar
, &vscroll_req
);
376 GtkRequisition hscroll_req
;
377 hscroll_req
.width
= 2;
378 hscroll_req
.height
= 2;
379 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
380 (scroll_window
->hscrollbar
, &hscroll_req
);
382 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget
) );
384 if (scroll_window
->vscrollbar_visible
)
386 dw
+= vscroll_req
.width
;
387 dw
+= scroll_class
->scrollbar_spacing
;
390 if (scroll_window
->hscrollbar_visible
)
392 dh
+= hscroll_req
.height
;
393 dh
+= scroll_class
->scrollbar_spacing
;
399 if (GTK_WIDGET_NO_WINDOW (widget
))
401 dx
+= widget
->allocation
.x
;
402 dy
+= widget
->allocation
.y
;
405 if (win
->HasFlag(wxRAISED_BORDER
))
407 gtk_draw_shadow( widget
->style
,
412 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
416 if (win
->HasFlag(wxSUNKEN_BORDER
))
418 gtk_draw_shadow( widget
->style
,
423 widget
->allocation
.width
-dw
, widget
->allocation
.height
-dh
);
427 if (win
->HasFlag(wxSIMPLE_BORDER
))
430 gc
= gdk_gc_new( widget
->window
);
431 gdk_gc_set_foreground( gc
, &widget
->style
->black
);
432 gdk_draw_rectangle( widget
->window
, gc
, FALSE
,
434 widget
->allocation
.width
-dw
-1, widget
->allocation
.height
-dh
-1 );
438 #endif // __WXUNIVERSAL__
441 //-----------------------------------------------------------------------------
442 // "expose_event" of m_widget
443 //-----------------------------------------------------------------------------
445 gint
gtk_window_own_expose_callback( GtkWidget
*widget
, GdkEventExpose
*gdk_event
, wxWindowGTK
*win
)
447 if (gdk_event
->count
> 0) return FALSE
;
449 draw_frame( widget
, win
);
453 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
459 //-----------------------------------------------------------------------------
460 // "draw" of m_widget
461 //-----------------------------------------------------------------------------
465 static void gtk_window_own_draw_callback( GtkWidget
*widget
, GdkRectangle
*WXUNUSED(rect
), wxWindowGTK
*win
)
467 draw_frame( widget
, win
);
472 //-----------------------------------------------------------------------------
473 // "size_request" of m_widget
474 //-----------------------------------------------------------------------------
476 // make it extern because wxStatitText needs to disconnect this one
478 void wxgtk_window_size_request_callback(GtkWidget
*widget
,
479 GtkRequisition
*requisition
,
483 win
->GetSize( &w
, &h
);
489 requisition
->height
= h
;
490 requisition
->width
= w
;
493 //-----------------------------------------------------------------------------
494 // "expose_event" of m_wxwindow
495 //-----------------------------------------------------------------------------
497 static int gtk_window_expose_callback( GtkWidget
*widget
,
498 GdkEventExpose
*gdk_event
,
504 wxapp_install_idle_handler();
507 // This callback gets called in drawing-idle time under
508 // GTK 2.0, so we don't need to defer anything to idle
511 GtkPizza
*pizza
= GTK_PIZZA( widget
);
512 if (gdk_event
->window
!= pizza
->bin_window
) return FALSE
;
517 wxPrintf( wxT("OnExpose from ") );
518 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
519 wxPrintf( win
->GetClassInfo()->GetClassName() );
520 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event
->area
.x
,
521 (int)gdk_event
->area
.y
,
522 (int)gdk_event
->area
.width
,
523 (int)gdk_event
->area
.height
);
527 win
->GetUpdateRegion() = wxRegion( gdk_event
->region
);
529 win
->GtkSendPaintEvents();
532 // Let parent window draw window less widgets
533 (* GTK_WIDGET_CLASS (pizza_parent_class
)->expose_event
) (widget
, gdk_event
);
535 // This gets called immediately after an expose event
536 // under GTK 1.2 so we collect the calls and wait for
537 // the idle handler to pick things up.
539 win
->GetUpdateRegion().Union( gdk_event
->area
.x
,
541 gdk_event
->area
.width
,
542 gdk_event
->area
.height
);
543 win
->m_clearRegion
.Union( gdk_event
->area
.x
,
545 gdk_event
->area
.width
,
546 gdk_event
->area
.height
);
548 // Actual redrawing takes place in idle time.
555 //-----------------------------------------------------------------------------
556 // "event" of m_wxwindow
557 //-----------------------------------------------------------------------------
559 // GTK thinks it is clever and filters out a certain amount of "unneeded"
560 // expose events. We need them, of course, so we override the main event
561 // procedure in GtkWidget by giving our own handler for all system events.
562 // There, we look for expose events ourselves whereas all other events are
565 gint
gtk_window_event_event_callback( GtkWidget
*widget
,
566 GdkEventExpose
*event
,
569 if (event
->type
== GDK_EXPOSE
)
571 gint ret
= gtk_window_expose_callback( widget
, event
, win
);
578 //-----------------------------------------------------------------------------
579 // "draw" of m_wxwindow
580 //-----------------------------------------------------------------------------
584 // This callback is a complete replacement of the gtk_pizza_draw() function,
585 // which is disabled.
587 static void gtk_window_draw_callback( GtkWidget
*widget
,
594 wxapp_install_idle_handler();
596 // The wxNO_FULL_REPAINT_ON_RESIZE flag only works if
597 // there are no child windows.
598 if ((win
->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
)) &&
599 (win
->GetChildren().GetCount() == 0))
607 wxPrintf( wxT("OnDraw from ") );
608 if (win
->GetClassInfo() && win
->GetClassInfo()->GetClassName())
609 wxPrintf( win
->GetClassInfo()->GetClassName() );
610 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect
->x
,
617 #ifndef __WXUNIVERSAL__
618 GtkPizza
*pizza
= GTK_PIZZA (widget
);
620 if (win
->GetThemeEnabled())
622 wxWindow
*parent
= win
->GetParent();
623 while (parent
&& !parent
->IsTopLevel())
624 parent
= parent
->GetParent();
628 gtk_paint_flat_box (parent
->m_widget
->style
,
639 win
->m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
640 win
->GetUpdateRegion().Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
642 // Update immediately, not in idle time.
645 #ifndef __WXUNIVERSAL__
646 // Redraw child widgets
647 GList
*children
= pizza
->children
;
650 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
651 children
= children
->next
;
653 GdkRectangle child_area
;
654 if (gtk_widget_intersect (child
->widget
, rect
, &child_area
))
656 gtk_widget_draw (child
->widget
, &child_area
/* (GdkRectangle*) NULL*/ );
664 //-----------------------------------------------------------------------------
665 // "key_press_event" from any window
666 //-----------------------------------------------------------------------------
668 // set WXTRACE to this to see the key event codes on the console
669 #define TRACE_KEYS _T("keyevent")
671 // translates an X key symbol to WXK_XXX value
673 // if isChar is true it means that the value returned will be used for EVT_CHAR
674 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
675 // for example, while if it is false it means that the value is going to be
676 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
678 static long wxTranslateKeySymToWXKey(KeySym keysym
, bool isChar
)
684 // Shift, Control and Alt don't generate the CHAR events at all
687 key_code
= isChar
? 0 : WXK_SHIFT
;
691 key_code
= isChar
? 0 : WXK_CONTROL
;
699 key_code
= isChar
? 0 : WXK_ALT
;
702 // neither do the toggle modifies
703 case GDK_Scroll_Lock
:
704 key_code
= isChar
? 0 : WXK_SCROLL
;
708 key_code
= isChar
? 0 : WXK_CAPITAL
;
712 key_code
= isChar
? 0 : WXK_NUMLOCK
;
716 // various other special keys
729 case GDK_ISO_Left_Tab
:
736 key_code
= WXK_RETURN
;
740 key_code
= WXK_CLEAR
;
744 key_code
= WXK_PAUSE
;
748 key_code
= WXK_SELECT
;
752 key_code
= WXK_PRINT
;
756 key_code
= WXK_EXECUTE
;
760 key_code
= WXK_ESCAPE
;
763 // cursor and other extended keyboard keys
765 key_code
= WXK_DELETE
;
781 key_code
= WXK_RIGHT
;
788 case GDK_Prior
: // == GDK_Page_Up
789 key_code
= WXK_PRIOR
;
792 case GDK_Next
: // == GDK_Page_Down
805 key_code
= WXK_INSERT
;
820 key_code
= (isChar
? '0' : WXK_NUMPAD0
) + keysym
- GDK_KP_0
;
824 key_code
= isChar
? ' ' : WXK_NUMPAD_SPACE
;
828 key_code
= isChar
? WXK_TAB
: WXK_NUMPAD_TAB
;
832 key_code
= isChar
? WXK_RETURN
: WXK_NUMPAD_ENTER
;
836 key_code
= isChar
? WXK_F1
: WXK_NUMPAD_F1
;
840 key_code
= isChar
? WXK_F2
: WXK_NUMPAD_F2
;
844 key_code
= isChar
? WXK_F3
: WXK_NUMPAD_F3
;
848 key_code
= isChar
? WXK_F4
: WXK_NUMPAD_F4
;
852 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_HOME
;
856 key_code
= isChar
? WXK_LEFT
: WXK_NUMPAD_LEFT
;
860 key_code
= isChar
? WXK_UP
: WXK_NUMPAD_UP
;
864 key_code
= isChar
? WXK_RIGHT
: WXK_NUMPAD_RIGHT
;
868 key_code
= isChar
? WXK_DOWN
: WXK_NUMPAD_DOWN
;
871 case GDK_KP_Prior
: // == GDK_KP_Page_Up
872 key_code
= isChar
? WXK_PRIOR
: WXK_NUMPAD_PRIOR
;
875 case GDK_KP_Next
: // == GDK_KP_Page_Down
876 key_code
= isChar
? WXK_NEXT
: WXK_NUMPAD_NEXT
;
880 key_code
= isChar
? WXK_END
: WXK_NUMPAD_END
;
884 key_code
= isChar
? WXK_HOME
: WXK_NUMPAD_BEGIN
;
888 key_code
= isChar
? WXK_INSERT
: WXK_NUMPAD_INSERT
;
892 key_code
= isChar
? WXK_DELETE
: WXK_NUMPAD_DELETE
;
896 key_code
= isChar
? '=' : WXK_NUMPAD_EQUAL
;
899 case GDK_KP_Multiply
:
900 key_code
= isChar
? '*' : WXK_NUMPAD_MULTIPLY
;
904 key_code
= isChar
? '+' : WXK_NUMPAD_ADD
;
907 case GDK_KP_Separator
:
908 // FIXME: what is this?
909 key_code
= isChar
? '.' : WXK_NUMPAD_SEPARATOR
;
912 case GDK_KP_Subtract
:
913 key_code
= isChar
? '-' : WXK_NUMPAD_SUBTRACT
;
917 key_code
= isChar
? '.' : WXK_NUMPAD_DECIMAL
;
921 key_code
= isChar
? '/' : WXK_NUMPAD_DIVIDE
;
938 key_code
= WXK_F1
+ keysym
- GDK_F1
;
948 static inline bool wxIsAsciiKeysym(KeySym ks
)
954 wxTranslateGTKKeyEventToWx(wxKeyEvent
& event
,
956 GdkEventKey
*gdk_event
)
958 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
959 // but only event->keyval which is quite useless to us, so remember
960 // the last character from GDK_KEY_PRESS and reuse it as last resort
962 // NB: should be MT-safe as we're always called from the main thread only
967 } s_lastKeyPress
= { 0, 0 };
969 KeySym keysym
= gdk_event
->keyval
;
971 wxLogTrace(TRACE_KEYS
, _T("Key %s event: keysym = %ld"),
972 event
.GetEventType() == wxEVT_KEY_UP
? _T("release")
976 long key_code
= wxTranslateKeySymToWXKey(keysym
, FALSE
/* !isChar */);
980 // do we have the translation or is it a plain ASCII character?
981 if ( (gdk_event
->length
== 1) || wxIsAsciiKeysym(keysym
) )
983 // we should use keysym if it is ASCII as X does some translations
984 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
985 // which we don't want here (but which we do use for OnChar())
986 if ( !wxIsAsciiKeysym(keysym
) )
988 keysym
= (KeySym
)gdk_event
->string
[0];
991 // we want to always get the same key code when the same key is
992 // pressed regardless of the state of the modifies, i.e. on a
993 // standard US keyboard pressing '5' or '%' ('5' key with
994 // Shift) should result in the same key code in OnKeyDown():
995 // '5' (although OnChar() will get either '5' or '%').
997 // to do it we first translate keysym to keycode (== scan code)
998 // and then back but always using the lower register
999 Display
*dpy
= (Display
*)wxGetDisplay();
1000 KeyCode keycode
= XKeysymToKeycode(dpy
, keysym
);
1002 wxLogTrace(TRACE_KEYS
, _T("\t-> keycode %d"), keycode
);
1004 KeySym keysymNormalized
= XKeycodeToKeysym(dpy
, keycode
, 0);
1006 // use the normalized, i.e. lower register, keysym if we've
1008 key_code
= keysymNormalized
? keysymNormalized
: keysym
;
1010 // as explained above, we want to have lower register key codes
1011 // normally but for the letter keys we want to have the upper ones
1013 // NB: don't use XConvertCase() here, we want to do it for letters
1015 key_code
= toupper(key_code
);
1017 else // non ASCII key, what to do?
1019 // by default, ignore it
1022 // but if we have cached information from the last KEY_PRESS
1023 if ( gdk_event
->type
== GDK_KEY_RELEASE
)
1026 if ( keysym
== s_lastKeyPress
.keysym
)
1028 key_code
= s_lastKeyPress
.keycode
;
1033 if ( gdk_event
->type
== GDK_KEY_PRESS
)
1035 // remember it to be reused for KEY_UP event later
1036 s_lastKeyPress
.keysym
= keysym
;
1037 s_lastKeyPress
.keycode
= key_code
;
1041 wxLogTrace(TRACE_KEYS
, _T("\t-> wxKeyCode %ld"), key_code
);
1043 // sending unknown key events doesn't really make sense
1047 // now fill all the other fields
1050 GdkModifierType state
;
1051 if (gdk_event
->window
)
1052 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1054 event
.SetTimestamp( gdk_event
->time
);
1055 event
.m_shiftDown
= (gdk_event
->state
& GDK_SHIFT_MASK
) != 0;
1056 event
.m_controlDown
= (gdk_event
->state
& GDK_CONTROL_MASK
) != 0;
1057 event
.m_altDown
= (gdk_event
->state
& GDK_MOD1_MASK
) != 0;
1058 event
.m_metaDown
= (gdk_event
->state
& GDK_MOD2_MASK
) != 0;
1059 event
.m_keyCode
= key_code
;
1060 event
.m_scanCode
= gdk_event
->keyval
;
1061 event
.m_rawCode
= (wxUint32
) gdk_event
->keyval
;
1062 event
.m_rawFlags
= 0;
1065 event
.SetEventObject( win
);
1071 static gint
gtk_window_key_press_callback( GtkWidget
*widget
,
1072 GdkEventKey
*gdk_event
,
1078 wxapp_install_idle_handler();
1082 if (g_blockEventsOnDrag
)
1086 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1087 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1089 // unknown key pressed, ignore (the event would be useless anyhow)
1093 // Emit KEY_DOWN event
1094 bool ret
= win
->GetEventHandler()->ProcessEvent( event
);
1099 wxWindowGTK
*ancestor
= win
;
1102 int command
= ancestor
->GetAcceleratorTable()->GetCommand( event
);
1105 wxCommandEvent
command_event( wxEVT_COMMAND_MENU_SELECTED
, command
);
1106 ret
= ancestor
->GetEventHandler()->ProcessEvent( command_event
);
1109 if (ancestor
->IsTopLevel())
1111 ancestor
= ancestor
->GetParent();
1114 #endif // wxUSE_ACCEL
1116 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1117 // will only be sent if it is not in an accelerator table.
1121 KeySym keysym
= gdk_event
->keyval
;
1123 // In GTK 2.0, we need to hand over the key event to an input method
1124 // and the IM will emit a "commit" event containing the actual utf8
1125 // character. In that case the EVT_CHAR events will be sent from
1126 // there. But only do it this way for non-KeySym keys.
1127 key_code
= wxTranslateKeySymToWXKey(gdk_event
->keyval
, FALSE
/* isChar */);
1128 if ( !key_code
&& win
->m_imContext
)
1130 gtk_im_context_filter_keypress ( (GtkIMContext
*) win
->m_imContext
, gdk_event
);
1136 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1137 key_code
= wxTranslateKeySymToWXKey(keysym
, TRUE
/* isChar */);
1140 if ( gdk_event
->length
== 1 )
1142 key_code
= (unsigned char)gdk_event
->string
[0];
1144 else if ( wxIsAsciiKeysym(keysym
) )
1147 key_code
= (unsigned char)keysym
;
1153 wxLogTrace(TRACE_KEYS
, _T("Char event: %ld"), key_code
);
1155 event
.m_keyCode
= key_code
;
1157 // Implement OnCharHook by checking ancesteror top level windows
1158 wxWindow
*parent
= win
;
1159 while (parent
&& !parent
->IsTopLevel())
1160 parent
= parent
->GetParent();
1163 event
.SetEventType( wxEVT_CHAR_HOOK
);
1164 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1169 event
.SetEventType(wxEVT_CHAR
);
1170 ret
= win
->GetEventHandler()->ProcessEvent( event
);
1176 // win is a control: tab can be propagated up
1178 ((gdk_event
->keyval
== GDK_Tab
) || (gdk_event
->keyval
== GDK_ISO_Left_Tab
)) &&
1179 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1180 // have this style, yet choose not to process this particular TAB in which
1181 // case TAB must still work as a navigational character
1183 !win
->HasFlag(wxTE_PROCESS_TAB
) &&
1185 win
->GetParent() && (win
->GetParent()->HasFlag( wxTAB_TRAVERSAL
)) )
1187 wxNavigationKeyEvent new_event
;
1188 new_event
.SetEventObject( win
->GetParent() );
1189 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1190 new_event
.SetDirection( (gdk_event
->keyval
== GDK_Tab
) );
1191 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1192 new_event
.SetWindowChange( (gdk_event
->state
& GDK_CONTROL_MASK
) );
1193 new_event
.SetCurrentFocus( win
);
1194 ret
= win
->GetParent()->GetEventHandler()->ProcessEvent( new_event
);
1197 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1199 (gdk_event
->keyval
== GDK_Escape
) )
1201 // however only do it if we have a Cancel button in the dialog,
1202 // otherwise the user code may get confused by the events from a
1203 // non-existing button and, worse, a wxButton might get button event
1204 // from another button which is not really expected
1205 wxWindow
*winForCancel
= win
,
1207 while ( winForCancel
)
1209 btnCancel
= winForCancel
->FindWindow(wxID_CANCEL
);
1212 // found a cancel button
1216 if ( winForCancel
->IsTopLevel() )
1218 // no need to look further
1222 // maybe our parent has a cancel button?
1223 winForCancel
= winForCancel
->GetParent();
1228 wxCommandEvent
event(wxEVT_COMMAND_BUTTON_CLICKED
, wxID_CANCEL
);
1229 event
.SetEventObject(btnCancel
);
1230 ret
= btnCancel
->GetEventHandler()->ProcessEvent(event
);
1236 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_press_event" );
1244 static void gtk_wxwindow_commit_cb (GtkIMContext
*context
,
1250 wxKeyEvent
event( wxEVT_KEY_DOWN
);
1253 event
.m_uniChar
= g_utf8_get_char( str
);
1255 // Backward compatible for ISO-8859
1256 if (event
.m_uniChar
< 256)
1257 event
.m_keyCode
= event
.m_uniChar
;
1259 gunichar uniChar
= g_utf8_get_char( str
);
1260 // We cannot handle Unicode in non-Unicode mode
1261 if (uniChar
> 255) return;
1263 event
.m_keyCode
= uniChar
;
1267 // TODO: We still need to set all the extra attributes of the
1268 // event, modifiers and such...
1271 // Implement OnCharHook by checking ancestor top level windows
1272 wxWindow
*parent
= window
;
1273 while (parent
&& !parent
->IsTopLevel())
1274 parent
= parent
->GetParent();
1277 event
.SetEventType( wxEVT_CHAR_HOOK
);
1278 ret
= parent
->GetEventHandler()->ProcessEvent( event
);
1283 event
.SetEventType(wxEVT_CHAR
);
1284 ret
= window
->GetEventHandler()->ProcessEvent( event
);
1290 //-----------------------------------------------------------------------------
1291 // "key_release_event" from any window
1292 //-----------------------------------------------------------------------------
1294 static gint
gtk_window_key_release_callback( GtkWidget
*widget
,
1295 GdkEventKey
*gdk_event
,
1301 wxapp_install_idle_handler();
1306 if (g_blockEventsOnDrag
)
1309 wxKeyEvent
event( wxEVT_KEY_UP
);
1310 if ( !wxTranslateGTKKeyEventToWx(event
, win
, gdk_event
) )
1312 // unknown key pressed, ignore (the event would be useless anyhow
1316 if ( !win
->GetEventHandler()->ProcessEvent( event
) )
1319 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "key_release_event" );
1323 // ============================================================================
1325 // ============================================================================
1327 // ----------------------------------------------------------------------------
1328 // mouse event processing helpers
1329 // ----------------------------------------------------------------------------
1331 // init wxMouseEvent with the info from gdk_event
1333 // NB: this has to be a macro as gdk_event type is different for different
1334 // events we're used with
1335 #define InitMouseEvent(/* wxWindowGTK * */ win, \
1336 /* wxMouseEvent& */ event, \
1337 /* GdkEventXXX * */ gdk_event) \
1339 event.SetTimestamp( gdk_event->time ); \
1340 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1341 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1342 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1343 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1344 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1345 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1346 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1347 if (event.GetEventType()==wxEVT_MOUSEWHEEL) \
1349 if (((GdkEventButton*)gdk_event)->button == 4) \
1350 event.m_wheelRotation = 120; \
1351 else if (((GdkEventButton*)gdk_event)->button == 5) \
1352 event.m_wheelRotation = -120; \
1355 wxPoint pt = win->GetClientAreaOrigin(); \
1356 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1357 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1359 event.SetEventObject( win ); \
1360 event.SetId( win->GetId() ); \
1361 event.SetTimestamp( gdk_event->time ); \
1364 static void AdjustEventButtonState(wxMouseEvent& event)
1366 // GDK reports the old state of the button for a button press event, but
1367 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1368 // for a LEFT_DOWN event, not FALSE, so we will invert
1369 // left/right/middleDown for the corresponding click events
1371 if ((event
.GetEventType() == wxEVT_LEFT_DOWN
) ||
1372 (event
.GetEventType() == wxEVT_LEFT_DCLICK
) ||
1373 (event
.GetEventType() == wxEVT_LEFT_UP
))
1375 event
.m_leftDown
= !event
.m_leftDown
;
1379 if ((event
.GetEventType() == wxEVT_MIDDLE_DOWN
) ||
1380 (event
.GetEventType() == wxEVT_MIDDLE_DCLICK
) ||
1381 (event
.GetEventType() == wxEVT_MIDDLE_UP
))
1383 event
.m_middleDown
= !event
.m_middleDown
;
1387 if ((event
.GetEventType() == wxEVT_RIGHT_DOWN
) ||
1388 (event
.GetEventType() == wxEVT_RIGHT_DCLICK
) ||
1389 (event
.GetEventType() == wxEVT_RIGHT_UP
))
1391 event
.m_rightDown
= !event
.m_rightDown
;
1396 // find the window to send the mouse event too
1398 wxWindowGTK
*FindWindowForMouseEvent(wxWindowGTK
*win
, wxCoord
& x
, wxCoord
& y
)
1403 if (win
->m_wxwindow
)
1405 GtkPizza
*pizza
= GTK_PIZZA(win
->m_wxwindow
);
1406 xx
+= pizza
->xoffset
;
1407 yy
+= pizza
->yoffset
;
1410 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
1413 wxWindowGTK
*child
= node
->GetData();
1415 node
= node
->GetNext();
1416 if (!child
->IsShown())
1419 if (child
->IsTransparentForMouse())
1421 // wxStaticBox is transparent in the box itself
1422 int xx1
= child
->m_x
;
1423 int yy1
= child
->m_y
;
1424 int xx2
= child
->m_x
+ child
->m_width
;
1425 int yy2
= child
->m_y
+ child
->m_height
;
1428 if (((xx
>= xx1
) && (xx
<= xx1
+10) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1430 ((xx
>= xx2
-10) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy2
)) ||
1432 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy1
) && (yy
<= yy1
+10)) ||
1434 ((xx
>= xx1
) && (xx
<= xx2
) && (yy
>= yy2
-1) && (yy
<= yy2
)))
1445 if ((child
->m_wxwindow
== (GtkWidget
*) NULL
) &&
1446 (child
->m_x
<= xx
) &&
1447 (child
->m_y
<= yy
) &&
1448 (child
->m_x
+child
->m_width
>= xx
) &&
1449 (child
->m_y
+child
->m_height
>= yy
))
1462 //-----------------------------------------------------------------------------
1463 // "button_press_event"
1464 //-----------------------------------------------------------------------------
1466 static gint
gtk_window_button_press_callback( GtkWidget
*widget
,
1467 GdkEventButton
*gdk_event
,
1473 wxapp_install_idle_handler();
1476 wxPrintf( wxT("1) OnButtonPress from ") );
1477 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1478 wxPrintf( win->GetClassInfo()->GetClassName() );
1479 wxPrintf( wxT(".\n") );
1481 if (!win
->m_hasVMT
) return FALSE
;
1482 if (g_blockEventsOnDrag
) return TRUE
;
1483 if (g_blockEventsOnScroll
) return TRUE
;
1485 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1487 if (win
->m_wxwindow
&& (g_focusWindow
!= win
) && win
->AcceptsFocus())
1489 gtk_widget_grab_focus( win
->m_wxwindow
);
1491 wxPrintf( wxT("GrabFocus from ") );
1492 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1493 wxPrintf( win->GetClassInfo()->GetClassName() );
1494 wxPrintf( wxT(".\n") );
1498 // GDK sends surplus button down event
1499 // before a double click event. We
1500 // need to filter these out.
1501 if (gdk_event
->type
== GDK_BUTTON_PRESS
)
1503 GdkEvent
*peek_event
= gdk_event_peek();
1506 if (peek_event
->type
== GDK_2BUTTON_PRESS
)
1508 gdk_event_free( peek_event
);
1513 gdk_event_free( peek_event
);
1518 wxEventType event_type
= wxEVT_NULL
;
1520 if (gdk_event
->button
== 1)
1522 switch (gdk_event
->type
)
1524 case GDK_BUTTON_PRESS
: event_type
= wxEVT_LEFT_DOWN
; break;
1525 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_LEFT_DCLICK
; break;
1529 else if (gdk_event
->button
== 2)
1531 switch (gdk_event
->type
)
1533 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DOWN
; break;
1534 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_MIDDLE_DCLICK
; break;
1538 else if (gdk_event
->button
== 3)
1540 switch (gdk_event
->type
)
1542 case GDK_BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DOWN
; break;
1543 case GDK_2BUTTON_PRESS
: event_type
= wxEVT_RIGHT_DCLICK
; break;
1547 else if (gdk_event
->button
== 4)
1549 switch (gdk_event
->type
)
1551 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MOUSEWHEEL
; break;
1555 else if (gdk_event
->button
== 5)
1557 switch (gdk_event
->type
)
1559 case GDK_BUTTON_PRESS
: event_type
= wxEVT_MOUSEWHEEL
; break;
1564 if ( event_type
== wxEVT_NULL
)
1566 // unknown mouse button or click type
1570 wxMouseEvent
event( event_type
);
1571 InitMouseEvent( win
, event
, gdk_event
);
1573 AdjustEventButtonState(event
);
1575 // wxListBox actually get mouse events from the item, so we need to give it
1576 // a chance to correct this
1577 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1579 // find the correct window to send the event too: it may be a different one
1580 // from the one which got it at GTK+ level because some control don't have
1581 // their own X window and thus cannot get any events.
1582 if ( !g_captureWindow
)
1583 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1586 wxPrintf( wxT("2) OnButtonPress from ") );
1587 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1588 wxPrintf( win->GetClassInfo()->GetClassName() );
1589 wxPrintf( wxT(".\n") );
1593 if (event_type
== wxEVT_LEFT_DCLICK
)
1595 // GTK 1.2 crashes when intercepting double
1596 // click events from both wxSpinButton and
1598 if (GTK_IS_SPIN_BUTTON(win
->m_widget
))
1600 // Just disable this event for now.
1606 if (win
->GetEventHandler()->ProcessEvent( event
))
1608 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_press_event" );
1615 //-----------------------------------------------------------------------------
1616 // "button_release_event"
1617 //-----------------------------------------------------------------------------
1619 static gint
gtk_window_button_release_callback( GtkWidget
*widget
,
1620 GdkEventButton
*gdk_event
,
1626 wxapp_install_idle_handler();
1628 if (!win
->m_hasVMT
) return FALSE
;
1629 if (g_blockEventsOnDrag
) return FALSE
;
1630 if (g_blockEventsOnScroll
) return FALSE
;
1632 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1634 wxEventType event_type
= wxEVT_NULL
;
1636 switch (gdk_event
->button
)
1639 event_type
= wxEVT_LEFT_UP
;
1643 event_type
= wxEVT_MIDDLE_UP
;
1647 event_type
= wxEVT_RIGHT_UP
;
1651 // unknwon button, don't process
1655 wxMouseEvent
event( event_type
);
1656 InitMouseEvent( win
, event
, gdk_event
);
1658 AdjustEventButtonState(event
);
1660 // same wxListBox hack as above
1661 win
->FixUpMouseEvent(widget
, event
.m_x
, event
.m_y
);
1663 if ( event_type
== wxEVT_RIGHT_UP
)
1665 // generate a "context menu" event: this is similar to wxEVT_RIGHT_UP
1668 // (a) it's a command event and so is propagated to the parent
1669 // (b) under MSW it can be generated from kbd too
1670 // (c) it uses screen coords (because of (a))
1671 wxContextMenuEvent
evtCtx(wxEVT_CONTEXT_MENU
,
1673 win
->ClientToScreen(event
.GetPosition()));
1674 (void)win
->GetEventHandler()->ProcessEvent(evtCtx
);
1677 if ( !g_captureWindow
)
1678 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1680 if (win
->GetEventHandler()->ProcessEvent( event
))
1682 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "button_release_event" );
1689 //-----------------------------------------------------------------------------
1690 // "motion_notify_event"
1691 //-----------------------------------------------------------------------------
1693 static gint
gtk_window_motion_notify_callback( GtkWidget
*widget
,
1694 GdkEventMotion
*gdk_event
,
1700 wxapp_install_idle_handler();
1702 if (!win
->m_hasVMT
) return FALSE
;
1703 if (g_blockEventsOnDrag
) return FALSE
;
1704 if (g_blockEventsOnScroll
) return FALSE
;
1706 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1708 if (gdk_event
->is_hint
)
1712 GdkModifierType state
;
1713 gdk_window_get_pointer(gdk_event
->window
, &x
, &y
, &state
);
1719 printf( "OnMotion from " );
1720 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1721 printf( win->GetClassInfo()->GetClassName() );
1725 wxMouseEvent
event( wxEVT_MOTION
);
1726 InitMouseEvent(win
, event
, gdk_event
);
1728 if ( g_captureWindow
)
1730 // synthetize a mouse enter or leave event if needed
1731 GdkWindow
*winUnderMouse
= gdk_window_at_pointer(NULL
, NULL
);
1732 // This seems to be necessary and actually been added to
1733 // GDK itself in version 2.0.X
1736 bool hasMouse
= winUnderMouse
== gdk_event
->window
;
1737 if ( hasMouse
!= g_captureWindowHasMouse
)
1739 // the mouse changed window
1740 g_captureWindowHasMouse
= hasMouse
;
1742 wxMouseEvent
event(g_captureWindowHasMouse
? wxEVT_ENTER_WINDOW
1743 : wxEVT_LEAVE_WINDOW
);
1744 InitMouseEvent(win
, event
, gdk_event
);
1745 event
.SetEventObject(win
);
1746 win
->GetEventHandler()->ProcessEvent(event
);
1751 win
= FindWindowForMouseEvent(win
, event
.m_x
, event
.m_y
);
1754 if (win
->GetEventHandler()->ProcessEvent( event
))
1756 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "motion_notify_event" );
1763 //-----------------------------------------------------------------------------
1765 //-----------------------------------------------------------------------------
1767 // send the wxChildFocusEvent and wxFocusEvent, common code of
1768 // gtk_window_focus_in_callback() and SetFocus()
1769 static bool DoSendFocusEvents(wxWindow
*win
)
1771 // Notify the parent keeping track of focus for the kbd navigation
1772 // purposes that we got it.
1773 wxChildFocusEvent
eventChildFocus(win
);
1774 (void)win
->GetEventHandler()->ProcessEvent(eventChildFocus
);
1776 wxFocusEvent
eventFocus(wxEVT_SET_FOCUS
, win
->GetId());
1777 eventFocus
.SetEventObject(win
);
1779 return win
->GetEventHandler()->ProcessEvent(eventFocus
);
1782 static gint
gtk_window_focus_in_callback( GtkWidget
*widget
,
1783 GdkEvent
*WXUNUSED(event
),
1789 wxapp_install_idle_handler();
1791 if (!win
->m_hasVMT
) return FALSE
;
1792 if (g_blockEventsOnDrag
) return FALSE
;
1794 switch ( g_sendActivateEvent
)
1797 // we've got focus from outside, synthetize wxActivateEvent
1798 g_sendActivateEvent
= 1;
1802 // another our window just lost focus, it was already ours before
1803 // - don't send any wxActivateEvent
1804 g_sendActivateEvent
= -1;
1809 g_focusWindow
= win
;
1811 wxLogTrace(TRACE_FOCUS
,
1812 _T("%s: focus in"), win
->GetName().c_str());
1816 gdk_im_begin(win
->m_ic
, win
->m_wxwindow
->window
);
1820 // caret needs to be informed about focus change
1821 wxCaret
*caret
= win
->GetCaret();
1824 caret
->OnSetFocus();
1826 #endif // wxUSE_CARET
1828 g_activeFrameLostFocus
= FALSE
;
1830 wxWindowGTK
*active
= wxGetTopLevelParent(win
);
1831 if ( active
!= g_activeFrame
)
1833 if ( g_activeFrame
)
1835 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame
);
1836 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
1837 event
.SetEventObject(g_activeFrame
);
1838 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1841 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active
);
1842 g_activeFrame
= active
;
1843 wxActivateEvent
event(wxEVT_ACTIVATE
, TRUE
, g_activeFrame
->GetId());
1844 event
.SetEventObject(g_activeFrame
);
1845 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
1847 // Don't send focus events in addition to activate
1848 // if (win == g_activeFrame)
1852 // does the window itself think that it has the focus?
1853 if ( !win
->m_hasFocus
)
1855 // not yet, notify it
1856 win
->m_hasFocus
= TRUE
;
1858 if ( DoSendFocusEvents(win
) )
1860 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_in_event" );
1868 //-----------------------------------------------------------------------------
1869 // "focus_out_event"
1870 //-----------------------------------------------------------------------------
1872 static gint
gtk_window_focus_out_callback( GtkWidget
*widget
, GdkEventFocus
*gdk_event
, wxWindowGTK
*win
)
1877 wxapp_install_idle_handler();
1879 if (!win
->m_hasVMT
) return FALSE
;
1880 if (g_blockEventsOnDrag
) return FALSE
;
1882 wxLogTrace( TRACE_FOCUS
,
1883 _T("%s: focus out"), win
->GetName().c_str() );
1885 if ( !g_activeFrameLostFocus
&& g_activeFrame
)
1887 // VZ: commenting this out because it does happen (although not easy
1888 // to reproduce, I only see it when using wxMiniFrame and not
1889 // always) and makes using Mahogany quite annoying
1891 wxASSERT_MSG( wxGetTopLevelParent(win
) == g_activeFrame
,
1892 wxT("unfocusing window that hasn't gained focus properly") );
1895 g_activeFrameLostFocus
= TRUE
;
1898 // if the focus goes out of our app alltogether, OnIdle() will send
1899 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1900 // g_sendActivateEvent to -1
1901 g_sendActivateEvent
= 0;
1903 wxWindowGTK
*winFocus
= wxFindFocusedChild(win
);
1907 g_focusWindow
= (wxWindowGTK
*)NULL
;
1915 // caret needs to be informed about focus change
1916 wxCaret
*caret
= win
->GetCaret();
1919 caret
->OnKillFocus();
1921 #endif // wxUSE_CARET
1923 // don't send the window a kill focus event if it thinks that it doesn't
1924 // have focus already
1925 if ( win
->m_hasFocus
)
1927 win
->m_hasFocus
= FALSE
;
1929 wxFocusEvent
event( wxEVT_KILL_FOCUS
, win
->GetId() );
1930 event
.SetEventObject( win
);
1932 if (win
->GetEventHandler()->ProcessEvent( event
))
1934 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "focus_out_event" );
1942 //-----------------------------------------------------------------------------
1943 // "enter_notify_event"
1944 //-----------------------------------------------------------------------------
1947 gint
gtk_window_enter_callback( GtkWidget
*widget
,
1948 GdkEventCrossing
*gdk_event
,
1954 wxapp_install_idle_handler();
1956 if (!win
->m_hasVMT
) return FALSE
;
1957 if (g_blockEventsOnDrag
) return FALSE
;
1959 // Event was emitted after a grab
1960 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
1962 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
1966 GdkModifierType state
= (GdkModifierType
)0;
1968 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
1970 wxMouseEvent
event( wxEVT_ENTER_WINDOW
);
1971 InitMouseEvent(win
, event
, gdk_event
);
1972 wxPoint pt
= win
->GetClientAreaOrigin();
1973 event
.m_x
= x
+ pt
.x
;
1974 event
.m_y
= y
+ pt
.y
;
1976 if (win
->GetEventHandler()->ProcessEvent( event
))
1978 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "enter_notify_event" );
1985 //-----------------------------------------------------------------------------
1986 // "leave_notify_event"
1987 //-----------------------------------------------------------------------------
1989 static gint
gtk_window_leave_callback( GtkWidget
*widget
, GdkEventCrossing
*gdk_event
, wxWindowGTK
*win
)
1994 wxapp_install_idle_handler();
1996 if (!win
->m_hasVMT
) return FALSE
;
1997 if (g_blockEventsOnDrag
) return FALSE
;
1999 // Event was emitted after an ungrab
2000 if (gdk_event
->mode
!= GDK_CROSSING_NORMAL
) return FALSE
;
2002 if (!win
->IsOwnGtkWindow( gdk_event
->window
)) return FALSE
;
2004 wxMouseEvent
event( wxEVT_LEAVE_WINDOW
);
2005 event
.SetTimestamp( gdk_event
->time
);
2006 event
.SetEventObject( win
);
2010 GdkModifierType state
= (GdkModifierType
)0;
2012 gdk_window_get_pointer( widget
->window
, &x
, &y
, &state
);
2014 event
.m_shiftDown
= (state
& GDK_SHIFT_MASK
) != 0;
2015 event
.m_controlDown
= (state
& GDK_CONTROL_MASK
) != 0;
2016 event
.m_altDown
= (state
& GDK_MOD1_MASK
) != 0;
2017 event
.m_metaDown
= (state
& GDK_MOD2_MASK
) != 0;
2018 event
.m_leftDown
= (state
& GDK_BUTTON1_MASK
) != 0;
2019 event
.m_middleDown
= (state
& GDK_BUTTON2_MASK
) != 0;
2020 event
.m_rightDown
= (state
& GDK_BUTTON3_MASK
) != 0;
2022 wxPoint pt
= win
->GetClientAreaOrigin();
2023 event
.m_x
= x
+ pt
.x
;
2024 event
.m_y
= y
+ pt
.y
;
2026 if (win
->GetEventHandler()->ProcessEvent( event
))
2028 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget
), "leave_notify_event" );
2035 //-----------------------------------------------------------------------------
2036 // "value_changed" from m_vAdjust
2037 //-----------------------------------------------------------------------------
2039 static void gtk_window_vscroll_callback( GtkAdjustment
*adjust
,
2046 wxapp_install_idle_handler();
2048 if (g_blockEventsOnDrag
) return;
2050 if (!win
->m_hasVMT
) return;
2052 float diff
= adjust
->value
- win
->m_oldVerticalPos
;
2053 if (fabs(diff
) < 0.2) return;
2055 win
->m_oldVerticalPos
= adjust
->value
;
2058 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2060 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->vscrollbar
));
2062 int value
= (int)(adjust
->value
+0.5);
2064 wxScrollWinEvent
event( command
, value
, wxVERTICAL
);
2065 event
.SetEventObject( win
);
2066 win
->GetEventHandler()->ProcessEvent( event
);
2069 //-----------------------------------------------------------------------------
2070 // "value_changed" from m_hAdjust
2071 //-----------------------------------------------------------------------------
2073 static void gtk_window_hscroll_callback( GtkAdjustment
*adjust
,
2080 wxapp_install_idle_handler();
2082 if (g_blockEventsOnDrag
) return;
2083 if (!win
->m_hasVMT
) return;
2085 float diff
= adjust
->value
- win
->m_oldHorizontalPos
;
2086 if (fabs(diff
) < 0.2) return;
2089 GtkScrolledWindow
*sw
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2091 wxEventType command
= GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw
->hscrollbar
));
2093 win
->m_oldHorizontalPos
= adjust
->value
;
2095 int value
= (int)(adjust
->value
+0.5);
2097 wxScrollWinEvent
event( command
, value
, wxHORIZONTAL
);
2098 event
.SetEventObject( win
);
2099 win
->GetEventHandler()->ProcessEvent( event
);
2102 //-----------------------------------------------------------------------------
2103 // "button_press_event" from scrollbar
2104 //-----------------------------------------------------------------------------
2106 static gint
gtk_scrollbar_button_press_callback( GtkRange
*widget
,
2107 GdkEventButton
*gdk_event
,
2113 wxapp_install_idle_handler();
2116 g_blockEventsOnScroll
= TRUE
;
2118 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2120 win
->m_isScrolling
= (gdk_event
->window
== widget
->slider
);
2126 //-----------------------------------------------------------------------------
2127 // "button_release_event" from scrollbar
2128 //-----------------------------------------------------------------------------
2130 static gint
gtk_scrollbar_button_release_callback( GtkRange
*widget
,
2131 GdkEventButton
*WXUNUSED(gdk_event
),
2136 // don't test here as we can release the mouse while being over
2137 // a different window than the slider
2139 // if (gdk_event->window != widget->slider) return FALSE;
2141 g_blockEventsOnScroll
= FALSE
;
2143 if (win
->m_isScrolling
)
2145 wxEventType command
= wxEVT_SCROLLWIN_THUMBRELEASE
;
2149 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(win
->m_widget
);
2150 if (widget
== GTK_RANGE(scrolledWindow
->hscrollbar
))
2152 value
= (int)(win
->m_hAdjust
->value
+0.5);
2155 if (widget
== GTK_RANGE(scrolledWindow
->vscrollbar
))
2157 value
= (int)(win
->m_vAdjust
->value
+0.5);
2161 wxScrollWinEvent
event( command
, value
, dir
);
2162 event
.SetEventObject( win
);
2163 win
->GetEventHandler()->ProcessEvent( event
);
2166 win
->m_isScrolling
= FALSE
;
2171 // ----------------------------------------------------------------------------
2172 // this wxWindowBase function is implemented here (in platform-specific file)
2173 // because it is static and so couldn't be made virtual
2174 // ----------------------------------------------------------------------------
2176 wxWindow
*wxWindowBase::FindFocus()
2178 // the cast is necessary when we compile in wxUniversal mode
2179 return (wxWindow
*)g_focusWindow
;
2183 //-----------------------------------------------------------------------------
2184 // "realize" from m_widget
2185 //-----------------------------------------------------------------------------
2187 /* We cannot set colours and fonts before the widget has
2188 been realized, so we do this directly after realization. */
2191 gtk_window_realized_callback( GtkWidget
*m_widget
, wxWindow
*win
)
2196 wxapp_install_idle_handler();
2198 if (win
->m_delayedBackgroundColour
&& !win
->GetThemeEnabled())
2199 win
->GtkSetBackgroundColour( win
->GetBackgroundColour() );
2201 if (win
->m_delayedForegroundColour
&& !win
->GetThemeEnabled())
2202 win
->GtkSetForegroundColour( win
->GetForegroundColour() );
2205 if (win
->m_imContext
)
2207 GtkPizza
*pizza
= GTK_PIZZA( m_widget
);
2208 gtk_im_context_set_client_window( (GtkIMContext
*) win
->m_imContext
, pizza
->bin_window
);
2212 wxWindowCreateEvent
event( win
);
2213 event
.SetEventObject( win
);
2214 win
->GetEventHandler()->ProcessEvent( event
);
2219 //-----------------------------------------------------------------------------
2221 //-----------------------------------------------------------------------------
2224 void gtk_window_size_callback( GtkWidget
*WXUNUSED(widget
),
2225 GtkAllocation
*WXUNUSED(alloc
),
2229 wxapp_install_idle_handler();
2231 if (!win
->m_hasScrolling
) return;
2233 int client_width
= 0;
2234 int client_height
= 0;
2235 win
->GetClientSize( &client_width
, &client_height
);
2236 if ((client_width
== win
->m_oldClientWidth
) && (client_height
== win
->m_oldClientHeight
))
2239 win
->m_oldClientWidth
= client_width
;
2240 win
->m_oldClientHeight
= client_height
;
2242 if (!win
->m_nativeSizeEvent
)
2244 wxSizeEvent
event( win
->GetSize(), win
->GetId() );
2245 event
.SetEventObject( win
);
2246 win
->GetEventHandler()->ProcessEvent( event
);
2252 #define WXUNUSED_UNLESS_XIM(param) param
2254 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2257 /* Resize XIM window */
2260 void gtk_wxwindow_size_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2261 GtkAllocation
* WXUNUSED_UNLESS_XIM(alloc
),
2262 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2265 wxapp_install_idle_handler();
2271 if (gdk_ic_get_style (win
->m_ic
) & GDK_IM_PREEDIT_POSITION
)
2275 gdk_window_get_size (widget
->window
, &width
, &height
);
2276 win
->m_icattr
->preedit_area
.width
= width
;
2277 win
->m_icattr
->preedit_area
.height
= height
;
2278 gdk_ic_set_attr (win
->m_ic
, win
->m_icattr
, GDK_IC_PREEDIT_AREA
);
2283 //-----------------------------------------------------------------------------
2284 // "realize" from m_wxwindow
2285 //-----------------------------------------------------------------------------
2287 /* Initialize XIM support */
2290 gtk_wxwindow_realized_callback( GtkWidget
* WXUNUSED_UNLESS_XIM(widget
),
2291 wxWindowGTK
* WXUNUSED_UNLESS_XIM(win
) )
2294 wxapp_install_idle_handler();
2297 if (win
->m_ic
) return FALSE
;
2298 if (!widget
) return FALSE
;
2299 if (!gdk_im_ready()) return FALSE
;
2301 win
->m_icattr
= gdk_ic_attr_new();
2302 if (!win
->m_icattr
) return FALSE
;
2306 GdkColormap
*colormap
;
2307 GdkICAttr
*attr
= win
->m_icattr
;
2308 unsigned attrmask
= GDK_IC_ALL_REQ
;
2310 GdkIMStyle supported_style
= (GdkIMStyle
)
2311 (GDK_IM_PREEDIT_NONE
|
2312 GDK_IM_PREEDIT_NOTHING
|
2313 GDK_IM_PREEDIT_POSITION
|
2314 GDK_IM_STATUS_NONE
|
2315 GDK_IM_STATUS_NOTHING
);
2317 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2318 supported_style
= (GdkIMStyle
)(supported_style
& ~GDK_IM_PREEDIT_POSITION
);
2320 attr
->style
= style
= gdk_im_decide_style (supported_style
);
2321 attr
->client_window
= widget
->window
;
2323 if ((colormap
= gtk_widget_get_colormap (widget
)) !=
2324 gtk_widget_get_default_colormap ())
2326 attrmask
|= GDK_IC_PREEDIT_COLORMAP
;
2327 attr
->preedit_colormap
= colormap
;
2330 attrmask
|= GDK_IC_PREEDIT_FOREGROUND
;
2331 attrmask
|= GDK_IC_PREEDIT_BACKGROUND
;
2332 attr
->preedit_foreground
= widget
->style
->fg
[GTK_STATE_NORMAL
];
2333 attr
->preedit_background
= widget
->style
->base
[GTK_STATE_NORMAL
];
2335 switch (style
& GDK_IM_PREEDIT_MASK
)
2337 case GDK_IM_PREEDIT_POSITION
:
2338 if (widget
->style
&& widget
->style
->font
->type
!= GDK_FONT_FONTSET
)
2340 g_warning ("over-the-spot style requires fontset");
2344 gdk_window_get_size (widget
->window
, &width
, &height
);
2346 attrmask
|= GDK_IC_PREEDIT_POSITION_REQ
;
2347 attr
->spot_location
.x
= 0;
2348 attr
->spot_location
.y
= height
;
2349 attr
->preedit_area
.x
= 0;
2350 attr
->preedit_area
.y
= 0;
2351 attr
->preedit_area
.width
= width
;
2352 attr
->preedit_area
.height
= height
;
2353 attr
->preedit_fontset
= widget
->style
->font
;
2358 win
->m_ic
= gdk_ic_new (attr
, (GdkICAttributesType
)attrmask
);
2360 if (win
->m_ic
== NULL
)
2361 g_warning ("Can't create input context.");
2364 mask
= gdk_window_get_events (widget
->window
);
2365 mask
= (GdkEventMask
)(mask
| gdk_ic_get_events (win
->m_ic
));
2366 gdk_window_set_events (widget
->window
, mask
);
2368 if (GTK_WIDGET_HAS_FOCUS(widget
))
2369 gdk_im_begin (win
->m_ic
, widget
->window
);
2376 //-----------------------------------------------------------------------------
2377 // InsertChild for wxWindowGTK.
2378 //-----------------------------------------------------------------------------
2380 /* Callback for wxWindowGTK. This very strange beast has to be used because
2381 * C++ has no virtual methods in a constructor. We have to emulate a
2382 * virtual function here as wxNotebook requires a different way to insert
2383 * a child in it. I had opted for creating a wxNotebookPage window class
2384 * which would have made this superfluous (such in the MDI window system),
2385 * but no-one was listening to me... */
2387 static void wxInsertChildInWindow( wxWindowGTK
* parent
, wxWindowGTK
* child
)
2389 /* the window might have been scrolled already, do we
2390 have to adapt the position */
2391 GtkPizza
*pizza
= GTK_PIZZA(parent
->m_wxwindow
);
2392 child
->m_x
+= pizza
->xoffset
;
2393 child
->m_y
+= pizza
->yoffset
;
2395 gtk_pizza_put( GTK_PIZZA(parent
->m_wxwindow
),
2396 GTK_WIDGET(child
->m_widget
),
2403 //-----------------------------------------------------------------------------
2405 //-----------------------------------------------------------------------------
2407 wxWindow
*wxGetActiveWindow()
2409 return wxWindow::FindFocus();
2412 //-----------------------------------------------------------------------------
2414 //-----------------------------------------------------------------------------
2416 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2418 #ifdef __WXUNIVERSAL__
2419 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK
, wxWindowBase
)
2421 IMPLEMENT_DYNAMIC_CLASS(wxWindow
, wxWindowBase
)
2422 #endif // __WXUNIVERSAL__/__WXGTK__
2424 void wxWindowGTK::Init()
2430 m_widget
= (GtkWidget
*) NULL
;
2431 m_wxwindow
= (GtkWidget
*) NULL
;
2432 m_focusWidget
= (GtkWidget
*) NULL
;
2442 m_needParent
= TRUE
;
2443 m_isBeingDeleted
= FALSE
;
2446 m_nativeSizeEvent
= FALSE
;
2448 m_hasScrolling
= FALSE
;
2449 m_isScrolling
= FALSE
;
2451 m_hAdjust
= (GtkAdjustment
*) NULL
;
2452 m_vAdjust
= (GtkAdjustment
*) NULL
;
2453 m_oldHorizontalPos
=
2454 m_oldVerticalPos
= 0.0;
2456 m_oldClientHeight
= 0;
2459 m_widgetStyle
= (GtkStyle
*) NULL
;
2461 m_insertCallback
= (wxInsertChildFunction
) NULL
;
2463 m_acceptsFocus
= FALSE
;
2466 m_clipPaintRegion
= FALSE
;
2468 m_cursor
= *wxSTANDARD_CURSOR
;
2470 m_delayedForegroundColour
= FALSE
;
2471 m_delayedBackgroundColour
= FALSE
;
2475 m_x11Context
= NULL
;
2478 m_ic
= (GdkIC
*) NULL
;
2479 m_icattr
= (GdkICAttr
*) NULL
;
2484 wxWindowGTK::wxWindowGTK()
2489 wxWindowGTK::wxWindowGTK( wxWindow
*parent
,
2494 const wxString
&name
)
2498 Create( parent
, id
, pos
, size
, style
, name
);
2501 bool wxWindowGTK::Create( wxWindow
*parent
,
2506 const wxString
&name
)
2508 if (!PreCreation( parent
, pos
, size
) ||
2509 !CreateBase( parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
))
2511 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2515 m_insertCallback
= wxInsertChildInWindow
;
2517 // always needed for background clearing
2518 m_delayedBackgroundColour
= TRUE
;
2520 m_widget
= gtk_scrolled_window_new( (GtkAdjustment
*) NULL
, (GtkAdjustment
*) NULL
);
2521 GTK_WIDGET_UNSET_FLAGS( m_widget
, GTK_CAN_FOCUS
);
2523 GtkScrolledWindow
*scrolledWindow
= GTK_SCROLLED_WINDOW(m_widget
);
2525 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
2526 scroll_class
->scrollbar_spacing
= 0;
2528 gtk_scrolled_window_set_policy( scrolledWindow
, GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
2530 m_hAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->hscrollbar
) );
2531 m_vAdjust
= gtk_range_get_adjustment( GTK_RANGE(scrolledWindow
->vscrollbar
) );
2533 m_wxwindow
= gtk_pizza_new();
2535 #ifndef __WXUNIVERSAL__
2536 GtkPizza
*pizza
= GTK_PIZZA(m_wxwindow
);
2538 if (HasFlag(wxRAISED_BORDER
))
2540 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_OUT
);
2542 else if (HasFlag(wxSUNKEN_BORDER
))
2544 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_IN
);
2546 else if (HasFlag(wxSIMPLE_BORDER
))
2548 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_THIN
);
2552 gtk_pizza_set_shadow_type( pizza
, GTK_MYSHADOW_NONE
);
2554 #endif // __WXUNIVERSAL__
2556 gtk_container_add( GTK_CONTAINER(m_widget
), m_wxwindow
);
2558 GTK_WIDGET_SET_FLAGS( m_wxwindow
, GTK_CAN_FOCUS
);
2559 m_acceptsFocus
= TRUE
;
2561 // I _really_ don't want scrollbars in the beginning
2562 m_vAdjust
->lower
= 0.0;
2563 m_vAdjust
->upper
= 1.0;
2564 m_vAdjust
->value
= 0.0;
2565 m_vAdjust
->step_increment
= 1.0;
2566 m_vAdjust
->page_increment
= 1.0;
2567 m_vAdjust
->page_size
= 5.0;
2568 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
2569 m_hAdjust
->lower
= 0.0;
2570 m_hAdjust
->upper
= 1.0;
2571 m_hAdjust
->value
= 0.0;
2572 m_hAdjust
->step_increment
= 1.0;
2573 m_hAdjust
->page_increment
= 1.0;
2574 m_hAdjust
->page_size
= 5.0;
2575 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
2577 // these handlers block mouse events to any window during scrolling such as
2578 // motion events and prevent GTK and wxWindows from fighting over where the
2581 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_press_event",
2582 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2584 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_press_event",
2585 (GtkSignalFunc
)gtk_scrollbar_button_press_callback
, (gpointer
) this );
2587 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->vscrollbar
), "button_release_event",
2588 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2590 gtk_signal_connect( GTK_OBJECT(scrolledWindow
->hscrollbar
), "button_release_event",
2591 (GtkSignalFunc
)gtk_scrollbar_button_release_callback
, (gpointer
) this );
2593 // these handlers get notified when screen updates are required either when
2594 // scrolling or when the window size (and therefore scrollbar configuration)
2597 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
2598 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
2599 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
2600 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
2603 // Create input method handler
2604 m_imContext
= (GtkIMMulticontext
*) gtk_im_multicontext_new ();
2606 // Cannot handle drawing preedited text yet
2607 gtk_im_context_set_use_preedit( (GtkIMContext
*) m_imContext
, FALSE
);
2609 g_signal_connect (G_OBJECT (m_imContext
), "commit",
2610 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2613 gtk_widget_show( m_wxwindow
);
2616 m_parent
->DoAddChild( this );
2618 m_focusWidget
= m_wxwindow
;
2627 wxWindowGTK::~wxWindowGTK()
2631 if (g_focusWindow
== this)
2632 g_focusWindow
= NULL
;
2634 if (g_activeFrame
== this)
2635 g_activeFrame
= NULL
;
2637 if ( g_delayedFocus
== this )
2638 g_delayedFocus
= NULL
;
2640 m_isBeingDeleted
= TRUE
;
2649 m_parent
->RemoveChild( this );
2653 gdk_ic_destroy (m_ic
);
2655 gdk_ic_attr_destroy (m_icattr
);
2660 #if DISABLE_STYLE_IF_BROKEN_THEME
2661 // don't delete if it's a pixmap theme style
2662 if (!m_widgetStyle
->engine_data
)
2663 gtk_style_unref( m_widgetStyle
);
2665 m_widgetStyle
= (GtkStyle
*) NULL
;
2670 gtk_widget_destroy( m_wxwindow
);
2671 m_wxwindow
= (GtkWidget
*) NULL
;
2676 gtk_widget_destroy( m_widget
);
2677 m_widget
= (GtkWidget
*) NULL
;
2681 bool wxWindowGTK::PreCreation( wxWindowGTK
*parent
, const wxPoint
&pos
, const wxSize
&size
)
2683 wxCHECK_MSG( !m_needParent
|| parent
, FALSE
, wxT("Need complete parent.") );
2685 // This turns -1 into 30 so that a minimal window is
2686 // visible even although -1,-1 has been given as the
2687 // size of the window. the same trick is used in other
2688 // ports and should make debugging easier.
2689 m_width
= WidthDefault(size
.x
) ;
2690 m_height
= HeightDefault(size
.y
);
2695 // some reasonable defaults
2700 m_x
= (gdk_screen_width () - m_width
) / 2;
2701 if (m_x
< 10) m_x
= 10;
2705 m_y
= (gdk_screen_height () - m_height
) / 2;
2706 if (m_y
< 10) m_y
= 10;
2713 void wxWindowGTK::PostCreation()
2715 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2721 // these get reported to wxWindows -> wxPaintEvent
2723 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow
), TRUE
);
2725 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "expose_event",
2726 GTK_SIGNAL_FUNC(gtk_window_expose_callback
), (gpointer
)this );
2729 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "draw",
2730 GTK_SIGNAL_FUNC(gtk_window_draw_callback
), (gpointer
)this );
2732 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE
))
2734 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "event",
2735 GTK_SIGNAL_FUNC(gtk_window_event_event_callback
), (gpointer
)this );
2738 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), HasFlag( wxNO_FULL_REPAINT_ON_RESIZE ) );
2742 // Create input method handler
2743 m_imContext
= (GtkIMMulticontext
*) gtk_im_multicontext_new ();
2745 // Cannot handle drawing preedited text yet
2746 gtk_im_context_set_use_preedit( (GtkIMContext
*) m_imContext
, FALSE
);
2748 g_signal_connect (G_OBJECT (m_imContext
), "commit",
2749 G_CALLBACK (gtk_wxwindow_commit_cb
), this);
2753 // these are called when the "sunken" or "raised" borders are drawn
2754 gtk_signal_connect( GTK_OBJECT(m_widget
), "expose_event",
2755 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback
), (gpointer
)this );
2758 gtk_signal_connect( GTK_OBJECT(m_widget
), "draw",
2759 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback
), (gpointer
)this );
2765 if (m_focusWidget
== NULL
)
2766 m_focusWidget
= m_widget
;
2768 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_in_event",
2769 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback
), (gpointer
)this );
2771 gtk_signal_connect( GTK_OBJECT(m_focusWidget
), "focus_out_event",
2772 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback
), (gpointer
)this );
2774 // connect to the various key and mouse handlers
2776 GtkWidget
*connect_widget
= GetConnectWidget();
2778 ConnectWidget( connect_widget
);
2780 /* We cannot set colours, fonts and cursors before the widget has
2781 been realized, so we do this directly after realization */
2782 gtk_signal_connect( GTK_OBJECT(connect_widget
), "realize",
2783 GTK_SIGNAL_FUNC(gtk_window_realized_callback
), (gpointer
) this );
2787 // Catch native resize events
2788 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2789 GTK_SIGNAL_FUNC(gtk_window_size_callback
), (gpointer
)this );
2791 // Initialize XIM support
2792 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "realize",
2793 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback
), (gpointer
) this );
2795 // And resize XIM window
2796 gtk_signal_connect( GTK_OBJECT(m_wxwindow
), "size_allocate",
2797 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback
), (gpointer
)this );
2800 if ( !GTK_IS_COMBO(m_widget
))
2802 // This is needed if we want to add our windows into native
2803 // GTK control, such as the toolbar. With this callback, the
2804 // toolbar gets to know the correct size (the one set by the
2805 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2806 // when moving to GTK 2.0.
2807 gtk_signal_connect( GTK_OBJECT(m_widget
), "size_request",
2808 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback
),
2815 void wxWindowGTK::ConnectWidget( GtkWidget
*widget
)
2817 gtk_signal_connect( GTK_OBJECT(widget
), "key_press_event",
2818 GTK_SIGNAL_FUNC(gtk_window_key_press_callback
), (gpointer
)this );
2820 gtk_signal_connect( GTK_OBJECT(widget
), "key_release_event",
2821 GTK_SIGNAL_FUNC(gtk_window_key_release_callback
), (gpointer
)this );
2823 gtk_signal_connect( GTK_OBJECT(widget
), "button_press_event",
2824 GTK_SIGNAL_FUNC(gtk_window_button_press_callback
), (gpointer
)this );
2826 gtk_signal_connect( GTK_OBJECT(widget
), "button_release_event",
2827 GTK_SIGNAL_FUNC(gtk_window_button_release_callback
), (gpointer
)this );
2829 gtk_signal_connect( GTK_OBJECT(widget
), "motion_notify_event",
2830 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback
), (gpointer
)this );
2832 gtk_signal_connect( GTK_OBJECT(widget
), "enter_notify_event",
2833 GTK_SIGNAL_FUNC(gtk_window_enter_callback
), (gpointer
)this );
2835 gtk_signal_connect( GTK_OBJECT(widget
), "leave_notify_event",
2836 GTK_SIGNAL_FUNC(gtk_window_leave_callback
), (gpointer
)this );
2839 bool wxWindowGTK::Destroy()
2841 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2845 return wxWindowBase::Destroy();
2848 void wxWindowGTK::DoMoveWindow(int x
, int y
, int width
, int height
)
2850 gtk_pizza_set_size( GTK_PIZZA(m_parent
->m_wxwindow
), m_widget
, x
, y
, width
, height
);
2853 void wxWindowGTK::DoSetSize( int x
, int y
, int width
, int height
, int sizeFlags
)
2855 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
2856 wxASSERT_MSG( (m_parent
!= NULL
), wxT("wxWindowGTK::SetSize requires parent.\n") );
2859 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
2862 if (m_resizing
) return; /* I don't like recursions */
2865 int currentX
, currentY
;
2866 GetPosition(¤tX
, ¤tY
);
2871 AdjustForParentClientOrigin(x
, y
, sizeFlags
);
2873 if (m_parent
->m_wxwindow
== NULL
) /* i.e. wxNotebook */
2875 /* don't set the size for children of wxNotebook, just take the values. */
2883 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
2884 if ((sizeFlags
& wxSIZE_ALLOW_MINUS_ONE
) == 0)
2886 if (x
!= -1) m_x
= x
+ pizza
->xoffset
;
2887 if (y
!= -1) m_y
= y
+ pizza
->yoffset
;
2891 m_x
= x
+ pizza
->xoffset
;
2892 m_y
= y
+ pizza
->yoffset
;
2894 if (width
!= -1) m_width
= width
;
2895 if (height
!= -1) m_height
= height
;
2897 if ((sizeFlags
& wxSIZE_AUTO_WIDTH
) == wxSIZE_AUTO_WIDTH
)
2899 if (width
== -1) m_width
= 80;
2902 if ((sizeFlags
& wxSIZE_AUTO_HEIGHT
) == wxSIZE_AUTO_HEIGHT
)
2904 if (height
== -1) m_height
= 26;
2907 int minWidth
= GetMinWidth(),
2908 minHeight
= GetMinHeight(),
2909 maxWidth
= GetMaxWidth(),
2910 maxHeight
= GetMaxHeight();
2912 if ((minWidth
!= -1) && (m_width
< minWidth
)) m_width
= minWidth
;
2913 if ((minHeight
!= -1) && (m_height
< minHeight
)) m_height
= minHeight
;
2914 if ((maxWidth
!= -1) && (m_width
> maxWidth
)) m_width
= maxWidth
;
2915 if ((maxHeight
!= -1) && (m_height
> maxHeight
)) m_height
= maxHeight
;
2918 int bottom_border
= 0;
2921 if (GTK_WIDGET_CAN_DEFAULT(m_widget
))
2923 /* the default button has a border around it */
2929 DoMoveWindow( m_x
-border
,
2932 m_height
+border
+bottom_border
);
2937 /* Sometimes the client area changes size without the
2938 whole windows's size changing, but if the whole
2939 windows's size doesn't change, no wxSizeEvent will
2940 normally be sent. Here we add an extra test if
2941 the client test has been changed and this will
2943 GetClientSize( &m_oldClientWidth
, &m_oldClientHeight
);
2947 wxPrintf( "OnSize sent from " );
2948 if (GetClassInfo() && GetClassInfo()->GetClassName())
2949 wxPrintf( GetClassInfo()->GetClassName() );
2950 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2953 if (!m_nativeSizeEvent
)
2955 wxSizeEvent
event( wxSize(m_width
,m_height
), GetId() );
2956 event
.SetEventObject( this );
2957 GetEventHandler()->ProcessEvent( event
);
2963 void wxWindowGTK::OnInternalIdle()
2965 // Update invalidated regions.
2968 // Synthetize activate events.
2969 if ( g_sendActivateEvent
!= -1 )
2971 bool activate
= g_sendActivateEvent
!= 0;
2974 g_sendActivateEvent
= -1;
2976 wxTheApp
->SetActive(activate
, (wxWindow
*)g_focusWindowLast
);
2979 if ( g_activeFrameLostFocus
)
2981 if ( g_activeFrame
)
2983 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame
);
2984 wxActivateEvent
event(wxEVT_ACTIVATE
, FALSE
, g_activeFrame
->GetId());
2985 event
.SetEventObject(g_activeFrame
);
2986 g_activeFrame
->GetEventHandler()->ProcessEvent(event
);
2987 g_activeFrame
= NULL
;
2989 g_activeFrameLostFocus
= FALSE
;
2992 wxCursor cursor
= m_cursor
;
2993 if (g_globalCursor
.Ok()) cursor
= g_globalCursor
;
2997 /* I now set the cursor anew in every OnInternalIdle call
2998 as setting the cursor in a parent window also effects the
2999 windows above so that checking for the current cursor is
3004 GdkWindow
*window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3006 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3008 if (!g_globalCursor
.Ok())
3009 cursor
= *wxSTANDARD_CURSOR
;
3011 window
= m_widget
->window
;
3012 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3013 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3019 GdkWindow
*window
= m_widget
->window
;
3020 if ((window
) && !(GTK_WIDGET_NO_WINDOW(m_widget
)))
3021 gdk_window_set_cursor( window
, cursor
.GetCursor() );
3026 if (wxUpdateUIEvent::CanUpdate(this))
3027 UpdateWindowUI(wxUPDATE_UI_FROMIDLE
);
3030 void wxWindowGTK::DoGetSize( int *width
, int *height
) const
3032 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3034 if (width
) (*width
) = m_width
;
3035 if (height
) (*height
) = m_height
;
3038 void wxWindowGTK::DoSetClientSize( int width
, int height
)
3040 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3044 SetSize( width
, height
);
3051 #ifndef __WXUNIVERSAL__
3052 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3054 /* when using GTK 1.2 we set the shadow border size to 2 */
3058 if (HasFlag(wxSIMPLE_BORDER
))
3060 /* when using GTK 1.2 we set the simple border size to 1 */
3064 #endif // __WXUNIVERSAL__
3068 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3070 GtkRequisition vscroll_req
;
3071 vscroll_req
.width
= 2;
3072 vscroll_req
.height
= 2;
3073 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3074 (scroll_window
->vscrollbar
, &vscroll_req
);
3076 GtkRequisition hscroll_req
;
3077 hscroll_req
.width
= 2;
3078 hscroll_req
.height
= 2;
3079 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3080 (scroll_window
->hscrollbar
, &hscroll_req
);
3082 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3084 if (scroll_window
->vscrollbar_visible
)
3086 dw
+= vscroll_req
.width
;
3087 dw
+= scroll_class
->scrollbar_spacing
;
3090 if (scroll_window
->hscrollbar_visible
)
3092 dh
+= hscroll_req
.height
;
3093 dh
+= scroll_class
->scrollbar_spacing
;
3097 SetSize( width
+dw
, height
+dh
);
3101 void wxWindowGTK::DoGetClientSize( int *width
, int *height
) const
3103 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3107 if (width
) (*width
) = m_width
;
3108 if (height
) (*height
) = m_height
;
3115 #ifndef __WXUNIVERSAL__
3116 if (HasFlag(wxRAISED_BORDER
) || HasFlag(wxSUNKEN_BORDER
))
3118 /* when using GTK 1.2 we set the shadow border size to 2 */
3122 if (HasFlag(wxSIMPLE_BORDER
))
3124 /* when using GTK 1.2 we set the simple border size to 1 */
3128 #endif // __WXUNIVERSAL__
3132 GtkScrolledWindow
*scroll_window
= GTK_SCROLLED_WINDOW(m_widget
);
3134 GtkRequisition vscroll_req
;
3135 vscroll_req
.width
= 2;
3136 vscroll_req
.height
= 2;
3137 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->vscrollbar
) )->size_request
)
3138 (scroll_window
->vscrollbar
, &vscroll_req
);
3140 GtkRequisition hscroll_req
;
3141 hscroll_req
.width
= 2;
3142 hscroll_req
.height
= 2;
3143 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window
->hscrollbar
) )->size_request
)
3144 (scroll_window
->hscrollbar
, &hscroll_req
);
3146 GtkScrolledWindowClass
*scroll_class
= GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget
) );
3148 if (scroll_window
->vscrollbar_visible
)
3150 dw
+= vscroll_req
.width
;
3151 dw
+= scroll_class
->scrollbar_spacing
;
3154 if (scroll_window
->hscrollbar_visible
)
3156 dh
+= hscroll_req
.height
;
3157 dh
+= scroll_class
->scrollbar_spacing
;
3161 if (width
) (*width
) = m_width
- dw
;
3162 if (height
) (*height
) = m_height
- dh
;
3166 printf( "GetClientSize, name %s ", GetName().c_str() );
3167 if (width) printf( " width = %d", (*width) );
3168 if (height) printf( " height = %d", (*height) );
3173 void wxWindowGTK::DoGetPosition( int *x
, int *y
) const
3175 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3179 if (m_parent
&& m_parent
->m_wxwindow
)
3181 GtkPizza
*pizza
= GTK_PIZZA(m_parent
->m_wxwindow
);
3182 dx
= pizza
->xoffset
;
3183 dy
= pizza
->yoffset
;
3186 if (x
) (*x
) = m_x
- dx
;
3187 if (y
) (*y
) = m_y
- dy
;
3190 void wxWindowGTK::DoClientToScreen( int *x
, int *y
) const
3192 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3194 if (!m_widget
->window
) return;
3196 GdkWindow
*source
= (GdkWindow
*) NULL
;
3198 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3200 source
= m_widget
->window
;
3204 gdk_window_get_origin( source
, &org_x
, &org_y
);
3208 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3210 org_x
+= m_widget
->allocation
.x
;
3211 org_y
+= m_widget
->allocation
.y
;
3219 void wxWindowGTK::DoScreenToClient( int *x
, int *y
) const
3221 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3223 if (!m_widget
->window
) return;
3225 GdkWindow
*source
= (GdkWindow
*) NULL
;
3227 source
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3229 source
= m_widget
->window
;
3233 gdk_window_get_origin( source
, &org_x
, &org_y
);
3237 if (GTK_WIDGET_NO_WINDOW (m_widget
))
3239 org_x
+= m_widget
->allocation
.x
;
3240 org_y
+= m_widget
->allocation
.y
;
3248 bool wxWindowGTK::Show( bool show
)
3250 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3252 if (!wxWindowBase::Show(show
))
3259 gtk_widget_show( m_widget
);
3261 gtk_widget_hide( m_widget
);
3263 wxShowEvent
eventShow(GetId(), show
);
3264 eventShow
.m_eventObject
= this;
3266 GetEventHandler()->ProcessEvent(eventShow
);
3271 static void wxWindowNotifyEnable(wxWindowGTK
* win
, bool enable
)
3273 win
->OnParentEnable(enable
);
3275 // Recurse, so that children have the opportunity to Do The Right Thing
3276 // and reset colours that have been messed up by a parent's (really ancestor's)
3278 for ( wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
3280 node
= node
->GetNext() )
3282 wxWindow
*child
= node
->GetData();
3283 if (!child
->IsKindOf(CLASSINFO(wxDialog
)) && !child
->IsKindOf(CLASSINFO(wxFrame
)))
3284 wxWindowNotifyEnable(child
, enable
);
3288 bool wxWindowGTK::Enable( bool enable
)
3290 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3292 if (!wxWindowBase::Enable(enable
))
3298 gtk_widget_set_sensitive( m_widget
, enable
);
3300 gtk_widget_set_sensitive( m_wxwindow
, enable
);
3302 wxWindowNotifyEnable(this, enable
);
3307 int wxWindowGTK::GetCharHeight() const
3309 wxCHECK_MSG( (m_widget
!= NULL
), 12, wxT("invalid window") );
3311 wxCHECK_MSG( m_font
.Ok(), 12, wxT("invalid font") );
3314 PangoContext
*context
= NULL
;
3316 context
= gtk_widget_get_pango_context( m_widget
);
3321 PangoFontDescription
*desc
= m_font
.GetNativeFontInfo()->description
;
3322 PangoLayout
*layout
= pango_layout_new(context
);
3323 pango_layout_set_font_description(layout
, desc
);
3324 pango_layout_set_text(layout
, "H", 1);
3325 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3327 PangoRectangle rect
;
3328 pango_layout_line_get_extents(line
, NULL
, &rect
);
3330 g_object_unref( G_OBJECT( layout
) );
3332 return (int) (rect
.height
/ PANGO_SCALE
);
3334 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3336 return font
->ascent
+ font
->descent
;
3340 int wxWindowGTK::GetCharWidth() const
3342 wxCHECK_MSG( (m_widget
!= NULL
), 8, wxT("invalid window") );
3344 wxCHECK_MSG( m_font
.Ok(), 8, wxT("invalid font") );
3347 PangoContext
*context
= NULL
;
3349 context
= gtk_widget_get_pango_context( m_widget
);
3354 PangoFontDescription
*desc
= m_font
.GetNativeFontInfo()->description
;
3355 PangoLayout
*layout
= pango_layout_new(context
);
3356 pango_layout_set_font_description(layout
, desc
);
3357 pango_layout_set_text(layout
, "H", 1);
3358 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3360 PangoRectangle rect
;
3361 pango_layout_line_get_extents(line
, NULL
, &rect
);
3363 g_object_unref( G_OBJECT( layout
) );
3365 return (int) (rect
.width
/ PANGO_SCALE
);
3367 GdkFont
*font
= m_font
.GetInternalFont( 1.0 );
3369 return gdk_string_width( font
, "H" );
3373 void wxWindowGTK::GetTextExtent( const wxString
& string
,
3377 int *externalLeading
,
3378 const wxFont
*theFont
) const
3380 wxFont fontToUse
= m_font
;
3381 if (theFont
) fontToUse
= *theFont
;
3383 wxCHECK_RET( fontToUse
.Ok(), wxT("invalid font") );
3385 if (string
.IsEmpty())
3393 PangoContext
*context
= NULL
;
3395 context
= gtk_widget_get_pango_context( m_widget
);
3404 PangoFontDescription
*desc
= fontToUse
.GetNativeFontInfo()->description
;
3405 PangoLayout
*layout
= pango_layout_new(context
);
3406 pango_layout_set_font_description(layout
, desc
);
3409 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( string
);
3410 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3412 const wxWCharBuffer wdata
= wxConvLocal
.cMB2WC( string
);
3413 const wxCharBuffer data
= wxConvUTF8
.cWC2MB( wdata
);
3414 pango_layout_set_text(layout
, (const char*) data
, strlen( (const char*) data
));
3417 PangoLayoutLine
*line
= (PangoLayoutLine
*)pango_layout_get_lines(layout
)->data
;
3419 PangoRectangle rect
;
3420 pango_layout_line_get_extents(line
, NULL
, &rect
);
3422 if (x
) (*x
) = (wxCoord
) (rect
.width
/ PANGO_SCALE
);
3423 if (y
) (*y
) = (wxCoord
) (rect
.height
/ PANGO_SCALE
);
3426 // Do something about metrics here
3429 if (externalLeading
) (*externalLeading
) = 0; // ??
3431 g_object_unref( G_OBJECT( layout
) );
3433 GdkFont
*font
= fontToUse
.GetInternalFont( 1.0 );
3434 if (x
) (*x
) = gdk_string_width( font
, wxGTK_CONV( string
) );
3435 if (y
) (*y
) = font
->ascent
+ font
->descent
;
3436 if (descent
) (*descent
) = font
->descent
;
3437 if (externalLeading
) (*externalLeading
) = 0; // ??
3441 void wxWindowGTK::SetFocus()
3443 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3447 // don't do anything if we already have focus
3453 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow
))
3455 gtk_widget_grab_focus (m_wxwindow
);
3460 if (GTK_WIDGET_CAN_FOCUS(m_widget
) && !GTK_WIDGET_HAS_FOCUS (m_widget
) )
3462 if (!GTK_WIDGET_REALIZED(m_widget
))
3464 // we can't set the focus to the widget now so we remember that
3465 // it should be focused and will do it later, during the idle
3466 // time, as soon as we can
3467 wxLogTrace(TRACE_FOCUS
,
3468 _T("Delaying setting focus to %s(%s)"),
3469 GetClassInfo()->GetClassName(), GetLabel().c_str());
3471 g_delayedFocus
= this;
3475 wxLogTrace(TRACE_FOCUS
,
3476 _T("Setting focus to %s(%s)"),
3477 GetClassInfo()->GetClassName(), GetLabel().c_str());
3479 gtk_widget_grab_focus (m_widget
);
3482 else if (GTK_IS_CONTAINER(m_widget
))
3484 SET_CONTAINER_FOCUS( m_widget
, GTK_DIR_TAB_FORWARD
);
3488 wxLogTrace(TRACE_FOCUS
,
3489 _T("Can't set focus to %s(%s)"),
3490 GetClassInfo()->GetClassName(), GetLabel().c_str());
3495 bool wxWindowGTK::AcceptsFocus() const
3497 return m_acceptsFocus
&& wxWindowBase::AcceptsFocus();
3500 bool wxWindowGTK::Reparent( wxWindowBase
*newParentBase
)
3502 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3504 wxWindowGTK
*oldParent
= m_parent
,
3505 *newParent
= (wxWindowGTK
*)newParentBase
;
3507 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3509 if ( !wxWindowBase::Reparent(newParent
) )
3512 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3514 /* prevent GTK from deleting the widget arbitrarily */
3515 gtk_widget_ref( m_widget
);
3519 gtk_container_remove( GTK_CONTAINER(m_widget
->parent
), m_widget
);
3522 wxASSERT( GTK_IS_WIDGET(m_widget
) );
3526 /* insert GTK representation */
3527 (*(newParent
->m_insertCallback
))(newParent
, this);
3530 /* reverse: prevent GTK from deleting the widget arbitrarily */
3531 gtk_widget_unref( m_widget
);
3536 void wxWindowGTK::DoAddChild(wxWindowGTK
*child
)
3538 wxASSERT_MSG( (m_widget
!= NULL
), wxT("invalid window") );
3540 wxASSERT_MSG( (child
!= NULL
), wxT("invalid child window") );
3542 wxASSERT_MSG( (m_insertCallback
!= NULL
), wxT("invalid child insertion function") );
3547 /* insert GTK representation */
3548 (*m_insertCallback
)(this, child
);
3551 void wxWindowGTK::Raise()
3553 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3555 if (!m_widget
->window
) return;
3557 gdk_window_raise( m_widget
->window
);
3560 void wxWindowGTK::Lower()
3562 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3564 if (!m_widget
->window
) return;
3566 gdk_window_lower( m_widget
->window
);
3569 bool wxWindowGTK::SetCursor( const wxCursor
&cursor
)
3571 wxCHECK_MSG( (m_widget
!= NULL
), FALSE
, wxT("invalid window") );
3573 if (cursor
== m_cursor
)
3577 wxapp_install_idle_handler();
3579 if (cursor
== wxNullCursor
)
3580 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR
);
3582 return wxWindowBase::SetCursor( cursor
);
3585 void wxWindowGTK::WarpPointer( int x
, int y
)
3587 wxCHECK_RET( (m_widget
!= NULL
), wxT("invalid window") );
3589 // We provide this function ourselves as it is
3590 // missing in GDK (top of this file).
3592 GdkWindow
*window
= (GdkWindow
*) NULL
;
3594 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3596 window
= GetConnectWidget()->window
;
3599 gdk_window_warp_pointer( window
, x
, y
);
3603 void wxWindowGTK::Refresh( bool eraseBackground
, const wxRect
*rect
)
3605 if (!m_widget
) return;
3606 if (!m_widget
->window
) return;
3610 wxapp_install_idle_handler();
3612 wxRect
myRect(0,0,0,0);
3613 if (m_wxwindow
&& rect
)
3615 myRect
.SetSize(wxSize( m_wxwindow
->allocation
.width
,
3616 m_wxwindow
->allocation
.height
));
3617 myRect
.Intersect(*rect
);
3618 if (!myRect
.width
|| !myRect
.height
)
3619 // nothing to do, rectangle is empty
3624 if (eraseBackground
&& m_wxwindow
&& m_wxwindow
->window
)
3628 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3629 m_clearRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3633 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3634 m_clearRegion
.Clear();
3635 m_clearRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3643 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3644 m_updateRegion
.Union( rect
->x
, rect
->y
, rect
->width
, rect
->height
);
3648 GdkRectangle gdk_rect
;
3649 gdk_rect
.x
= rect
->x
;
3650 gdk_rect
.y
= rect
->y
;
3651 gdk_rect
.width
= rect
->width
;
3652 gdk_rect
.height
= rect
->height
;
3653 gtk_widget_draw( m_widget
, &gdk_rect
);
3660 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3661 m_updateRegion
.Clear();
3662 m_updateRegion
.Union( 0, 0, m_wxwindow
->allocation
.width
, m_wxwindow
->allocation
.height
);
3666 gtk_widget_draw( m_widget
, (GdkRectangle
*) NULL
);
3674 GdkRectangle gdk_rect
;
3675 gdk_rect
.x
= rect
->x
;
3676 gdk_rect
.y
= rect
->y
;
3677 gdk_rect
.width
= rect
->width
;
3678 gdk_rect
.height
= rect
->height
;
3679 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, &gdk_rect
, TRUE
);
3683 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow
)->bin_window
, NULL
, TRUE
);
3689 void wxWindowGTK::Update()
3694 void wxWindowGTK::GtkUpdate()
3697 if (m_wxwindow
&& GTK_PIZZA(m_wxwindow
)->bin_window
)
3698 gdk_window_process_updates( GTK_PIZZA(m_wxwindow
)->bin_window
, FALSE
);
3700 if (!m_updateRegion
.IsEmpty())
3701 GtkSendPaintEvents();
3705 void wxWindowGTK::GtkSendPaintEvents()
3710 m_clearRegion
.Clear();
3712 m_updateRegion
.Clear();
3716 // Clip to paint region in wxClientDC
3717 m_clipPaintRegion
= TRUE
;
3720 // widget to draw on
3721 GtkPizza
*pizza
= GTK_PIZZA (m_wxwindow
);
3723 // later for GTK 2.0, too.
3724 if (GetThemeEnabled())
3726 // find ancestor from which to steal background
3727 wxWindow
*parent
= GetParent();
3728 while (parent
&& !parent
->IsTopLevel())
3729 parent
= parent
->GetParent();
3731 parent
= (wxWindow
*)this;
3733 wxRegionIterator
upd( m_updateRegion
);
3737 rect
.x
= upd
.GetX();
3738 rect
.y
= upd
.GetY();
3739 rect
.width
= upd
.GetWidth();
3740 rect
.height
= upd
.GetHeight();
3742 gtk_paint_flat_box( parent
->m_widget
->style
,
3759 wxWindowDC
dc( (wxWindow
*)this );
3760 dc
.SetClippingRegion( m_updateRegion
);
3762 wxEraseEvent
erase_event( GetId(), &dc
);
3763 erase_event
.SetEventObject( this );
3765 GetEventHandler()->ProcessEvent(erase_event
);
3768 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
3770 wxWindowDC
dc( (wxWindow
*)this );
3771 if (m_clearRegion
.IsEmpty())
3772 dc
.SetClippingRegion( m_updateRegion
);
3774 dc
.SetClippingRegion( m_clearRegion
);
3776 wxEraseEvent
erase_event( GetId(), &dc
);
3777 erase_event
.SetEventObject( this );
3779 if (!GetEventHandler()->ProcessEvent(erase_event
))
3783 g_eraseGC
= gdk_gc_new( pizza
->bin_window
);
3784 gdk_gc_set_fill( g_eraseGC
, GDK_SOLID
);
3786 gdk_gc_set_foreground( g_eraseGC
, m_backgroundColour
.GetColor() );
3788 wxRegionIterator
upd( m_clearRegion
);
3791 gdk_draw_rectangle( pizza
->bin_window
, g_eraseGC
, 1,
3792 upd
.GetX(), upd
.GetY(), upd
.GetWidth(), upd
.GetHeight() );
3796 m_clearRegion
.Clear();
3800 wxNcPaintEvent
nc_paint_event( GetId() );
3801 nc_paint_event
.SetEventObject( this );
3802 GetEventHandler()->ProcessEvent( nc_paint_event
);
3804 wxPaintEvent
paint_event( GetId() );
3805 paint_event
.SetEventObject( this );
3806 GetEventHandler()->ProcessEvent( paint_event
);
3808 m_clipPaintRegion
= FALSE
;
3810 #ifndef __WXUNIVERSAL__
3812 // The following code will result in all window-less widgets
3813 // being redrawn because the wxWindows class is allowed to
3814 // paint over the window-less widgets.
3816 GList
*children
= pizza
->children
;
3819 GtkPizzaChild
*child
= (GtkPizzaChild
*) children
->data
;
3820 children
= children
->next
;
3822 if (GTK_WIDGET_NO_WINDOW (child
->widget
) &&
3823 GTK_WIDGET_DRAWABLE (child
->widget
))
3825 // Get intersection of widget area and update region
3826 wxRegion
region( m_updateRegion
);
3828 GdkEventExpose gdk_event
;
3829 gdk_event
.type
= GDK_EXPOSE
;
3830 gdk_event
.window
= pizza
->bin_window
;
3831 gdk_event
.count
= 0;
3833 wxRegionIterator
upd( m_updateRegion
);
3837 rect
.x
= upd
.GetX();
3838 rect
.y
= upd
.GetY();
3839 rect
.width
= upd
.GetWidth();
3840 rect
.height
= upd
.GetHeight();
3842 if (gtk_widget_intersect (child
->widget
, &rect
, &gdk_event
.area
))
3844 gtk_widget_event (child
->widget
, (GdkEvent
*) &gdk_event
);
3854 m_updateRegion
.Clear();
3857 void wxWindowGTK::Clear()
3859 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
3862 if (m_wxwindow
&& m_wxwindow
->window
)
3864 m_clearRegion
.Clear();
3865 wxSize
size( GetClientSize() );
3866 m_clearRegion
.Union( 0,0,size
.x
,size
.y
);
3868 // Better do this in idle?
3875 void wxWindowGTK::DoSetToolTip( wxToolTip
*tip
)
3877 wxWindowBase::DoSetToolTip(tip
);
3880 m_tooltip
->Apply( (wxWindow
*)this );
3883 void wxWindowGTK::ApplyToolTip( GtkTooltips
*tips
, const wxChar
*tip
)
3885 gtk_tooltips_set_tip( tips
, GetConnectWidget(), wxConvCurrent
->cWX2MB(tip
), (gchar
*) NULL
);
3887 #endif // wxUSE_TOOLTIPS
3889 void wxWindowGTK::GtkSetBackgroundColour( const wxColour
&colour
)
3891 GdkWindow
*window
= (GdkWindow
*) NULL
;
3893 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3895 window
= GetConnectWidget()->window
;
3899 // We need the pixel value e.g. for background clearing.
3900 m_backgroundColour
.CalcPixel( gdk_window_get_colormap( window
) );
3904 // wxMSW doesn't clear the window here, either.
3905 gdk_window_set_background( window
, m_backgroundColour
.GetColor() );
3911 bool wxWindowGTK::SetBackgroundColour( const wxColour
&colour
)
3913 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3915 if (!wxWindowBase::SetBackgroundColour(colour
))
3918 GdkWindow
*window
= (GdkWindow
*) NULL
;
3920 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3922 window
= GetConnectWidget()->window
;
3926 // indicate that a new style has been set
3927 // but it couldn't get applied as the
3928 // widget hasn't been realized yet.
3929 m_delayedBackgroundColour
= TRUE
;
3934 GtkSetBackgroundColour( colour
);
3940 void wxWindowGTK::GtkSetForegroundColour( const wxColour
&colour
)
3942 GdkWindow
*window
= (GdkWindow
*) NULL
;
3944 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3946 window
= GetConnectWidget()->window
;
3953 bool wxWindowGTK::SetForegroundColour( const wxColour
&colour
)
3955 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
3957 if (!wxWindowBase::SetForegroundColour(colour
))
3959 // don't leave if the GTK widget has just
3961 if (!m_delayedForegroundColour
) return FALSE
;
3964 GdkWindow
*window
= (GdkWindow
*) NULL
;
3966 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
3968 window
= GetConnectWidget()->window
;
3972 // indicate that a new style has been set
3973 // but it couldn't get applied as the
3974 // widget hasn't been realized yet.
3975 m_delayedForegroundColour
= TRUE
;
3979 GtkSetForegroundColour( colour
);
3986 PangoContext
*wxWindowGTK::GtkGetPangoDefaultContext()
3988 return gtk_widget_get_pango_context( m_widget
);
3991 PangoContext
*wxWindowGTK::GtkGetPangoX11Context()
3994 m_x11Context
= pango_x_get_context( gdk_display
);
3996 return m_x11Context
;
4000 GtkStyle
*wxWindowGTK::GetWidgetStyle()
4004 GtkStyle
*remake
= gtk_style_copy( m_widgetStyle
);
4006 // FIXME: no more klass in 2.0
4008 remake
->klass
= m_widgetStyle
->klass
;
4011 gtk_style_unref( m_widgetStyle
);
4012 m_widgetStyle
= remake
;
4016 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4019 def
= gtk_widget_get_default_style();
4021 m_widgetStyle
= gtk_style_copy( def
);
4023 // FIXME: no more klass in 2.0
4025 m_widgetStyle
->klass
= def
->klass
;
4029 return m_widgetStyle
;
4032 void wxWindowGTK::SetWidgetStyle()
4034 #if DISABLE_STYLE_IF_BROKEN_THEME
4035 if (m_widget
->style
->engine_data
)
4037 static bool s_warningPrinted
= FALSE
;
4038 if (!s_warningPrinted
)
4040 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
4041 s_warningPrinted
= TRUE
;
4043 m_widgetStyle
= m_widget
->style
;
4048 GtkStyle
*style
= GetWidgetStyle();
4050 if (m_font
!= wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT
))
4053 pango_font_description_free( style
->font_desc
);
4054 style
->font_desc
= pango_font_description_copy( m_font
.GetNativeFontInfo()->description
);
4056 gdk_font_unref( style
->font
);
4057 style
->font
= gdk_font_ref( m_font
.GetInternalFont( 1.0 ) );
4061 if (m_foregroundColour
.Ok())
4063 m_foregroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
4064 if (m_foregroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT
))
4066 style
->fg
[GTK_STATE_NORMAL
] = *m_foregroundColour
.GetColor();
4067 style
->fg
[GTK_STATE_PRELIGHT
] = *m_foregroundColour
.GetColor();
4068 style
->fg
[GTK_STATE_ACTIVE
] = *m_foregroundColour
.GetColor();
4072 // Try to restore the gtk default style. This is still a little
4073 // oversimplified for what is probably really needed here for controls
4074 // other than buttons, but is better than not being able to (re)set a
4075 // control's foreground colour to *wxBLACK -- RL
4076 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4079 def
= gtk_widget_get_default_style();
4081 style
->fg
[GTK_STATE_NORMAL
] = def
->fg
[GTK_STATE_NORMAL
];
4082 style
->fg
[GTK_STATE_PRELIGHT
] = def
->fg
[GTK_STATE_PRELIGHT
];
4083 style
->fg
[GTK_STATE_ACTIVE
] = def
->fg
[GTK_STATE_ACTIVE
];
4087 if (m_backgroundColour
.Ok())
4089 m_backgroundColour
.CalcPixel( gtk_widget_get_colormap( m_widget
) );
4090 if (m_backgroundColour
!= wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE
))
4092 style
->bg
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
4093 style
->base
[GTK_STATE_NORMAL
] = *m_backgroundColour
.GetColor();
4094 style
->bg
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
4095 style
->base
[GTK_STATE_PRELIGHT
] = *m_backgroundColour
.GetColor();
4096 style
->bg
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
4097 style
->base
[GTK_STATE_ACTIVE
] = *m_backgroundColour
.GetColor();
4098 style
->bg
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
4099 style
->base
[GTK_STATE_INSENSITIVE
] = *m_backgroundColour
.GetColor();
4103 // Try to restore the gtk default style. This is still a little
4104 // oversimplified for what is probably really needed here for controls
4105 // other than buttons, but is better than not being able to (re)set a
4106 // control's background colour to default grey and means resetting a
4107 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
4109 GtkStyle
*def
= gtk_rc_get_style( m_widget
);
4112 def
= gtk_widget_get_default_style();
4114 style
->bg
[GTK_STATE_NORMAL
] = def
->bg
[GTK_STATE_NORMAL
];
4115 style
->base
[GTK_STATE_NORMAL
] = def
->base
[GTK_STATE_NORMAL
];
4116 style
->bg
[GTK_STATE_PRELIGHT
] = def
->bg
[GTK_STATE_PRELIGHT
];
4117 style
->base
[GTK_STATE_PRELIGHT
] = def
->base
[GTK_STATE_PRELIGHT
];
4118 style
->bg
[GTK_STATE_ACTIVE
] = def
->bg
[GTK_STATE_ACTIVE
];
4119 style
->base
[GTK_STATE_ACTIVE
] = def
->base
[GTK_STATE_ACTIVE
];
4120 style
->bg
[GTK_STATE_INSENSITIVE
] = def
->bg
[GTK_STATE_INSENSITIVE
];
4121 style
->base
[GTK_STATE_INSENSITIVE
] = def
->base
[GTK_STATE_INSENSITIVE
];
4126 void wxWindowGTK::ApplyWidgetStyle()
4130 //-----------------------------------------------------------------------------
4131 // Pop-up menu stuff
4132 //-----------------------------------------------------------------------------
4134 #if wxUSE_MENUS_NATIVE
4137 void gtk_pop_hide_callback( GtkWidget
*WXUNUSED(widget
), bool* is_waiting
)
4139 *is_waiting
= FALSE
;
4142 static void SetInvokingWindow( wxMenu
*menu
, wxWindowGTK
*win
)
4144 menu
->SetInvokingWindow( win
);
4145 wxMenuItemList::compatibility_iterator node
= menu
->GetMenuItems().GetFirst();
4148 wxMenuItem
*menuitem
= node
->GetData();
4149 if (menuitem
->IsSubMenu())
4151 SetInvokingWindow( menuitem
->GetSubMenu(), win
);
4154 node
= node
->GetNext();
4158 // used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
4159 // wxPopupMenuPositionCallback()
4161 // should be safe even in the MT case as the user can hardly popup 2 menus
4162 // simultaneously, can he?
4163 static gint gs_pop_x
= 0;
4164 static gint gs_pop_y
= 0;
4166 extern "C" void wxPopupMenuPositionCallback( GtkMenu
*menu
,
4169 gboolean
* WXUNUSED(whatever
),
4171 gpointer
WXUNUSED(user_data
) )
4173 // ensure that the menu appears entirely on screen
4175 gtk_widget_get_child_requisition(GTK_WIDGET(menu
), &req
);
4177 wxSize sizeScreen
= wxGetDisplaySize();
4179 gint xmax
= sizeScreen
.x
- req
.width
,
4180 ymax
= sizeScreen
.y
- req
.height
;
4182 *x
= gs_pop_x
< xmax
? gs_pop_x
: xmax
;
4183 *y
= gs_pop_y
< ymax
? gs_pop_y
: ymax
;
4186 bool wxWindowGTK::DoPopupMenu( wxMenu
*menu
, int x
, int y
)
4188 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4190 wxCHECK_MSG( menu
!= NULL
, FALSE
, wxT("invalid popup-menu") );
4192 SetInvokingWindow( menu
, this );
4198 ClientToScreen( &gs_pop_x
, &gs_pop_y
);
4200 bool is_waiting
= TRUE
;
4202 gtk_signal_connect( GTK_OBJECT(menu
->m_menu
),
4204 GTK_SIGNAL_FUNC(gtk_pop_hide_callback
),
4205 (gpointer
)&is_waiting
);
4208 GTK_MENU(menu
->m_menu
),
4209 (GtkWidget
*) NULL
, // parent menu shell
4210 (GtkWidget
*) NULL
, // parent menu item
4211 wxPopupMenuPositionCallback
, // function to position it
4212 NULL
, // client data
4213 0, // button used to activate it
4215 gtk_get_current_event_time()
4223 gtk_main_iteration();
4229 #endif // wxUSE_MENUS_NATIVE
4231 #if wxUSE_DRAG_AND_DROP
4233 void wxWindowGTK::SetDropTarget( wxDropTarget
*dropTarget
)
4235 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4237 GtkWidget
*dnd_widget
= GetConnectWidget();
4239 if (m_dropTarget
) m_dropTarget
->UnregisterWidget( dnd_widget
);
4241 if (m_dropTarget
) delete m_dropTarget
;
4242 m_dropTarget
= dropTarget
;
4244 if (m_dropTarget
) m_dropTarget
->RegisterWidget( dnd_widget
);
4247 #endif // wxUSE_DRAG_AND_DROP
4249 GtkWidget
* wxWindowGTK::GetConnectWidget()
4251 GtkWidget
*connect_widget
= m_widget
;
4252 if (m_wxwindow
) connect_widget
= m_wxwindow
;
4254 return connect_widget
;
4257 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow
*window
)
4260 return (window
== GTK_PIZZA(m_wxwindow
)->bin_window
);
4262 return (window
== m_widget
->window
);
4265 bool wxWindowGTK::SetFont( const wxFont
&font
)
4267 wxCHECK_MSG( m_widget
!= NULL
, FALSE
, wxT("invalid window") );
4269 if (!wxWindowBase::SetFont(font
))
4274 wxColour sysbg
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE
);
4275 if ( sysbg
== m_backgroundColour
)
4277 m_backgroundColour
= wxNullColour
;
4279 m_backgroundColour
= sysbg
;
4289 void wxWindowGTK::DoCaptureMouse()
4291 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4293 GdkWindow
*window
= (GdkWindow
*) NULL
;
4295 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4297 window
= GetConnectWidget()->window
;
4299 wxCHECK_RET( window
, _T("CaptureMouse() failed") );
4301 wxCursor
* cursor
= & m_cursor
;
4303 cursor
= wxSTANDARD_CURSOR
;
4305 gdk_pointer_grab( window
, FALSE
,
4307 (GDK_BUTTON_PRESS_MASK
|
4308 GDK_BUTTON_RELEASE_MASK
|
4309 GDK_POINTER_MOTION_HINT_MASK
|
4310 GDK_POINTER_MOTION_MASK
),
4312 cursor
->GetCursor(),
4313 (guint32
)GDK_CURRENT_TIME
);
4314 g_captureWindow
= this;
4315 g_captureWindowHasMouse
= TRUE
;
4318 void wxWindowGTK::DoReleaseMouse()
4320 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4322 wxCHECK_RET( g_captureWindow
, wxT("can't release mouse - not captured") );
4324 g_captureWindow
= (wxWindowGTK
*) NULL
;
4326 GdkWindow
*window
= (GdkWindow
*) NULL
;
4328 window
= GTK_PIZZA(m_wxwindow
)->bin_window
;
4330 window
= GetConnectWidget()->window
;
4335 gdk_pointer_ungrab ( (guint32
)GDK_CURRENT_TIME
);
4339 wxWindow
*wxWindowBase::GetCapture()
4341 return (wxWindow
*)g_captureWindow
;
4344 bool wxWindowGTK::IsRetained() const
4349 void wxWindowGTK::SetScrollbar( int orient
, int pos
, int thumbVisible
,
4350 int range
, bool refresh
)
4352 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4354 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4356 m_hasScrolling
= TRUE
;
4358 if (orient
== wxHORIZONTAL
)
4360 float fpos
= (float)pos
;
4361 float frange
= (float)range
;
4362 float fthumb
= (float)thumbVisible
;
4363 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4364 if (fpos
< 0.0) fpos
= 0.0;
4366 if ((fabs(frange
-m_hAdjust
->upper
) < 0.2) &&
4367 (fabs(fthumb
-m_hAdjust
->page_size
) < 0.2))
4369 SetScrollPos( orient
, pos
, refresh
);
4373 m_oldHorizontalPos
= fpos
;
4375 m_hAdjust
->lower
= 0.0;
4376 m_hAdjust
->upper
= frange
;
4377 m_hAdjust
->value
= fpos
;
4378 m_hAdjust
->step_increment
= 1.0;
4379 m_hAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4380 m_hAdjust
->page_size
= fthumb
;
4384 float fpos
= (float)pos
;
4385 float frange
= (float)range
;
4386 float fthumb
= (float)thumbVisible
;
4387 if (fpos
> frange
-fthumb
) fpos
= frange
-fthumb
;
4388 if (fpos
< 0.0) fpos
= 0.0;
4390 if ((fabs(frange
-m_vAdjust
->upper
) < 0.2) &&
4391 (fabs(fthumb
-m_vAdjust
->page_size
) < 0.2))
4393 SetScrollPos( orient
, pos
, refresh
);
4397 m_oldVerticalPos
= fpos
;
4399 m_vAdjust
->lower
= 0.0;
4400 m_vAdjust
->upper
= frange
;
4401 m_vAdjust
->value
= fpos
;
4402 m_vAdjust
->step_increment
= 1.0;
4403 m_vAdjust
->page_increment
= (float)(wxMax(fthumb
,0));
4404 m_vAdjust
->page_size
= fthumb
;
4407 if (orient
== wxHORIZONTAL
)
4408 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "changed" );
4410 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "changed" );
4413 void wxWindowGTK::SetScrollPos( int orient
, int pos
, bool WXUNUSED(refresh
) )
4415 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4417 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4419 if (orient
== wxHORIZONTAL
)
4421 float fpos
= (float)pos
;
4422 if (fpos
> m_hAdjust
->upper
- m_hAdjust
->page_size
) fpos
= m_hAdjust
->upper
- m_hAdjust
->page_size
;
4423 if (fpos
< 0.0) fpos
= 0.0;
4424 m_oldHorizontalPos
= fpos
;
4426 if (fabs(fpos
-m_hAdjust
->value
) < 0.2) return;
4427 m_hAdjust
->value
= fpos
;
4431 float fpos
= (float)pos
;
4432 if (fpos
> m_vAdjust
->upper
- m_vAdjust
->page_size
) fpos
= m_vAdjust
->upper
- m_vAdjust
->page_size
;
4433 if (fpos
< 0.0) fpos
= 0.0;
4434 m_oldVerticalPos
= fpos
;
4436 if (fabs(fpos
-m_vAdjust
->value
) < 0.2) return;
4437 m_vAdjust
->value
= fpos
;
4440 if (m_wxwindow
->window
)
4442 if (orient
== wxHORIZONTAL
)
4444 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust
),
4445 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4447 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust
), "value_changed" );
4449 gtk_signal_connect( GTK_OBJECT(m_hAdjust
), "value_changed",
4450 (GtkSignalFunc
) gtk_window_hscroll_callback
, (gpointer
) this );
4454 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust
),
4455 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4457 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust
), "value_changed" );
4459 gtk_signal_connect( GTK_OBJECT(m_vAdjust
), "value_changed",
4460 (GtkSignalFunc
) gtk_window_vscroll_callback
, (gpointer
) this );
4465 int wxWindowGTK::GetScrollThumb( int orient
) const
4467 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4469 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4471 if (orient
== wxHORIZONTAL
)
4472 return (int)(m_hAdjust
->page_size
+0.5);
4474 return (int)(m_vAdjust
->page_size
+0.5);
4477 int wxWindowGTK::GetScrollPos( int orient
) const
4479 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4481 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4483 if (orient
== wxHORIZONTAL
)
4484 return (int)(m_hAdjust
->value
+0.5);
4486 return (int)(m_vAdjust
->value
+0.5);
4489 int wxWindowGTK::GetScrollRange( int orient
) const
4491 wxCHECK_MSG( m_widget
!= NULL
, 0, wxT("invalid window") );
4493 wxCHECK_MSG( m_wxwindow
!= NULL
, 0, wxT("window needs client area for scrolling") );
4495 if (orient
== wxHORIZONTAL
)
4496 return (int)(m_hAdjust
->upper
+0.5);
4498 return (int)(m_vAdjust
->upper
+0.5);
4501 void wxWindowGTK::ScrollWindow( int dx
, int dy
, const wxRect
* WXUNUSED(rect
) )
4503 wxCHECK_RET( m_widget
!= NULL
, wxT("invalid window") );
4505 wxCHECK_RET( m_wxwindow
!= NULL
, wxT("window needs client area for scrolling") );
4507 // No scrolling requested.
4508 if ((dx
== 0) && (dy
== 0)) return;
4511 if (!m_updateRegion
.IsEmpty())
4513 m_updateRegion
.Offset( dx
, dy
);
4517 GetClientSize( &cw
, &ch
);
4518 m_updateRegion
.Intersect( 0, 0, cw
, ch
);
4521 if (!m_clearRegion
.IsEmpty())
4523 m_clearRegion
.Offset( dx
, dy
);
4527 GetClientSize( &cw
, &ch
);
4528 m_clearRegion
.Intersect( 0, 0, cw
, ch
);
4532 m_clipPaintRegion
= TRUE
;
4534 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow
), -dx
, -dy
);
4536 m_clipPaintRegion
= FALSE
;
4540 // Find the wxWindow at the current mouse position, also returning the mouse
4542 wxWindow
* wxFindWindowAtPointer(wxPoint
& pt
)
4544 pt
= wxGetMousePosition();
4545 wxWindow
* found
= wxFindWindowAtPoint(pt
);
4549 // Get the current mouse position.
4550 wxPoint
wxGetMousePosition()
4552 /* This crashes when used within wxHelpContext,
4553 so we have to use the X-specific implementation below.
4555 GdkModifierType *mask;
4556 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4558 return wxPoint(x, y);
4562 GdkWindow
* windowAtPtr
= gdk_window_at_pointer(& x
, & y
);
4564 Display
*display
= windowAtPtr
? GDK_WINDOW_XDISPLAY(windowAtPtr
) : GDK_DISPLAY();
4565 Window rootWindow
= RootWindowOfScreen (DefaultScreenOfDisplay(display
));
4566 Window rootReturn
, childReturn
;
4567 int rootX
, rootY
, winX
, winY
;
4568 unsigned int maskReturn
;
4570 XQueryPointer (display
,
4574 &rootX
, &rootY
, &winX
, &winY
, &maskReturn
);
4575 return wxPoint(rootX
, rootY
);
4579 // ----------------------------------------------------------------------------
4581 // ----------------------------------------------------------------------------
4583 class wxWinModule
: public wxModule
4590 DECLARE_DYNAMIC_CLASS(wxWinModule
)
4593 IMPLEMENT_DYNAMIC_CLASS(wxWinModule
, wxModule
)
4595 bool wxWinModule::OnInit()
4597 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4598 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4603 void wxWinModule::OnExit()
4606 gdk_gc_unref( g_eraseGC
);