]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/window.cpp
Committing in .
[wxWidgets.git] / src / gtk / window.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
f6bcfd97 2// Name: gtk/window.cpp
c801d85f
KB
3// Purpose:
4// Author: Robert Roebling
c67d8618 5// Id: $Id$
01111366 6// Copyright: (c) 1998 Robert Roebling, Julian Smart
5e0aa05a 7// Licence: wxWindows licence
c801d85f
KB
8/////////////////////////////////////////////////////////////////////////////
9
10
11#ifdef __GNUG__
bfc6fde4 12 #pragma implementation "window.h"
c801d85f
KB
13#endif
14
d02af7bb
JJ
15#ifdef __VMS
16#define XWarpPointer XWARPPOINTER
17#endif
18
c801d85f
KB
19#include "wx/defs.h"
20#include "wx/window.h"
33611ebb 21#include "wx/dcclient.h"
c801d85f
KB
22#include "wx/frame.h"
23#include "wx/app.h"
24#include "wx/layout.h"
25#include "wx/utils.h"
26#include "wx/dialog.h"
27#include "wx/msgdlg.h"
bfc6fde4 28
06cfab17 29#if wxUSE_DRAG_AND_DROP
bfc6fde4 30 #include "wx/dnd.h"
ac57418f 31#endif
bfc6fde4 32
cad880f5 33#if wxUSE_TOOLTIPS
bfc6fde4 34 #include "wx/tooltip.h"
cad880f5 35#endif
bfc6fde4 36
f6bcfd97
BP
37#if wxUSE_CARET
38 #include "wx/caret.h"
39#endif // wxUSE_CARET
40
ab93a576
RD
41#if wxUSE_TEXTCTRL
42#include "wx/textctrl.h"
43#endif
44
30dea054 45#include "wx/menu.h"
d4c99d6f 46#include "wx/statusbr.h"
b4071e91 47#include "wx/intl.h"
3bc755fc 48#include "wx/settings.h"
3069ac4e 49#include "wx/log.h"
b4071e91 50
3ac8d3bc
RR
51#ifdef __WXDEBUG__
52 #include "wx/thread.h"
53#endif
54
b4071e91 55#include <math.h>
c801d85f 56
3ac8d3bc
RR
57#include <gdk/gdk.h>
58#include <gtk/gtk.h>
59#include <gdk/gdkprivate.h>
60#include <gdk/gdkkeysyms.h>
3ac8d3bc 61#include <gdk/gdkx.h>
6bc8a1c8 62
8cb9f0d0
RR
63#include <gtk/gtk.h>
64#include <gtk/gtkprivate.h>
65
66#include "wx/gtk/win_gtk.h"
67
868a2826
RR
68//-----------------------------------------------------------------------------
69// documentation on internals
70//-----------------------------------------------------------------------------
71
72/*
73 I have been asked several times about writing some documentation about
74 the GTK port of wxWindows, especially its internal structures. Obviously,
75 you cannot understand wxGTK without knowing a little about the GTK, but
47d67540 76 some more information about what the wxWindow, which is the base class
868a2826 77 for all other window classes, does seems required as well.
47d67540 78
30760ce7
RR
79 I)
80
868a2826 81 What does wxWindow do? It contains the common interface for the following
e380f72b 82 jobs of its descendants:
47d67540 83
868a2826 84 1) Define the rudimentary behaviour common to all window classes, such as
e380f72b
RR
85 resizing, intercepting user input (so as to make it possible to use these
86 events for special purposes in a derived class), window names etc.
868a2826
RR
87
88 2) Provide the possibility to contain and manage children, if the derived
89 class is allowed to contain children, which holds true for those window
e380f72b 90 classes which do not display a native GTK widget. To name them, these
868a2826 91 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
47d67540 92 work classes are a special case and are handled a bit differently from
e380f72b 93 the rest. The same holds true for the wxNotebook class.
47d67540 94
868a2826
RR
95 3) Provide the possibility to draw into a client area of a window. This,
96 too, only holds true for classes that do not display a native GTK widget
97 as above.
47d67540 98
e380f72b
RR
99 4) Provide the entire mechanism for scrolling widgets. This actual inter-
100 face for this is usually in wxScrolledWindow, but the GTK implementation
868a2826 101 is in this class.
47d67540 102
868a2826
RR
103 5) A multitude of helper or extra methods for special purposes, such as
104 Drag'n'Drop, managing validators etc.
47d67540 105
30760ce7
RR
106 6) Display a border (sunken, raised, simple or none).
107
e380f72b
RR
108 Normally one might expect, that one wxWindows window would always correspond
109 to one GTK widget. Under GTK, there is no such allround widget that has all
868a2826
RR
110 the functionality. Moreover, the GTK defines a client area as a different
111 widget from the actual widget you are handling. Last but not least some
112 special classes (e.g. wxFrame) handle different categories of widgets and
113 still have the possibility to draw something in the client area.
114 It was therefore required to write a special purpose GTK widget, that would
115 represent a client area in the sense of wxWindows capable to do the jobs
116 2), 3) and 4). I have written this class and it resides in win_gtk.c of
117 this directory.
47d67540 118
868a2826 119 All windows must have a widget, with which they interact with other under-
e380f72b 120 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
868a2826 121 thw wxWindow class has a member variable called m_widget which holds a
e380f72b
RR
122 pointer to this widget. When the window class represents a GTK native widget,
123 this is (in most cases) the only GTK widget the class manages. E.g. the
124 wxStatitText class handles only a GtkLabel widget a pointer to which you
125 can find in m_widget (defined in wxWindow)
8bbe427f 126
e380f72b 127 When the class has a client area for drawing into and for containing children
da048e3d 128 it has to handle the client area widget (of the type GtkPizza, defined in
8bbe427f
VZ
129 win_gtk.c), but there could be any number of widgets, handled by a class
130 The common rule for all windows is only, that the widget that interacts with
131 the rest of GTK must be referenced in m_widget and all other widgets must be
132 children of this widget on the GTK level. The top-most widget, which also
133 represents the client area, must be in the m_wxwindow field and must be of
da048e3d 134 the type GtkPizza.
47d67540 135
868a2826
RR
136 As I said, the window classes that display a GTK native widget only have
137 one widget, so in the case of e.g. the wxButton class m_widget holds a
138 pointer to a GtkButton widget. But windows with client areas (for drawing
139 and children) have a m_widget field that is a pointer to a GtkScrolled-
da048e3d 140 Window and a m_wxwindow field that is pointer to a GtkPizza and this
868a2826 141 one is (in the GTK sense) a child of the GtkScrolledWindow.
47d67540 142
868a2826
RR
143 If the m_wxwindow field is set, then all input to this widget is inter-
144 cepted and sent to the wxWindows class. If not, all input to the widget
145 that gets pointed to by m_widget gets intercepted and sent to the class.
148cd9b6 146
30760ce7 147 II)
148cd9b6 148
30760ce7
RR
149 The design of scrolling in wxWindows is markedly different from that offered
150 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
151 clicking on a scrollbar belonging to scrolled window will inevitably move
152 the window. In wxWindows, the scrollbar will only emit an event, send this
153 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
da048e3d 154 which actually moves the window and its subchildren. Note that GtkPizza
30760ce7
RR
155 memorizes how much it has been scrolled but that wxWindows forgets this
156 so that the two coordinates systems have to be kept in synch. This is done
da048e3d 157 in various places using the pizza->xoffset and pizza->yoffset values.
148cd9b6
VZ
158
159 III)
160
30760ce7
RR
161 Singularily the most broken code in GTK is the code that is supposes to
162 inform subwindows (child windows) about new positions. Very often, duplicate
163 events are sent without changes in size or position, equally often no
164 events are sent at all (All this is due to a bug in the GtkContainer code
165 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
166 GTK's own system and it simply waits for size events for toplevel windows
167 and then iterates down the respective size events to all window. This has
168 the disadvantage, that windows might get size events before the GTK widget
169 actually has the reported size. This doesn't normally pose any problem, but
3017f78d 170 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
30760ce7
RR
171 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
172 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
173 window that is used for OpenGl output really has that size (as reported by
174 GTK).
175
176 IV)
148cd9b6 177
30760ce7
RR
178 If someone at some point of time feels the immense desire to have a look at,
179 change or attempt to optimse the Refresh() logic, this person will need an
180 intimate understanding of what a "draw" and what an "expose" events are and
181 what there are used for, in particular when used in connection with GTK's
182 own windowless widgets. Beware.
148cd9b6 183
30760ce7 184 V)
148cd9b6 185
30760ce7
RR
186 Cursors, too, have been a constant source of pleasure. The main difficulty
187 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
188 for the parent. To prevent this from doing too much harm, I use idle time
189 to set the cursor over and over again, starting from the toplevel windows
190 and ending with the youngest generation (speaking of parent and child windows).
191 Also don't forget that cursors (like much else) are connected to GdkWindows,
192 not GtkWidgets and that the "window" field of a GtkWidget might very well
148cd9b6 193 point to the GdkWindow of the parent widget (-> "window less widget") and
30760ce7 194 that the two obviously have very different meanings.
868a2826
RR
195
196*/
197
f03fc89f
VZ
198//-----------------------------------------------------------------------------
199// data
200//-----------------------------------------------------------------------------
201
202extern wxList wxPendingDelete;
203extern bool g_blockEventsOnDrag;
204extern bool g_blockEventsOnScroll;
238d735d 205extern wxCursor g_globalCursor;
f68586e5 206
1e6feb95
VZ
207// mouse capture state: the window which has it and if the mouse is currently
208// inside it
209static wxWindowGTK *g_captureWindow = (wxWindowGTK*) NULL;
210static bool g_captureWindowHasMouse = FALSE;
211
212/* extern */ wxWindowGTK *g_focusWindow = (wxWindowGTK*) NULL;
213
214// the last window which had the focus - this is normally never NULL (except
215// if we never had focus at all) as even when g_focusWindow is NULL it still
216// keeps its previous value
217static wxWindowGTK *g_focusWindowLast = (wxWindowGTK *)NULL;
148cd9b6 218
e8c12a53
VS
219// the frame that is currently active (i.e. its child has focus). It is
220// used to generate wxActivateEvents
221static wxWindowGTK *g_activeFrame = (wxWindowGTK *)NULL;
222static bool g_activeFrameLostFocus = FALSE;
223
148cd9b6
VZ
224// if we detect that the app has got/lost the focus, we set this variable to
225// either TRUE or FALSE and an activate event will be sent during the next
226// OnIdle() call and it is reset to -1: this value means that we shouldn't
227// send any activate events at all
228static int g_sendActivateEvent = -1;
f03fc89f
VZ
229
230/* hack: we need something to pass to gtk_menu_popup, so we store the time of
231 the last click here */
232static guint32 gs_timeLastClick = 0;
233
3ac8d3bc
RR
234extern bool g_mainThreadLocked;
235
2e563988
RR
236//-----------------------------------------------------------------------------
237// debug
238//-----------------------------------------------------------------------------
239
d52e91c9 240#ifndef __WXGTK20__
a56fcaaf 241#define DISABLE_STYLE_IF_BROKEN_THEME 1
d52e91c9 242#endif
a56fcaaf 243
2e563988
RR
244#ifdef __WXDEBUG__
245
c6e62f74
KB
246#if wxUSE_THREADS
247# define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
248#else
249# define DEBUG_MAIN_THREAD
250#endif
3ac8d3bc 251
2e563988
RR
252static gint gtk_debug_focus_in_callback( GtkWidget *WXUNUSED(widget),
253 GdkEvent *WXUNUSED(event),
014b0d06 254 const wxChar *WXUNUSED(name) )
2e563988 255{
053dcf1a 256/*
167e3718
VZ
257 static bool s_done = FALSE;
258 if ( !s_done )
259 {
260 wxLog::AddTraceMask("focus");
261 s_done = TRUE;
262 }
223d09f6 263 wxLogTrace(wxT("FOCUS NOW AT: %s"), name);
053dcf1a 264*/
2e563988
RR
265
266 return FALSE;
267}
268
269void debug_focus_in( GtkWidget* widget, const wxChar* name, const wxChar *window )
270{
9a8c7620
VZ
271 // suppress warnings about gtk_debug_focus_in_callback being unused with
272 // this "if ( 0 )"
273 if ( 0 )
274 {
275 wxString tmp = name;
276 tmp += wxT(" FROM ");
277 tmp += window;
2e563988 278
9a8c7620 279 wxChar *s = new wxChar[tmp.Length()+1];
2e563988 280
9a8c7620 281 wxStrcpy( s, tmp );
2e563988 282
9a8c7620
VZ
283 gtk_signal_connect( GTK_OBJECT(widget), "focus_in_event",
284 GTK_SIGNAL_FUNC(gtk_debug_focus_in_callback), (gpointer)s );
285 }
2e563988
RR
286}
287
559d79aa
BJ
288#else
289#define DEBUG_MAIN_THREAD
f03fc89f 290#endif // Debug
ff8bfdbb 291
85eb36c2
RR
292//-----------------------------------------------------------------------------
293// missing gdk functions
294//-----------------------------------------------------------------------------
295
296void
297gdk_window_warp_pointer (GdkWindow *window,
c50f1fb9
VZ
298 gint x,
299 gint y)
85eb36c2 300{
dd00f3f6 301#ifndef __WXGTK20__
85eb36c2 302 GdkWindowPrivate *priv;
dd00f3f6 303#endif
c50f1fb9 304
85eb36c2 305 if (!window)
27df579a 306 window = GDK_ROOT_PARENT();
c50f1fb9 307
dd00f3f6
OK
308#ifdef __WXGTK20__
309 if (!GDK_WINDOW_DESTROYED(window))
310 {
311 XWarpPointer (GDK_WINDOW_XDISPLAY(window),
312 None, /* not source window -> move from anywhere */
313 GDK_WINDOW_XID(window), /* dest window */
314 0, 0, 0, 0, /* not source window -> move from anywhere */
315 x, y );
316 }
317#else
85eb36c2 318 priv = (GdkWindowPrivate*) window;
c50f1fb9 319
85eb36c2
RR
320 if (!priv->destroyed)
321 {
c50f1fb9 322 XWarpPointer (priv->xdisplay,
85eb36c2 323 None, /* not source window -> move from anywhere */
c50f1fb9 324 priv->xwindow, /* dest window */
85eb36c2 325 0, 0, 0, 0, /* not source window -> move from anywhere */
c50f1fb9 326 x, y );
85eb36c2 327 }
dd00f3f6 328#endif
85eb36c2
RR
329}
330
acfd422a 331//-----------------------------------------------------------------------------
a2053b27 332// idle system
acfd422a
RR
333//-----------------------------------------------------------------------------
334
a2053b27
RR
335extern void wxapp_install_idle_handler();
336extern bool g_isIdle;
337
ed673c6a
RR
338//-----------------------------------------------------------------------------
339// local code (see below)
340//-----------------------------------------------------------------------------
341
f6bcfd97 342// returns the child of win which currently has focus or NULL if not found
1e6feb95 343//
fc71ef6e 344// Note: can't be static, needed by textctrl.cpp.
3379ed37 345wxWindow *wxFindFocusedChild(wxWindowGTK *win)
f6bcfd97 346{
3379ed37 347 wxWindow *winFocus = wxWindowGTK::FindFocus();
f6bcfd97 348 if ( !winFocus )
3379ed37 349 return (wxWindow *)NULL;
f6bcfd97
BP
350
351 if ( winFocus == win )
3379ed37 352 return (wxWindow *)win;
f6bcfd97
BP
353
354 for ( wxWindowList::Node *node = win->GetChildren().GetFirst();
355 node;
356 node = node->GetNext() )
357 {
3379ed37 358 wxWindow *child = wxFindFocusedChild(node->GetData());
f6bcfd97
BP
359 if ( child )
360 return child;
361 }
362
3379ed37 363 return (wxWindow *)NULL;
f6bcfd97
BP
364}
365
e8c12a53
VS
366// Returns toplevel grandparent of given window:
367static wxWindowGTK* wxGetTopLevelParent(wxWindowGTK *win)
368{
369 wxWindowGTK *p = win;
370 while (p && !p->IsTopLevel())
371 p = p->GetParent();
372 return p;
373}
374
375
1e6feb95 376static void draw_frame( GtkWidget *widget, wxWindowGTK *win )
ed673c6a 377{
1e6feb95
VZ
378 // wxUniversal widgets draw the borders and scrollbars themselves
379#ifndef __WXUNIVERSAL__
ed673c6a
RR
380 if (!win->m_hasVMT)
381 return;
382
383 int dw = 0;
384 int dh = 0;
385
5b8a521e 386 if (win->m_hasScrolling)
ed673c6a 387 {
beab25bd 388 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(widget);
2daa0ce9 389
beab25bd
RR
390 GtkRequisition vscroll_req;
391 vscroll_req.width = 2;
392 vscroll_req.height = 2;
393 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
394 (scroll_window->vscrollbar, &vscroll_req );
2daa0ce9 395
beab25bd
RR
396 GtkRequisition hscroll_req;
397 hscroll_req.width = 2;
398 hscroll_req.height = 2;
399 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
400 (scroll_window->hscrollbar, &hscroll_req );
9000c624 401
beab25bd 402 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget) );
ed673c6a 403
beab25bd
RR
404 if (scroll_window->vscrollbar_visible)
405 {
406 dw += vscroll_req.width;
407 dw += scroll_class->scrollbar_spacing;
408 }
ed673c6a 409
beab25bd
RR
410 if (scroll_window->hscrollbar_visible)
411 {
412 dh += hscroll_req.height;
413 dh += scroll_class->scrollbar_spacing;
414 }
415}
ed673c6a
RR
416
417 int dx = 0;
418 int dy = 0;
419 if (GTK_WIDGET_NO_WINDOW (widget))
420 {
421 dx += widget->allocation.x;
422 dy += widget->allocation.y;
423 }
424
425 if (win->HasFlag(wxRAISED_BORDER))
426 {
427 gtk_draw_shadow( widget->style,
428 widget->window,
429 GTK_STATE_NORMAL,
430 GTK_SHADOW_OUT,
431 dx, dy,
07f5b19a 432 widget->allocation.width-dw, widget->allocation.height-dh );
ed673c6a
RR
433 return;
434 }
435
436 if (win->HasFlag(wxSUNKEN_BORDER))
437 {
438 gtk_draw_shadow( widget->style,
439 widget->window,
440 GTK_STATE_NORMAL,
441 GTK_SHADOW_IN,
442 dx, dy,
07f5b19a 443 widget->allocation.width-dw, widget->allocation.height-dh );
ed673c6a
RR
444 return;
445 }
148cd9b6 446
ed673c6a
RR
447 if (win->HasFlag(wxSIMPLE_BORDER))
448 {
449 GdkGC *gc;
b02da6b1 450 gc = gdk_gc_new( widget->window );
ed673c6a 451 gdk_gc_set_foreground( gc, &widget->style->black );
148cd9b6 452 gdk_draw_rectangle( widget->window, gc, FALSE,
ed673c6a 453 dx, dy,
07f5b19a 454 widget->allocation.width-dw-1, widget->allocation.height-dh-1 );
ed673c6a
RR
455 gdk_gc_unref( gc );
456 return;
457 }
1e6feb95 458#endif // __WXUNIVERSAL__
ed673c6a
RR
459}
460
461//-----------------------------------------------------------------------------
462// "expose_event" of m_widget
463//-----------------------------------------------------------------------------
464
1e6feb95 465gint gtk_window_own_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindowGTK *win )
ed673c6a 466{
b6fa52db 467 if (gdk_event->count > 0) return FALSE;
1e6feb95 468
ed673c6a 469 draw_frame( widget, win );
1e6feb95 470
b6fa52db 471 return TRUE;
ed673c6a
RR
472}
473
474//-----------------------------------------------------------------------------
147bc491 475// "draw" of m_widget
ed673c6a
RR
476//-----------------------------------------------------------------------------
477
1e6feb95 478static void gtk_window_own_draw_callback( GtkWidget *widget, GdkRectangle *WXUNUSED(rect), wxWindowGTK *win )
ed673c6a
RR
479{
480 draw_frame( widget, win );
481}
482
c5b42c87 483//-----------------------------------------------------------------------------
da048e3d 484// key code mapping routines
c5b42c87
RR
485//-----------------------------------------------------------------------------
486
2d451165 487static long map_to_unmodified_wx_keysym( GdkEventKey *event )
c5b42c87 488{
654d9052
VZ
489 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
490 // but only event->keyval which is quite useless to us, so remember
491 // the last character from GDK_KEY_PRESS and resue it as last resort
492 //
493 // NB: should be MT-neutral as always called from main thread only
494 static struct
495 {
496 KeySym keysym;
497 long keycode;
498 } s_lastKeyPress = { 0, 0 };
499
2d451165 500 KeySym keysym = event->keyval;
f17393f1 501 long key_code;
c5b42c87 502
654d9052 503 switch ( keysym )
c5b42c87
RR
504 {
505 case GDK_Shift_L:
506 case GDK_Shift_R: key_code = WXK_SHIFT; break;
507 case GDK_Control_L:
508 case GDK_Control_R: key_code = WXK_CONTROL; break;
c50f1fb9
VZ
509 case GDK_Meta_L:
510 case GDK_Meta_R:
511 case GDK_Alt_L:
512 case GDK_Alt_R:
513 case GDK_Super_L:
514 case GDK_Super_R: key_code = WXK_ALT; break;
c5b42c87
RR
515 case GDK_Menu: key_code = WXK_MENU; break;
516 case GDK_Help: key_code = WXK_HELP; break;
517 case GDK_BackSpace: key_code = WXK_BACK; break;
518 case GDK_ISO_Left_Tab:
519 case GDK_Tab: key_code = WXK_TAB; break;
520 case GDK_Linefeed: key_code = WXK_RETURN; break;
521 case GDK_Clear: key_code = WXK_CLEAR; break;
522 case GDK_Return: key_code = WXK_RETURN; break;
523 case GDK_Pause: key_code = WXK_PAUSE; break;
524 case GDK_Scroll_Lock: key_code = WXK_SCROLL; break;
525 case GDK_Escape: key_code = WXK_ESCAPE; break;
526 case GDK_Delete: key_code = WXK_DELETE; break;
527 case GDK_Home: key_code = WXK_HOME; break;
528 case GDK_Left: key_code = WXK_LEFT; break;
529 case GDK_Up: key_code = WXK_UP; break;
530 case GDK_Right: key_code = WXK_RIGHT; break;
531 case GDK_Down: key_code = WXK_DOWN; break;
532 case GDK_Prior: key_code = WXK_PRIOR; break;
533// case GDK_Page_Up: key_code = WXK_PAGEUP; break;
534 case GDK_Next: key_code = WXK_NEXT; break;
535// case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
536 case GDK_End: key_code = WXK_END; break;
537 case GDK_Begin: key_code = WXK_HOME; break;
538 case GDK_Select: key_code = WXK_SELECT; break;
539 case GDK_Print: key_code = WXK_PRINT; break;
540 case GDK_Execute: key_code = WXK_EXECUTE; break;
541 case GDK_Insert: key_code = WXK_INSERT; break;
542 case GDK_Num_Lock: key_code = WXK_NUMLOCK; break;
543
544 case GDK_KP_0: key_code = WXK_NUMPAD0; break;
545 case GDK_KP_1: key_code = WXK_NUMPAD1; break;
546 case GDK_KP_2: key_code = WXK_NUMPAD2; break;
547 case GDK_KP_3: key_code = WXK_NUMPAD3; break;
548 case GDK_KP_4: key_code = WXK_NUMPAD4; break;
549 case GDK_KP_5: key_code = WXK_NUMPAD5; break;
550 case GDK_KP_6: key_code = WXK_NUMPAD6; break;
551 case GDK_KP_7: key_code = WXK_NUMPAD7; break;
552 case GDK_KP_8: key_code = WXK_NUMPAD8; break;
553 case GDK_KP_9: key_code = WXK_NUMPAD9; break;
554 case GDK_KP_Space: key_code = WXK_NUMPAD_SPACE; break;
555 case GDK_KP_Tab: key_code = WXK_NUMPAD_TAB; break;
556 case GDK_KP_Enter: key_code = WXK_NUMPAD_ENTER; break;
557 case GDK_KP_F1: key_code = WXK_NUMPAD_F1; break;
558 case GDK_KP_F2: key_code = WXK_NUMPAD_F2; break;
559 case GDK_KP_F3: key_code = WXK_NUMPAD_F3; break;
560 case GDK_KP_F4: key_code = WXK_NUMPAD_F4; break;
561 case GDK_KP_Home: key_code = WXK_NUMPAD_HOME; break;
562 case GDK_KP_Left: key_code = WXK_NUMPAD_LEFT; break;
563 case GDK_KP_Up: key_code = WXK_NUMPAD_UP; break;
564 case GDK_KP_Right: key_code = WXK_NUMPAD_RIGHT; break;
565 case GDK_KP_Down: key_code = WXK_NUMPAD_DOWN; break;
566 case GDK_KP_Prior: key_code = WXK_NUMPAD_PRIOR; break;
567// case GDK_KP_Page_Up: key_code = WXK_NUMPAD_PAGEUP; break;
21884766 568 case GDK_KP_Next: key_code = WXK_NUMPAD_NEXT; break;
c5b42c87
RR
569// case GDK_KP_Page_Down: key_code = WXK_NUMPAD_PAGEDOWN; break;
570 case GDK_KP_End: key_code = WXK_NUMPAD_END; break;
571 case GDK_KP_Begin: key_code = WXK_NUMPAD_BEGIN; break;
572 case GDK_KP_Insert: key_code = WXK_NUMPAD_INSERT; break;
573 case GDK_KP_Delete: key_code = WXK_NUMPAD_DELETE; break;
574 case GDK_KP_Equal: key_code = WXK_NUMPAD_EQUAL; break;
575 case GDK_KP_Multiply: key_code = WXK_NUMPAD_MULTIPLY; break;
576 case GDK_KP_Add: key_code = WXK_NUMPAD_ADD; break;
577 case GDK_KP_Separator: key_code = WXK_NUMPAD_SEPARATOR; break;
578 case GDK_KP_Subtract: key_code = WXK_NUMPAD_SUBTRACT; break;
579 case GDK_KP_Decimal: key_code = WXK_NUMPAD_DECIMAL; break;
580 case GDK_KP_Divide: key_code = WXK_NUMPAD_DIVIDE; break;
c50f1fb9 581
c5b42c87
RR
582 case GDK_F1: key_code = WXK_F1; break;
583 case GDK_F2: key_code = WXK_F2; break;
584 case GDK_F3: key_code = WXK_F3; break;
585 case GDK_F4: key_code = WXK_F4; break;
586 case GDK_F5: key_code = WXK_F5; break;
587 case GDK_F6: key_code = WXK_F6; break;
588 case GDK_F7: key_code = WXK_F7; break;
589 case GDK_F8: key_code = WXK_F8; break;
590 case GDK_F9: key_code = WXK_F9; break;
591 case GDK_F10: key_code = WXK_F10; break;
592 case GDK_F11: key_code = WXK_F11; break;
593 case GDK_F12: key_code = WXK_F12; break;
594 default:
654d9052
VZ
595 {
596 // do we have the translation?
597 if ( event->length == 1 )
c5b42c87 598 {
654d9052 599 keysym = (KeySym)event->string[0];
f17393f1 600 }
654d9052
VZ
601 else if ( (keysym & 0xFF) != keysym )
602 {
603 // non ASCII key, what to do?
604
605 if ( event->type == GDK_KEY_RELEASE )
606 {
607 // reuse the one from the last keypress if any
608 if ( keysym == s_lastKeyPress.keysym )
609 {
610 key_code = s_lastKeyPress.keycode;
611
612 // skip "return 0"
613 break;
614 }
615 }
616
617 // ignore this one, we don't know it
618 return 0;
619 }
620 //else: ASCII key, ok
621
622 guint upper = gdk_keyval_to_upper( (guint)keysym );
623 key_code = upper ? upper : keysym;
624
625 if ( event->type == GDK_KEY_PRESS )
f17393f1 626 {
654d9052
VZ
627 // remember it to be reused below later
628 s_lastKeyPress.keysym = keysym;
629 s_lastKeyPress.keycode = key_code;
c5b42c87 630 }
654d9052 631 }
c5b42c87
RR
632 }
633
f17393f1 634 return key_code;
c5b42c87
RR
635}
636
2d451165 637static long map_to_wx_keysym( GdkEventKey *event )
c5b42c87 638{
2d451165 639 KeySym keysym = event->keyval;
c5b42c87
RR
640 guint key_code = 0;
641
642 switch (keysym)
643 {
c5b42c87
RR
644 case GDK_Menu: key_code = WXK_MENU; break;
645 case GDK_Help: key_code = WXK_HELP; break;
646 case GDK_BackSpace: key_code = WXK_BACK; break;
647 case GDK_ISO_Left_Tab:
648 case GDK_Tab: key_code = WXK_TAB; break;
649 case GDK_Linefeed: key_code = WXK_RETURN; break;
650 case GDK_Clear: key_code = WXK_CLEAR; break;
651 case GDK_Return: key_code = WXK_RETURN; break;
652 case GDK_Pause: key_code = WXK_PAUSE; break;
653 case GDK_Scroll_Lock: key_code = WXK_SCROLL; break;
654 case GDK_Escape: key_code = WXK_ESCAPE; break;
655 case GDK_Delete: key_code = WXK_DELETE; break;
656 case GDK_Home: key_code = WXK_HOME; break;
657 case GDK_Left: key_code = WXK_LEFT; break;
658 case GDK_Up: key_code = WXK_UP; break;
659 case GDK_Right: key_code = WXK_RIGHT; break;
660 case GDK_Down: key_code = WXK_DOWN; break;
661 case GDK_Prior: key_code = WXK_PRIOR; break;
662// case GDK_Page_Up: key_code = WXK_PAGEUP; break;
663 case GDK_Next: key_code = WXK_NEXT; break;
664// case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
665 case GDK_End: key_code = WXK_END; break;
666 case GDK_Begin: key_code = WXK_HOME; break;
667 case GDK_Select: key_code = WXK_SELECT; break;
668 case GDK_Print: key_code = WXK_PRINT; break;
669 case GDK_Execute: key_code = WXK_EXECUTE; break;
670 case GDK_Insert: key_code = WXK_INSERT; break;
671 case GDK_Num_Lock: key_code = WXK_NUMLOCK; break;
672
673 case GDK_KP_0: key_code = '0'; break;
674 case GDK_KP_1: key_code = '1'; break;
675 case GDK_KP_2: key_code = '2'; break;
676 case GDK_KP_3: key_code = '3'; break;
677 case GDK_KP_4: key_code = '4'; break;
678 case GDK_KP_5: key_code = '5'; break;
679 case GDK_KP_6: key_code = '6'; break;
680 case GDK_KP_7: key_code = '7'; break;
681 case GDK_KP_8: key_code = '8'; break;
682 case GDK_KP_9: key_code = '9'; break;
683 case GDK_KP_Space: key_code = ' '; break;
684 case GDK_KP_Tab: key_code = WXK_TAB; break; /* or '\t' ??? */
685 case GDK_KP_Enter: key_code = WXK_RETURN; break; /* or '\r' ??? */
686 case GDK_KP_F1: key_code = WXK_NUMPAD_F1; break;
687 case GDK_KP_F2: key_code = WXK_NUMPAD_F2; break;
688 case GDK_KP_F3: key_code = WXK_NUMPAD_F3; break;
689 case GDK_KP_F4: key_code = WXK_NUMPAD_F4; break;
690 case GDK_KP_Home: key_code = WXK_HOME; break;
691 case GDK_KP_Left: key_code = WXK_LEFT; break;
692 case GDK_KP_Up: key_code = WXK_UP; break;
693 case GDK_KP_Right: key_code = WXK_RIGHT; break;
694 case GDK_KP_Down: key_code = WXK_DOWN; break;
695 case GDK_KP_Prior: key_code = WXK_PRIOR; break;
696// case GDK_KP_Page_Up: key_code = WXK_PAGEUP; break;
21884766 697 case GDK_KP_Next: key_code = WXK_NEXT; break;
c5b42c87
RR
698// case GDK_KP_Page_Down: key_code = WXK_PAGEDOWN; break;
699 case GDK_KP_End: key_code = WXK_END; break;
700 case GDK_KP_Begin: key_code = WXK_HOME; break;
701 case GDK_KP_Insert: key_code = WXK_INSERT; break;
702 case GDK_KP_Delete: key_code = WXK_DELETE; break;
703 case GDK_KP_Equal: key_code = '='; break;
704 case GDK_KP_Multiply: key_code = '*'; break;
705 case GDK_KP_Add: key_code = '+'; break;
706 case GDK_KP_Separator: key_code = ','; break;
707 case GDK_KP_Subtract: key_code = '-'; break;
708 case GDK_KP_Decimal: key_code = '.'; break;
709 case GDK_KP_Divide: key_code = '/'; break;
c50f1fb9 710
c5b42c87
RR
711 case GDK_F1: key_code = WXK_F1; break;
712 case GDK_F2: key_code = WXK_F2; break;
713 case GDK_F3: key_code = WXK_F3; break;
714 case GDK_F4: key_code = WXK_F4; break;
715 case GDK_F5: key_code = WXK_F5; break;
716 case GDK_F6: key_code = WXK_F6; break;
717 case GDK_F7: key_code = WXK_F7; break;
718 case GDK_F8: key_code = WXK_F8; break;
719 case GDK_F9: key_code = WXK_F9; break;
720 case GDK_F10: key_code = WXK_F10; break;
721 case GDK_F11: key_code = WXK_F11; break;
722 case GDK_F12: key_code = WXK_F12; break;
723 default:
f17393f1
VZ
724 if (event->length == 1)
725 {
29d18d69
VZ
726 key_code = (unsigned char)*event->string;
727 }
728 else if ((keysym & 0xFF) == keysym)
729 {
730 key_code = (guint)keysym;
c5b42c87 731 }
c5b42c87
RR
732 }
733
f17393f1 734 return key_code;
c5b42c87
RR
735}
736
47c93b63
RR
737//-----------------------------------------------------------------------------
738// "size_request" of m_widget
739//-----------------------------------------------------------------------------
740
741static void gtk_window_size_request_callback( GtkWidget *widget, GtkRequisition *requisition, wxWindow *win )
742{
743 int w,h;
744 win->GetSize( &w, &h );
745 if (w < 2) w = 2;
746 if (h < 2) h = 2;
1e6feb95 747
47c93b63
RR
748 requisition->height = h;
749 requisition->width = w;
750}
751
c801d85f 752//-----------------------------------------------------------------------------
034be888 753// "expose_event" of m_wxwindow
c801d85f
KB
754//-----------------------------------------------------------------------------
755
1e6feb95
VZ
756static int gtk_window_expose_callback( GtkWidget *widget,
757 GdkEventExpose *gdk_event,
758 wxWindow *win )
47d67540 759{
3ac8d3bc
RR
760 DEBUG_MAIN_THREAD
761
b6fa52db
RR
762 if (g_isIdle)
763 wxapp_install_idle_handler();
1e6feb95 764
40c70187 765/*
8cb9f0d0 766 if (win->GetName() == wxT("panel"))
3d2d8da1
RR
767 {
768 wxPrintf( wxT("OnExpose from ") );
769 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
770 wxPrintf( win->GetClassInfo()->GetClassName() );
771 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event->area.x,
772 (int)gdk_event->area.y,
773 (int)gdk_event->area.width,
774 (int)gdk_event->area.height );
775 }
40c70187 776*/
1e6feb95 777
2e09dc2d 778#ifndef __WXUNIVERSAL__
2bc6945a 779 GtkPizza *pizza = GTK_PIZZA (widget);
a2d93e73 780
a2d93e73
JS
781 if (win->GetThemeEnabled())
782 {
783 wxWindow *parent = win->GetParent();
784 while (parent && !parent->IsTopLevel())
785 parent = parent->GetParent();
786 if (!parent)
787 parent = win;
788
90350682
VZ
789 gtk_paint_flat_box (parent->m_widget->style,
790 pizza->bin_window,
791 GTK_STATE_NORMAL,
792 GTK_SHADOW_NONE,
793 &gdk_event->area,
794 parent->m_widget,
795 (char *)"base",
796 0, 0, -1, -1);
2bc6945a 797 }
2e09dc2d 798#endif
1e6feb95 799
2bc6945a
RR
800 win->GetUpdateRegion().Union( gdk_event->area.x,
801 gdk_event->area.y,
802 gdk_event->area.width,
803 gdk_event->area.height );
0e09f76e 804
8f3e7ecc 805 // Actual redrawing takes place in idle time.
2e09dc2d 806 win->Update();
f7a11f8c 807
b6fa52db
RR
808 return TRUE;
809}
810
811//-----------------------------------------------------------------------------
812// "event" of m_wxwindow
813//-----------------------------------------------------------------------------
814
beab25bd
RR
815// GTK thinks it is clever and filters out a certain amount of "unneeded"
816// expose events. We need them, of course, so we override the main event
817// procedure in GtkWidget by giving our own handler for all system events.
818// There, we look for expose events ourselves whereas all other events are
819// handled normally.
b6fa52db 820
1e6feb95
VZ
821gint gtk_window_event_event_callback( GtkWidget *widget,
822 GdkEventExpose *event,
823 wxWindow *win )
b6fa52db
RR
824{
825 if (event->type == GDK_EXPOSE)
826 {
827 gint ret = gtk_window_expose_callback( widget, event, win );
828 return ret;
829 }
830
b6fa52db 831 return FALSE;
362c6693 832}
c801d85f
KB
833
834//-----------------------------------------------------------------------------
034be888 835// "draw" of m_wxwindow
2f2aa628 836//-----------------------------------------------------------------------------
c801d85f 837
beab25bd
RR
838// This callback is a complete replacement of the gtk_pizza_draw() function,
839// which disabled.
b6fa52db 840
1e6feb95
VZ
841static void gtk_window_draw_callback( GtkWidget *widget,
842 GdkRectangle *rect,
843 wxWindow *win )
47d67540 844{
3ac8d3bc
RR
845 DEBUG_MAIN_THREAD
846
c50f1fb9 847 if (g_isIdle)
a2053b27 848 wxapp_install_idle_handler();
2d19ad25 849
beab25bd
RR
850 // The wxNO_FULL_REPAINT_ON_RESIZE flag only works if
851 // there are no child windows.
e22454be
RR
852 if ((win->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE)) &&
853 (win->GetChildren().GetCount() == 0))
854 {
855 return;
856 }
2d19ad25 857
40c70187 858/*
8cb9f0d0 859 if (win->GetName() == wxT("panel"))
3d2d8da1
RR
860 {
861 wxPrintf( wxT("OnDraw from ") );
862 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
863 wxPrintf( win->GetClassInfo()->GetClassName() );
864 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect->x,
865 (int)rect->y,
866 (int)rect->width,
867 (int)rect->height );
868 }
40c70187 869*/
1e6feb95 870
2e09dc2d 871#ifndef __WXUNIVERSAL__
b420fb6a 872 GtkPizza *pizza = GTK_PIZZA (widget);
2bc6945a 873
9cc7121f 874 if (win->GetThemeEnabled())
789dbcd4 875 {
9cc7121f
RR
876 wxWindow *parent = win->GetParent();
877 while (parent && !parent->IsTopLevel())
789dbcd4 878 parent = parent->GetParent();
9cc7121f
RR
879 if (!parent)
880 parent = win;
881
90350682
VZ
882 gtk_paint_flat_box (parent->m_widget->style,
883 pizza->bin_window,
884 GTK_STATE_NORMAL,
885 GTK_SHADOW_NONE,
886 rect,
887 parent->m_widget,
888 (char *)"base",
889 0, 0, -1, -1);
789dbcd4 890 }
1e6feb95
VZ
891
892
9cc7121f
RR
893 if (!(GTK_WIDGET_APP_PAINTABLE (widget)) &&
894 (pizza->clear_on_draw))
895 {
896 gdk_window_clear_area( pizza->bin_window,
b420fb6a 897 rect->x, rect->y, rect->width, rect->height);
9cc7121f 898 }
2e09dc2d 899#endif
1e6feb95 900
9cc7121f 901 win->GetUpdateRegion().Union( rect->x, rect->y, rect->width, rect->height );
148cd9b6 902
8f3e7ecc 903 // Actual redrawing takes place in idle time.
2e09dc2d
RR
904
905 win->Update();
1e6feb95 906
8f3e7ecc 907#ifndef __WXUNIVERSAL__
beab25bd 908 // Redraw child widgets
e22454be
RR
909 GList *children = pizza->children;
910 while (children)
911 {
beab25bd
RR
912 GtkPizzaChild *child = (GtkPizzaChild*) children->data;
913 children = children->next;
b420fb6a 914
beab25bd
RR
915 GdkRectangle child_area;
916 if (gtk_widget_intersect (child->widget, rect, &child_area))
917 {
918 gtk_widget_draw (child->widget, &child_area /* (GdkRectangle*) NULL*/ );
919 }
e22454be 920 }
8f3e7ecc 921#endif
362c6693 922}
c801d85f
KB
923
924//-----------------------------------------------------------------------------
b292e2f5 925// "key_press_event" from any window
c801d85f 926//-----------------------------------------------------------------------------
c801d85f 927
f17393f1
VZ
928// turn on to see the key event codes on the console
929#undef DEBUG_KEY_EVENTS
930
1e6feb95
VZ
931static gint gtk_window_key_press_callback( GtkWidget *widget,
932 GdkEventKey *gdk_event,
933 wxWindow *win )
47d67540 934{
3ac8d3bc
RR
935 DEBUG_MAIN_THREAD
936
c50f1fb9 937 if (g_isIdle)
a2053b27
RR
938 wxapp_install_idle_handler();
939
940 if (!win->m_hasVMT) return FALSE;
f5e27805 941 if (g_blockEventsOnDrag) return FALSE;
c801d85f 942
3d6f7261 943
b0e813a0
RR
944 int x = 0;
945 int y = 0;
946 GdkModifierType state;
f17393f1
VZ
947 if (gdk_event->window)
948 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
47d67540 949
3017f78d 950 bool ret = FALSE;
148cd9b6 951
2d451165 952 long key_code = map_to_unmodified_wx_keysym( gdk_event );
f17393f1
VZ
953
954#ifdef DEBUG_KEY_EVENTS
955 wxPrintf(_T("Key press event: %d => %ld\n"), gdk_event->keyval, key_code);
956#endif // DEBUG_KEY_EVENTS
957
f0492f7d 958 /* sending unknown key events doesn't really make sense */
f17393f1
VZ
959 if (key_code == 0)
960 return FALSE;
f0492f7d 961
c50f1fb9 962 wxKeyEvent event( wxEVT_KEY_DOWN );
d1367c3d 963 event.SetTimestamp( gdk_event->time );
f5e27805
RR
964 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
965 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
966 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
967 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
968 event.m_keyCode = key_code;
b0e813a0
RR
969 event.m_scanCode = gdk_event->keyval;
970 event.m_x = x;
971 event.m_y = y;
f5e27805 972 event.SetEventObject( win );
c5b42c87 973 ret = win->GetEventHandler()->ProcessEvent( event );
c50f1fb9 974
88ac883a 975#if wxUSE_ACCEL
f5e27805 976 if (!ret)
47d67540 977 {
1e6feb95 978 wxWindowGTK *ancestor = win;
f5e27805
RR
979 while (ancestor)
980 {
981 int command = ancestor->GetAcceleratorTable()->GetCommand( event );
982 if (command != -1)
983 {
984 wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
985 ret = ancestor->GetEventHandler()->ProcessEvent( command_event );
986 break;
987 }
f6bcfd97 988 if (ancestor->IsTopLevel())
b02da6b1 989 break;
f5e27805
RR
990 ancestor = ancestor->GetParent();
991 }
bcf1fa6b 992 }
88ac883a 993#endif // wxUSE_ACCEL
3017f78d 994
d728dd40 995 /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
3017f78d 996 will only be sent if it is not in an accelerator table. */
f17393f1 997 if ( !ret )
d728dd40 998 {
f17393f1
VZ
999 key_code = map_to_wx_keysym( gdk_event );
1000
1001 if ( key_code )
1002 {
1003#ifdef DEBUG_KEY_EVENTS
1004 wxPrintf(_T("Char event: %ld\n"), key_code);
1005#endif // DEBUG_KEY_EVENTS
1006
1007 // reuse the ame event object, just change its type and use the
1008 // translated keycode instead of the raw one
1009 event.SetEventType(wxEVT_CHAR);
1010 event.m_keyCode = key_code;
1011
1012 ret = win->GetEventHandler()->ProcessEvent( event );
1013 }
d728dd40
KB
1014 }
1015
053f9cc1 1016 /* win is a control: tab can be propagated up */
f17393f1 1017 if ( !ret &&
5664fc32 1018 ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) &&
f6bcfd97
BP
1019// VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1020// have this style, yet choose not to process this particular TAB in which
1021// case TAB must still work as a navigational character
1022#if 0
f17393f1 1023 !win->HasFlag(wxTE_PROCESS_TAB) &&
f6bcfd97 1024#endif // 0
f17393f1 1025 win->GetParent() && (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) )
b292e2f5
RR
1026 {
1027 wxNavigationKeyEvent new_event;
8253c7fd 1028 new_event.SetEventObject( win->GetParent() );
f03fc89f 1029 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
5664fc32 1030 new_event.SetDirection( (gdk_event->keyval == GDK_Tab) );
f03fc89f 1031 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
b98d804b 1032 new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) );
b292e2f5 1033 new_event.SetCurrentFocus( win );
8253c7fd 1034 ret = win->GetParent()->GetEventHandler()->ProcessEvent( new_event );
b292e2f5 1035 }
ff8bfdbb 1036
801aa178 1037 /* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
f17393f1 1038 if ( !ret &&
b98d804b
RR
1039 (gdk_event->keyval == GDK_Escape) )
1040 {
1041 wxCommandEvent new_event(wxEVT_COMMAND_BUTTON_CLICKED,wxID_CANCEL);
1042 new_event.SetEventObject( win );
1043 ret = win->GetEventHandler()->ProcessEvent( new_event );
1044 }
c50f1fb9 1045
da048e3d 1046 /* Doesn't work. */
f17393f1
VZ
1047#if 0 // (GTK_MINOR_VERSION > 0)
1048 /* Pressing F10 will activate the menu bar of the top frame. */
801aa178
RR
1049 if ( (!ret) &&
1050 (gdk_event->keyval == GDK_F10) )
1051 {
1e6feb95 1052 wxWindowGTK *ancestor = win;
801aa178
RR
1053 while (ancestor)
1054 {
1055 if (wxIsKindOf(ancestor,wxFrame))
c50f1fb9
VZ
1056 {
1057 wxFrame *frame = (wxFrame*) ancestor;
801aa178 1058 wxMenuBar *menubar = frame->GetMenuBar();
c50f1fb9
VZ
1059 if (menubar)
1060 {
801aa178 1061 wxNode *node = menubar->GetMenus().First();
c50f1fb9
VZ
1062 if (node)
1063 {
3017f78d
RR
1064 wxMenu *firstMenu = (wxMenu*) node->Data();
1065 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu->m_owner) );
1066 ret = TRUE;
c50f1fb9
VZ
1067 break;
1068 }
1069 }
1070 }
801aa178
RR
1071 ancestor = ancestor->GetParent();
1072 }
1073 }
f17393f1 1074#endif // 0
ca298c88 1075
f5e27805
RR
1076 if (ret)
1077 {
b292e2f5 1078 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
f03fc89f 1079 return TRUE;
f5e27805 1080 }
47d67540 1081
034be888 1082 return FALSE;
362c6693 1083}
c801d85f 1084
b666df2c
RR
1085//-----------------------------------------------------------------------------
1086// "key_release_event" from any window
1087//-----------------------------------------------------------------------------
1088
1e6feb95 1089static gint gtk_window_key_release_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindowGTK *win )
b666df2c 1090{
3ac8d3bc
RR
1091 DEBUG_MAIN_THREAD
1092
c50f1fb9 1093 if (g_isIdle)
a2053b27
RR
1094 wxapp_install_idle_handler();
1095
1096 if (!win->m_hasVMT) return FALSE;
b666df2c
RR
1097 if (g_blockEventsOnDrag) return FALSE;
1098
2d451165 1099 long key_code = map_to_unmodified_wx_keysym( gdk_event );
c50f1fb9 1100
f17393f1
VZ
1101#ifdef DEBUG_KEY_EVENTS
1102 wxPrintf(_T("Key release event: %d => %ld\n"), gdk_event->keyval, key_code);
1103#endif // DEBUG_KEY_EVENTS
1104
f0492f7d
RR
1105 /* sending unknown key events doesn't really make sense */
1106 if (key_code == 0) return FALSE;
b666df2c 1107
b0e813a0
RR
1108 int x = 0;
1109 int y = 0;
1110 GdkModifierType state;
f17393f1
VZ
1111 if (gdk_event->window)
1112 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
b666df2c
RR
1113
1114 wxKeyEvent event( wxEVT_KEY_UP );
d1367c3d 1115 event.SetTimestamp( gdk_event->time );
b666df2c
RR
1116 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1117 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1118 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1119 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1120 event.m_keyCode = key_code;
b0e813a0
RR
1121 event.m_scanCode = gdk_event->keyval;
1122 event.m_x = x;
1123 event.m_y = y;
b666df2c
RR
1124 event.SetEventObject( win );
1125
034be888 1126 if (win->GetEventHandler()->ProcessEvent( event ))
b666df2c 1127 {
b98d804b 1128 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_release_event" );
f03fc89f 1129 return TRUE;
b666df2c
RR
1130 }
1131
034be888 1132 return FALSE;
b666df2c
RR
1133}
1134
c5f9d156
VS
1135// ============================================================================
1136// the mouse events
1137// ============================================================================
1138
1139// init wxMouseEvent with the info from gdk_event
1140#define InitMouseEvent(win, event, gdk_event) \
1141 { \
1142 event.SetTimestamp( gdk_event->time ); \
1143 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1144 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1145 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1146 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1147 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1148 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1149 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1150\
1151 wxPoint pt = win->GetClientAreaOrigin(); \
1152 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1153 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1154 }
1155
2daa0ce9
VZ
1156// ----------------------------------------------------------------------------
1157// mouse event processing helper
1158// ----------------------------------------------------------------------------
1159
1160static void AdjustEventButtonState(wxMouseEvent& event)
1161{
1162 // GDK reports the old state of the button for a button press event, but
1163 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1164 // for a LEFT_DOWN event, not FALSE, so we will invert
1165 // left/right/middleDown for the corresponding click events
1e6feb95 1166
1a8caf94
RR
1167 if ((event.GetEventType() == wxEVT_LEFT_DOWN) ||
1168 (event.GetEventType() == wxEVT_LEFT_DCLICK) ||
1169 (event.GetEventType() == wxEVT_LEFT_UP))
1170 {
1171 event.m_leftDown = !event.m_leftDown;
1172 return;
1173 }
1174
1175 if ((event.GetEventType() == wxEVT_MIDDLE_DOWN) ||
1176 (event.GetEventType() == wxEVT_MIDDLE_DCLICK) ||
1177 (event.GetEventType() == wxEVT_MIDDLE_UP))
2daa0ce9 1178 {
1a8caf94
RR
1179 event.m_middleDown = !event.m_middleDown;
1180 return;
1181 }
1182
1183 if ((event.GetEventType() == wxEVT_RIGHT_DOWN) ||
1184 (event.GetEventType() == wxEVT_RIGHT_DCLICK) ||
1185 (event.GetEventType() == wxEVT_RIGHT_UP))
1186 {
1187 event.m_rightDown = !event.m_rightDown;
1188 return;
2daa0ce9
VZ
1189 }
1190}
1191
c801d85f 1192//-----------------------------------------------------------------------------
2f2aa628
RR
1193// "button_press_event"
1194//-----------------------------------------------------------------------------
c801d85f 1195
1e6feb95 1196static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindowGTK *win )
903f689b 1197{
3ac8d3bc
RR
1198 DEBUG_MAIN_THREAD
1199
c50f1fb9 1200 if (g_isIdle)
a2053b27
RR
1201 wxapp_install_idle_handler();
1202
1203/*
223d09f6 1204 wxPrintf( wxT("1) OnButtonPress from ") );
a2053b27
RR
1205 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1206 wxPrintf( win->GetClassInfo()->GetClassName() );
223d09f6 1207 wxPrintf( wxT(".\n") );
a2053b27 1208*/
a2053b27 1209 if (!win->m_hasVMT) return FALSE;
f5e27805 1210 if (g_blockEventsOnDrag) return TRUE;
76ed8f8d 1211 if (g_blockEventsOnScroll) return TRUE;
c801d85f 1212
034be888
RR
1213 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1214
a2053b27 1215 if (win->m_wxwindow)
c801d85f 1216 {
a2053b27 1217 if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow) && !GTK_WIDGET_HAS_FOCUS (win->m_wxwindow) )
f5e27805 1218 {
a2053b27 1219 gtk_widget_grab_focus (win->m_wxwindow);
47d67540 1220
c801d85f 1221/*
223d09f6 1222 wxPrintf( wxT("GrabFocus from ") );
f5e27805 1223 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
a2053b27 1224 wxPrintf( win->GetClassInfo()->GetClassName() );
223d09f6 1225 wxPrintf( wxT(".\n") );
c801d85f 1226*/
47d67540 1227
f5e27805 1228 }
362c6693 1229 }
47d67540 1230
2daa0ce9 1231 wxEventType event_type = wxEVT_NULL;
47d67540 1232
f5e27805 1233 if (gdk_event->button == 1)
c801d85f 1234 {
f5e27805
RR
1235 switch (gdk_event->type)
1236 {
1237 case GDK_BUTTON_PRESS: event_type = wxEVT_LEFT_DOWN; break;
1238 case GDK_2BUTTON_PRESS: event_type = wxEVT_LEFT_DCLICK; break;
1239 default: break;
1240 }
362c6693 1241 }
f5e27805 1242 else if (gdk_event->button == 2)
c801d85f 1243 {
f5e27805
RR
1244 switch (gdk_event->type)
1245 {
1246 case GDK_BUTTON_PRESS: event_type = wxEVT_MIDDLE_DOWN; break;
1247 case GDK_2BUTTON_PRESS: event_type = wxEVT_MIDDLE_DCLICK; break;
1248 default: break;
1249 }
362c6693 1250 }
f5e27805 1251 else if (gdk_event->button == 3)
c801d85f 1252 {
f5e27805
RR
1253 switch (gdk_event->type)
1254 {
1255 case GDK_BUTTON_PRESS: event_type = wxEVT_RIGHT_DOWN; break;
1256 case GDK_2BUTTON_PRESS: event_type = wxEVT_RIGHT_DCLICK; break;
1257 default: break;
1258 }
362c6693 1259 }
47d67540 1260
2daa0ce9
VZ
1261 if ( event_type == wxEVT_NULL )
1262 {
1263 // unknown mouse button or click type
1264 return FALSE;
1265 }
1266
f5e27805 1267 wxMouseEvent event( event_type );
c5f9d156 1268 InitMouseEvent( win, event, gdk_event );
47d67540 1269
2daa0ce9 1270 AdjustEventButtonState(event);
94633ad9 1271
e2762ff0 1272 // wxListBox actually get mouse events from the item
94633ad9 1273
e2762ff0
RR
1274 if (win->m_isListBox)
1275 {
1276 event.m_x += widget->allocation.x;
1277 event.m_y += widget->allocation.y;
1278 }
2daa0ce9 1279
f5e27805
RR
1280 // Some control don't have their own X window and thus cannot get
1281 // any events.
47d67540 1282
72195a0f 1283 if (!g_captureWindow)
2f2aa628 1284 {
b02da6b1
VZ
1285 wxCoord x = event.m_x;
1286 wxCoord y = event.m_y;
2f073eb2
RR
1287 if (win->m_wxwindow)
1288 {
da048e3d 1289 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
b02da6b1
VZ
1290 x += pizza->xoffset;
1291 y += pizza->yoffset;
2f073eb2
RR
1292 }
1293
db1b4961 1294 wxNode *node = win->GetChildren().First();
f5e27805
RR
1295 while (node)
1296 {
1e6feb95 1297 wxWindowGTK *child = (wxWindowGTK*)node->Data();
148cd9b6 1298
f96ac56a 1299 node = node->Next();
b02da6b1
VZ
1300 if (!child->IsShown())
1301 continue;
ff8bfdbb 1302
a2053b27 1303 if (child->m_isStaticBox)
ff8bfdbb
VZ
1304 {
1305 // wxStaticBox is transparent in the box itself
a2053b27
RR
1306 int xx1 = child->m_x;
1307 int yy1 = child->m_y;
1308 int xx2 = child->m_x + child->m_width;
1309 int yy2 = child->m_x + child->m_height;
ff8bfdbb
VZ
1310
1311 // left
1312 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1313 // right
1314 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1315 // top
1316 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1317 // bottom
1318 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1319 {
1ecc4d80 1320 win = child;
a2053b27
RR
1321 event.m_x -= child->m_x;
1322 event.m_y -= child->m_y;
1ecc4d80 1323 break;
ff8bfdbb
VZ
1324 }
1325
1326 }
1327 else
1328 {
a2053b27 1329 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
2f073eb2
RR
1330 (child->m_x <= x) &&
1331 (child->m_y <= y) &&
1332 (child->m_x+child->m_width >= x) &&
1333 (child->m_y+child->m_height >= y))
1ecc4d80
RR
1334 {
1335 win = child;
a2053b27
RR
1336 event.m_x -= child->m_x;
1337 event.m_y -= child->m_y;
1ecc4d80 1338 break;
ff8bfdbb 1339 }
f5e27805 1340 }
f5e27805 1341 }
2f2aa628 1342 }
ff8bfdbb 1343
f5e27805 1344 event.SetEventObject( win );
47d67540 1345
f5e27805 1346 gs_timeLastClick = gdk_event->time;
47d67540 1347
2f073eb2
RR
1348/*
1349 wxPrintf( wxT("2) OnButtonPress from ") );
1350 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1351 wxPrintf( win->GetClassInfo()->GetClassName() );
1352 wxPrintf( wxT(".\n") );
1353*/
1354
f5e27805 1355 if (win->GetEventHandler()->ProcessEvent( event ))
034be888 1356 {
f5e27805 1357 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_press_event" );
f03fc89f 1358 return TRUE;
034be888 1359 }
47d67540 1360
034be888 1361 return FALSE;
362c6693 1362}
c801d85f
KB
1363
1364//-----------------------------------------------------------------------------
97b3455a 1365// "button_release_event"
2f2aa628 1366//-----------------------------------------------------------------------------
c801d85f 1367
1e6feb95 1368static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindowGTK *win )
47d67540 1369{
3ac8d3bc
RR
1370 DEBUG_MAIN_THREAD
1371
c50f1fb9 1372 if (g_isIdle)
a2053b27
RR
1373 wxapp_install_idle_handler();
1374
1375 if (!win->m_hasVMT) return FALSE;
034be888
RR
1376 if (g_blockEventsOnDrag) return FALSE;
1377 if (g_blockEventsOnScroll) return FALSE;
c801d85f 1378
034be888 1379 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
47d67540 1380
c801d85f 1381/*
f5e27805
RR
1382 printf( "OnButtonRelease from " );
1383 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1384 printf( win->GetClassInfo()->GetClassName() );
1385 printf( ".\n" );
c801d85f 1386*/
47d67540 1387
f5e27805 1388 wxEventType event_type = wxEVT_NULL;
47d67540 1389
f5e27805
RR
1390 switch (gdk_event->button)
1391 {
1392 case 1: event_type = wxEVT_LEFT_UP; break;
1393 case 2: event_type = wxEVT_MIDDLE_UP; break;
1394 case 3: event_type = wxEVT_RIGHT_UP; break;
2daa0ce9 1395 default: return FALSE;
f5e27805 1396 }
47d67540 1397
f5e27805 1398 wxMouseEvent event( event_type );
c5f9d156 1399 InitMouseEvent( win, event, gdk_event );
f5e27805 1400
2daa0ce9
VZ
1401 AdjustEventButtonState(event);
1402
e2762ff0 1403 // wxListBox actually get mouse events from the item
94633ad9 1404
e2762ff0
RR
1405 if (win->m_isListBox)
1406 {
1407 event.m_x += widget->allocation.x;
1408 event.m_y += widget->allocation.y;
1409 }
1410
f5e27805
RR
1411 // Some control don't have their own X window and thus cannot get
1412 // any events.
1413
72195a0f 1414 if (!g_captureWindow)
2f2aa628 1415 {
b02da6b1
VZ
1416 wxCoord x = event.m_x;
1417 wxCoord y = event.m_y;
2f073eb2
RR
1418 if (win->m_wxwindow)
1419 {
da048e3d 1420 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
b02da6b1
VZ
1421 x += pizza->xoffset;
1422 y += pizza->yoffset;
2f073eb2
RR
1423 }
1424
db1b4961 1425 wxNode *node = win->GetChildren().First();
f5e27805
RR
1426 while (node)
1427 {
1e6feb95 1428 wxWindowGTK *child = (wxWindowGTK*)node->Data();
ff8bfdbb 1429
f96ac56a 1430 node = node->Next();
b02da6b1
VZ
1431 if (!child->IsShown())
1432 continue;
f96ac56a 1433
a2053b27 1434 if (child->m_isStaticBox)
ff8bfdbb
VZ
1435 {
1436 // wxStaticBox is transparent in the box itself
a2053b27
RR
1437 int xx1 = child->m_x;
1438 int yy1 = child->m_y;
1439 int xx2 = child->m_x + child->m_width;
1440 int yy2 = child->m_x + child->m_height;
ff8bfdbb
VZ
1441
1442 // left
1443 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1444 // right
1445 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1446 // top
1447 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1448 // bottom
1449 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1450 {
1ecc4d80 1451 win = child;
a2053b27
RR
1452 event.m_x -= child->m_x;
1453 event.m_y -= child->m_y;
1ecc4d80 1454 break;
ff8bfdbb
VZ
1455 }
1456
1457 }
1458 else
1459 {
a2053b27 1460 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
2f073eb2
RR
1461 (child->m_x <= x) &&
1462 (child->m_y <= y) &&
1463 (child->m_x+child->m_width >= x) &&
1464 (child->m_y+child->m_height >= y))
1ecc4d80
RR
1465 {
1466 win = child;
a2053b27
RR
1467 event.m_x -= child->m_x;
1468 event.m_y -= child->m_y;
1ecc4d80 1469 break;
ff8bfdbb 1470 }
f5e27805 1471 }
f5e27805 1472 }
2f2aa628 1473 }
47d67540 1474
f5e27805 1475 event.SetEventObject( win );
47d67540 1476
f5e27805 1477 if (win->GetEventHandler()->ProcessEvent( event ))
034be888 1478 {
f5e27805 1479 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_release_event" );
f03fc89f 1480 return TRUE;
034be888 1481 }
47d67540 1482
034be888 1483 return FALSE;
362c6693 1484}
c801d85f
KB
1485
1486//-----------------------------------------------------------------------------
2f2aa628
RR
1487// "motion_notify_event"
1488//-----------------------------------------------------------------------------
c801d85f 1489
1e6feb95
VZ
1490static gint gtk_window_motion_notify_callback( GtkWidget *widget,
1491 GdkEventMotion *gdk_event,
1492 wxWindowGTK *win )
47d67540 1493{
3ac8d3bc
RR
1494 DEBUG_MAIN_THREAD
1495
c50f1fb9 1496 if (g_isIdle)
a2053b27
RR
1497 wxapp_install_idle_handler();
1498
1499 if (!win->m_hasVMT) return FALSE;
034be888
RR
1500 if (g_blockEventsOnDrag) return FALSE;
1501 if (g_blockEventsOnScroll) return FALSE;
148cd9b6 1502
034be888
RR
1503 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1504
ff8bfdbb 1505 if (gdk_event->is_hint)
aae24d21 1506 {
f7a11f8c
RR
1507 int x = 0;
1508 int y = 0;
1509 GdkModifierType state;
1510 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
1511 gdk_event->x = x;
1512 gdk_event->y = y;
aae24d21 1513 }
ff8bfdbb 1514
c801d85f 1515/*
e380f72b
RR
1516 printf( "OnMotion from " );
1517 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1518 printf( win->GetClassInfo()->GetClassName() );
1519 printf( ".\n" );
aae24d21 1520*/
47d67540 1521
e380f72b 1522 wxMouseEvent event( wxEVT_MOTION );
c5f9d156 1523 InitMouseEvent(win, event, gdk_event);
e380f72b 1524
1e6feb95 1525 if ( g_captureWindow )
2f2aa628 1526 {
1e6feb95
VZ
1527 // synthetize a mouse enter or leave event if needed
1528 GdkWindow *winUnderMouse = gdk_window_at_pointer(NULL, NULL);
1529 bool hasMouse = winUnderMouse == gdk_event->window;
1530 if ( hasMouse != g_captureWindowHasMouse )
1531 {
1532 // the mouse changed window
1533 g_captureWindowHasMouse = hasMouse;
1534
1535 wxMouseEvent event(g_captureWindowHasMouse ? wxEVT_ENTER_WINDOW
1536 : wxEVT_LEAVE_WINDOW);
c5f9d156 1537 InitMouseEvent(win, event, gdk_event);
1e6feb95
VZ
1538 event.SetEventObject(win);
1539 win->GetEventHandler()->ProcessEvent(event);
1540 }
1541 }
1542 else // no capture
1543 {
1544 // Some control don't have their own X window and thus cannot get
1545 // any events.
1546
b02da6b1
VZ
1547 wxCoord x = event.m_x;
1548 wxCoord y = event.m_y;
2f073eb2
RR
1549 if (win->m_wxwindow)
1550 {
da048e3d 1551 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
b02da6b1
VZ
1552 x += pizza->xoffset;
1553 y += pizza->yoffset;
2f073eb2
RR
1554 }
1555
db1b4961 1556 wxNode *node = win->GetChildren().First();
e380f72b
RR
1557 while (node)
1558 {
1e6feb95 1559 wxWindowGTK *child = (wxWindowGTK*)node->Data();
ff8bfdbb 1560
f96ac56a 1561 node = node->Next();
b02da6b1
VZ
1562 if (!child->IsShown())
1563 continue;
f96ac56a 1564
a2053b27 1565 if (child->m_isStaticBox)
ff8bfdbb
VZ
1566 {
1567 // wxStaticBox is transparent in the box itself
a2053b27
RR
1568 int xx1 = child->m_x;
1569 int yy1 = child->m_y;
1570 int xx2 = child->m_x + child->m_width;
1571 int yy2 = child->m_x + child->m_height;
ff8bfdbb
VZ
1572
1573 // left
1574 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1575 // right
1576 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1577 // top
1578 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1579 // bottom
1580 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1581 {
1ecc4d80 1582 win = child;
a2053b27
RR
1583 event.m_x -= child->m_x;
1584 event.m_y -= child->m_y;
1ecc4d80 1585 break;
ff8bfdbb
VZ
1586 }
1587
1588 }
1589 else
1590 {
a2053b27 1591 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
2f073eb2
RR
1592 (child->m_x <= x) &&
1593 (child->m_y <= y) &&
1594 (child->m_x+child->m_width >= x) &&
1595 (child->m_y+child->m_height >= y))
1ecc4d80
RR
1596 {
1597 win = child;
a2053b27
RR
1598 event.m_x -= child->m_x;
1599 event.m_y -= child->m_y;
1ecc4d80 1600 break;
ff8bfdbb 1601 }
e380f72b 1602 }
e380f72b 1603 }
2f2aa628 1604 }
47d67540 1605
e380f72b 1606 event.SetEventObject( win );
47d67540 1607
e380f72b 1608 if (win->GetEventHandler()->ProcessEvent( event ))
034be888 1609 {
e380f72b 1610 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "motion_notify_event" );
f03fc89f 1611 return TRUE;
034be888 1612 }
47d67540 1613
034be888 1614 return FALSE;
362c6693 1615}
c801d85f
KB
1616
1617//-----------------------------------------------------------------------------
2f2aa628
RR
1618// "focus_in_event"
1619//-----------------------------------------------------------------------------
c801d85f 1620
1e6feb95
VZ
1621static gint gtk_window_focus_in_callback( GtkWidget *widget,
1622 GdkEvent *WXUNUSED(event),
1623 wxWindow *win )
c801d85f 1624{
3ac8d3bc
RR
1625 DEBUG_MAIN_THREAD
1626
c50f1fb9 1627 if (g_isIdle)
a2053b27
RR
1628 wxapp_install_idle_handler();
1629
1630 if (!win->m_hasVMT) return FALSE;
034be888 1631 if (g_blockEventsOnDrag) return FALSE;
ff8bfdbb 1632
148cd9b6
VZ
1633 switch ( g_sendActivateEvent )
1634 {
1635 case -1:
76fcf0f2 1636 // we've got focus from outside, synthetize wxActivateEvent
148cd9b6
VZ
1637 g_sendActivateEvent = 1;
1638 break;
1639
1640 case 0:
1641 // another our window just lost focus, it was already ours before
1642 // - don't send any wxActivateEvent
1643 g_sendActivateEvent = -1;
1644 break;
1645 }
1646
1e6feb95 1647 g_focusWindowLast =
b292e2f5 1648 g_focusWindow = win;
ff8bfdbb 1649
2b328fc9 1650#if 0
76fcf0f2 1651 wxPrintf( "OnSetFocus from " );
e380f72b 1652 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
76fcf0f2
RR
1653 wxPrintf( win->GetClassInfo()->GetClassName() );
1654 wxPrintf( ".\n" );
1655#endif
47d67540 1656
456bc6d9
VZ
1657 // notify the parent keeping track of focus for the kbd navigation
1658 // purposes that we got it
5314ac16
VZ
1659 wxChildFocusEvent eventFocus(win);
1660 (void)win->GetEventHandler()->ProcessEvent(eventFocus);
148cd9b6 1661
b79395c5
RR
1662#ifdef HAVE_XIM
1663 if (win->m_ic)
1664 gdk_im_begin(win->m_ic, win->m_wxwindow->window);
1665#endif
1666
1e6feb95 1667#if wxUSE_CARET
f6bcfd97
BP
1668 // caret needs to be informed about focus change
1669 wxCaret *caret = win->GetCaret();
1670 if ( caret )
1671 {
1672 caret->OnSetFocus();
1673 }
1674#endif // wxUSE_CARET
1675
e8c12a53
VS
1676 wxWindowGTK *active = wxGetTopLevelParent(win);
1677 if ( active != g_activeFrame )
942bef71 1678 {
e8c12a53
VS
1679 if ( g_activeFrame )
1680 {
45eb5249 1681 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame);
e8c12a53
VS
1682 wxActivateEvent event(wxEVT_ACTIVATE, FALSE, g_activeFrame->GetId());
1683 event.SetEventObject(g_activeFrame);
1684 g_activeFrame->GetEventHandler()->ProcessEvent(event);
1685 }
47d67540 1686
45eb5249 1687 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active);
e8c12a53
VS
1688 g_activeFrame = active;
1689 wxActivateEvent event(wxEVT_ACTIVATE, TRUE, g_activeFrame->GetId());
1690 event.SetEventObject(g_activeFrame);
1691 g_activeFrame->GetEventHandler()->ProcessEvent(event);
942bef71 1692 }
e8c12a53
VS
1693 g_activeFrameLostFocus = FALSE;
1694
942bef71 1695
5cd09f0b
RR
1696 wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() );
1697 event.SetEventObject( win );
1698
1699 if (win->GetEventHandler()->ProcessEvent( event ))
1700 {
1701 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
1702 return TRUE;
034be888 1703 }
ca298c88 1704
942bef71 1705
034be888 1706 return FALSE;
362c6693 1707}
c801d85f
KB
1708
1709//-----------------------------------------------------------------------------
2f2aa628
RR
1710// "focus_out_event"
1711//-----------------------------------------------------------------------------
c801d85f 1712
b231914f
VZ
1713static GtkWidget *gs_widgetLastFocus = NULL;
1714
1e6feb95 1715static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindowGTK *win )
c801d85f 1716{
3ac8d3bc
RR
1717 DEBUG_MAIN_THREAD
1718
c50f1fb9 1719 if (g_isIdle)
a2053b27
RR
1720 wxapp_install_idle_handler();
1721
1722 if (!win->m_hasVMT) return FALSE;
034be888 1723 if (g_blockEventsOnDrag) return FALSE;
ca298c88 1724
b231914f
VZ
1725 // VZ: this is really weird but GTK+ seems to call us from inside
1726 // gtk_widget_grab_focus(), i.e. it first sends "focus_out" signal to
1727 // this widget and then "focus_in". This is totally unexpected and
1728 // completely breaks wxUniv code so ignore this dummy event (we can't
1729 // be losing focus if we're about to acquire it!)
1730 if ( widget == gs_widgetLastFocus )
1731 {
1732 gs_widgetLastFocus = NULL;
1733
55fb2c6c 1734 return FALSE;
b231914f
VZ
1735 }
1736
45eb5249
VS
1737 if ( !g_activeFrameLostFocus && g_activeFrame )
1738 {
c0ad3d42
VZ
1739 // VZ: commenting this out because it does happen (although not easy
1740 // to reproduce, I only see it when using wxMiniFrame and not
1741 // always) and makes using Mahogany quite annoying
1742#if 0
1743 wxASSERT_MSG( wxGetTopLevelParent(win) == g_activeFrame,
1744 wxT("unfocusing window that hasn't gained focus properly") )
1745#endif // 0
1746
45eb5249
VS
1747 g_activeFrameLostFocus = TRUE;
1748 }
1749
148cd9b6
VZ
1750 // if the focus goes out of our app alltogether, OnIdle() will send
1751 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1752 // g_sendActivateEvent to -1
1753 g_sendActivateEvent = 0;
1754
3379ed37 1755 wxWindowGTK *winFocus = wxFindFocusedChild(win);
f6bcfd97
BP
1756 if ( winFocus )
1757 win = winFocus;
1758
1e6feb95 1759 g_focusWindow = (wxWindowGTK *)NULL;
148cd9b6 1760
76fcf0f2
RR
1761#if 0
1762 wxPrintf( "OnKillFocus from " );
e380f72b 1763 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
76fcf0f2
RR
1764 wxPrintf( win->GetClassInfo()->GetClassName() );
1765 wxPrintf( ".\n" );
1766#endif
47d67540 1767
b79395c5
RR
1768#ifdef HAVE_XIM
1769 if (win->m_ic)
1770 gdk_im_end();
1771#endif
1772
1e6feb95 1773#if wxUSE_CARET
f6bcfd97
BP
1774 // caret needs to be informed about focus change
1775 wxCaret *caret = win->GetCaret();
1776 if ( caret )
1777 {
1778 caret->OnKillFocus();
1779 }
1780#endif // wxUSE_CARET
1781
5cd09f0b
RR
1782 wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
1783 event.SetEventObject( win );
1784
1785 if (win->GetEventHandler()->ProcessEvent( event ))
1786 {
1787 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_out_event" );
1788 return TRUE;
034be888 1789 }
ca298c88 1790
034be888 1791 return FALSE;
362c6693 1792}
c801d85f 1793
b4071e91
RR
1794//-----------------------------------------------------------------------------
1795// "enter_notify_event"
1796//-----------------------------------------------------------------------------
1797
1e6feb95 1798static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win )
b4071e91 1799{
3ac8d3bc
RR
1800 DEBUG_MAIN_THREAD
1801
c50f1fb9 1802 if (g_isIdle)
a2053b27 1803 wxapp_install_idle_handler();
ca298c88 1804
a2053b27
RR
1805 if (!win->m_hasVMT) return FALSE;
1806 if (g_blockEventsOnDrag) return FALSE;
47d67540 1807
a2053b27 1808 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
b292e2f5 1809
e380f72b 1810 wxMouseEvent event( wxEVT_ENTER_WINDOW );
d1367c3d 1811 event.SetTimestamp( gdk_event->time );
e380f72b 1812 event.SetEventObject( win );
ff8bfdbb 1813
4a33eba6
RR
1814 int x = 0;
1815 int y = 0;
1816 GdkModifierType state = (GdkModifierType)0;
ff8bfdbb 1817
a2053b27 1818 gdk_window_get_pointer( widget->window, &x, &y, &state );
ff8bfdbb 1819
c5f9d156
VS
1820 InitMouseEvent(win, event, gdk_event);
1821 wxPoint pt = win->GetClientAreaOrigin();
1822 event.m_x = x + pt.x;
1823 event.m_y = y + pt.y;
ff8bfdbb 1824
e380f72b 1825 if (win->GetEventHandler()->ProcessEvent( event ))
034be888 1826 {
e380f72b 1827 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "enter_notify_event" );
034be888
RR
1828 return TRUE;
1829 }
ca298c88 1830
034be888 1831 return FALSE;
b4071e91 1832}
47d67540 1833
b4071e91
RR
1834//-----------------------------------------------------------------------------
1835// "leave_notify_event"
1836//-----------------------------------------------------------------------------
1837
1e6feb95 1838static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win )
b4071e91 1839{
3ac8d3bc
RR
1840 DEBUG_MAIN_THREAD
1841
c50f1fb9 1842 if (g_isIdle)
a2053b27 1843 wxapp_install_idle_handler();
acfd422a 1844
a2053b27
RR
1845 if (!win->m_hasVMT) return FALSE;
1846 if (g_blockEventsOnDrag) return FALSE;
b292e2f5 1847
a2053b27 1848 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
c50f1fb9 1849
e380f72b 1850 wxMouseEvent event( wxEVT_LEAVE_WINDOW );
d1367c3d 1851 event.SetTimestamp( gdk_event->time );
e380f72b 1852 event.SetEventObject( win );
47d67540 1853
4a33eba6
RR
1854 int x = 0;
1855 int y = 0;
1856 GdkModifierType state = (GdkModifierType)0;
ff8bfdbb 1857
4a33eba6 1858 gdk_window_get_pointer( widget->window, &x, &y, &state );
ff8bfdbb 1859
4a33eba6
RR
1860 event.m_shiftDown = (state & GDK_SHIFT_MASK);
1861 event.m_controlDown = (state & GDK_CONTROL_MASK);
1862 event.m_altDown = (state & GDK_MOD1_MASK);
1863 event.m_metaDown = (state & GDK_MOD2_MASK);
1864 event.m_leftDown = (state & GDK_BUTTON1_MASK);
1865 event.m_middleDown = (state & GDK_BUTTON2_MASK);
1866 event.m_rightDown = (state & GDK_BUTTON3_MASK);
1867
c5f9d156
VS
1868 wxPoint pt = win->GetClientAreaOrigin();
1869 event.m_x = x + pt.x;
1870 event.m_y = y + pt.y;
ff8bfdbb 1871
e380f72b 1872 if (win->GetEventHandler()->ProcessEvent( event ))
034be888 1873 {
e380f72b 1874 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "leave_notify_event" );
034be888
RR
1875 return TRUE;
1876 }
ca298c88 1877
034be888 1878 return FALSE;
b4071e91 1879}
47d67540 1880
c801d85f 1881//-----------------------------------------------------------------------------
2f2aa628
RR
1882// "value_changed" from m_vAdjust
1883//-----------------------------------------------------------------------------
c801d85f 1884
1e6feb95 1885static void gtk_window_vscroll_callback( GtkAdjustment *adjust, wxWindowGTK *win )
c801d85f 1886{
3ac8d3bc
RR
1887 DEBUG_MAIN_THREAD
1888
c50f1fb9 1889 if (g_isIdle)
a2053b27 1890 wxapp_install_idle_handler();
c801d85f 1891
a2053b27 1892 if (g_blockEventsOnDrag) return;
47d67540 1893
a2053b27 1894 if (!win->m_hasVMT) return;
148cd9b6 1895
5e014a0c 1896 float diff = adjust->value - win->m_oldVerticalPos;
e380f72b 1897 if (fabs(diff) < 0.2) return;
148cd9b6 1898
5e014a0c 1899 win->m_oldVerticalPos = adjust->value;
47d67540 1900
5e014a0c
RR
1901 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1902 GtkRange *range = GTK_RANGE( scrolledWindow->vscrollbar );
148cd9b6 1903
5e014a0c
RR
1904 wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK;
1905 if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP;
1906 else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN;
1907 else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP;
1908 else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN;
148cd9b6 1909
5e014a0c 1910 int value = (int)(adjust->value+0.5);
c801d85f 1911
c5b42c87 1912 wxScrollWinEvent event( command, value, wxVERTICAL );
e380f72b
RR
1913 event.SetEventObject( win );
1914 win->GetEventHandler()->ProcessEvent( event );
362c6693 1915}
c801d85f
KB
1916
1917//-----------------------------------------------------------------------------
2f2aa628
RR
1918// "value_changed" from m_hAdjust
1919//-----------------------------------------------------------------------------
c801d85f 1920
1e6feb95 1921static void gtk_window_hscroll_callback( GtkAdjustment *adjust, wxWindowGTK *win )
47d67540 1922{
3ac8d3bc
RR
1923 DEBUG_MAIN_THREAD
1924
c50f1fb9 1925 if (g_isIdle)
a2053b27 1926 wxapp_install_idle_handler();
47d67540 1927
a2053b27
RR
1928 if (g_blockEventsOnDrag) return;
1929 if (!win->m_hasVMT) return;
47d67540 1930
5e014a0c 1931 float diff = adjust->value - win->m_oldHorizontalPos;
e380f72b 1932 if (fabs(diff) < 0.2) return;
148cd9b6 1933
5e014a0c 1934 win->m_oldHorizontalPos = adjust->value;
8bbe427f 1935
5e014a0c
RR
1936 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1937 GtkRange *range = GTK_RANGE( scrolledWindow->hscrollbar );
148cd9b6 1938
5e014a0c
RR
1939 wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK;
1940 if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP;
1941 else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN;
1942 else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP;
1943 else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN;
148cd9b6 1944
5e014a0c 1945 int value = (int)(adjust->value+0.5);
47d67540 1946
c5b42c87 1947 wxScrollWinEvent event( command, value, wxHORIZONTAL );
e380f72b
RR
1948 event.SetEventObject( win );
1949 win->GetEventHandler()->ProcessEvent( event );
362c6693 1950}
c801d85f 1951
cb43b372
RR
1952//-----------------------------------------------------------------------------
1953// "button_press_event" from scrollbar
1954//-----------------------------------------------------------------------------
1955
2a23d363
RR
1956static gint gtk_scrollbar_button_press_callback( GtkRange *widget,
1957 GdkEventButton *gdk_event,
1e6feb95 1958 wxWindowGTK *win)
cb43b372 1959{
3ac8d3bc
RR
1960 DEBUG_MAIN_THREAD
1961
c50f1fb9 1962 if (g_isIdle)
a2053b27
RR
1963 wxapp_install_idle_handler();
1964
d6d26e04 1965
5b8a521e 1966 g_blockEventsOnScroll = TRUE;
2a23d363 1967 win->m_isScrolling = (gdk_event->window == widget->slider);
47d67540 1968
e380f72b 1969 return FALSE;
cb43b372
RR
1970}
1971
1972//-----------------------------------------------------------------------------
1973// "button_release_event" from scrollbar
1974//-----------------------------------------------------------------------------
1975
88413fec 1976static gint gtk_scrollbar_button_release_callback( GtkRange *widget,
8bbe427f 1977 GdkEventButton *WXUNUSED(gdk_event),
1e6feb95 1978 wxWindowGTK *win)
cb43b372 1979{
3ac8d3bc
RR
1980 DEBUG_MAIN_THREAD
1981
1ecc4d80 1982// don't test here as we can release the mouse while being over
5e014a0c 1983// a different window than the slider
76ed8f8d
RR
1984//
1985// if (gdk_event->window != widget->slider) return FALSE;
cb43b372 1986
5b8a521e 1987 g_blockEventsOnScroll = FALSE;
47d67540 1988
2a23d363 1989 if (win->m_isScrolling)
88413fec 1990 {
d6d26e04 1991 wxEventType command = wxEVT_SCROLLWIN_THUMBRELEASE;
2a23d363
RR
1992 int value = -1;
1993 int dir = -1;
2daa0ce9 1994
2a23d363
RR
1995 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1996 if (widget == GTK_RANGE(scrolledWindow->hscrollbar))
1997 {
1998 value = (int)(win->m_hAdjust->value+0.5);
1999 dir = wxHORIZONTAL;
2000 }
2001 if (widget == GTK_RANGE(scrolledWindow->vscrollbar))
2002 {
2003 value = (int)(win->m_vAdjust->value+0.5);
2004 dir = wxVERTICAL;
2005 }
2daa0ce9 2006
2a23d363 2007 wxScrollWinEvent event( command, value, dir );
2a23d363
RR
2008 event.SetEventObject( win );
2009 win->GetEventHandler()->ProcessEvent( event );
88413fec
RR
2010 }
2011
2a23d363 2012 win->m_isScrolling = FALSE;
2daa0ce9 2013
e380f72b 2014 return FALSE;
cb43b372
RR
2015}
2016
f03fc89f
VZ
2017// ----------------------------------------------------------------------------
2018// this wxWindowBase function is implemented here (in platform-specific file)
2019// because it is static and so couldn't be made virtual
2020// ----------------------------------------------------------------------------
2b07d713 2021
f03fc89f 2022wxWindow *wxWindowBase::FindFocus()
2b07d713 2023{
1e6feb95
VZ
2024 // the cast is necessary when we compile in wxUniversal mode
2025 return (wxWindow *)g_focusWindow;
2b07d713 2026}
ca298c88 2027
a2053b27
RR
2028//-----------------------------------------------------------------------------
2029// "realize" from m_widget
2030//-----------------------------------------------------------------------------
2031
b79395c5
RR
2032/* We cannot set colours and fonts before the widget has
2033 been realized, so we do this directly after realization. */
a2053b27
RR
2034
2035static gint
63081513 2036gtk_window_realized_callback( GtkWidget *WXUNUSED(m_widget), wxWindow *win )
a2053b27 2037{
3ac8d3bc
RR
2038 DEBUG_MAIN_THREAD
2039
c50f1fb9 2040 if (g_isIdle)
a2053b27
RR
2041 wxapp_install_idle_handler();
2042
739730ca
RR
2043 if (win->m_delayedBackgroundColour)
2044 win->SetBackgroundColour( win->GetBackgroundColour() );
a2053b27 2045
739730ca
RR
2046 if (win->m_delayedForegroundColour)
2047 win->SetForegroundColour( win->GetForegroundColour() );
a2053b27 2048
3c679789
RR
2049 wxWindowCreateEvent event( win );
2050 event.SetEventObject( win );
2051 win->GetEventHandler()->ProcessEvent( event );
1e6feb95 2052
a2053b27
RR
2053 return FALSE;
2054}
2055
b79395c5
RR
2056//-----------------------------------------------------------------------------
2057// "size_allocate"
2058//-----------------------------------------------------------------------------
2059
8f75cb6c 2060static
adc1999b
RR
2061void gtk_window_size_callback( GtkWidget *WXUNUSED(widget),
2062 GtkAllocation *WXUNUSED(alloc),
8f75cb6c
RR
2063 wxWindow *win )
2064{
2065 if (g_isIdle)
2066 wxapp_install_idle_handler();
2daa0ce9 2067
5b8a521e 2068 if (!win->m_hasScrolling) return;
2daa0ce9 2069
5b8a521e
RR
2070 int client_width = 0;
2071 int client_height = 0;
2072 win->GetClientSize( &client_width, &client_height );
2073 if ((client_width == win->m_oldClientWidth) && (client_height == win->m_oldClientHeight))
2074 return;
2daa0ce9 2075
5b8a521e
RR
2076 win->m_oldClientWidth = client_width;
2077 win->m_oldClientHeight = client_height;
2daa0ce9 2078
5b8a521e
RR
2079 if (!win->m_nativeSizeEvent)
2080 {
2081 wxSizeEvent event( win->GetSize(), win->GetId() );
2082 event.SetEventObject( win );
2083 win->GetEventHandler()->ProcessEvent( event );
2084 }
8f75cb6c
RR
2085}
2086
2087
3ed2e7ce
VZ
2088#ifdef HAVE_XIM
2089 #define WXUNUSED_UNLESS_XIM(param) param
2090#else
2091 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2092#endif
2093
b79395c5
RR
2094/* Resize XIM window */
2095
3ed2e7ce 2096static
8f75cb6c
RR
2097void gtk_wxwindow_size_callback( GtkWidget* WXUNUSED_UNLESS_XIM(widget),
2098 GtkAllocation* WXUNUSED_UNLESS_XIM(alloc),
1e6feb95 2099 wxWindowGTK* WXUNUSED_UNLESS_XIM(win) )
b79395c5
RR
2100{
2101 if (g_isIdle)
2102 wxapp_install_idle_handler();
2daa0ce9 2103
9a8c7620 2104#ifdef HAVE_XIM
b79395c5
RR
2105 if (!win->m_ic)
2106 return;
2107
b79395c5
RR
2108 if (gdk_ic_get_style (win->m_ic) & GDK_IM_PREEDIT_POSITION)
2109 {
2110 gint width, height;
2111
3ed2e7ce 2112 gdk_window_get_size (widget->window, &width, &height);
b79395c5
RR
2113 win->m_icattr->preedit_area.width = width;
2114 win->m_icattr->preedit_area.height = height;
2115 gdk_ic_set_attr (win->m_ic, win->m_icattr, GDK_IC_PREEDIT_AREA);
2116 }
9a8c7620 2117#endif // HAVE_XIM
b79395c5
RR
2118}
2119
63081513
RR
2120//-----------------------------------------------------------------------------
2121// "realize" from m_wxwindow
2122//-----------------------------------------------------------------------------
2123
2124/* Initialize XIM support */
2125
2126static gint
3ed2e7ce 2127gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget),
1e6feb95 2128 wxWindowGTK * WXUNUSED_UNLESS_XIM(win) )
63081513
RR
2129{
2130 if (g_isIdle)
2131 wxapp_install_idle_handler();
2132
d06800f1 2133#ifdef HAVE_XIM
63081513
RR
2134 if (win->m_ic) return FALSE;
2135 if (!widget) return FALSE;
2136 if (!gdk_im_ready()) return FALSE;
2137
2138 win->m_icattr = gdk_ic_attr_new();
2139 if (!win->m_icattr) return FALSE;
2daa0ce9 2140
63081513
RR
2141 gint width, height;
2142 GdkEventMask mask;
2143 GdkColormap *colormap;
2144 GdkICAttr *attr = win->m_icattr;
b58b1dfc 2145 unsigned attrmask = GDK_IC_ALL_REQ;
63081513 2146 GdkIMStyle style;
b79395c5
RR
2147 GdkIMStyle supported_style = (GdkIMStyle)
2148 (GDK_IM_PREEDIT_NONE |
1e6feb95
VZ
2149 GDK_IM_PREEDIT_NOTHING |
2150 GDK_IM_PREEDIT_POSITION |
2151 GDK_IM_STATUS_NONE |
2152 GDK_IM_STATUS_NOTHING);
63081513
RR
2153
2154 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
1e6feb95 2155 supported_style = (GdkIMStyle)(supported_style & ~GDK_IM_PREEDIT_POSITION);
63081513
RR
2156
2157 attr->style = style = gdk_im_decide_style (supported_style);
2158 attr->client_window = widget->window;
2159
2160 if ((colormap = gtk_widget_get_colormap (widget)) !=
1e6feb95 2161 gtk_widget_get_default_colormap ())
63081513 2162 {
5cd09f0b
RR
2163 attrmask |= GDK_IC_PREEDIT_COLORMAP;
2164 attr->preedit_colormap = colormap;
63081513 2165 }
2daa0ce9 2166
63081513
RR
2167 attrmask |= GDK_IC_PREEDIT_FOREGROUND;
2168 attrmask |= GDK_IC_PREEDIT_BACKGROUND;
2169 attr->preedit_foreground = widget->style->fg[GTK_STATE_NORMAL];
2170 attr->preedit_background = widget->style->base[GTK_STATE_NORMAL];
2171
2172 switch (style & GDK_IM_PREEDIT_MASK)
2173 {
1e6feb95
VZ
2174 case GDK_IM_PREEDIT_POSITION:
2175 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
2176 {
2177 g_warning ("over-the-spot style requires fontset");
2178 break;
2179 }
63081513 2180
1e6feb95 2181 gdk_window_get_size (widget->window, &width, &height);
63081513 2182
1e6feb95
VZ
2183 attrmask |= GDK_IC_PREEDIT_POSITION_REQ;
2184 attr->spot_location.x = 0;
2185 attr->spot_location.y = height;
2186 attr->preedit_area.x = 0;
2187 attr->preedit_area.y = 0;
2188 attr->preedit_area.width = width;
2189 attr->preedit_area.height = height;
2190 attr->preedit_fontset = widget->style->font;
63081513 2191
1e6feb95 2192 break;
b79395c5 2193 }
2daa0ce9 2194
b58b1dfc 2195 win->m_ic = gdk_ic_new (attr, (GdkICAttributesType)attrmask);
2daa0ce9 2196
63081513 2197 if (win->m_ic == NULL)
1e6feb95 2198 g_warning ("Can't create input context.");
63081513 2199 else
1e6feb95
VZ
2200 {
2201 mask = gdk_window_get_events (widget->window);
2202 mask = (GdkEventMask)(mask | gdk_ic_get_events (win->m_ic));
2203 gdk_window_set_events (widget->window, mask);
2204
2205 if (GTK_WIDGET_HAS_FOCUS(widget))
2206 gdk_im_begin (win->m_ic, widget->window);
2207 }
2208#endif // HAVE_XIM
63081513
RR
2209
2210 return FALSE;
2211}
2212
6ca41e57 2213//-----------------------------------------------------------------------------
1e6feb95 2214// InsertChild for wxWindowGTK.
6ca41e57
RR
2215//-----------------------------------------------------------------------------
2216
1e6feb95 2217/* Callback for wxWindowGTK. This very strange beast has to be used because
b1170810
RR
2218 * C++ has no virtual methods in a constructor. We have to emulate a
2219 * virtual function here as wxNotebook requires a different way to insert
2220 * a child in it. I had opted for creating a wxNotebookPage window class
2221 * which would have made this superfluous (such in the MDI window system),
2222 * but no-one was listening to me... */
6ca41e57 2223
1e6feb95 2224static void wxInsertChildInWindow( wxWindowGTK* parent, wxWindowGTK* child )
6ca41e57 2225{
bf0c00c6
RR
2226 /* the window might have been scrolled already, do we
2227 have to adapt the position */
da048e3d
RR
2228 GtkPizza *pizza = GTK_PIZZA(parent->m_wxwindow);
2229 child->m_x += pizza->xoffset;
2230 child->m_y += pizza->yoffset;
148cd9b6 2231
da048e3d 2232 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
a2053b27
RR
2233 GTK_WIDGET(child->m_widget),
2234 child->m_x,
2235 child->m_y,
2236 child->m_width,
2237 child->m_height );
6ca41e57
RR
2238}
2239
bbe0af5b
RR
2240//-----------------------------------------------------------------------------
2241// global functions
2242//-----------------------------------------------------------------------------
2243
1e6feb95 2244wxWindow *wxGetActiveWindow()
bbe0af5b 2245{
1e6feb95
VZ
2246 // the cast is necessary when we compile in wxUniversal mode
2247 return (wxWindow *)g_focusWindow;
bbe0af5b
RR
2248}
2249
c801d85f 2250//-----------------------------------------------------------------------------
1e6feb95 2251// wxWindowGTK
c801d85f
KB
2252//-----------------------------------------------------------------------------
2253
6522713c
VZ
2254// in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2255// method
1e6feb95 2256#ifdef __WXUNIVERSAL__
6522713c
VZ
2257 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK, wxWindowBase)
2258#else // __WXGTK__
1e6feb95 2259 IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
6522713c 2260#endif // __WXUNIVERSAL__/__WXGTK__
c801d85f 2261
1e6feb95 2262void wxWindowGTK::Init()
c801d85f 2263{
f03fc89f
VZ
2264 // common init
2265 InitBase();
68995f26 2266
f03fc89f 2267 // GTK specific
a2053b27 2268 m_widget = (GtkWidget *) NULL;
e380f72b 2269 m_wxwindow = (GtkWidget *) NULL;
76fcf0f2 2270 m_focusWidget = (GtkWidget *) NULL;
8bbe427f 2271
f03fc89f 2272 // position/size
a2053b27
RR
2273 m_x = 0;
2274 m_y = 0;
2275 m_width = 0;
e380f72b 2276 m_height = 0;
8bbe427f 2277
e380f72b
RR
2278 m_sizeSet = FALSE;
2279 m_hasVMT = FALSE;
2280 m_needParent = TRUE;
31c6b4fc 2281 m_isBeingDeleted = FALSE;
148cd9b6 2282
147bc491 2283 m_noExpose = FALSE;
30760ce7 2284 m_nativeSizeEvent = FALSE;
94633ad9 2285
a2053b27 2286 m_hasScrolling = FALSE;
846e1424 2287 m_isScrolling = FALSE;
f03fc89f 2288
a2053b27 2289 m_hAdjust = (GtkAdjustment*) NULL;
e380f72b 2290 m_vAdjust = (GtkAdjustment*) NULL;
a2053b27 2291 m_oldHorizontalPos = 0.0;
e380f72b 2292 m_oldVerticalPos = 0.0;
8bbe427f 2293
e380f72b 2294 m_resizing = FALSE;
e380f72b 2295 m_widgetStyle = (GtkStyle*) NULL;
8bbe427f 2296
ddb6bc71 2297 m_insertCallback = (wxInsertChildFunction) NULL;
8bbe427f 2298
1ecc4d80 2299 m_isStaticBox = FALSE;
953704c1 2300 m_isRadioButton = FALSE;
e2762ff0 2301 m_isListBox = FALSE;
54517652 2302 m_isFrame = FALSE;
b292e2f5 2303 m_acceptsFocus = FALSE;
148cd9b6 2304
b6fa52db 2305 m_clipPaintRegion = FALSE;
b6fa52db 2306
5e014a0c 2307 m_cursor = *wxSTANDARD_CURSOR;
2daa0ce9 2308
f6bcfd97
BP
2309 m_delayedForegroundColour = FALSE;
2310 m_delayedBackgroundColour = FALSE;
1e6feb95 2311
63081513
RR
2312#ifdef HAVE_XIM
2313 m_ic = (GdkIC*) NULL;
2314 m_icattr = (GdkICAttr*) NULL;
2315#endif
362c6693 2316}
c801d85f 2317
1e6feb95 2318wxWindowGTK::wxWindowGTK()
68995f26
VZ
2319{
2320 Init();
2321}
2322
1e6feb95
VZ
2323wxWindowGTK::wxWindowGTK( wxWindow *parent,
2324 wxWindowID id,
2325 const wxPoint &pos,
2326 const wxSize &size,
2327 long style,
2328 const wxString &name )
6ca41e57 2329{
68995f26
VZ
2330 Init();
2331
e380f72b 2332 Create( parent, id, pos, size, style, name );
6ca41e57 2333}
8bbe427f 2334
1e6feb95
VZ
2335bool wxWindowGTK::Create( wxWindow *parent,
2336 wxWindowID id,
2337 const wxPoint &pos,
2338 const wxSize &size,
2339 long style,
2340 const wxString &name )
c801d85f 2341{
4dcaf11a
RR
2342 if (!PreCreation( parent, pos, size ) ||
2343 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
2344 {
1e6feb95 2345 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
b02da6b1 2346 return FALSE;
4dcaf11a 2347 }
47d67540 2348
ddb6bc71 2349 m_insertCallback = wxInsertChildInWindow;
1e6feb95 2350
e380f72b 2351 m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
38c7b3d3 2352 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
ff8bfdbb 2353
f03fc89f 2354 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
47d67540 2355
dd00f3f6 2356 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
e380f72b 2357 scroll_class->scrollbar_spacing = 0;
47d67540 2358
f03fc89f 2359 gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
47d67540 2360
f03fc89f
VZ
2361 m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->hscrollbar) );
2362 m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->vscrollbar) );
47d67540 2363
da048e3d 2364 m_wxwindow = gtk_pizza_new();
38c7b3d3 2365
034be888 2366 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
58dea4b0 2367
1e6feb95 2368#ifndef __WXUNIVERSAL__
034be888 2369#if (GTK_MINOR_VERSION > 0)
da048e3d 2370 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
b292e2f5 2371
f03fc89f 2372 if (HasFlag(wxRAISED_BORDER))
034be888 2373 {
da048e3d 2374 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_OUT );
034be888 2375 }
f03fc89f 2376 else if (HasFlag(wxSUNKEN_BORDER))
034be888 2377 {
da048e3d 2378 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_IN );
5e014a0c
RR
2379 }
2380 else if (HasFlag(wxSIMPLE_BORDER))
2381 {
da048e3d 2382 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_THIN );
034be888
RR
2383 }
2384 else
2385 {
da048e3d 2386 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_NONE );
034be888 2387 }
f03fc89f
VZ
2388#else // GTK_MINOR_VERSION == 0
2389 GtkViewport *viewport = GTK_VIEWPORT(scrolledWindow->viewport);
b292e2f5 2390
f03fc89f 2391 if (HasFlag(wxRAISED_BORDER))
e380f72b
RR
2392 {
2393 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_OUT );
2394 }
f03fc89f 2395 else if (HasFlag(wxSUNKEN_BORDER))
e380f72b
RR
2396 {
2397 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_IN );
2398 }
2399 else
2400 {
2401 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_NONE );
2402 }
f03fc89f 2403#endif // GTK_MINOR_VERSION
1e6feb95 2404#endif // __WXUNIVERSAL__
47d67540 2405
3da17724
RR
2406 GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
2407 m_acceptsFocus = TRUE;
ca298c88 2408
034be888 2409#if (GTK_MINOR_VERSION == 0)
e380f72b
RR
2410 // shut the viewport up
2411 gtk_viewport_set_hadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
2412 gtk_viewport_set_vadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
f03fc89f 2413#endif // GTK_MINOR_VERSION == 0
e380f72b
RR
2414
2415 // I _really_ don't want scrollbars in the beginning
a2053b27
RR
2416 m_vAdjust->lower = 0.0;
2417 m_vAdjust->upper = 1.0;
2418 m_vAdjust->value = 0.0;
2419 m_vAdjust->step_increment = 1.0;
2420 m_vAdjust->page_increment = 1.0;
2421 m_vAdjust->page_size = 5.0;
2422 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
2423 m_hAdjust->lower = 0.0;
2424 m_hAdjust->upper = 1.0;
2425 m_hAdjust->value = 0.0;
2426 m_hAdjust->step_increment = 1.0;
2427 m_hAdjust->page_increment = 1.0;
2428 m_hAdjust->page_size = 5.0;
2429 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
f03fc89f
VZ
2430
2431 // these handlers block mouse events to any window during scrolling such as
2432 // motion events and prevent GTK and wxWindows from fighting over where the
2433 // slider should be
2434
2435 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_press_event",
76ed8f8d
RR
2436 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2437
f03fc89f 2438 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_press_event",
76ed8f8d
RR
2439 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2440
f03fc89f 2441 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_release_event",
76ed8f8d
RR
2442 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2443
f03fc89f 2444 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_release_event",
76ed8f8d 2445 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
8bbe427f 2446
034be888 2447 // these handlers get notified when screen updates are required either when
76ed8f8d
RR
2448 // scrolling or when the window size (and therefore scrollbar configuration)
2449 // has changed
2450
2451 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
2452 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
2453 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
2454 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
2455
f03fc89f 2456 gtk_widget_show( m_wxwindow );
47d67540 2457
f03fc89f
VZ
2458 if (m_parent)
2459 m_parent->DoAddChild( this );
94633ad9 2460
76fcf0f2 2461 m_focusWidget = m_wxwindow;
8bbe427f 2462
e380f72b 2463 PostCreation();
8bbe427f 2464
e380f72b 2465 Show( TRUE );
c801d85f 2466
e380f72b 2467 return TRUE;
362c6693 2468}
c801d85f 2469
1e6feb95 2470wxWindowGTK::~wxWindowGTK()
c801d85f 2471{
44cd54c2
JS
2472 if (g_focusWindow == this)
2473 g_focusWindow = NULL;
2474
e8c12a53
VS
2475 if (g_activeFrame == this)
2476 g_activeFrame = NULL;
2477
31c6b4fc 2478 m_isBeingDeleted = TRUE;
43a18898 2479 m_hasVMT = FALSE;
47d67540 2480
f03fc89f
VZ
2481 if (m_widget)
2482 Show( FALSE );
8bbe427f 2483
a2053b27
RR
2484 DestroyChildren();
2485
f03fc89f
VZ
2486 if (m_parent)
2487 m_parent->RemoveChild( this );
c801d85f 2488
63081513
RR
2489#ifdef HAVE_XIM
2490 if (m_ic)
2491 gdk_ic_destroy (m_ic);
2492 if (m_icattr)
2493 gdk_ic_attr_destroy (m_icattr);
2494#endif
2495
f03fc89f 2496 if (m_widgetStyle)
a2053b27 2497 {
a56fcaaf 2498#if DISABLE_STYLE_IF_BROKEN_THEME
bce1406b
RR
2499 // don't delete if it's a pixmap theme style
2500 if (!m_widgetStyle->engine_data)
2501 gtk_style_unref( m_widgetStyle );
1e6feb95 2502#endif
c50f1fb9 2503 m_widgetStyle = (GtkStyle*) NULL;
a2053b27 2504 }
c801d85f 2505
f03fc89f 2506 if (m_wxwindow)
a2053b27 2507 {
f03fc89f 2508 gtk_widget_destroy( m_wxwindow );
c50f1fb9 2509 m_wxwindow = (GtkWidget*) NULL;
a2053b27 2510 }
8bbe427f 2511
f03fc89f 2512 if (m_widget)
a2053b27 2513 {
f03fc89f 2514 gtk_widget_destroy( m_widget );
c50f1fb9 2515 m_widget = (GtkWidget*) NULL;
a2053b27 2516 }
362c6693 2517}
c801d85f 2518
1e6feb95 2519bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos, const wxSize &size )
c801d85f 2520{
223d09f6 2521 wxCHECK_MSG( !m_needParent || parent, FALSE, wxT("Need complete parent.") );
8bbe427f 2522
4dcaf11a
RR
2523 /* this turns -1 into 20 so that a minimal window is
2524 visible even although -1,-1 has been given as the
2525 size of the window. the same trick is used in other
2526 ports and should make debugging easier */
f03fc89f
VZ
2527 m_width = WidthDefault(size.x);
2528 m_height = HeightDefault(size.y);
8bbe427f 2529
43a18898
RR
2530 m_x = (int)pos.x;
2531 m_y = (int)pos.y;
8bbe427f 2532
4dcaf11a 2533 /* some reasonable defaults */
148cd9b6 2534 if (!parent)
6ca41e57 2535 {
43a18898
RR
2536 if (m_x == -1)
2537 {
2538 m_x = (gdk_screen_width () - m_width) / 2;
2539 if (m_x < 10) m_x = 10;
2540 }
2541 if (m_y == -1)
2542 {
2543 m_y = (gdk_screen_height () - m_height) / 2;
2544 if (m_y < 10) m_y = 10;
2545 }
6ca41e57 2546 }
148cd9b6 2547
4dcaf11a 2548 return TRUE;
c801d85f
KB
2549}
2550
1e6feb95 2551void wxWindowGTK::PostCreation()
c801d85f 2552{
223d09f6 2553 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
94633ad9 2554
43a18898
RR
2555 if (m_wxwindow)
2556 {
147bc491 2557 if (!m_noExpose)
b02da6b1 2558 {
76fcf0f2 2559 // these get reported to wxWindows -> wxPaintEvent
1e6feb95 2560
b420fb6a
RR
2561 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow), TRUE );
2562
147bc491
RR
2563 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
2564 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
2565
2566 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
2567 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
e22454be
RR
2568
2569 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE))
2570 {
2571 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "event",
2572 GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this );
2573 }
b02da6b1 2574 }
148cd9b6 2575
76fcf0f2 2576 // these are called when the "sunken" or "raised" borders are drawn */
034be888
RR
2577 gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
2578 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
2579
2580 gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
2581 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
43a18898 2582 }
47d67540 2583
76fcf0f2 2584 // focus handling
63081513 2585
76fcf0f2
RR
2586 if (m_focusWidget == NULL)
2587 m_focusWidget = m_widget;
2daa0ce9 2588
76fcf0f2
RR
2589#if 0
2590 if (GetClassInfo() && GetClassInfo()->GetClassName())
2591 wxPrintf( GetClassInfo()->GetClassName() );
2592 wxPrintf( ".\n" );
2593#endif
63081513 2594
76fcf0f2
RR
2595 gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_in_event",
2596 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
2597
2598 gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_out_event",
2599 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
2600
2601 // connect to the various key and mouse handlers
63081513 2602
a2053b27 2603 GtkWidget *connect_widget = GetConnectWidget();
f03fc89f 2604
a2053b27 2605 ConnectWidget( connect_widget );
47d67540 2606
63081513 2607 /* We cannot set colours, fonts and cursors before the widget has
a2053b27
RR
2608 been realized, so we do this directly after realization */
2609 gtk_signal_connect( GTK_OBJECT(connect_widget), "realize",
c50f1fb9 2610 GTK_SIGNAL_FUNC(gtk_window_realized_callback), (gpointer) this );
2daa0ce9 2611
63081513
RR
2612 if (m_wxwindow)
2613 {
47c93b63 2614 // Catch native resize events
8f75cb6c
RR
2615 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2616 GTK_SIGNAL_FUNC(gtk_window_size_callback), (gpointer)this );
2daa0ce9 2617
47c93b63 2618 // Initialize XIM support
63081513
RR
2619 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "realize",
2620 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback), (gpointer) this );
8f75cb6c 2621
47c93b63 2622 // And resize XIM window
b79395c5
RR
2623 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2624 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this );
63081513 2625 }
2daa0ce9 2626
47c93b63
RR
2627 if (!GTK_IS_COMBO(m_widget))
2628 {
2629 // This is needed if we want to add our windows into native
2630 // GTK control, such as the toolbar. With this callback, the
2631 // toolbar gets to know the correct size (the one set by the
2632 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2633 // when moving to GTK 2.0.
2634 gtk_signal_connect( GTK_OBJECT(m_widget), "size_request",
2635 GTK_SIGNAL_FUNC(gtk_window_size_request_callback), (gpointer) this );
2636 }
1e6feb95 2637
43a18898 2638 m_hasVMT = TRUE;
b4071e91
RR
2639}
2640
1e6feb95 2641void wxWindowGTK::ConnectWidget( GtkWidget *widget )
b4071e91 2642{
43a18898
RR
2643 gtk_signal_connect( GTK_OBJECT(widget), "key_press_event",
2644 GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this );
c801d85f 2645
b666df2c
RR
2646 gtk_signal_connect( GTK_OBJECT(widget), "key_release_event",
2647 GTK_SIGNAL_FUNC(gtk_window_key_release_callback), (gpointer)this );
2648
43a18898
RR
2649 gtk_signal_connect( GTK_OBJECT(widget), "button_press_event",
2650 GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
47d67540 2651
43a18898
RR
2652 gtk_signal_connect( GTK_OBJECT(widget), "button_release_event",
2653 GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
47d67540 2654
43a18898
RR
2655 gtk_signal_connect( GTK_OBJECT(widget), "motion_notify_event",
2656 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
47d67540 2657
43a18898
RR
2658 gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event",
2659 GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
47d67540 2660
43a18898
RR
2661 gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
2662 GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
362c6693 2663}
c801d85f 2664
1e6feb95 2665bool wxWindowGTK::Destroy()
c801d85f 2666{
223d09f6 2667 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
47d67540 2668
43a18898 2669 m_hasVMT = FALSE;
c801d85f 2670
f03fc89f 2671 return wxWindowBase::Destroy();
362c6693 2672}
c801d85f 2673
1e6feb95 2674void wxWindowGTK::DoMoveWindow(int x, int y, int width, int height)
23efdd02
RR
2675{
2676 gtk_pizza_set_size( GTK_PIZZA(m_parent->m_wxwindow), m_widget, x, y, width, height );
2677}
2daa0ce9 2678
1e6feb95 2679void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
c801d85f 2680{
223d09f6 2681 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
1e6feb95 2682 wxASSERT_MSG( (m_parent != NULL), wxT("wxWindowGTK::SetSize requires parent.\n") );
8bbe427f 2683
33611ebb 2684/*
f94fca1b 2685 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
33611ebb
RR
2686*/
2687
e27ce4e9 2688 if (m_resizing) return; /* I don't like recursions */
fb1585ae 2689 m_resizing = TRUE;
1e6feb95 2690
b9f29261
VS
2691 int currentX, currentY;
2692 GetPosition(&currentX, &currentY);
2693 if (x == -1)
2694 x = currentX;
a200c35e 2695 if (y == -1)
b9f29261 2696 y = currentY;
a200c35e
VS
2697 AdjustForParentClientOrigin(x, y, sizeFlags);
2698
a2053b27 2699 if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
fb1585ae 2700 {
e27ce4e9 2701 /* don't set the size for children of wxNotebook, just take the values. */
fb1585ae
RR
2702 m_x = x;
2703 m_y = y;
2704 m_width = width;
ba4e3652 2705 m_height = height;
fb1585ae 2706 }
ba4e3652 2707 else
fb1585ae 2708 {
da048e3d 2709 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
148cd9b6 2710
85ad5eb5 2711 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
ba4e3652 2712 {
da048e3d
RR
2713 if (x != -1) m_x = x + pizza->xoffset;
2714 if (y != -1) m_y = y + pizza->yoffset;
ba4e3652
RR
2715 if (width != -1) m_width = width;
2716 if (height != -1) m_height = height;
2717 }
2718 else
2719 {
da048e3d
RR
2720 m_x = x + pizza->xoffset;
2721 m_y = y + pizza->yoffset;
ba4e3652
RR
2722 m_width = width;
2723 m_height = height;
2724 }
47d67540 2725
ba4e3652
RR
2726 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
2727 {
2728 if (width == -1) m_width = 80;
2729 }
2730
2731 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
2732 {
2733 if (height == -1) m_height = 26;
2734 }
8bbe427f 2735
e7dda1ff
VS
2736 int minWidth = GetMinWidth(),
2737 minHeight = GetMinHeight(),
2738 maxWidth = GetMaxWidth(),
2739 maxHeight = GetMaxHeight();
2740
2741 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
2742 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
2743 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
2744 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
47d67540 2745
a2053b27 2746 int border = 0;
c50f1fb9 2747 int bottom_border = 0;
f03fc89f 2748
29f538ce 2749 if (GTK_WIDGET_CAN_DEFAULT(m_widget))
c50f1fb9
VZ
2750 {
2751 /* the default button has a border around it */
2752 border = 6;
2753 bottom_border = 5;
2754 }
2755
23efdd02
RR
2756 DoMoveWindow( m_x-border,
2757 m_y-border,
2758 m_width+2*border,
2759 m_height+border+bottom_border );
54517652 2760 }
148cd9b6 2761
5b8a521e
RR
2762 if (m_hasScrolling)
2763 {
1e6feb95 2764 /* Sometimes the client area changes size without the
b6fa52db
RR
2765 whole windows's size changing, but if the whole
2766 windows's size doesn't change, no wxSizeEvent will
2767 normally be sent. Here we add an extra test if
2768 the client test has been changed and this will
2769 be used then. */
5b8a521e
RR
2770 GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
2771 }
2772
54517652 2773/*
6d693bb4
RR
2774 wxPrintf( "OnSize sent from " );
2775 if (GetClassInfo() && GetClassInfo()->GetClassName())
2776 wxPrintf( GetClassInfo()->GetClassName() );
2777 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2778*/
2779
30760ce7
RR
2780 if (!m_nativeSizeEvent)
2781 {
2782 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
2783 event.SetEventObject( this );
2784 GetEventHandler()->ProcessEvent( event );
2785 }
6d693bb4 2786
fb1585ae 2787 m_resizing = FALSE;
362c6693 2788}
c801d85f 2789
1e6feb95 2790void wxWindowGTK::OnInternalIdle()
9390a202 2791{
beab25bd
RR
2792 // Update invalidated regions.
2793 Update();
2794
2795 // Synthetize activate events.
148cd9b6
VZ
2796 if ( g_sendActivateEvent != -1 )
2797 {
2798 bool activate = g_sendActivateEvent != 0;
2799
2800 // do it only once
2801 g_sendActivateEvent = -1;
2802
1e6feb95 2803 wxTheApp->SetActive(activate, (wxWindow *)g_focusWindowLast);
148cd9b6
VZ
2804 }
2805
e8c12a53
VS
2806 if ( g_activeFrameLostFocus )
2807 {
2808 if ( g_activeFrame )
2809 {
45eb5249 2810 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame);
e8c12a53
VS
2811 wxActivateEvent event(wxEVT_ACTIVATE, FALSE, g_activeFrame->GetId());
2812 event.SetEventObject(g_activeFrame);
2813 g_activeFrame->GetEventHandler()->ProcessEvent(event);
2814 g_activeFrame = NULL;
2815 }
2816 g_activeFrameLostFocus = FALSE;
2817 }
2818
9146082c
RR
2819 wxCursor cursor = m_cursor;
2820 if (g_globalCursor.Ok()) cursor = g_globalCursor;
c50f1fb9 2821
f7a11f8c 2822 if (cursor.Ok())
9146082c 2823 {
3017f78d 2824 /* I now set the cursor anew in every OnInternalIdle call
b02da6b1
VZ
2825 as setting the cursor in a parent window also effects the
2826 windows above so that checking for the current cursor is
2827 not possible. */
148cd9b6 2828
9146082c 2829 if (m_wxwindow)
6a008b33 2830 {
da048e3d 2831 GdkWindow *window = GTK_PIZZA(m_wxwindow)->bin_window;
6a008b33 2832 if (window)
c50f1fb9 2833 gdk_window_set_cursor( window, cursor.GetCursor() );
6a008b33
VZ
2834
2835 if (!g_globalCursor.Ok())
2836 cursor = *wxSTANDARD_CURSOR;
2837
2838 window = m_widget->window;
5e014a0c 2839 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
9146082c 2840 gdk_window_set_cursor( window, cursor.GetCursor() );
5e014a0c 2841
6a008b33
VZ
2842 }
2843 else
2844 {
5e014a0c 2845
9146082c 2846 GdkWindow *window = m_widget->window;
5e014a0c 2847 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
9146082c 2848 gdk_window_set_cursor( window, cursor.GetCursor() );
5e014a0c 2849
6a008b33 2850 }
9146082c 2851 }
6a008b33 2852
9390a202
RR
2853 UpdateWindowUI();
2854}
2855
1e6feb95 2856void wxWindowGTK::DoGetSize( int *width, int *height ) const
c801d85f 2857{
223d09f6 2858 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 2859
fb1585ae
RR
2860 if (width) (*width) = m_width;
2861 if (height) (*height) = m_height;
362c6693 2862}
c801d85f 2863
1e6feb95 2864void wxWindowGTK::DoSetClientSize( int width, int height )
c801d85f 2865{
223d09f6 2866 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 2867
1ecc4d80 2868 if (!m_wxwindow)
c801d85f 2869 {
1ecc4d80 2870 SetSize( width, height );
c801d85f
KB
2871 }
2872 else
2873 {
1ecc4d80
RR
2874 int dw = 0;
2875 int dh = 0;
2876
1e6feb95 2877#ifndef __WXUNIVERSAL__
98d3fdbe
RR
2878 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
2879 {
5e014a0c 2880 /* when using GTK 1.2 we set the shadow border size to 2 */
6a008b33 2881 dw += 2 * 2;
98d3fdbe
RR
2882 dh += 2 * 2;
2883 }
5e014a0c
RR
2884 if (HasFlag(wxSIMPLE_BORDER))
2885 {
2886 /* when using GTK 1.2 we set the simple border size to 1 */
2887 dw += 1 * 2;
2888 dh += 1 * 2;
2889 }
1e6feb95 2890#endif // __WXUNIVERSAL__
034be888 2891
5b8a521e 2892 if (m_hasScrolling)
98d3fdbe 2893 {
324dbfec 2894 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2daa0ce9 2895
9000c624
RR
2896 GtkRequisition vscroll_req;
2897 vscroll_req.width = 2;
2898 vscroll_req.height = 2;
dd00f3f6 2899 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
9000c624 2900 (scroll_window->vscrollbar, &vscroll_req );
2daa0ce9 2901
9000c624
RR
2902 GtkRequisition hscroll_req;
2903 hscroll_req.width = 2;
2904 hscroll_req.height = 2;
dd00f3f6 2905 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
9000c624
RR
2906 (scroll_window->hscrollbar, &hscroll_req );
2907
dd00f3f6 2908 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
324dbfec 2909
1ecc4d80
RR
2910 if (scroll_window->vscrollbar_visible)
2911 {
9000c624 2912 dw += vscroll_req.width;
1ecc4d80
RR
2913 dw += scroll_class->scrollbar_spacing;
2914 }
2915
2916 if (scroll_window->hscrollbar_visible)
2917 {
9000c624 2918 dh += hscroll_req.height;
63cc5d9d 2919 dh += scroll_class->scrollbar_spacing;
1ecc4d80 2920 }
9000c624 2921 }
1ecc4d80 2922
034be888 2923 SetSize( width+dw, height+dh );
1ecc4d80 2924 }
362c6693 2925}
c801d85f 2926
1e6feb95 2927void wxWindowGTK::DoGetClientSize( int *width, int *height ) const
c801d85f 2928{
223d09f6 2929 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 2930
1ecc4d80
RR
2931 if (!m_wxwindow)
2932 {
2933 if (width) (*width) = m_width;
2934 if (height) (*height) = m_height;
c801d85f
KB
2935 }
2936 else
2937 {
1ecc4d80
RR
2938 int dw = 0;
2939 int dh = 0;
2940
1e6feb95 2941#ifndef __WXUNIVERSAL__
98d3fdbe
RR
2942 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
2943 {
5e014a0c 2944 /* when using GTK 1.2 we set the shadow border size to 2 */
6a008b33 2945 dw += 2 * 2;
98d3fdbe
RR
2946 dh += 2 * 2;
2947 }
5e014a0c
RR
2948 if (HasFlag(wxSIMPLE_BORDER))
2949 {
2950 /* when using GTK 1.2 we set the simple border size to 1 */
2951 dw += 1 * 2;
2952 dh += 1 * 2;
2953 }
1e6feb95 2954#endif // __WXUNIVERSAL__
9000c624 2955
5b8a521e 2956 if (m_hasScrolling)
98d3fdbe 2957 {
6a008b33 2958 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2daa0ce9 2959
9000c624
RR
2960 GtkRequisition vscroll_req;
2961 vscroll_req.width = 2;
2962 vscroll_req.height = 2;
dd00f3f6 2963 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
9000c624 2964 (scroll_window->vscrollbar, &vscroll_req );
2daa0ce9 2965
9000c624
RR
2966 GtkRequisition hscroll_req;
2967 hscroll_req.width = 2;
2968 hscroll_req.height = 2;
dd00f3f6 2969 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
9000c624
RR
2970 (scroll_window->hscrollbar, &hscroll_req );
2971
dd00f3f6 2972 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
6a008b33 2973
1ecc4d80
RR
2974 if (scroll_window->vscrollbar_visible)
2975 {
9000c624 2976 dw += vscroll_req.width;
1ecc4d80
RR
2977 dw += scroll_class->scrollbar_spacing;
2978 }
2979
2980 if (scroll_window->hscrollbar_visible)
2981 {
9000c624 2982 dh += hscroll_req.height;
1ecc4d80
RR
2983 dh += scroll_class->scrollbar_spacing;
2984 }
6a008b33 2985 }
47d67540 2986
1ecc4d80
RR
2987 if (width) (*width) = m_width - dw;
2988 if (height) (*height) = m_height - dh;
2989 }
1e6feb95 2990
f94fca1b
RR
2991/*
2992 printf( "GetClientSize, name %s ", GetName().c_str() );
2993 if (width) printf( " width = %d", (*width) );
2994 if (height) printf( " height = %d", (*height) );
2995 printf( "\n" );
2996*/
362c6693 2997}
c801d85f 2998
1e6feb95 2999void wxWindowGTK::DoGetPosition( int *x, int *y ) const
c801d85f 3000{
223d09f6 3001 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3002
bf0c00c6
RR
3003 int dx = 0;
3004 int dy = 0;
3005 if (m_parent && m_parent->m_wxwindow)
3006 {
da048e3d 3007 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
b02da6b1
VZ
3008 dx = pizza->xoffset;
3009 dy = pizza->yoffset;
bf0c00c6 3010 }
94633ad9 3011
496beb3f
VS
3012 if (x) (*x) = m_x - dx;
3013 if (y) (*y) = m_y - dy;
362c6693 3014}
c801d85f 3015
1e6feb95 3016void wxWindowGTK::DoClientToScreen( int *x, int *y ) const
c801d85f 3017{
223d09f6 3018 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3019
a2053b27
RR
3020 if (!m_widget->window) return;
3021
43a18898
RR
3022 GdkWindow *source = (GdkWindow *) NULL;
3023 if (m_wxwindow)
da048e3d 3024 source = GTK_PIZZA(m_wxwindow)->bin_window;
43a18898
RR
3025 else
3026 source = m_widget->window;
47d67540 3027
43a18898
RR
3028 int org_x = 0;
3029 int org_y = 0;
3030 gdk_window_get_origin( source, &org_x, &org_y );
c801d85f 3031
43a18898 3032 if (!m_wxwindow)
c801d85f 3033 {
43a18898
RR
3034 if (GTK_WIDGET_NO_WINDOW (m_widget))
3035 {
3036 org_x += m_widget->allocation.x;
3037 org_y += m_widget->allocation.y;
3038 }
362c6693 3039 }
47d67540 3040
43a18898
RR
3041 if (x) *x += org_x;
3042 if (y) *y += org_y;
362c6693 3043}
c801d85f 3044
1e6feb95 3045void wxWindowGTK::DoScreenToClient( int *x, int *y ) const
c801d85f 3046{
223d09f6 3047 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3048
a2053b27
RR
3049 if (!m_widget->window) return;
3050
1ecc4d80
RR
3051 GdkWindow *source = (GdkWindow *) NULL;
3052 if (m_wxwindow)
da048e3d 3053 source = GTK_PIZZA(m_wxwindow)->bin_window;
1ecc4d80
RR
3054 else
3055 source = m_widget->window;
47d67540 3056
1ecc4d80
RR
3057 int org_x = 0;
3058 int org_y = 0;
3059 gdk_window_get_origin( source, &org_x, &org_y );
c801d85f 3060
1ecc4d80 3061 if (!m_wxwindow)
c801d85f 3062 {
1ecc4d80
RR
3063 if (GTK_WIDGET_NO_WINDOW (m_widget))
3064 {
3065 org_x += m_widget->allocation.x;
3066 org_y += m_widget->allocation.y;
3067 }
362c6693 3068 }
47d67540 3069
1ecc4d80
RR
3070 if (x) *x -= org_x;
3071 if (y) *y -= org_y;
362c6693 3072}
c801d85f 3073
1e6feb95 3074bool wxWindowGTK::Show( bool show )
c801d85f 3075{
223d09f6 3076 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
47d67540 3077
739730ca
RR
3078 if (!wxWindowBase::Show(show))
3079 {
3080 // nothing to do
f03fc89f 3081 return FALSE;
739730ca 3082 }
8bbe427f 3083
f03fc89f
VZ
3084 if (show)
3085 gtk_widget_show( m_widget );
1ecc4d80 3086 else
f03fc89f 3087 gtk_widget_hide( m_widget );
8bbe427f 3088
f03fc89f 3089 return TRUE;
362c6693 3090}
c801d85f 3091
3379ed37 3092static void wxWindowNotifyEnable(wxWindowGTK* win, bool enable)
fdca68a6
JS
3093{
3094 win->OnParentEnable(enable);
3095
3096 // Recurse, so that children have the opportunity to Do The Right Thing
3097 // and reset colours that have been messed up by a parent's (really ancestor's)
3098 // Enable call
3099 for ( wxWindowList::Node *node = win->GetChildren().GetFirst();
3100 node;
3101 node = node->GetNext() )
3102 {
3103 wxWindow *child = node->GetData();
3104 if (!child->IsKindOf(CLASSINFO(wxDialog)) && !child->IsKindOf(CLASSINFO(wxFrame)))
3105 wxWindowNotifyEnable(child, enable);
3106 }
3107}
3108
3379ed37 3109bool wxWindowGTK::Enable( bool enable )
c801d85f 3110{
223d09f6 3111 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
5e0aa05a 3112
739730ca
RR
3113 if (!wxWindowBase::Enable(enable))
3114 {
3115 // nothing to do
f03fc89f 3116 return FALSE;
739730ca 3117 }
1ecc4d80 3118
f03fc89f
VZ
3119 gtk_widget_set_sensitive( m_widget, enable );
3120 if ( m_wxwindow )
3121 gtk_widget_set_sensitive( m_wxwindow, enable );
ff8bfdbb 3122
fdca68a6 3123 wxWindowNotifyEnable(this, enable);
513903c4 3124
f03fc89f 3125 return TRUE;
362c6693 3126}
c801d85f 3127
1e6feb95 3128int wxWindowGTK::GetCharHeight() const
2f2aa628 3129{
223d09f6 3130 wxCHECK_MSG( (m_widget != NULL), 12, wxT("invalid window") );
47d67540 3131
223d09f6 3132 wxCHECK_MSG( m_font.Ok(), 12, wxT("invalid font") );
2f2aa628 3133
f03fc89f
VZ
3134 GdkFont *font = m_font.GetInternalFont( 1.0 );
3135
3136 return font->ascent + font->descent;
362c6693 3137}
c801d85f 3138
1e6feb95 3139int wxWindowGTK::GetCharWidth() const
c33c4050 3140{
223d09f6 3141 wxCHECK_MSG( (m_widget != NULL), 8, wxT("invalid window") );
47d67540 3142
223d09f6 3143 wxCHECK_MSG( m_font.Ok(), 8, wxT("invalid font") );
47d67540 3144
463c1fa1 3145 GdkFont *font = m_font.GetInternalFont( 1.0 );
ff8bfdbb 3146
463c1fa1 3147 return gdk_string_width( font, "H" );
c33c4050
RR
3148}
3149
1e6feb95 3150void wxWindowGTK::GetTextExtent( const wxString& string,
f03fc89f
VZ
3151 int *x,
3152 int *y,
3153 int *descent,
3154 int *externalLeading,
3155 const wxFont *theFont ) const
c33c4050 3156{
463c1fa1
RR
3157 wxFont fontToUse = m_font;
3158 if (theFont) fontToUse = *theFont;
47d67540 3159
223d09f6 3160 wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
47d67540 3161
463c1fa1 3162 GdkFont *font = fontToUse.GetInternalFont( 1.0 );
05939a81 3163 if (x) (*x) = gdk_string_width( font, string.mbc_str() );
463c1fa1
RR
3164 if (y) (*y) = font->ascent + font->descent;
3165 if (descent) (*descent) = font->descent;
3166 if (externalLeading) (*externalLeading) = 0; // ??
c33c4050
RR
3167}
3168
1e6feb95 3169void wxWindowGTK::SetFocus()
c801d85f 3170{
223d09f6 3171 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2daa0ce9 3172
780bb874
RR
3173#if 0
3174 wxPrintf( "SetFocus from " );
3175 if (GetClassInfo() && GetClassInfo()->GetClassName())
3176 wxPrintf( GetClassInfo()->GetClassName() );
3177 wxPrintf( ".\n" );
3178#endif
3179
354aa1e3
RR
3180 if (m_wxwindow)
3181 {
173348db 3182 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
b231914f
VZ
3183 {
3184 // see comment in gtk_window_focus_out_callback()
3185 gs_widgetLastFocus = m_wxwindow;
173348db 3186 gtk_widget_grab_focus (m_wxwindow);
b231914f 3187 }
354aa1e3 3188 }
b231914f 3189 else if (m_widget)
c801d85f 3190 {
173348db 3191 if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
463c1fa1 3192 {
354aa1e3 3193 gtk_widget_grab_focus (m_widget);
463c1fa1 3194 }
354aa1e3 3195 else if (GTK_IS_CONTAINER(m_widget))
ff8bfdbb 3196 {
354aa1e3 3197 gtk_container_focus( GTK_CONTAINER(m_widget), GTK_DIR_TAB_FORWARD );
ff8bfdbb
VZ
3198 }
3199 else
3200 {
b02da6b1 3201 // ?
ff8bfdbb 3202 }
362c6693 3203 }
94633ad9 3204
780bb874
RR
3205#if 0
3206 wxPrintf( "SetFocus finished in " );
3207 if (GetClassInfo() && GetClassInfo()->GetClassName())
3208 wxPrintf( GetClassInfo()->GetClassName() );
3209 wxPrintf( ".\n" );
3210#endif
3211
362c6693 3212}
c801d85f 3213
1e6feb95 3214bool wxWindowGTK::AcceptsFocus() const
b292e2f5 3215{
f03fc89f 3216 return m_acceptsFocus && wxWindowBase::AcceptsFocus();
b292e2f5
RR
3217}
3218
1e6feb95 3219bool wxWindowGTK::Reparent( wxWindowBase *newParentBase )
463c1fa1 3220{
223d09f6 3221 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
c50f1fb9 3222
1e6feb95
VZ
3223 wxWindowGTK *oldParent = m_parent,
3224 *newParent = (wxWindowGTK *)newParentBase;
a2053b27 3225
5fd11f09
RR
3226 wxASSERT( GTK_IS_WIDGET(m_widget) );
3227
f03fc89f
VZ
3228 if ( !wxWindowBase::Reparent(newParent) )
3229 return FALSE;
8bbe427f 3230
5fd11f09
RR
3231 wxASSERT( GTK_IS_WIDGET(m_widget) );
3232
3233 /* prevent GTK from deleting the widget arbitrarily */
3234 gtk_widget_ref( m_widget );
3235
8ce63e9d
RR
3236 if (oldParent)
3237 {
3017f78d 3238 gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget );
8ce63e9d 3239 }
c50f1fb9 3240
5fd11f09
RR
3241 wxASSERT( GTK_IS_WIDGET(m_widget) );
3242
8ce63e9d
RR
3243 if (newParent)
3244 {
3245 /* insert GTK representation */
3246 (*(newParent->m_insertCallback))(newParent, this);
3247 }
c50f1fb9 3248
5fd11f09
RR
3249 /* reverse: prevent GTK from deleting the widget arbitrarily */
3250 gtk_widget_unref( m_widget );
148cd9b6 3251
f03fc89f 3252 return TRUE;
362c6693 3253}
c801d85f 3254
1e6feb95 3255void wxWindowGTK::DoAddChild(wxWindowGTK *child)
ddb6bc71 3256{
223d09f6 3257 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
ddb6bc71 3258
223d09f6 3259 wxASSERT_MSG( (child != NULL), wxT("invalid child window") );
ddb6bc71 3260
223d09f6 3261 wxASSERT_MSG( (m_insertCallback != NULL), wxT("invalid child insertion function") );
c50f1fb9 3262
ddb6bc71
RR
3263 /* add to list */
3264 AddChild( child );
c50f1fb9 3265
ddb6bc71
RR
3266 /* insert GTK representation */
3267 (*m_insertCallback)(this, child);
3268}
3269
1e6feb95 3270void wxWindowGTK::Raise()
362c6693 3271{
223d09f6 3272 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3273
a2053b27
RR
3274 if (!m_widget->window) return;
3275
f03fc89f 3276 gdk_window_raise( m_widget->window );
362c6693
RR
3277}
3278
1e6feb95 3279void wxWindowGTK::Lower()
362c6693 3280{
223d09f6 3281 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3282
a2053b27
RR
3283 if (!m_widget->window) return;
3284
f03fc89f 3285 gdk_window_lower( m_widget->window );
362c6693 3286}
c801d85f 3287
1e6feb95 3288bool wxWindowGTK::SetCursor( const wxCursor &cursor )
86b29a61 3289{
223d09f6 3290 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
86b29a61 3291
f6bcfd97
BP
3292 if (cursor == m_cursor)
3293 return FALSE;
3294
3295 if (g_isIdle)
3296 wxapp_install_idle_handler();
1e6feb95 3297
f6bcfd97
BP
3298 if (cursor == wxNullCursor)
3299 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR );
3300 else
3301 return wxWindowBase::SetCursor( cursor );
362c6693 3302}
c801d85f 3303
1e6feb95 3304void wxWindowGTK::WarpPointer( int x, int y )
4f22cf8d 3305{
223d09f6 3306 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
85eb36c2 3307
3bcc8d15
RR
3308 // We provide this function ourselves as it is
3309 // missing in GDK (top of this file).
148cd9b6 3310
ed673c6a
RR
3311 GdkWindow *window = (GdkWindow*) NULL;
3312 if (m_wxwindow)
da048e3d 3313 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a
RR
3314 else
3315 window = GetConnectWidget()->window;
148cd9b6 3316
ed673c6a
RR
3317 if (window)
3318 gdk_window_warp_pointer( window, x, y );
4f22cf8d
RR
3319}
3320
1e6feb95 3321void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
c801d85f 3322{
f2593d0d 3323 if (!m_widget) return;
a2053b27
RR
3324 if (!m_widget->window) return;
3325
1e6feb95
VZ
3326 // temporarily hide the caret to avoid nasty interactions between caret
3327 // drawing and the window contents redraw
3328#if 0 // def wxUSE_CARET -- doesn't seem to help :-(
3329 wxCaretSuspend cs((wxWindow *)this);
3330#endif // wxUSE_CARET
3331
139adb6a 3332 if (eraseBackground && m_wxwindow && m_wxwindow->window)
c801d85f 3333 {
139adb6a
RR
3334 if (rect)
3335 {
3bcc8d15
RR
3336 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3337 m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height );
139adb6a
RR
3338 }
3339 else
3340 {
3bcc8d15
RR
3341 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3342 m_clearRegion.Clear();
3343 m_clearRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
139adb6a
RR
3344 }
3345 }
ff8bfdbb 3346
3bcc8d15 3347 if (rect)
139adb6a
RR
3348 {
3349 if (m_wxwindow)
b02da6b1 3350 {
23716407 3351 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3bcc8d15 3352 m_updateRegion.Union( rect->x, rect->y, rect->width, rect->height );
b02da6b1 3353 }
ff8bfdbb 3354 else
b6fa52db 3355 {
3bcc8d15
RR
3356 GdkRectangle gdk_rect;
3357 gdk_rect.x = rect->x;
3358 gdk_rect.y = rect->y;
3359 gdk_rect.width = rect->width;
3360 gdk_rect.height = rect->height;
3361 gtk_widget_draw( m_widget, &gdk_rect );
b6fa52db 3362 }
362c6693 3363 }
c801d85f 3364 else
139adb6a 3365 {
139adb6a 3366 if (m_wxwindow)
b02da6b1 3367 {
23716407 3368 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3bcc8d15
RR
3369 m_updateRegion.Clear();
3370 m_updateRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
b02da6b1 3371 }
139adb6a 3372 else
b6fa52db 3373 {
3bcc8d15 3374 gtk_widget_draw( m_widget, (GdkRectangle*) NULL );
b6fa52db 3375 }
139adb6a 3376 }
362c6693 3377}
c801d85f 3378
beab25bd
RR
3379void wxWindowGTK::Update()
3380{
3381 if (!m_updateRegion.IsEmpty())
3382 {
23716407 3383 GtkSendPaintEvents();
beab25bd
RR
3384 }
3385}
3386
3387void wxWindowGTK::GtkSendPaintEvents()
3388{
3bcc8d15
RR
3389 if (!m_wxwindow)
3390 {
3391 m_clearRegion.Clear();
3392 m_updateRegion.Clear();
3393 return;
3394 }
beab25bd 3395
3bcc8d15 3396 m_clipPaintRegion = TRUE;
beab25bd 3397
2e09dc2d 3398 // if (!m_clearRegion.IsEmpty()) // always send an erase event
beab25bd 3399 {
3bcc8d15
RR
3400 wxWindowDC dc( (wxWindow*)this );
3401 dc.SetClippingRegion( m_clearRegion );
3402
3403 wxEraseEvent erase_event( GetId(), &dc );
3404 erase_event.SetEventObject( this );
3405
beab25bd
RR
3406 if (!GetEventHandler()->ProcessEvent(erase_event))
3407 {
3bcc8d15 3408 wxRegionIterator upd( m_clearRegion );
beab25bd
RR
3409 while (upd)
3410 {
3bcc8d15
RR
3411 gdk_window_clear_area( GTK_PIZZA(m_wxwindow)->bin_window,
3412 upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
beab25bd
RR
3413 upd ++;
3414 }
3415 }
3bcc8d15 3416 m_clearRegion.Clear();
beab25bd 3417 }
beab25bd
RR
3418
3419 wxNcPaintEvent nc_paint_event( GetId() );
3420 nc_paint_event.SetEventObject( this );
3421 GetEventHandler()->ProcessEvent( nc_paint_event );
3422
3423 wxPaintEvent paint_event( GetId() );
3424 paint_event.SetEventObject( this );
3425 GetEventHandler()->ProcessEvent( paint_event );
3426
beab25bd 3427 m_clipPaintRegion = FALSE;
c89f5c02 3428
8f3e7ecc
RR
3429#ifndef __WXUNIVERSAL__
3430 // The following code will result in all window-less widgets
3431 // being redrawn because the wxWindows class is allowed to
3432 // paint over the window-less widgets.
3433
c89f5c02 3434 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
8f3e7ecc
RR
3435
3436 GList *children = pizza->children;
3437 while (children)
c89f5c02 3438 {
8f3e7ecc
RR
3439 GtkPizzaChild *child = (GtkPizzaChild*) children->data;
3440 children = children->next;
c89f5c02 3441
8f3e7ecc
RR
3442 if (GTK_WIDGET_NO_WINDOW (child->widget) &&
3443 GTK_WIDGET_DRAWABLE (child->widget))
3444 {
3445 // Get intersection of widget area and update region
3446 wxRegion region( m_updateRegion );
3447
3448 GdkEventExpose gdk_event;
3449 gdk_event.type = GDK_EXPOSE;
3450 gdk_event.window = pizza->bin_window;
3451 gdk_event.count = 0;
3452
3453 wxRegionIterator upd( m_updateRegion );
3454 while (upd)
c89f5c02 3455 {
8f3e7ecc
RR
3456 GdkRectangle rect;
3457 rect.x = upd.GetX();
3458 rect.y = upd.GetY();
3459 rect.width = upd.GetWidth();
3460 rect.height = upd.GetHeight();
c89f5c02 3461
8f3e7ecc
RR
3462 if (gtk_widget_intersect (child->widget, &rect, &gdk_event.area))
3463 {
3464 gtk_widget_event (child->widget, (GdkEvent*) &gdk_event);
3465 }
3466
3467 upd ++;
c89f5c02
RR
3468 }
3469 }
3470 }
8f3e7ecc 3471#endif
c89f5c02
RR
3472
3473 m_updateRegion.Clear();
beab25bd
RR
3474}
3475
1e6feb95 3476void wxWindowGTK::Clear()
c801d85f 3477{
223d09f6 3478 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
47d67540 3479
a2053b27
RR
3480 if (!m_widget->window) return;
3481
f234c60c
RR
3482 if (m_wxwindow && m_wxwindow->window)
3483 {
c916e13b 3484// gdk_window_clear( m_wxwindow->window );
f234c60c 3485 }
362c6693 3486}
c801d85f 3487
ff8bfdbb 3488#if wxUSE_TOOLTIPS
1e6feb95 3489void wxWindowGTK::DoSetToolTip( wxToolTip *tip )
b1170810 3490{
f03fc89f 3491 wxWindowBase::DoSetToolTip(tip);
ff8bfdbb 3492
f03fc89f 3493 if (m_tooltip)
3379ed37 3494 m_tooltip->Apply( (wxWindow *)this );
b1170810
RR
3495}
3496
1e6feb95 3497void wxWindowGTK::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
b1170810 3498{
dcf924a3 3499 gtk_tooltips_set_tip( tips, GetConnectWidget(), wxConvCurrent->cWX2MB(tip), (gchar*) NULL );
301cd871 3500}
ff8bfdbb 3501#endif // wxUSE_TOOLTIPS
b1170810 3502
1e6feb95 3503bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
c801d85f 3504{
223d09f6 3505 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
8bbe427f 3506
739730ca
RR
3507 if (!wxWindowBase::SetBackgroundColour(colour))
3508 {
3509 // don't leave if the GTK widget has just
3510 // been realized
3511 if (!m_delayedBackgroundColour) return FALSE;
3512 }
c50f1fb9 3513
ed673c6a
RR
3514 GdkWindow *window = (GdkWindow*) NULL;
3515 if (m_wxwindow)
da048e3d 3516 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a
RR
3517 else
3518 window = GetConnectWidget()->window;
148cd9b6 3519
ed673c6a 3520 if (!window)
739730ca
RR
3521 {
3522 // indicate that a new style has been set
c50f1fb9
VZ
3523 // but it couldn't get applied as the
3524 // widget hasn't been realized yet.
3525 m_delayedBackgroundColour = TRUE;
739730ca 3526 }
ca298c88 3527
0f2f4986 3528 if ((m_wxwindow) &&
103aab26 3529 (m_wxwindow->window) &&
a756f210 3530 (m_backgroundColour != wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)))
3bc755fc 3531 {
a2053b27
RR
3532 /* wxMSW doesn't clear the window here. I don't do that either to
3533 provide compatibility. call Clear() to do the job. */
ca298c88 3534
ed673c6a
RR
3535 m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
3536 gdk_window_set_background( window, m_backgroundColour.GetColor() );
3bc755fc 3537 }
8bbe427f 3538
0f2f4986 3539 ApplyWidgetStyle();
c801d85f 3540
f03fc89f 3541 return TRUE;
6de97a3b
RR
3542}
3543
1e6feb95 3544bool wxWindowGTK::SetForegroundColour( const wxColour &colour )
6de97a3b 3545{
223d09f6 3546 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
8bbe427f 3547
739730ca
RR
3548 if (!wxWindowBase::SetForegroundColour(colour))
3549 {
3550 // don't leave if the GTK widget has just
3551 // been realized
3552 if (!m_delayedForegroundColour) return FALSE;
3553 }
c50f1fb9 3554
ed673c6a
RR
3555 GdkWindow *window = (GdkWindow*) NULL;
3556 if (m_wxwindow)
da048e3d 3557 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a
RR
3558 else
3559 window = GetConnectWidget()->window;
148cd9b6 3560
ed673c6a 3561 if (!window)
739730ca
RR
3562 {
3563 // indicate that a new style has been set
c50f1fb9
VZ
3564 // but it couldn't get applied as the
3565 // widget hasn't been realized yet.
3566 m_delayedForegroundColour = TRUE;
739730ca 3567 }
2b07d713 3568
0f2f4986 3569 ApplyWidgetStyle();
f03fc89f
VZ
3570
3571 return TRUE;
58614078
RR
3572}
3573
1e6feb95 3574GtkStyle *wxWindowGTK::GetWidgetStyle()
58614078 3575{
103aab26
RR
3576 if (m_widgetStyle)
3577 {
3578 GtkStyle *remake = gtk_style_copy( m_widgetStyle );
dd00f3f6
OK
3579#ifdef __WXGTK20__
3580 /* FIXME: is this necessary? */
3581 _G_TYPE_IGC(remake, GtkObjectClass) = _G_TYPE_IGC(m_widgetStyle, GtkObjectClass);
3582#else
103aab26 3583 remake->klass = m_widgetStyle->klass;
dd00f3f6 3584#endif
2daa0ce9 3585
103aab26
RR
3586 gtk_style_unref( m_widgetStyle );
3587 m_widgetStyle = remake;
3588 }
3589 else
3590 {
3591 GtkStyle *def = gtk_rc_get_style( m_widget );
e6527f9d 3592
103aab26
RR
3593 if (!def)
3594 def = gtk_widget_get_default_style();
e6527f9d 3595
103aab26 3596 m_widgetStyle = gtk_style_copy( def );
dd00f3f6
OK
3597#ifdef __WXGTK20__
3598 /* FIXME: is this necessary? */
3599 _G_TYPE_IGC(m_widgetStyle, GtkObjectClass) = _G_TYPE_IGC(def, GtkObjectClass);
3600#else
103aab26 3601 m_widgetStyle->klass = def->klass;
dd00f3f6 3602#endif
103aab26 3603 }
8bbe427f 3604
1ecc4d80 3605 return m_widgetStyle;
58614078
RR
3606}
3607
1e6feb95 3608void wxWindowGTK::SetWidgetStyle()
58614078 3609{
8f3e7ecc 3610#if DISABLE_STYLE_IF_BROKEN_THEME
fb65642c
RR
3611 if (m_widget->style->engine_data)
3612 {
3613 static bool s_warningPrinted = FALSE;
3614 if (!s_warningPrinted)
3615 {
3616 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3617 s_warningPrinted = TRUE;
3618 }
3619 m_widgetStyle = m_widget->style;
3620 return;
3621 }
a56fcaaf 3622#endif
fb65642c 3623
1ecc4d80
RR
3624 GtkStyle *style = GetWidgetStyle();
3625
a756f210 3626 if (m_font != wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ))
db434467
RR
3627 {
3628 gdk_font_unref( style->font );
3629 style->font = gdk_font_ref( m_font.GetInternalFont( 1.0 ) );
3630 }
1ecc4d80
RR
3631
3632 if (m_foregroundColour.Ok())
3633 {
454e2a22 3634 m_foregroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
a756f210 3635 if (m_foregroundColour != wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT))
db434467
RR
3636 {
3637 style->fg[GTK_STATE_NORMAL] = *m_foregroundColour.GetColor();
3638 style->fg[GTK_STATE_PRELIGHT] = *m_foregroundColour.GetColor();
3639 style->fg[GTK_STATE_ACTIVE] = *m_foregroundColour.GetColor();
3640 }
1e6feb95 3641 else
f6bcfd97
BP
3642 {
3643 // Try to restore the gtk default style. This is still a little
3644 // oversimplified for what is probably really needed here for controls
3645 // other than buttons, but is better than not being able to (re)set a
3646 // control's foreground colour to *wxBLACK -- RL
3647 GtkStyle *def = gtk_rc_get_style( m_widget );
3648
3649 if (!def)
3650 def = gtk_widget_get_default_style();
3651
3652 style->fg[GTK_STATE_NORMAL] = def->fg[GTK_STATE_NORMAL];
3653 style->fg[GTK_STATE_PRELIGHT] = def->fg[GTK_STATE_PRELIGHT];
3654 style->fg[GTK_STATE_ACTIVE] = def->fg[GTK_STATE_ACTIVE];
3655 }
1ecc4d80
RR
3656 }
3657
3658 if (m_backgroundColour.Ok())
3659 {
454e2a22 3660 m_backgroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
a756f210 3661 if (m_backgroundColour != wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE))
db434467
RR
3662 {
3663 style->bg[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
3664 style->base[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
3665 style->bg[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
3666 style->base[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
3667 style->bg[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
3668 style->base[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
3669 style->bg[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
3670 style->base[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
f6bcfd97
BP
3671 }
3672 else
3673 {
3674 // Try to restore the gtk default style. This is still a little
3675 // oversimplified for what is probably really needed here for controls
3676 // other than buttons, but is better than not being able to (re)set a
3677 // control's background colour to default grey and means resetting a
1e6feb95 3678 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
f6bcfd97
BP
3679 // behavior -- RL
3680 GtkStyle *def = gtk_rc_get_style( m_widget );
3681
3682 if (!def)
3683 def = gtk_widget_get_default_style();
3684
3685 style->bg[GTK_STATE_NORMAL] = def->bg[GTK_STATE_NORMAL];
3686 style->base[GTK_STATE_NORMAL] = def->base[GTK_STATE_NORMAL];
3687 style->bg[GTK_STATE_PRELIGHT] = def->bg[GTK_STATE_PRELIGHT];
3688 style->base[GTK_STATE_PRELIGHT] = def->base[GTK_STATE_PRELIGHT];
3689 style->bg[GTK_STATE_ACTIVE] = def->bg[GTK_STATE_ACTIVE];
3690 style->base[GTK_STATE_ACTIVE] = def->base[GTK_STATE_ACTIVE];
3691 style->bg[GTK_STATE_INSENSITIVE] = def->bg[GTK_STATE_INSENSITIVE];
3692 style->base[GTK_STATE_INSENSITIVE] = def->base[GTK_STATE_INSENSITIVE];
3693 }
1ecc4d80 3694 }
a81258be
RR
3695}
3696
1e6feb95 3697void wxWindowGTK::ApplyWidgetStyle()
a81258be 3698{
6de97a3b
RR
3699}
3700
2259e007
RR
3701//-----------------------------------------------------------------------------
3702// Pop-up menu stuff
3703//-----------------------------------------------------------------------------
3704
6522713c 3705#if wxUSE_MENUS_NATIVE
1e6feb95 3706
90350682
VZ
3707extern "C"
3708void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting )
2259e007
RR
3709{
3710 *is_waiting = FALSE;
3711}
3712
1e6feb95 3713static void SetInvokingWindow( wxMenu *menu, wxWindowGTK *win )
30dea054 3714{
1ecc4d80 3715 menu->SetInvokingWindow( win );
1987af7e 3716 wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
1ecc4d80
RR
3717 while (node)
3718 {
1987af7e 3719 wxMenuItem *menuitem = node->GetData();
1ecc4d80
RR
3720 if (menuitem->IsSubMenu())
3721 {
ff8bfdbb
VZ
3722 SetInvokingWindow( menuitem->GetSubMenu(), win );
3723 }
1987af7e
VZ
3724
3725 node = node->GetNext();
1ecc4d80 3726 }
362c6693 3727}
30dea054 3728
e3473203
VZ
3729// used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
3730// wxPopupMenuPositionCallback()
3731//
3732// should be safe even in the MT case as the user can hardly popup 2 menus
3733// simultaneously, can he?
0c77152e
RR
3734static gint gs_pop_x = 0;
3735static gint gs_pop_y = 0;
3736
295272bd
VZ
3737extern "C" void wxPopupMenuPositionCallback( GtkMenu *menu,
3738 gint *x, gint *y,
3739 gpointer WXUNUSED(user_data) )
0c77152e 3740{
e3473203
VZ
3741 // ensure that the menu appears entirely on screen
3742 GtkRequisition req;
3743 gtk_widget_get_child_requisition(GTK_WIDGET(menu), &req);
3744
3745 wxSize sizeScreen = wxGetDisplaySize();
3746
3747 gint xmax = sizeScreen.x - req.width,
3748 ymax = sizeScreen.y - req.height;
3749
3750 *x = gs_pop_x < xmax ? gs_pop_x : xmax;
3751 *y = gs_pop_y < ymax ? gs_pop_y : ymax;
0c77152e
RR
3752}
3753
1e6feb95 3754bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
30dea054 3755{
223d09f6 3756 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
47d67540 3757
223d09f6 3758 wxCHECK_MSG( menu != NULL, FALSE, wxT("invalid popup-menu") );
8bbe427f 3759
1ecc4d80 3760 SetInvokingWindow( menu, this );
ff8bfdbb 3761
631f1bfe
JS
3762 menu->UpdateUI();
3763
0c77152e
RR
3764 gs_pop_x = x;
3765 gs_pop_y = y;
e3473203 3766 ClientToScreen( &gs_pop_x, &gs_pop_y );
ff8bfdbb 3767
2259e007 3768 bool is_waiting = TRUE;
148cd9b6 3769
90350682
VZ
3770 gtk_signal_connect( GTK_OBJECT(menu->m_menu),
3771 "hide",
3772 GTK_SIGNAL_FUNC(gtk_pop_hide_callback),
3773 (gpointer)&is_waiting );
2259e007 3774
1ecc4d80 3775 gtk_menu_popup(
47d67540 3776 GTK_MENU(menu->m_menu),
e3473203
VZ
3777 (GtkWidget *) NULL, // parent menu shell
3778 (GtkWidget *) NULL, // parent menu item
3779 wxPopupMenuPositionCallback, // function to position it
3780 NULL, // client data
3781 0, // button used to activate it
3782 gs_timeLastClick // the time of activation
47d67540 3783 );
148cd9b6 3784
956dbab1
RR
3785 while (is_waiting)
3786 {
3787 while (gtk_events_pending())
3788 gtk_main_iteration();
3789 }
2259e007 3790
1ecc4d80 3791 return TRUE;
30dea054
RR
3792}
3793
6522713c 3794#endif // wxUSE_MENUS_NATIVE
1e6feb95 3795
06cfab17 3796#if wxUSE_DRAG_AND_DROP
ac57418f 3797
1e6feb95 3798void wxWindowGTK::SetDropTarget( wxDropTarget *dropTarget )
c801d85f 3799{
223d09f6 3800 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
47d67540 3801
1ecc4d80 3802 GtkWidget *dnd_widget = GetConnectWidget();
47d67540 3803
1ecc4d80 3804 if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
47d67540 3805
1ecc4d80
RR
3806 if (m_dropTarget) delete m_dropTarget;
3807 m_dropTarget = dropTarget;
47d67540 3808
1ecc4d80 3809 if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
362c6693 3810}
c801d85f 3811
f03fc89f 3812#endif // wxUSE_DRAG_AND_DROP
ac57418f 3813
1e6feb95 3814GtkWidget* wxWindowGTK::GetConnectWidget()
e3e65dac 3815{
1ecc4d80
RR
3816 GtkWidget *connect_widget = m_widget;
3817 if (m_wxwindow) connect_widget = m_wxwindow;
47d67540 3818
1ecc4d80 3819 return connect_widget;
e3e65dac 3820}
47d67540 3821
1e6feb95 3822bool wxWindowGTK::IsOwnGtkWindow( GdkWindow *window )
903f689b 3823{
148cd9b6 3824 if (m_wxwindow)
da048e3d 3825 return (window == GTK_PIZZA(m_wxwindow)->bin_window);
148cd9b6 3826
1ecc4d80 3827 return (window == m_widget->window);
903f689b
RR
3828}
3829
1e6feb95 3830bool wxWindowGTK::SetFont( const wxFont &font )
c801d85f 3831{
223d09f6 3832 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
c801d85f 3833
739730ca
RR
3834 if (!wxWindowBase::SetFont(font))
3835 {
454e2a22 3836 return FALSE;
739730ca 3837 }
9c288e4d 3838
a756f210 3839 wxColour sysbg = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
f03fc89f 3840 if ( sysbg == m_backgroundColour )
ae0bdb01
RR
3841 {
3842 m_backgroundColour = wxNullColour;
3843 ApplyWidgetStyle();
ff8bfdbb
VZ
3844 m_backgroundColour = sysbg;
3845 }
ae0bdb01
RR
3846 else
3847 {
3848 ApplyWidgetStyle();
3849 }
c801d85f 3850
f03fc89f 3851 return TRUE;
362c6693 3852}
c801d85f 3853
94633ad9 3854void wxWindowGTK::DoCaptureMouse()
c801d85f 3855{
b231914f
VZ
3856 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3857
ed673c6a 3858 GdkWindow *window = (GdkWindow*) NULL;
b231914f
VZ
3859 if (m_wxwindow)
3860 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a 3861 else
b231914f 3862 window = GetConnectWidget()->window;
148cd9b6 3863
e4606ed9 3864 wxCHECK_RET( window, _T("CaptureMouse() failed") );
c50f1fb9 3865
b231914f 3866 wxCursor* cursor = & m_cursor;
cca602ac
JS
3867 if (!cursor->Ok())
3868 cursor = wxSTANDARD_CURSOR;
3869
ed673c6a 3870 gdk_pointer_grab( window, FALSE,
1ecc4d80
RR
3871 (GdkEventMask)
3872 (GDK_BUTTON_PRESS_MASK |
3873 GDK_BUTTON_RELEASE_MASK |
148cd9b6 3874 GDK_POINTER_MOTION_HINT_MASK |
1ecc4d80 3875 GDK_POINTER_MOTION_MASK),
ff8bfdbb 3876 (GdkWindow *) NULL,
cca602ac 3877 cursor->GetCursor(),
b02da6b1 3878 (guint32)GDK_CURRENT_TIME );
b231914f 3879 g_captureWindow = this;
1e6feb95 3880 g_captureWindowHasMouse = TRUE;
362c6693 3881}
c801d85f 3882
94633ad9 3883void wxWindowGTK::DoReleaseMouse()
c801d85f 3884{
b231914f
VZ
3885 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3886
e4606ed9 3887 wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") );
47d67540 3888
c43430bb
VS
3889 g_captureWindow = (wxWindowGTK*) NULL;
3890
ed673c6a 3891 GdkWindow *window = (GdkWindow*) NULL;
b231914f
VZ
3892 if (m_wxwindow)
3893 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a 3894 else
b231914f 3895 window = GetConnectWidget()->window;
148cd9b6 3896
b02da6b1
VZ
3897 if (!window)
3898 return;
c50f1fb9 3899
b02da6b1 3900 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
362c6693 3901}
c801d85f 3902
1e6feb95
VZ
3903/* static */
3904wxWindow *wxWindowBase::GetCapture()
3905{
3906 return (wxWindow *)g_captureWindow;
3907}
3908
3909bool wxWindowGTK::IsRetained() const
c801d85f 3910{
1ecc4d80 3911 return FALSE;
362c6693 3912}
c801d85f 3913
1e6feb95 3914void wxWindowGTK::SetScrollbar( int orient, int pos, int thumbVisible,
cb43b372 3915 int range, bool refresh )
c801d85f 3916{
223d09f6 3917 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
8bbe427f 3918
223d09f6 3919 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
c801d85f 3920
1ecc4d80 3921 m_hasScrolling = TRUE;
47d67540 3922
1ecc4d80 3923 if (orient == wxHORIZONTAL)
cb43b372 3924 {
1ecc4d80
RR
3925 float fpos = (float)pos;
3926 float frange = (float)range;
3927 float fthumb = (float)thumbVisible;
3928 if (fpos > frange-fthumb) fpos = frange-fthumb;
3929 if (fpos < 0.0) fpos = 0.0;
3930
3931 if ((fabs(frange-m_hAdjust->upper) < 0.2) &&
3932 (fabs(fthumb-m_hAdjust->page_size) < 0.2))
3933 {
3934 SetScrollPos( orient, pos, refresh );
3935 return;
3936 }
47d67540 3937
1ecc4d80 3938 m_oldHorizontalPos = fpos;
47d67540 3939
1ecc4d80
RR
3940 m_hAdjust->lower = 0.0;
3941 m_hAdjust->upper = frange;
3942 m_hAdjust->value = fpos;
3943 m_hAdjust->step_increment = 1.0;
3944 m_hAdjust->page_increment = (float)(wxMax(fthumb,0));
3945 m_hAdjust->page_size = fthumb;
cb43b372 3946 }
1ecc4d80
RR
3947 else
3948 {
3949 float fpos = (float)pos;
3950 float frange = (float)range;
3951 float fthumb = (float)thumbVisible;
3952 if (fpos > frange-fthumb) fpos = frange-fthumb;
3953 if (fpos < 0.0) fpos = 0.0;
3954
3955 if ((fabs(frange-m_vAdjust->upper) < 0.2) &&
3956 (fabs(fthumb-m_vAdjust->page_size) < 0.2))
3957 {
3958 SetScrollPos( orient, pos, refresh );
3959 return;
3960 }
47d67540 3961
1ecc4d80 3962 m_oldVerticalPos = fpos;
47d67540 3963
1ecc4d80
RR
3964 m_vAdjust->lower = 0.0;
3965 m_vAdjust->upper = frange;
3966 m_vAdjust->value = fpos;
3967 m_vAdjust->step_increment = 1.0;
3968 m_vAdjust->page_increment = (float)(wxMax(fthumb,0));
3969 m_vAdjust->page_size = fthumb;
3970 }
47d67540 3971
eb082a08
RR
3972 if (orient == wxHORIZONTAL)
3973 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
3974 else
3975 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
362c6693 3976}
c801d85f 3977
1e6feb95 3978void wxWindowGTK::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
c801d85f 3979{
223d09f6 3980 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
1ecc4d80 3981
223d09f6 3982 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
1ecc4d80
RR
3983
3984 if (orient == wxHORIZONTAL)
3985 {
3986 float fpos = (float)pos;
3987 if (fpos > m_hAdjust->upper - m_hAdjust->page_size) fpos = m_hAdjust->upper - m_hAdjust->page_size;
3988 if (fpos < 0.0) fpos = 0.0;
3989 m_oldHorizontalPos = fpos;
3990
3991 if (fabs(fpos-m_hAdjust->value) < 0.2) return;
3992 m_hAdjust->value = fpos;
3993 }
3994 else
3995 {
3996 float fpos = (float)pos;
3997 if (fpos > m_vAdjust->upper - m_vAdjust->page_size) fpos = m_vAdjust->upper - m_vAdjust->page_size;
3998 if (fpos < 0.0) fpos = 0.0;
3999 m_oldVerticalPos = fpos;
ff8bfdbb 4000
1ecc4d80
RR
4001 if (fabs(fpos-m_vAdjust->value) < 0.2) return;
4002 m_vAdjust->value = fpos;
4003 }
47d67540 4004
5b8a521e 4005 if (m_wxwindow->window)
47d67540 4006 {
5b8a521e 4007 if (orient == wxHORIZONTAL)
473d087e
RR
4008 {
4009 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust),
4010 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
2daa0ce9 4011
5b8a521e 4012 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
2daa0ce9 4013
473d087e
RR
4014 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
4015 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
4016 }
5b8a521e 4017 else
473d087e
RR
4018 {
4019 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust),
4020 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
2daa0ce9 4021
5b8a521e 4022 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
473d087e
RR
4023
4024 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
4025 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
4026 }
cb43b372 4027 }
362c6693 4028}
c801d85f 4029
1e6feb95 4030int wxWindowGTK::GetScrollThumb( int orient ) const
c801d85f 4031{
223d09f6 4032 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
47d67540 4033
223d09f6 4034 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
47d67540 4035
1ecc4d80
RR
4036 if (orient == wxHORIZONTAL)
4037 return (int)(m_hAdjust->page_size+0.5);
4038 else
4039 return (int)(m_vAdjust->page_size+0.5);
362c6693 4040}
c801d85f 4041
1e6feb95 4042int wxWindowGTK::GetScrollPos( int orient ) const
c801d85f 4043{
223d09f6 4044 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
47d67540 4045
223d09f6 4046 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
c801d85f 4047
1ecc4d80
RR
4048 if (orient == wxHORIZONTAL)
4049 return (int)(m_hAdjust->value+0.5);
4050 else
4051 return (int)(m_vAdjust->value+0.5);
362c6693 4052}
c801d85f 4053
1e6feb95 4054int wxWindowGTK::GetScrollRange( int orient ) const
c801d85f 4055{
223d09f6 4056 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
47d67540 4057
223d09f6 4058 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
c801d85f 4059
1ecc4d80
RR
4060 if (orient == wxHORIZONTAL)
4061 return (int)(m_hAdjust->upper+0.5);
4062 else
4063 return (int)(m_vAdjust->upper+0.5);
362c6693 4064}
c801d85f 4065
1e6feb95 4066void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
c801d85f 4067{
223d09f6 4068 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
47d67540 4069
223d09f6 4070 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
1e6feb95 4071
f47ae6e7 4072 // No scrolling requested.
8e217128 4073 if ((dx == 0) && (dy == 0)) return;
f47ae6e7 4074
35917d22
RR
4075 if (!m_updateRegion.IsEmpty())
4076 {
4077 m_updateRegion.Offset( dx, dy );
4078
4079 int cw = 0;
4080 int ch = 0;
4081 GetClientSize( &cw, &ch );
4082 m_updateRegion.Intersect( 0, 0, cw, ch );
4083 }
4084
3bcc8d15
RR
4085 if (!m_clearRegion.IsEmpty())
4086 {
4087 m_clearRegion.Offset( dx, dy );
4088
4089 int cw = 0;
4090 int ch = 0;
4091 GetClientSize( &cw, &ch );
4092 m_clearRegion.Intersect( 0, 0, cw, ch );
4093 }
4094
f47ae6e7 4095#if 1
c801d85f 4096
b6fa52db 4097 m_clipPaintRegion = TRUE;
f47ae6e7 4098
da048e3d 4099 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
f47ae6e7 4100
b6fa52db 4101 m_clipPaintRegion = FALSE;
1e6feb95 4102
f47ae6e7
RR
4103#else
4104
8e217128
RR
4105 if (m_children.GetCount() > 0)
4106 {
4107 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
4108 }
4109 else
4110 {
4111 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
1e6feb95 4112
8e217128
RR
4113 pizza->xoffset -= dx;
4114 pizza->yoffset -= dy;
1e6feb95 4115
8e217128
RR
4116 GdkGC *m_scrollGC = gdk_gc_new( pizza->bin_window );
4117 gdk_gc_set_exposures( m_scrollGC, TRUE );
4118
4119 int cw = 0;
4120 int ch = 0;
4121 GetClientSize( &cw, &ch );
4122 int w = cw - abs(dx);
4123 int h = ch - abs(dy);
4124
4125 if ((h < 0) || (w < 0))
4126 {
4127 Refresh();
1e6feb95 4128 }
8e217128
RR
4129 else
4130 {
4131 int s_x = 0;
4132 int s_y = 0;
4133 if (dx < 0) s_x = -dx;
4134 if (dy < 0) s_y = -dy;
4135 int d_x = 0;
4136 int d_y = 0;
4137 if (dx > 0) d_x = dx;
4138 if (dy > 0) d_y = dy;
4139
4140 gdk_window_copy_area( pizza->bin_window, m_scrollGC, d_x, d_y,
4141 pizza->bin_window, s_x, s_y, w, h );
4142
4143 wxRect rect;
4144 if (dx < 0) rect.x = cw+dx; else rect.x = 0;
4145 if (dy < 0) rect.y = ch+dy; else rect.y = 0;
4146 if (dy != 0) rect.width = cw; else rect.width = abs(dx);
4147 if (dx != 0) rect.height = ch; else rect.height = abs(dy);
4148
4149 Refresh( TRUE, &rect );
4150 }
1e6feb95 4151
8e217128
RR
4152 gdk_gc_unref( m_scrollGC );
4153 }
f47ae6e7 4154#endif
c801d85f 4155}
3723b7b1 4156
3723b7b1
JS
4157// Find the wxWindow at the current mouse position, also returning the mouse
4158// position.
4159wxWindow* wxFindWindowAtPointer(wxPoint& pt)
4160{
59a12e90
JS
4161 pt = wxGetMousePosition();
4162 wxWindow* found = wxFindWindowAtPoint(pt);
4163 return found;
3723b7b1
JS
4164}
4165
4166// Get the current mouse position.
4167wxPoint wxGetMousePosition()
4168{
59a12e90
JS
4169 /* This crashes when used within wxHelpContext,
4170 so we have to use the X-specific implementation below.
4171 gint x, y;
4172 GdkModifierType *mask;
4173 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4174
4175 return wxPoint(x, y);
4176 */
4177
3723b7b1
JS
4178 int x, y;
4179 GdkWindow* windowAtPtr = gdk_window_at_pointer(& x, & y);
57591e0e
JS
4180 if (!windowAtPtr)
4181 return wxPoint(-999, -999);
59a12e90
JS
4182
4183 Display *display = GDK_WINDOW_XDISPLAY(windowAtPtr);
4184 Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
4185 Window rootReturn, childReturn;
4186 int rootX, rootY, winX, winY;
4187 unsigned int maskReturn;
4188
4189 XQueryPointer (display,
5cd09f0b
RR
4190 rootWindow,
4191 &rootReturn,
59a12e90
JS
4192 &childReturn,
4193 &rootX, &rootY, &winX, &winY, &maskReturn);
4194 return wxPoint(rootX, rootY);
4195
3723b7b1
JS
4196}
4197