]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/window.cpp
no changes (de-TABified, undid some horrors with which someone replaced my ?: operators
[wxWidgets.git] / src / gtk1 / 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
2bc6945a 778 GtkPizza *pizza = GTK_PIZZA (widget);
a2d93e73 779
a2d93e73
JS
780 if (win->GetThemeEnabled())
781 {
782 wxWindow *parent = win->GetParent();
783 while (parent && !parent->IsTopLevel())
784 parent = parent->GetParent();
785 if (!parent)
786 parent = win;
787
90350682
VZ
788 gtk_paint_flat_box (parent->m_widget->style,
789 pizza->bin_window,
790 GTK_STATE_NORMAL,
791 GTK_SHADOW_NONE,
792 &gdk_event->area,
793 parent->m_widget,
794 (char *)"base",
795 0, 0, -1, -1);
2bc6945a 796 }
1e6feb95 797
2bc6945a
RR
798 win->GetUpdateRegion().Union( gdk_event->area.x,
799 gdk_event->area.y,
800 gdk_event->area.width,
801 gdk_event->area.height );
0e09f76e 802
8f3e7ecc 803 // Actual redrawing takes place in idle time.
f7a11f8c 804
b6fa52db
RR
805 return TRUE;
806}
807
808//-----------------------------------------------------------------------------
809// "event" of m_wxwindow
810//-----------------------------------------------------------------------------
811
beab25bd
RR
812// GTK thinks it is clever and filters out a certain amount of "unneeded"
813// expose events. We need them, of course, so we override the main event
814// procedure in GtkWidget by giving our own handler for all system events.
815// There, we look for expose events ourselves whereas all other events are
816// handled normally.
b6fa52db 817
1e6feb95
VZ
818gint gtk_window_event_event_callback( GtkWidget *widget,
819 GdkEventExpose *event,
820 wxWindow *win )
b6fa52db
RR
821{
822 if (event->type == GDK_EXPOSE)
823 {
824 gint ret = gtk_window_expose_callback( widget, event, win );
825 return ret;
826 }
827
b6fa52db 828 return FALSE;
362c6693 829}
c801d85f
KB
830
831//-----------------------------------------------------------------------------
034be888 832// "draw" of m_wxwindow
2f2aa628 833//-----------------------------------------------------------------------------
c801d85f 834
beab25bd
RR
835// This callback is a complete replacement of the gtk_pizza_draw() function,
836// which disabled.
b6fa52db 837
1e6feb95
VZ
838static void gtk_window_draw_callback( GtkWidget *widget,
839 GdkRectangle *rect,
840 wxWindow *win )
47d67540 841{
3ac8d3bc
RR
842 DEBUG_MAIN_THREAD
843
c50f1fb9 844 if (g_isIdle)
a2053b27 845 wxapp_install_idle_handler();
2d19ad25 846
beab25bd
RR
847 // The wxNO_FULL_REPAINT_ON_RESIZE flag only works if
848 // there are no child windows.
e22454be
RR
849 if ((win->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE)) &&
850 (win->GetChildren().GetCount() == 0))
851 {
852 return;
853 }
2d19ad25 854
40c70187 855/*
8cb9f0d0 856 if (win->GetName() == wxT("panel"))
3d2d8da1
RR
857 {
858 wxPrintf( wxT("OnDraw from ") );
859 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
860 wxPrintf( win->GetClassInfo()->GetClassName() );
861 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect->x,
862 (int)rect->y,
863 (int)rect->width,
864 (int)rect->height );
865 }
40c70187 866*/
1e6feb95 867
b420fb6a 868 GtkPizza *pizza = GTK_PIZZA (widget);
2bc6945a 869
9cc7121f 870 if (win->GetThemeEnabled())
789dbcd4 871 {
9cc7121f
RR
872 wxWindow *parent = win->GetParent();
873 while (parent && !parent->IsTopLevel())
789dbcd4 874 parent = parent->GetParent();
9cc7121f
RR
875 if (!parent)
876 parent = win;
877
90350682
VZ
878 gtk_paint_flat_box (parent->m_widget->style,
879 pizza->bin_window,
880 GTK_STATE_NORMAL,
881 GTK_SHADOW_NONE,
882 rect,
883 parent->m_widget,
884 (char *)"base",
885 0, 0, -1, -1);
789dbcd4 886 }
1e6feb95
VZ
887
888
9cc7121f
RR
889 if (!(GTK_WIDGET_APP_PAINTABLE (widget)) &&
890 (pizza->clear_on_draw))
891 {
892 gdk_window_clear_area( pizza->bin_window,
b420fb6a 893 rect->x, rect->y, rect->width, rect->height);
9cc7121f 894 }
1e6feb95 895
9cc7121f 896 win->GetUpdateRegion().Union( rect->x, rect->y, rect->width, rect->height );
148cd9b6 897
8f3e7ecc 898 // Actual redrawing takes place in idle time.
1e6feb95 899
8f3e7ecc 900#ifndef __WXUNIVERSAL__
beab25bd 901 // Redraw child widgets
e22454be
RR
902 GList *children = pizza->children;
903 while (children)
904 {
beab25bd
RR
905 GtkPizzaChild *child = (GtkPizzaChild*) children->data;
906 children = children->next;
b420fb6a 907
beab25bd
RR
908 GdkRectangle child_area;
909 if (gtk_widget_intersect (child->widget, rect, &child_area))
910 {
911 gtk_widget_draw (child->widget, &child_area /* (GdkRectangle*) NULL*/ );
912 }
e22454be 913 }
8f3e7ecc 914#endif
362c6693 915}
c801d85f
KB
916
917//-----------------------------------------------------------------------------
b292e2f5 918// "key_press_event" from any window
c801d85f 919//-----------------------------------------------------------------------------
c801d85f 920
f17393f1
VZ
921// turn on to see the key event codes on the console
922#undef DEBUG_KEY_EVENTS
923
1e6feb95
VZ
924static gint gtk_window_key_press_callback( GtkWidget *widget,
925 GdkEventKey *gdk_event,
926 wxWindow *win )
47d67540 927{
3ac8d3bc
RR
928 DEBUG_MAIN_THREAD
929
c50f1fb9 930 if (g_isIdle)
a2053b27
RR
931 wxapp_install_idle_handler();
932
933 if (!win->m_hasVMT) return FALSE;
f5e27805 934 if (g_blockEventsOnDrag) return FALSE;
c801d85f 935
3d6f7261 936
b0e813a0
RR
937 int x = 0;
938 int y = 0;
939 GdkModifierType state;
f17393f1
VZ
940 if (gdk_event->window)
941 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
47d67540 942
3017f78d 943 bool ret = FALSE;
148cd9b6 944
2d451165 945 long key_code = map_to_unmodified_wx_keysym( gdk_event );
f17393f1
VZ
946
947#ifdef DEBUG_KEY_EVENTS
948 wxPrintf(_T("Key press event: %d => %ld\n"), gdk_event->keyval, key_code);
949#endif // DEBUG_KEY_EVENTS
950
f0492f7d 951 /* sending unknown key events doesn't really make sense */
f17393f1
VZ
952 if (key_code == 0)
953 return FALSE;
f0492f7d 954
c50f1fb9 955 wxKeyEvent event( wxEVT_KEY_DOWN );
d1367c3d 956 event.SetTimestamp( gdk_event->time );
f5e27805
RR
957 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
958 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
959 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
960 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
961 event.m_keyCode = key_code;
b0e813a0
RR
962 event.m_scanCode = gdk_event->keyval;
963 event.m_x = x;
964 event.m_y = y;
f5e27805 965 event.SetEventObject( win );
c5b42c87 966 ret = win->GetEventHandler()->ProcessEvent( event );
c50f1fb9 967
88ac883a 968#if wxUSE_ACCEL
f5e27805 969 if (!ret)
47d67540 970 {
1e6feb95 971 wxWindowGTK *ancestor = win;
f5e27805
RR
972 while (ancestor)
973 {
974 int command = ancestor->GetAcceleratorTable()->GetCommand( event );
975 if (command != -1)
976 {
977 wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
978 ret = ancestor->GetEventHandler()->ProcessEvent( command_event );
979 break;
980 }
f6bcfd97 981 if (ancestor->IsTopLevel())
b02da6b1 982 break;
f5e27805
RR
983 ancestor = ancestor->GetParent();
984 }
bcf1fa6b 985 }
88ac883a 986#endif // wxUSE_ACCEL
3017f78d 987
d728dd40 988 /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
3017f78d 989 will only be sent if it is not in an accelerator table. */
f17393f1 990 if ( !ret )
d728dd40 991 {
f17393f1
VZ
992 key_code = map_to_wx_keysym( gdk_event );
993
994 if ( key_code )
995 {
996#ifdef DEBUG_KEY_EVENTS
997 wxPrintf(_T("Char event: %ld\n"), key_code);
998#endif // DEBUG_KEY_EVENTS
999
1000 // reuse the ame event object, just change its type and use the
1001 // translated keycode instead of the raw one
1002 event.SetEventType(wxEVT_CHAR);
1003 event.m_keyCode = key_code;
1004
1005 ret = win->GetEventHandler()->ProcessEvent( event );
1006 }
d728dd40
KB
1007 }
1008
053f9cc1 1009 /* win is a control: tab can be propagated up */
f17393f1 1010 if ( !ret &&
5664fc32 1011 ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) &&
f6bcfd97
BP
1012// VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1013// have this style, yet choose not to process this particular TAB in which
1014// case TAB must still work as a navigational character
1015#if 0
f17393f1 1016 !win->HasFlag(wxTE_PROCESS_TAB) &&
f6bcfd97 1017#endif // 0
f17393f1 1018 win->GetParent() && (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) )
b292e2f5
RR
1019 {
1020 wxNavigationKeyEvent new_event;
8253c7fd 1021 new_event.SetEventObject( win->GetParent() );
f03fc89f 1022 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
5664fc32 1023 new_event.SetDirection( (gdk_event->keyval == GDK_Tab) );
f03fc89f 1024 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
b98d804b 1025 new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) );
b292e2f5 1026 new_event.SetCurrentFocus( win );
8253c7fd 1027 ret = win->GetParent()->GetEventHandler()->ProcessEvent( new_event );
b292e2f5 1028 }
ff8bfdbb 1029
801aa178 1030 /* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
f17393f1 1031 if ( !ret &&
b98d804b
RR
1032 (gdk_event->keyval == GDK_Escape) )
1033 {
1034 wxCommandEvent new_event(wxEVT_COMMAND_BUTTON_CLICKED,wxID_CANCEL);
1035 new_event.SetEventObject( win );
1036 ret = win->GetEventHandler()->ProcessEvent( new_event );
1037 }
c50f1fb9 1038
da048e3d 1039 /* Doesn't work. */
f17393f1
VZ
1040#if 0 // (GTK_MINOR_VERSION > 0)
1041 /* Pressing F10 will activate the menu bar of the top frame. */
801aa178
RR
1042 if ( (!ret) &&
1043 (gdk_event->keyval == GDK_F10) )
1044 {
1e6feb95 1045 wxWindowGTK *ancestor = win;
801aa178
RR
1046 while (ancestor)
1047 {
1048 if (wxIsKindOf(ancestor,wxFrame))
c50f1fb9
VZ
1049 {
1050 wxFrame *frame = (wxFrame*) ancestor;
801aa178 1051 wxMenuBar *menubar = frame->GetMenuBar();
c50f1fb9
VZ
1052 if (menubar)
1053 {
801aa178 1054 wxNode *node = menubar->GetMenus().First();
c50f1fb9
VZ
1055 if (node)
1056 {
3017f78d
RR
1057 wxMenu *firstMenu = (wxMenu*) node->Data();
1058 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu->m_owner) );
1059 ret = TRUE;
c50f1fb9
VZ
1060 break;
1061 }
1062 }
1063 }
801aa178
RR
1064 ancestor = ancestor->GetParent();
1065 }
1066 }
f17393f1 1067#endif // 0
ca298c88 1068
f5e27805
RR
1069 if (ret)
1070 {
b292e2f5 1071 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
f03fc89f 1072 return TRUE;
f5e27805 1073 }
47d67540 1074
034be888 1075 return FALSE;
362c6693 1076}
c801d85f 1077
b666df2c
RR
1078//-----------------------------------------------------------------------------
1079// "key_release_event" from any window
1080//-----------------------------------------------------------------------------
1081
1e6feb95 1082static gint gtk_window_key_release_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindowGTK *win )
b666df2c 1083{
3ac8d3bc
RR
1084 DEBUG_MAIN_THREAD
1085
c50f1fb9 1086 if (g_isIdle)
a2053b27
RR
1087 wxapp_install_idle_handler();
1088
1089 if (!win->m_hasVMT) return FALSE;
b666df2c
RR
1090 if (g_blockEventsOnDrag) return FALSE;
1091
2d451165 1092 long key_code = map_to_unmodified_wx_keysym( gdk_event );
c50f1fb9 1093
f17393f1
VZ
1094#ifdef DEBUG_KEY_EVENTS
1095 wxPrintf(_T("Key release event: %d => %ld\n"), gdk_event->keyval, key_code);
1096#endif // DEBUG_KEY_EVENTS
1097
f0492f7d
RR
1098 /* sending unknown key events doesn't really make sense */
1099 if (key_code == 0) return FALSE;
b666df2c 1100
b0e813a0
RR
1101 int x = 0;
1102 int y = 0;
1103 GdkModifierType state;
f17393f1
VZ
1104 if (gdk_event->window)
1105 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
b666df2c
RR
1106
1107 wxKeyEvent event( wxEVT_KEY_UP );
d1367c3d 1108 event.SetTimestamp( gdk_event->time );
b666df2c
RR
1109 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1110 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1111 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1112 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1113 event.m_keyCode = key_code;
b0e813a0
RR
1114 event.m_scanCode = gdk_event->keyval;
1115 event.m_x = x;
1116 event.m_y = y;
b666df2c
RR
1117 event.SetEventObject( win );
1118
034be888 1119 if (win->GetEventHandler()->ProcessEvent( event ))
b666df2c 1120 {
b98d804b 1121 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_release_event" );
f03fc89f 1122 return TRUE;
b666df2c
RR
1123 }
1124
034be888 1125 return FALSE;
b666df2c
RR
1126}
1127
c5f9d156
VS
1128// ============================================================================
1129// the mouse events
1130// ============================================================================
1131
1132// init wxMouseEvent with the info from gdk_event
1133#define InitMouseEvent(win, event, gdk_event) \
1134 { \
1135 event.SetTimestamp( gdk_event->time ); \
1136 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1137 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1138 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1139 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1140 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1141 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1142 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1143\
1144 wxPoint pt = win->GetClientAreaOrigin(); \
1145 event.m_x = (wxCoord)gdk_event->x - pt.x; \
1146 event.m_y = (wxCoord)gdk_event->y - pt.y; \
1147 }
1148
2daa0ce9
VZ
1149// ----------------------------------------------------------------------------
1150// mouse event processing helper
1151// ----------------------------------------------------------------------------
1152
1153static void AdjustEventButtonState(wxMouseEvent& event)
1154{
1155 // GDK reports the old state of the button for a button press event, but
1156 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1157 // for a LEFT_DOWN event, not FALSE, so we will invert
1158 // left/right/middleDown for the corresponding click events
1e6feb95 1159
1a8caf94
RR
1160 if ((event.GetEventType() == wxEVT_LEFT_DOWN) ||
1161 (event.GetEventType() == wxEVT_LEFT_DCLICK) ||
1162 (event.GetEventType() == wxEVT_LEFT_UP))
1163 {
1164 event.m_leftDown = !event.m_leftDown;
1165 return;
1166 }
1167
1168 if ((event.GetEventType() == wxEVT_MIDDLE_DOWN) ||
1169 (event.GetEventType() == wxEVT_MIDDLE_DCLICK) ||
1170 (event.GetEventType() == wxEVT_MIDDLE_UP))
2daa0ce9 1171 {
1a8caf94
RR
1172 event.m_middleDown = !event.m_middleDown;
1173 return;
1174 }
1175
1176 if ((event.GetEventType() == wxEVT_RIGHT_DOWN) ||
1177 (event.GetEventType() == wxEVT_RIGHT_DCLICK) ||
1178 (event.GetEventType() == wxEVT_RIGHT_UP))
1179 {
1180 event.m_rightDown = !event.m_rightDown;
1181 return;
2daa0ce9
VZ
1182 }
1183}
1184
c801d85f 1185//-----------------------------------------------------------------------------
2f2aa628
RR
1186// "button_press_event"
1187//-----------------------------------------------------------------------------
c801d85f 1188
1e6feb95 1189static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindowGTK *win )
903f689b 1190{
3ac8d3bc
RR
1191 DEBUG_MAIN_THREAD
1192
c50f1fb9 1193 if (g_isIdle)
a2053b27
RR
1194 wxapp_install_idle_handler();
1195
1196/*
223d09f6 1197 wxPrintf( wxT("1) OnButtonPress from ") );
a2053b27
RR
1198 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1199 wxPrintf( win->GetClassInfo()->GetClassName() );
223d09f6 1200 wxPrintf( wxT(".\n") );
a2053b27 1201*/
a2053b27 1202 if (!win->m_hasVMT) return FALSE;
f5e27805 1203 if (g_blockEventsOnDrag) return TRUE;
76ed8f8d 1204 if (g_blockEventsOnScroll) return TRUE;
c801d85f 1205
034be888
RR
1206 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1207
a2053b27 1208 if (win->m_wxwindow)
c801d85f 1209 {
a2053b27 1210 if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow) && !GTK_WIDGET_HAS_FOCUS (win->m_wxwindow) )
f5e27805 1211 {
a2053b27 1212 gtk_widget_grab_focus (win->m_wxwindow);
47d67540 1213
c801d85f 1214/*
223d09f6 1215 wxPrintf( wxT("GrabFocus from ") );
f5e27805 1216 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
a2053b27 1217 wxPrintf( win->GetClassInfo()->GetClassName() );
223d09f6 1218 wxPrintf( wxT(".\n") );
c801d85f 1219*/
47d67540 1220
f5e27805 1221 }
362c6693 1222 }
47d67540 1223
2daa0ce9 1224 wxEventType event_type = wxEVT_NULL;
47d67540 1225
f5e27805 1226 if (gdk_event->button == 1)
c801d85f 1227 {
f5e27805
RR
1228 switch (gdk_event->type)
1229 {
1230 case GDK_BUTTON_PRESS: event_type = wxEVT_LEFT_DOWN; break;
1231 case GDK_2BUTTON_PRESS: event_type = wxEVT_LEFT_DCLICK; break;
1232 default: break;
1233 }
362c6693 1234 }
f5e27805 1235 else if (gdk_event->button == 2)
c801d85f 1236 {
f5e27805
RR
1237 switch (gdk_event->type)
1238 {
1239 case GDK_BUTTON_PRESS: event_type = wxEVT_MIDDLE_DOWN; break;
1240 case GDK_2BUTTON_PRESS: event_type = wxEVT_MIDDLE_DCLICK; break;
1241 default: break;
1242 }
362c6693 1243 }
f5e27805 1244 else if (gdk_event->button == 3)
c801d85f 1245 {
f5e27805
RR
1246 switch (gdk_event->type)
1247 {
1248 case GDK_BUTTON_PRESS: event_type = wxEVT_RIGHT_DOWN; break;
1249 case GDK_2BUTTON_PRESS: event_type = wxEVT_RIGHT_DCLICK; break;
1250 default: break;
1251 }
362c6693 1252 }
47d67540 1253
2daa0ce9
VZ
1254 if ( event_type == wxEVT_NULL )
1255 {
1256 // unknown mouse button or click type
1257 return FALSE;
1258 }
1259
f5e27805 1260 wxMouseEvent event( event_type );
c5f9d156 1261 InitMouseEvent( win, event, gdk_event );
47d67540 1262
2daa0ce9 1263 AdjustEventButtonState(event);
94633ad9 1264
e2762ff0 1265 // wxListBox actually get mouse events from the item
94633ad9 1266
e2762ff0
RR
1267 if (win->m_isListBox)
1268 {
1269 event.m_x += widget->allocation.x;
1270 event.m_y += widget->allocation.y;
1271 }
2daa0ce9 1272
f5e27805
RR
1273 // Some control don't have their own X window and thus cannot get
1274 // any events.
47d67540 1275
72195a0f 1276 if (!g_captureWindow)
2f2aa628 1277 {
b02da6b1
VZ
1278 wxCoord x = event.m_x;
1279 wxCoord y = event.m_y;
2f073eb2
RR
1280 if (win->m_wxwindow)
1281 {
da048e3d 1282 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
b02da6b1
VZ
1283 x += pizza->xoffset;
1284 y += pizza->yoffset;
2f073eb2
RR
1285 }
1286
db1b4961 1287 wxNode *node = win->GetChildren().First();
f5e27805
RR
1288 while (node)
1289 {
1e6feb95 1290 wxWindowGTK *child = (wxWindowGTK*)node->Data();
148cd9b6 1291
f96ac56a 1292 node = node->Next();
b02da6b1
VZ
1293 if (!child->IsShown())
1294 continue;
ff8bfdbb 1295
a2053b27 1296 if (child->m_isStaticBox)
ff8bfdbb
VZ
1297 {
1298 // wxStaticBox is transparent in the box itself
a2053b27
RR
1299 int xx1 = child->m_x;
1300 int yy1 = child->m_y;
1301 int xx2 = child->m_x + child->m_width;
1302 int yy2 = child->m_x + child->m_height;
ff8bfdbb
VZ
1303
1304 // left
1305 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1306 // right
1307 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1308 // top
1309 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1310 // bottom
1311 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1312 {
1ecc4d80 1313 win = child;
a2053b27
RR
1314 event.m_x -= child->m_x;
1315 event.m_y -= child->m_y;
1ecc4d80 1316 break;
ff8bfdbb
VZ
1317 }
1318
1319 }
1320 else
1321 {
a2053b27 1322 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
2f073eb2
RR
1323 (child->m_x <= x) &&
1324 (child->m_y <= y) &&
1325 (child->m_x+child->m_width >= x) &&
1326 (child->m_y+child->m_height >= y))
1ecc4d80
RR
1327 {
1328 win = child;
a2053b27
RR
1329 event.m_x -= child->m_x;
1330 event.m_y -= child->m_y;
1ecc4d80 1331 break;
ff8bfdbb 1332 }
f5e27805 1333 }
f5e27805 1334 }
2f2aa628 1335 }
ff8bfdbb 1336
f5e27805 1337 event.SetEventObject( win );
47d67540 1338
f5e27805 1339 gs_timeLastClick = gdk_event->time;
47d67540 1340
2f073eb2
RR
1341/*
1342 wxPrintf( wxT("2) OnButtonPress from ") );
1343 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1344 wxPrintf( win->GetClassInfo()->GetClassName() );
1345 wxPrintf( wxT(".\n") );
1346*/
1347
f5e27805 1348 if (win->GetEventHandler()->ProcessEvent( event ))
034be888 1349 {
f5e27805 1350 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_press_event" );
f03fc89f 1351 return TRUE;
034be888 1352 }
47d67540 1353
034be888 1354 return FALSE;
362c6693 1355}
c801d85f
KB
1356
1357//-----------------------------------------------------------------------------
97b3455a 1358// "button_release_event"
2f2aa628 1359//-----------------------------------------------------------------------------
c801d85f 1360
1e6feb95 1361static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindowGTK *win )
47d67540 1362{
3ac8d3bc
RR
1363 DEBUG_MAIN_THREAD
1364
c50f1fb9 1365 if (g_isIdle)
a2053b27
RR
1366 wxapp_install_idle_handler();
1367
1368 if (!win->m_hasVMT) return FALSE;
034be888
RR
1369 if (g_blockEventsOnDrag) return FALSE;
1370 if (g_blockEventsOnScroll) return FALSE;
c801d85f 1371
034be888 1372 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
47d67540 1373
c801d85f 1374/*
f5e27805
RR
1375 printf( "OnButtonRelease from " );
1376 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1377 printf( win->GetClassInfo()->GetClassName() );
1378 printf( ".\n" );
c801d85f 1379*/
47d67540 1380
f5e27805 1381 wxEventType event_type = wxEVT_NULL;
47d67540 1382
f5e27805
RR
1383 switch (gdk_event->button)
1384 {
1385 case 1: event_type = wxEVT_LEFT_UP; break;
1386 case 2: event_type = wxEVT_MIDDLE_UP; break;
1387 case 3: event_type = wxEVT_RIGHT_UP; break;
2daa0ce9 1388 default: return FALSE;
f5e27805 1389 }
47d67540 1390
f5e27805 1391 wxMouseEvent event( event_type );
c5f9d156 1392 InitMouseEvent( win, event, gdk_event );
f5e27805 1393
2daa0ce9
VZ
1394 AdjustEventButtonState(event);
1395
e2762ff0 1396 // wxListBox actually get mouse events from the item
94633ad9 1397
e2762ff0
RR
1398 if (win->m_isListBox)
1399 {
1400 event.m_x += widget->allocation.x;
1401 event.m_y += widget->allocation.y;
1402 }
1403
f5e27805
RR
1404 // Some control don't have their own X window and thus cannot get
1405 // any events.
1406
72195a0f 1407 if (!g_captureWindow)
2f2aa628 1408 {
b02da6b1
VZ
1409 wxCoord x = event.m_x;
1410 wxCoord y = event.m_y;
2f073eb2
RR
1411 if (win->m_wxwindow)
1412 {
da048e3d 1413 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
b02da6b1
VZ
1414 x += pizza->xoffset;
1415 y += pizza->yoffset;
2f073eb2
RR
1416 }
1417
db1b4961 1418 wxNode *node = win->GetChildren().First();
f5e27805
RR
1419 while (node)
1420 {
1e6feb95 1421 wxWindowGTK *child = (wxWindowGTK*)node->Data();
ff8bfdbb 1422
f96ac56a 1423 node = node->Next();
b02da6b1
VZ
1424 if (!child->IsShown())
1425 continue;
f96ac56a 1426
a2053b27 1427 if (child->m_isStaticBox)
ff8bfdbb
VZ
1428 {
1429 // wxStaticBox is transparent in the box itself
a2053b27
RR
1430 int xx1 = child->m_x;
1431 int yy1 = child->m_y;
1432 int xx2 = child->m_x + child->m_width;
1433 int yy2 = child->m_x + child->m_height;
ff8bfdbb
VZ
1434
1435 // left
1436 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1437 // right
1438 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1439 // top
1440 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1441 // bottom
1442 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1443 {
1ecc4d80 1444 win = child;
a2053b27
RR
1445 event.m_x -= child->m_x;
1446 event.m_y -= child->m_y;
1ecc4d80 1447 break;
ff8bfdbb
VZ
1448 }
1449
1450 }
1451 else
1452 {
a2053b27 1453 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
2f073eb2
RR
1454 (child->m_x <= x) &&
1455 (child->m_y <= y) &&
1456 (child->m_x+child->m_width >= x) &&
1457 (child->m_y+child->m_height >= y))
1ecc4d80
RR
1458 {
1459 win = child;
a2053b27
RR
1460 event.m_x -= child->m_x;
1461 event.m_y -= child->m_y;
1ecc4d80 1462 break;
ff8bfdbb 1463 }
f5e27805 1464 }
f5e27805 1465 }
2f2aa628 1466 }
47d67540 1467
f5e27805 1468 event.SetEventObject( win );
47d67540 1469
f5e27805 1470 if (win->GetEventHandler()->ProcessEvent( event ))
034be888 1471 {
f5e27805 1472 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_release_event" );
f03fc89f 1473 return TRUE;
034be888 1474 }
47d67540 1475
034be888 1476 return FALSE;
362c6693 1477}
c801d85f
KB
1478
1479//-----------------------------------------------------------------------------
2f2aa628
RR
1480// "motion_notify_event"
1481//-----------------------------------------------------------------------------
c801d85f 1482
1e6feb95
VZ
1483static gint gtk_window_motion_notify_callback( GtkWidget *widget,
1484 GdkEventMotion *gdk_event,
1485 wxWindowGTK *win )
47d67540 1486{
3ac8d3bc
RR
1487 DEBUG_MAIN_THREAD
1488
c50f1fb9 1489 if (g_isIdle)
a2053b27
RR
1490 wxapp_install_idle_handler();
1491
1492 if (!win->m_hasVMT) return FALSE;
034be888
RR
1493 if (g_blockEventsOnDrag) return FALSE;
1494 if (g_blockEventsOnScroll) return FALSE;
148cd9b6 1495
034be888
RR
1496 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1497
ff8bfdbb 1498 if (gdk_event->is_hint)
aae24d21 1499 {
f7a11f8c
RR
1500 int x = 0;
1501 int y = 0;
1502 GdkModifierType state;
1503 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
1504 gdk_event->x = x;
1505 gdk_event->y = y;
aae24d21 1506 }
ff8bfdbb 1507
c801d85f 1508/*
e380f72b
RR
1509 printf( "OnMotion from " );
1510 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1511 printf( win->GetClassInfo()->GetClassName() );
1512 printf( ".\n" );
aae24d21 1513*/
47d67540 1514
e380f72b 1515 wxMouseEvent event( wxEVT_MOTION );
c5f9d156 1516 InitMouseEvent(win, event, gdk_event);
e380f72b 1517
1e6feb95 1518 if ( g_captureWindow )
2f2aa628 1519 {
1e6feb95
VZ
1520 // synthetize a mouse enter or leave event if needed
1521 GdkWindow *winUnderMouse = gdk_window_at_pointer(NULL, NULL);
1522 bool hasMouse = winUnderMouse == gdk_event->window;
1523 if ( hasMouse != g_captureWindowHasMouse )
1524 {
1525 // the mouse changed window
1526 g_captureWindowHasMouse = hasMouse;
1527
1528 wxMouseEvent event(g_captureWindowHasMouse ? wxEVT_ENTER_WINDOW
1529 : wxEVT_LEAVE_WINDOW);
c5f9d156 1530 InitMouseEvent(win, event, gdk_event);
1e6feb95
VZ
1531 event.SetEventObject(win);
1532 win->GetEventHandler()->ProcessEvent(event);
1533 }
1534 }
1535 else // no capture
1536 {
1537 // Some control don't have their own X window and thus cannot get
1538 // any events.
1539
b02da6b1
VZ
1540 wxCoord x = event.m_x;
1541 wxCoord y = event.m_y;
2f073eb2
RR
1542 if (win->m_wxwindow)
1543 {
da048e3d 1544 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
b02da6b1
VZ
1545 x += pizza->xoffset;
1546 y += pizza->yoffset;
2f073eb2
RR
1547 }
1548
db1b4961 1549 wxNode *node = win->GetChildren().First();
e380f72b
RR
1550 while (node)
1551 {
1e6feb95 1552 wxWindowGTK *child = (wxWindowGTK*)node->Data();
ff8bfdbb 1553
f96ac56a 1554 node = node->Next();
b02da6b1
VZ
1555 if (!child->IsShown())
1556 continue;
f96ac56a 1557
a2053b27 1558 if (child->m_isStaticBox)
ff8bfdbb
VZ
1559 {
1560 // wxStaticBox is transparent in the box itself
a2053b27
RR
1561 int xx1 = child->m_x;
1562 int yy1 = child->m_y;
1563 int xx2 = child->m_x + child->m_width;
1564 int yy2 = child->m_x + child->m_height;
ff8bfdbb
VZ
1565
1566 // left
1567 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1568 // right
1569 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1570 // top
1571 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1572 // bottom
1573 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1574 {
1ecc4d80 1575 win = child;
a2053b27
RR
1576 event.m_x -= child->m_x;
1577 event.m_y -= child->m_y;
1ecc4d80 1578 break;
ff8bfdbb
VZ
1579 }
1580
1581 }
1582 else
1583 {
a2053b27 1584 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
2f073eb2
RR
1585 (child->m_x <= x) &&
1586 (child->m_y <= y) &&
1587 (child->m_x+child->m_width >= x) &&
1588 (child->m_y+child->m_height >= y))
1ecc4d80
RR
1589 {
1590 win = child;
a2053b27
RR
1591 event.m_x -= child->m_x;
1592 event.m_y -= child->m_y;
1ecc4d80 1593 break;
ff8bfdbb 1594 }
e380f72b 1595 }
e380f72b 1596 }
2f2aa628 1597 }
47d67540 1598
e380f72b 1599 event.SetEventObject( win );
47d67540 1600
e380f72b 1601 if (win->GetEventHandler()->ProcessEvent( event ))
034be888 1602 {
e380f72b 1603 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "motion_notify_event" );
f03fc89f 1604 return TRUE;
034be888 1605 }
47d67540 1606
034be888 1607 return FALSE;
362c6693 1608}
c801d85f
KB
1609
1610//-----------------------------------------------------------------------------
2f2aa628
RR
1611// "focus_in_event"
1612//-----------------------------------------------------------------------------
c801d85f 1613
1e6feb95
VZ
1614static gint gtk_window_focus_in_callback( GtkWidget *widget,
1615 GdkEvent *WXUNUSED(event),
1616 wxWindow *win )
c801d85f 1617{
3ac8d3bc
RR
1618 DEBUG_MAIN_THREAD
1619
c50f1fb9 1620 if (g_isIdle)
a2053b27
RR
1621 wxapp_install_idle_handler();
1622
1623 if (!win->m_hasVMT) return FALSE;
034be888 1624 if (g_blockEventsOnDrag) return FALSE;
ff8bfdbb 1625
148cd9b6
VZ
1626 switch ( g_sendActivateEvent )
1627 {
1628 case -1:
76fcf0f2 1629 // we've got focus from outside, synthetize wxActivateEvent
148cd9b6
VZ
1630 g_sendActivateEvent = 1;
1631 break;
1632
1633 case 0:
1634 // another our window just lost focus, it was already ours before
1635 // - don't send any wxActivateEvent
1636 g_sendActivateEvent = -1;
1637 break;
1638 }
1639
1e6feb95 1640 g_focusWindowLast =
b292e2f5 1641 g_focusWindow = win;
ff8bfdbb 1642
76fcf0f2
RR
1643#if 0
1644 wxPrintf( "OnSetFocus from " );
e380f72b 1645 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
76fcf0f2
RR
1646 wxPrintf( win->GetClassInfo()->GetClassName() );
1647 wxPrintf( ".\n" );
1648#endif
47d67540 1649
456bc6d9
VZ
1650 // notify the parent keeping track of focus for the kbd navigation
1651 // purposes that we got it
5314ac16
VZ
1652 wxChildFocusEvent eventFocus(win);
1653 (void)win->GetEventHandler()->ProcessEvent(eventFocus);
148cd9b6 1654
b79395c5
RR
1655#ifdef HAVE_XIM
1656 if (win->m_ic)
1657 gdk_im_begin(win->m_ic, win->m_wxwindow->window);
1658#endif
1659
1e6feb95 1660#if wxUSE_CARET
f6bcfd97
BP
1661 // caret needs to be informed about focus change
1662 wxCaret *caret = win->GetCaret();
1663 if ( caret )
1664 {
1665 caret->OnSetFocus();
1666 }
1667#endif // wxUSE_CARET
1668
e8c12a53
VS
1669 wxWindowGTK *active = wxGetTopLevelParent(win);
1670 if ( active != g_activeFrame )
942bef71 1671 {
e8c12a53
VS
1672 if ( g_activeFrame )
1673 {
45eb5249 1674 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame);
e8c12a53
VS
1675 wxActivateEvent event(wxEVT_ACTIVATE, FALSE, g_activeFrame->GetId());
1676 event.SetEventObject(g_activeFrame);
1677 g_activeFrame->GetEventHandler()->ProcessEvent(event);
1678 }
47d67540 1679
45eb5249 1680 wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active);
e8c12a53
VS
1681 g_activeFrame = active;
1682 wxActivateEvent event(wxEVT_ACTIVATE, TRUE, g_activeFrame->GetId());
1683 event.SetEventObject(g_activeFrame);
1684 g_activeFrame->GetEventHandler()->ProcessEvent(event);
942bef71 1685 }
e8c12a53
VS
1686 g_activeFrameLostFocus = FALSE;
1687
942bef71 1688
5cd09f0b
RR
1689 wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() );
1690 event.SetEventObject( win );
1691
1692 if (win->GetEventHandler()->ProcessEvent( event ))
1693 {
1694 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
1695 return TRUE;
034be888 1696 }
ca298c88 1697
942bef71 1698
034be888 1699 return FALSE;
362c6693 1700}
c801d85f
KB
1701
1702//-----------------------------------------------------------------------------
2f2aa628
RR
1703// "focus_out_event"
1704//-----------------------------------------------------------------------------
c801d85f 1705
b231914f
VZ
1706static GtkWidget *gs_widgetLastFocus = NULL;
1707
1e6feb95 1708static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindowGTK *win )
c801d85f 1709{
3ac8d3bc
RR
1710 DEBUG_MAIN_THREAD
1711
c50f1fb9 1712 if (g_isIdle)
a2053b27
RR
1713 wxapp_install_idle_handler();
1714
1715 if (!win->m_hasVMT) return FALSE;
034be888 1716 if (g_blockEventsOnDrag) return FALSE;
ca298c88 1717
b231914f
VZ
1718 // VZ: this is really weird but GTK+ seems to call us from inside
1719 // gtk_widget_grab_focus(), i.e. it first sends "focus_out" signal to
1720 // this widget and then "focus_in". This is totally unexpected and
1721 // completely breaks wxUniv code so ignore this dummy event (we can't
1722 // be losing focus if we're about to acquire it!)
1723 if ( widget == gs_widgetLastFocus )
1724 {
1725 gs_widgetLastFocus = NULL;
1726
55fb2c6c 1727 return FALSE;
b231914f
VZ
1728 }
1729
45eb5249
VS
1730 if ( !g_activeFrameLostFocus && g_activeFrame )
1731 {
c0ad3d42
VZ
1732 // VZ: commenting this out because it does happen (although not easy
1733 // to reproduce, I only see it when using wxMiniFrame and not
1734 // always) and makes using Mahogany quite annoying
1735#if 0
1736 wxASSERT_MSG( wxGetTopLevelParent(win) == g_activeFrame,
1737 wxT("unfocusing window that hasn't gained focus properly") )
1738#endif // 0
1739
45eb5249
VS
1740 g_activeFrameLostFocus = TRUE;
1741 }
1742
148cd9b6
VZ
1743 // if the focus goes out of our app alltogether, OnIdle() will send
1744 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1745 // g_sendActivateEvent to -1
1746 g_sendActivateEvent = 0;
1747
3379ed37 1748 wxWindowGTK *winFocus = wxFindFocusedChild(win);
f6bcfd97
BP
1749 if ( winFocus )
1750 win = winFocus;
1751
1e6feb95 1752 g_focusWindow = (wxWindowGTK *)NULL;
148cd9b6 1753
76fcf0f2
RR
1754#if 0
1755 wxPrintf( "OnKillFocus from " );
e380f72b 1756 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
76fcf0f2
RR
1757 wxPrintf( win->GetClassInfo()->GetClassName() );
1758 wxPrintf( ".\n" );
1759#endif
47d67540 1760
b79395c5
RR
1761#ifdef HAVE_XIM
1762 if (win->m_ic)
1763 gdk_im_end();
1764#endif
1765
1e6feb95 1766#if wxUSE_CARET
f6bcfd97
BP
1767 // caret needs to be informed about focus change
1768 wxCaret *caret = win->GetCaret();
1769 if ( caret )
1770 {
1771 caret->OnKillFocus();
1772 }
1773#endif // wxUSE_CARET
1774
5cd09f0b
RR
1775 wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
1776 event.SetEventObject( win );
1777
1778 if (win->GetEventHandler()->ProcessEvent( event ))
1779 {
1780 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_out_event" );
1781 return TRUE;
034be888 1782 }
ca298c88 1783
034be888 1784 return FALSE;
362c6693 1785}
c801d85f 1786
b4071e91
RR
1787//-----------------------------------------------------------------------------
1788// "enter_notify_event"
1789//-----------------------------------------------------------------------------
1790
1e6feb95 1791static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win )
b4071e91 1792{
3ac8d3bc
RR
1793 DEBUG_MAIN_THREAD
1794
c50f1fb9 1795 if (g_isIdle)
a2053b27 1796 wxapp_install_idle_handler();
ca298c88 1797
a2053b27
RR
1798 if (!win->m_hasVMT) return FALSE;
1799 if (g_blockEventsOnDrag) return FALSE;
47d67540 1800
a2053b27 1801 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
b292e2f5 1802
e380f72b 1803 wxMouseEvent event( wxEVT_ENTER_WINDOW );
d1367c3d 1804 event.SetTimestamp( gdk_event->time );
e380f72b 1805 event.SetEventObject( win );
ff8bfdbb 1806
4a33eba6
RR
1807 int x = 0;
1808 int y = 0;
1809 GdkModifierType state = (GdkModifierType)0;
ff8bfdbb 1810
a2053b27 1811 gdk_window_get_pointer( widget->window, &x, &y, &state );
ff8bfdbb 1812
c5f9d156
VS
1813 InitMouseEvent(win, event, gdk_event);
1814 wxPoint pt = win->GetClientAreaOrigin();
1815 event.m_x = x + pt.x;
1816 event.m_y = y + pt.y;
ff8bfdbb 1817
e380f72b 1818 if (win->GetEventHandler()->ProcessEvent( event ))
034be888 1819 {
e380f72b 1820 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "enter_notify_event" );
034be888
RR
1821 return TRUE;
1822 }
ca298c88 1823
034be888 1824 return FALSE;
b4071e91 1825}
47d67540 1826
b4071e91
RR
1827//-----------------------------------------------------------------------------
1828// "leave_notify_event"
1829//-----------------------------------------------------------------------------
1830
1e6feb95 1831static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win )
b4071e91 1832{
3ac8d3bc
RR
1833 DEBUG_MAIN_THREAD
1834
c50f1fb9 1835 if (g_isIdle)
a2053b27 1836 wxapp_install_idle_handler();
acfd422a 1837
a2053b27
RR
1838 if (!win->m_hasVMT) return FALSE;
1839 if (g_blockEventsOnDrag) return FALSE;
b292e2f5 1840
a2053b27 1841 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
c50f1fb9 1842
e380f72b 1843 wxMouseEvent event( wxEVT_LEAVE_WINDOW );
d1367c3d 1844 event.SetTimestamp( gdk_event->time );
e380f72b 1845 event.SetEventObject( win );
47d67540 1846
4a33eba6
RR
1847 int x = 0;
1848 int y = 0;
1849 GdkModifierType state = (GdkModifierType)0;
ff8bfdbb 1850
4a33eba6 1851 gdk_window_get_pointer( widget->window, &x, &y, &state );
ff8bfdbb 1852
4a33eba6
RR
1853 event.m_shiftDown = (state & GDK_SHIFT_MASK);
1854 event.m_controlDown = (state & GDK_CONTROL_MASK);
1855 event.m_altDown = (state & GDK_MOD1_MASK);
1856 event.m_metaDown = (state & GDK_MOD2_MASK);
1857 event.m_leftDown = (state & GDK_BUTTON1_MASK);
1858 event.m_middleDown = (state & GDK_BUTTON2_MASK);
1859 event.m_rightDown = (state & GDK_BUTTON3_MASK);
1860
c5f9d156
VS
1861 wxPoint pt = win->GetClientAreaOrigin();
1862 event.m_x = x + pt.x;
1863 event.m_y = y + pt.y;
ff8bfdbb 1864
e380f72b 1865 if (win->GetEventHandler()->ProcessEvent( event ))
034be888 1866 {
e380f72b 1867 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "leave_notify_event" );
034be888
RR
1868 return TRUE;
1869 }
ca298c88 1870
034be888 1871 return FALSE;
b4071e91 1872}
47d67540 1873
c801d85f 1874//-----------------------------------------------------------------------------
2f2aa628
RR
1875// "value_changed" from m_vAdjust
1876//-----------------------------------------------------------------------------
c801d85f 1877
1e6feb95 1878static void gtk_window_vscroll_callback( GtkAdjustment *adjust, wxWindowGTK *win )
c801d85f 1879{
3ac8d3bc
RR
1880 DEBUG_MAIN_THREAD
1881
c50f1fb9 1882 if (g_isIdle)
a2053b27 1883 wxapp_install_idle_handler();
c801d85f 1884
a2053b27 1885 if (g_blockEventsOnDrag) return;
47d67540 1886
a2053b27 1887 if (!win->m_hasVMT) return;
148cd9b6 1888
5e014a0c 1889 float diff = adjust->value - win->m_oldVerticalPos;
e380f72b 1890 if (fabs(diff) < 0.2) return;
148cd9b6 1891
5e014a0c 1892 win->m_oldVerticalPos = adjust->value;
47d67540 1893
5e014a0c
RR
1894 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1895 GtkRange *range = GTK_RANGE( scrolledWindow->vscrollbar );
148cd9b6 1896
5e014a0c
RR
1897 wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK;
1898 if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP;
1899 else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN;
1900 else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP;
1901 else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN;
148cd9b6 1902
5e014a0c 1903 int value = (int)(adjust->value+0.5);
c801d85f 1904
c5b42c87 1905 wxScrollWinEvent event( command, value, wxVERTICAL );
e380f72b
RR
1906 event.SetEventObject( win );
1907 win->GetEventHandler()->ProcessEvent( event );
362c6693 1908}
c801d85f
KB
1909
1910//-----------------------------------------------------------------------------
2f2aa628
RR
1911// "value_changed" from m_hAdjust
1912//-----------------------------------------------------------------------------
c801d85f 1913
1e6feb95 1914static void gtk_window_hscroll_callback( GtkAdjustment *adjust, wxWindowGTK *win )
47d67540 1915{
3ac8d3bc
RR
1916 DEBUG_MAIN_THREAD
1917
c50f1fb9 1918 if (g_isIdle)
a2053b27 1919 wxapp_install_idle_handler();
47d67540 1920
a2053b27
RR
1921 if (g_blockEventsOnDrag) return;
1922 if (!win->m_hasVMT) return;
47d67540 1923
5e014a0c 1924 float diff = adjust->value - win->m_oldHorizontalPos;
e380f72b 1925 if (fabs(diff) < 0.2) return;
148cd9b6 1926
5e014a0c 1927 win->m_oldHorizontalPos = adjust->value;
8bbe427f 1928
5e014a0c
RR
1929 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1930 GtkRange *range = GTK_RANGE( scrolledWindow->hscrollbar );
148cd9b6 1931
5e014a0c
RR
1932 wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK;
1933 if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP;
1934 else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN;
1935 else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP;
1936 else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN;
148cd9b6 1937
5e014a0c 1938 int value = (int)(adjust->value+0.5);
47d67540 1939
c5b42c87 1940 wxScrollWinEvent event( command, value, wxHORIZONTAL );
e380f72b
RR
1941 event.SetEventObject( win );
1942 win->GetEventHandler()->ProcessEvent( event );
362c6693 1943}
c801d85f 1944
cb43b372
RR
1945//-----------------------------------------------------------------------------
1946// "button_press_event" from scrollbar
1947//-----------------------------------------------------------------------------
1948
2a23d363
RR
1949static gint gtk_scrollbar_button_press_callback( GtkRange *widget,
1950 GdkEventButton *gdk_event,
1e6feb95 1951 wxWindowGTK *win)
cb43b372 1952{
3ac8d3bc
RR
1953 DEBUG_MAIN_THREAD
1954
c50f1fb9 1955 if (g_isIdle)
a2053b27
RR
1956 wxapp_install_idle_handler();
1957
d6d26e04 1958
5b8a521e 1959 g_blockEventsOnScroll = TRUE;
2a23d363 1960 win->m_isScrolling = (gdk_event->window == widget->slider);
47d67540 1961
e380f72b 1962 return FALSE;
cb43b372
RR
1963}
1964
1965//-----------------------------------------------------------------------------
1966// "button_release_event" from scrollbar
1967//-----------------------------------------------------------------------------
1968
88413fec 1969static gint gtk_scrollbar_button_release_callback( GtkRange *widget,
8bbe427f 1970 GdkEventButton *WXUNUSED(gdk_event),
1e6feb95 1971 wxWindowGTK *win)
cb43b372 1972{
3ac8d3bc
RR
1973 DEBUG_MAIN_THREAD
1974
1ecc4d80 1975// don't test here as we can release the mouse while being over
5e014a0c 1976// a different window than the slider
76ed8f8d
RR
1977//
1978// if (gdk_event->window != widget->slider) return FALSE;
cb43b372 1979
5b8a521e 1980 g_blockEventsOnScroll = FALSE;
47d67540 1981
2a23d363 1982 if (win->m_isScrolling)
88413fec 1983 {
d6d26e04 1984 wxEventType command = wxEVT_SCROLLWIN_THUMBRELEASE;
2a23d363
RR
1985 int value = -1;
1986 int dir = -1;
2daa0ce9 1987
2a23d363
RR
1988 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1989 if (widget == GTK_RANGE(scrolledWindow->hscrollbar))
1990 {
1991 value = (int)(win->m_hAdjust->value+0.5);
1992 dir = wxHORIZONTAL;
1993 }
1994 if (widget == GTK_RANGE(scrolledWindow->vscrollbar))
1995 {
1996 value = (int)(win->m_vAdjust->value+0.5);
1997 dir = wxVERTICAL;
1998 }
2daa0ce9 1999
2a23d363 2000 wxScrollWinEvent event( command, value, dir );
2a23d363
RR
2001 event.SetEventObject( win );
2002 win->GetEventHandler()->ProcessEvent( event );
88413fec
RR
2003 }
2004
2a23d363 2005 win->m_isScrolling = FALSE;
2daa0ce9 2006
e380f72b 2007 return FALSE;
cb43b372
RR
2008}
2009
f03fc89f
VZ
2010// ----------------------------------------------------------------------------
2011// this wxWindowBase function is implemented here (in platform-specific file)
2012// because it is static and so couldn't be made virtual
2013// ----------------------------------------------------------------------------
2b07d713 2014
f03fc89f 2015wxWindow *wxWindowBase::FindFocus()
2b07d713 2016{
1e6feb95
VZ
2017 // the cast is necessary when we compile in wxUniversal mode
2018 return (wxWindow *)g_focusWindow;
2b07d713 2019}
ca298c88 2020
a2053b27
RR
2021//-----------------------------------------------------------------------------
2022// "realize" from m_widget
2023//-----------------------------------------------------------------------------
2024
b79395c5
RR
2025/* We cannot set colours and fonts before the widget has
2026 been realized, so we do this directly after realization. */
a2053b27
RR
2027
2028static gint
63081513 2029gtk_window_realized_callback( GtkWidget *WXUNUSED(m_widget), wxWindow *win )
a2053b27 2030{
3ac8d3bc
RR
2031 DEBUG_MAIN_THREAD
2032
c50f1fb9 2033 if (g_isIdle)
a2053b27
RR
2034 wxapp_install_idle_handler();
2035
739730ca
RR
2036 if (win->m_delayedBackgroundColour)
2037 win->SetBackgroundColour( win->GetBackgroundColour() );
a2053b27 2038
739730ca
RR
2039 if (win->m_delayedForegroundColour)
2040 win->SetForegroundColour( win->GetForegroundColour() );
a2053b27 2041
3c679789
RR
2042 wxWindowCreateEvent event( win );
2043 event.SetEventObject( win );
2044 win->GetEventHandler()->ProcessEvent( event );
1e6feb95 2045
a2053b27
RR
2046 return FALSE;
2047}
2048
b79395c5
RR
2049//-----------------------------------------------------------------------------
2050// "size_allocate"
2051//-----------------------------------------------------------------------------
2052
8f75cb6c 2053static
adc1999b
RR
2054void gtk_window_size_callback( GtkWidget *WXUNUSED(widget),
2055 GtkAllocation *WXUNUSED(alloc),
8f75cb6c
RR
2056 wxWindow *win )
2057{
2058 if (g_isIdle)
2059 wxapp_install_idle_handler();
2daa0ce9 2060
5b8a521e 2061 if (!win->m_hasScrolling) return;
2daa0ce9 2062
5b8a521e
RR
2063 int client_width = 0;
2064 int client_height = 0;
2065 win->GetClientSize( &client_width, &client_height );
2066 if ((client_width == win->m_oldClientWidth) && (client_height == win->m_oldClientHeight))
2067 return;
2daa0ce9 2068
5b8a521e
RR
2069 win->m_oldClientWidth = client_width;
2070 win->m_oldClientHeight = client_height;
2daa0ce9 2071
5b8a521e
RR
2072 if (!win->m_nativeSizeEvent)
2073 {
2074 wxSizeEvent event( win->GetSize(), win->GetId() );
2075 event.SetEventObject( win );
2076 win->GetEventHandler()->ProcessEvent( event );
2077 }
8f75cb6c
RR
2078}
2079
2080
3ed2e7ce
VZ
2081#ifdef HAVE_XIM
2082 #define WXUNUSED_UNLESS_XIM(param) param
2083#else
2084 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2085#endif
2086
b79395c5
RR
2087/* Resize XIM window */
2088
3ed2e7ce 2089static
8f75cb6c
RR
2090void gtk_wxwindow_size_callback( GtkWidget* WXUNUSED_UNLESS_XIM(widget),
2091 GtkAllocation* WXUNUSED_UNLESS_XIM(alloc),
1e6feb95 2092 wxWindowGTK* WXUNUSED_UNLESS_XIM(win) )
b79395c5
RR
2093{
2094 if (g_isIdle)
2095 wxapp_install_idle_handler();
2daa0ce9 2096
9a8c7620 2097#ifdef HAVE_XIM
b79395c5
RR
2098 if (!win->m_ic)
2099 return;
2100
b79395c5
RR
2101 if (gdk_ic_get_style (win->m_ic) & GDK_IM_PREEDIT_POSITION)
2102 {
2103 gint width, height;
2104
3ed2e7ce 2105 gdk_window_get_size (widget->window, &width, &height);
b79395c5
RR
2106 win->m_icattr->preedit_area.width = width;
2107 win->m_icattr->preedit_area.height = height;
2108 gdk_ic_set_attr (win->m_ic, win->m_icattr, GDK_IC_PREEDIT_AREA);
2109 }
9a8c7620 2110#endif // HAVE_XIM
b79395c5
RR
2111}
2112
63081513
RR
2113//-----------------------------------------------------------------------------
2114// "realize" from m_wxwindow
2115//-----------------------------------------------------------------------------
2116
2117/* Initialize XIM support */
2118
2119static gint
3ed2e7ce 2120gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget),
1e6feb95 2121 wxWindowGTK * WXUNUSED_UNLESS_XIM(win) )
63081513
RR
2122{
2123 if (g_isIdle)
2124 wxapp_install_idle_handler();
2125
d06800f1 2126#ifdef HAVE_XIM
63081513
RR
2127 if (win->m_ic) return FALSE;
2128 if (!widget) return FALSE;
2129 if (!gdk_im_ready()) return FALSE;
2130
2131 win->m_icattr = gdk_ic_attr_new();
2132 if (!win->m_icattr) return FALSE;
2daa0ce9 2133
63081513
RR
2134 gint width, height;
2135 GdkEventMask mask;
2136 GdkColormap *colormap;
2137 GdkICAttr *attr = win->m_icattr;
b58b1dfc 2138 unsigned attrmask = GDK_IC_ALL_REQ;
63081513 2139 GdkIMStyle style;
b79395c5
RR
2140 GdkIMStyle supported_style = (GdkIMStyle)
2141 (GDK_IM_PREEDIT_NONE |
1e6feb95
VZ
2142 GDK_IM_PREEDIT_NOTHING |
2143 GDK_IM_PREEDIT_POSITION |
2144 GDK_IM_STATUS_NONE |
2145 GDK_IM_STATUS_NOTHING);
63081513
RR
2146
2147 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
1e6feb95 2148 supported_style = (GdkIMStyle)(supported_style & ~GDK_IM_PREEDIT_POSITION);
63081513
RR
2149
2150 attr->style = style = gdk_im_decide_style (supported_style);
2151 attr->client_window = widget->window;
2152
2153 if ((colormap = gtk_widget_get_colormap (widget)) !=
1e6feb95 2154 gtk_widget_get_default_colormap ())
63081513 2155 {
5cd09f0b
RR
2156 attrmask |= GDK_IC_PREEDIT_COLORMAP;
2157 attr->preedit_colormap = colormap;
63081513 2158 }
2daa0ce9 2159
63081513
RR
2160 attrmask |= GDK_IC_PREEDIT_FOREGROUND;
2161 attrmask |= GDK_IC_PREEDIT_BACKGROUND;
2162 attr->preedit_foreground = widget->style->fg[GTK_STATE_NORMAL];
2163 attr->preedit_background = widget->style->base[GTK_STATE_NORMAL];
2164
2165 switch (style & GDK_IM_PREEDIT_MASK)
2166 {
1e6feb95
VZ
2167 case GDK_IM_PREEDIT_POSITION:
2168 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
2169 {
2170 g_warning ("over-the-spot style requires fontset");
2171 break;
2172 }
63081513 2173
1e6feb95 2174 gdk_window_get_size (widget->window, &width, &height);
63081513 2175
1e6feb95
VZ
2176 attrmask |= GDK_IC_PREEDIT_POSITION_REQ;
2177 attr->spot_location.x = 0;
2178 attr->spot_location.y = height;
2179 attr->preedit_area.x = 0;
2180 attr->preedit_area.y = 0;
2181 attr->preedit_area.width = width;
2182 attr->preedit_area.height = height;
2183 attr->preedit_fontset = widget->style->font;
63081513 2184
1e6feb95 2185 break;
b79395c5 2186 }
2daa0ce9 2187
b58b1dfc 2188 win->m_ic = gdk_ic_new (attr, (GdkICAttributesType)attrmask);
2daa0ce9 2189
63081513 2190 if (win->m_ic == NULL)
1e6feb95 2191 g_warning ("Can't create input context.");
63081513 2192 else
1e6feb95
VZ
2193 {
2194 mask = gdk_window_get_events (widget->window);
2195 mask = (GdkEventMask)(mask | gdk_ic_get_events (win->m_ic));
2196 gdk_window_set_events (widget->window, mask);
2197
2198 if (GTK_WIDGET_HAS_FOCUS(widget))
2199 gdk_im_begin (win->m_ic, widget->window);
2200 }
2201#endif // HAVE_XIM
63081513
RR
2202
2203 return FALSE;
2204}
2205
6ca41e57 2206//-----------------------------------------------------------------------------
1e6feb95 2207// InsertChild for wxWindowGTK.
6ca41e57
RR
2208//-----------------------------------------------------------------------------
2209
1e6feb95 2210/* Callback for wxWindowGTK. This very strange beast has to be used because
b1170810
RR
2211 * C++ has no virtual methods in a constructor. We have to emulate a
2212 * virtual function here as wxNotebook requires a different way to insert
2213 * a child in it. I had opted for creating a wxNotebookPage window class
2214 * which would have made this superfluous (such in the MDI window system),
2215 * but no-one was listening to me... */
6ca41e57 2216
1e6feb95 2217static void wxInsertChildInWindow( wxWindowGTK* parent, wxWindowGTK* child )
6ca41e57 2218{
bf0c00c6
RR
2219 /* the window might have been scrolled already, do we
2220 have to adapt the position */
da048e3d
RR
2221 GtkPizza *pizza = GTK_PIZZA(parent->m_wxwindow);
2222 child->m_x += pizza->xoffset;
2223 child->m_y += pizza->yoffset;
148cd9b6 2224
da048e3d 2225 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
a2053b27
RR
2226 GTK_WIDGET(child->m_widget),
2227 child->m_x,
2228 child->m_y,
2229 child->m_width,
2230 child->m_height );
6ca41e57
RR
2231}
2232
bbe0af5b
RR
2233//-----------------------------------------------------------------------------
2234// global functions
2235//-----------------------------------------------------------------------------
2236
1e6feb95 2237wxWindow *wxGetActiveWindow()
bbe0af5b 2238{
1e6feb95
VZ
2239 // the cast is necessary when we compile in wxUniversal mode
2240 return (wxWindow *)g_focusWindow;
bbe0af5b
RR
2241}
2242
c801d85f 2243//-----------------------------------------------------------------------------
1e6feb95 2244// wxWindowGTK
c801d85f
KB
2245//-----------------------------------------------------------------------------
2246
6522713c
VZ
2247// in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2248// method
1e6feb95 2249#ifdef __WXUNIVERSAL__
6522713c
VZ
2250 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK, wxWindowBase)
2251#else // __WXGTK__
1e6feb95 2252 IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
6522713c 2253#endif // __WXUNIVERSAL__/__WXGTK__
c801d85f 2254
1e6feb95 2255void wxWindowGTK::Init()
c801d85f 2256{
f03fc89f
VZ
2257 // common init
2258 InitBase();
68995f26 2259
f03fc89f 2260 // GTK specific
a2053b27 2261 m_widget = (GtkWidget *) NULL;
e380f72b 2262 m_wxwindow = (GtkWidget *) NULL;
76fcf0f2 2263 m_focusWidget = (GtkWidget *) NULL;
8bbe427f 2264
f03fc89f 2265 // position/size
a2053b27
RR
2266 m_x = 0;
2267 m_y = 0;
2268 m_width = 0;
e380f72b 2269 m_height = 0;
8bbe427f 2270
e380f72b
RR
2271 m_sizeSet = FALSE;
2272 m_hasVMT = FALSE;
2273 m_needParent = TRUE;
31c6b4fc 2274 m_isBeingDeleted = FALSE;
148cd9b6 2275
147bc491 2276 m_noExpose = FALSE;
30760ce7 2277 m_nativeSizeEvent = FALSE;
94633ad9 2278
a2053b27 2279 m_hasScrolling = FALSE;
846e1424 2280 m_isScrolling = FALSE;
f03fc89f 2281
a2053b27 2282 m_hAdjust = (GtkAdjustment*) NULL;
e380f72b 2283 m_vAdjust = (GtkAdjustment*) NULL;
a2053b27 2284 m_oldHorizontalPos = 0.0;
e380f72b 2285 m_oldVerticalPos = 0.0;
8bbe427f 2286
e380f72b 2287 m_resizing = FALSE;
e380f72b 2288 m_widgetStyle = (GtkStyle*) NULL;
8bbe427f 2289
ddb6bc71 2290 m_insertCallback = (wxInsertChildFunction) NULL;
8bbe427f 2291
1ecc4d80 2292 m_isStaticBox = FALSE;
953704c1 2293 m_isRadioButton = FALSE;
e2762ff0 2294 m_isListBox = FALSE;
54517652 2295 m_isFrame = FALSE;
b292e2f5 2296 m_acceptsFocus = FALSE;
148cd9b6 2297
b6fa52db 2298 m_clipPaintRegion = FALSE;
b6fa52db 2299
5e014a0c 2300 m_cursor = *wxSTANDARD_CURSOR;
2daa0ce9 2301
f6bcfd97
BP
2302 m_delayedForegroundColour = FALSE;
2303 m_delayedBackgroundColour = FALSE;
1e6feb95 2304
63081513
RR
2305#ifdef HAVE_XIM
2306 m_ic = (GdkIC*) NULL;
2307 m_icattr = (GdkICAttr*) NULL;
2308#endif
362c6693 2309}
c801d85f 2310
1e6feb95 2311wxWindowGTK::wxWindowGTK()
68995f26
VZ
2312{
2313 Init();
2314}
2315
1e6feb95
VZ
2316wxWindowGTK::wxWindowGTK( wxWindow *parent,
2317 wxWindowID id,
2318 const wxPoint &pos,
2319 const wxSize &size,
2320 long style,
2321 const wxString &name )
6ca41e57 2322{
68995f26
VZ
2323 Init();
2324
e380f72b 2325 Create( parent, id, pos, size, style, name );
6ca41e57 2326}
8bbe427f 2327
1e6feb95
VZ
2328bool wxWindowGTK::Create( wxWindow *parent,
2329 wxWindowID id,
2330 const wxPoint &pos,
2331 const wxSize &size,
2332 long style,
2333 const wxString &name )
c801d85f 2334{
4dcaf11a
RR
2335 if (!PreCreation( parent, pos, size ) ||
2336 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
2337 {
1e6feb95 2338 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
b02da6b1 2339 return FALSE;
4dcaf11a 2340 }
47d67540 2341
ddb6bc71 2342 m_insertCallback = wxInsertChildInWindow;
1e6feb95 2343
e380f72b 2344 m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
38c7b3d3 2345 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
ff8bfdbb 2346
f03fc89f 2347 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
47d67540 2348
dd00f3f6 2349 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
e380f72b 2350 scroll_class->scrollbar_spacing = 0;
47d67540 2351
f03fc89f 2352 gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
47d67540 2353
f03fc89f
VZ
2354 m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->hscrollbar) );
2355 m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->vscrollbar) );
47d67540 2356
da048e3d 2357 m_wxwindow = gtk_pizza_new();
38c7b3d3 2358
034be888 2359 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
58dea4b0 2360
1e6feb95 2361#ifndef __WXUNIVERSAL__
034be888 2362#if (GTK_MINOR_VERSION > 0)
da048e3d 2363 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
b292e2f5 2364
f03fc89f 2365 if (HasFlag(wxRAISED_BORDER))
034be888 2366 {
da048e3d 2367 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_OUT );
034be888 2368 }
f03fc89f 2369 else if (HasFlag(wxSUNKEN_BORDER))
034be888 2370 {
da048e3d 2371 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_IN );
5e014a0c
RR
2372 }
2373 else if (HasFlag(wxSIMPLE_BORDER))
2374 {
da048e3d 2375 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_THIN );
034be888
RR
2376 }
2377 else
2378 {
da048e3d 2379 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_NONE );
034be888 2380 }
f03fc89f
VZ
2381#else // GTK_MINOR_VERSION == 0
2382 GtkViewport *viewport = GTK_VIEWPORT(scrolledWindow->viewport);
b292e2f5 2383
f03fc89f 2384 if (HasFlag(wxRAISED_BORDER))
e380f72b
RR
2385 {
2386 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_OUT );
2387 }
f03fc89f 2388 else if (HasFlag(wxSUNKEN_BORDER))
e380f72b
RR
2389 {
2390 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_IN );
2391 }
2392 else
2393 {
2394 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_NONE );
2395 }
f03fc89f 2396#endif // GTK_MINOR_VERSION
1e6feb95 2397#endif // __WXUNIVERSAL__
47d67540 2398
3da17724
RR
2399 GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
2400 m_acceptsFocus = TRUE;
ca298c88 2401
034be888 2402#if (GTK_MINOR_VERSION == 0)
e380f72b
RR
2403 // shut the viewport up
2404 gtk_viewport_set_hadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
2405 gtk_viewport_set_vadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
f03fc89f 2406#endif // GTK_MINOR_VERSION == 0
e380f72b
RR
2407
2408 // I _really_ don't want scrollbars in the beginning
a2053b27
RR
2409 m_vAdjust->lower = 0.0;
2410 m_vAdjust->upper = 1.0;
2411 m_vAdjust->value = 0.0;
2412 m_vAdjust->step_increment = 1.0;
2413 m_vAdjust->page_increment = 1.0;
2414 m_vAdjust->page_size = 5.0;
2415 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
2416 m_hAdjust->lower = 0.0;
2417 m_hAdjust->upper = 1.0;
2418 m_hAdjust->value = 0.0;
2419 m_hAdjust->step_increment = 1.0;
2420 m_hAdjust->page_increment = 1.0;
2421 m_hAdjust->page_size = 5.0;
2422 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
f03fc89f
VZ
2423
2424 // these handlers block mouse events to any window during scrolling such as
2425 // motion events and prevent GTK and wxWindows from fighting over where the
2426 // slider should be
2427
2428 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_press_event",
76ed8f8d
RR
2429 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2430
f03fc89f 2431 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_press_event",
76ed8f8d
RR
2432 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2433
f03fc89f 2434 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_release_event",
76ed8f8d
RR
2435 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2436
f03fc89f 2437 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_release_event",
76ed8f8d 2438 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
8bbe427f 2439
034be888 2440 // these handlers get notified when screen updates are required either when
76ed8f8d
RR
2441 // scrolling or when the window size (and therefore scrollbar configuration)
2442 // has changed
2443
2444 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
2445 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
2446 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
2447 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
2448
f03fc89f 2449 gtk_widget_show( m_wxwindow );
47d67540 2450
f03fc89f
VZ
2451 if (m_parent)
2452 m_parent->DoAddChild( this );
94633ad9 2453
76fcf0f2 2454 m_focusWidget = m_wxwindow;
8bbe427f 2455
e380f72b 2456 PostCreation();
8bbe427f 2457
e380f72b 2458 Show( TRUE );
c801d85f 2459
e380f72b 2460 return TRUE;
362c6693 2461}
c801d85f 2462
1e6feb95 2463wxWindowGTK::~wxWindowGTK()
c801d85f 2464{
44cd54c2
JS
2465 if (g_focusWindow == this)
2466 g_focusWindow = NULL;
2467
e8c12a53
VS
2468 if (g_activeFrame == this)
2469 g_activeFrame = NULL;
2470
31c6b4fc 2471 m_isBeingDeleted = TRUE;
43a18898 2472 m_hasVMT = FALSE;
47d67540 2473
f03fc89f
VZ
2474 if (m_widget)
2475 Show( FALSE );
8bbe427f 2476
a2053b27
RR
2477 DestroyChildren();
2478
f03fc89f
VZ
2479 if (m_parent)
2480 m_parent->RemoveChild( this );
c801d85f 2481
63081513
RR
2482#ifdef HAVE_XIM
2483 if (m_ic)
2484 gdk_ic_destroy (m_ic);
2485 if (m_icattr)
2486 gdk_ic_attr_destroy (m_icattr);
2487#endif
2488
f03fc89f 2489 if (m_widgetStyle)
a2053b27 2490 {
a56fcaaf 2491#if DISABLE_STYLE_IF_BROKEN_THEME
bce1406b
RR
2492 // don't delete if it's a pixmap theme style
2493 if (!m_widgetStyle->engine_data)
2494 gtk_style_unref( m_widgetStyle );
1e6feb95 2495#endif
c50f1fb9 2496 m_widgetStyle = (GtkStyle*) NULL;
a2053b27 2497 }
c801d85f 2498
f03fc89f 2499 if (m_wxwindow)
a2053b27 2500 {
f03fc89f 2501 gtk_widget_destroy( m_wxwindow );
c50f1fb9 2502 m_wxwindow = (GtkWidget*) NULL;
a2053b27 2503 }
8bbe427f 2504
f03fc89f 2505 if (m_widget)
a2053b27 2506 {
f03fc89f 2507 gtk_widget_destroy( m_widget );
c50f1fb9 2508 m_widget = (GtkWidget*) NULL;
a2053b27 2509 }
362c6693 2510}
c801d85f 2511
1e6feb95 2512bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos, const wxSize &size )
c801d85f 2513{
223d09f6 2514 wxCHECK_MSG( !m_needParent || parent, FALSE, wxT("Need complete parent.") );
8bbe427f 2515
4dcaf11a
RR
2516 /* this turns -1 into 20 so that a minimal window is
2517 visible even although -1,-1 has been given as the
2518 size of the window. the same trick is used in other
2519 ports and should make debugging easier */
f03fc89f
VZ
2520 m_width = WidthDefault(size.x);
2521 m_height = HeightDefault(size.y);
8bbe427f 2522
43a18898
RR
2523 m_x = (int)pos.x;
2524 m_y = (int)pos.y;
8bbe427f 2525
4dcaf11a 2526 /* some reasonable defaults */
148cd9b6 2527 if (!parent)
6ca41e57 2528 {
43a18898
RR
2529 if (m_x == -1)
2530 {
2531 m_x = (gdk_screen_width () - m_width) / 2;
2532 if (m_x < 10) m_x = 10;
2533 }
2534 if (m_y == -1)
2535 {
2536 m_y = (gdk_screen_height () - m_height) / 2;
2537 if (m_y < 10) m_y = 10;
2538 }
6ca41e57 2539 }
148cd9b6 2540
4dcaf11a 2541 return TRUE;
c801d85f
KB
2542}
2543
1e6feb95 2544void wxWindowGTK::PostCreation()
c801d85f 2545{
223d09f6 2546 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
94633ad9 2547
43a18898
RR
2548 if (m_wxwindow)
2549 {
147bc491 2550 if (!m_noExpose)
b02da6b1 2551 {
76fcf0f2 2552 // these get reported to wxWindows -> wxPaintEvent
1e6feb95 2553
b420fb6a
RR
2554 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow), TRUE );
2555
147bc491
RR
2556 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
2557 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
2558
2559 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
2560 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
e22454be
RR
2561
2562 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE))
2563 {
2564 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "event",
2565 GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this );
2566 }
b02da6b1 2567 }
148cd9b6 2568
76fcf0f2 2569 // these are called when the "sunken" or "raised" borders are drawn */
034be888
RR
2570 gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
2571 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
2572
2573 gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
2574 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
43a18898 2575 }
47d67540 2576
76fcf0f2 2577 // focus handling
63081513 2578
76fcf0f2
RR
2579 if (m_focusWidget == NULL)
2580 m_focusWidget = m_widget;
2daa0ce9 2581
76fcf0f2
RR
2582#if 0
2583 if (GetClassInfo() && GetClassInfo()->GetClassName())
2584 wxPrintf( GetClassInfo()->GetClassName() );
2585 wxPrintf( ".\n" );
2586#endif
63081513 2587
76fcf0f2
RR
2588 gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_in_event",
2589 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
2590
2591 gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_out_event",
2592 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
2593
2594 // connect to the various key and mouse handlers
63081513 2595
a2053b27 2596 GtkWidget *connect_widget = GetConnectWidget();
f03fc89f 2597
a2053b27 2598 ConnectWidget( connect_widget );
47d67540 2599
63081513 2600 /* We cannot set colours, fonts and cursors before the widget has
a2053b27
RR
2601 been realized, so we do this directly after realization */
2602 gtk_signal_connect( GTK_OBJECT(connect_widget), "realize",
c50f1fb9 2603 GTK_SIGNAL_FUNC(gtk_window_realized_callback), (gpointer) this );
2daa0ce9 2604
63081513
RR
2605 if (m_wxwindow)
2606 {
47c93b63 2607 // Catch native resize events
8f75cb6c
RR
2608 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2609 GTK_SIGNAL_FUNC(gtk_window_size_callback), (gpointer)this );
2daa0ce9 2610
47c93b63 2611 // Initialize XIM support
63081513
RR
2612 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "realize",
2613 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback), (gpointer) this );
8f75cb6c 2614
47c93b63 2615 // And resize XIM window
b79395c5
RR
2616 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2617 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this );
63081513 2618 }
2daa0ce9 2619
47c93b63
RR
2620 if (!GTK_IS_COMBO(m_widget))
2621 {
2622 // This is needed if we want to add our windows into native
2623 // GTK control, such as the toolbar. With this callback, the
2624 // toolbar gets to know the correct size (the one set by the
2625 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2626 // when moving to GTK 2.0.
2627 gtk_signal_connect( GTK_OBJECT(m_widget), "size_request",
2628 GTK_SIGNAL_FUNC(gtk_window_size_request_callback), (gpointer) this );
2629 }
1e6feb95 2630
43a18898 2631 m_hasVMT = TRUE;
b4071e91
RR
2632}
2633
1e6feb95 2634void wxWindowGTK::ConnectWidget( GtkWidget *widget )
b4071e91 2635{
43a18898
RR
2636 gtk_signal_connect( GTK_OBJECT(widget), "key_press_event",
2637 GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this );
c801d85f 2638
b666df2c
RR
2639 gtk_signal_connect( GTK_OBJECT(widget), "key_release_event",
2640 GTK_SIGNAL_FUNC(gtk_window_key_release_callback), (gpointer)this );
2641
43a18898
RR
2642 gtk_signal_connect( GTK_OBJECT(widget), "button_press_event",
2643 GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
47d67540 2644
43a18898
RR
2645 gtk_signal_connect( GTK_OBJECT(widget), "button_release_event",
2646 GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
47d67540 2647
43a18898
RR
2648 gtk_signal_connect( GTK_OBJECT(widget), "motion_notify_event",
2649 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
47d67540 2650
43a18898
RR
2651 gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event",
2652 GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
47d67540 2653
43a18898
RR
2654 gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
2655 GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
362c6693 2656}
c801d85f 2657
1e6feb95 2658bool wxWindowGTK::Destroy()
c801d85f 2659{
223d09f6 2660 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
47d67540 2661
43a18898 2662 m_hasVMT = FALSE;
c801d85f 2663
f03fc89f 2664 return wxWindowBase::Destroy();
362c6693 2665}
c801d85f 2666
1e6feb95 2667void wxWindowGTK::DoMoveWindow(int x, int y, int width, int height)
23efdd02
RR
2668{
2669 gtk_pizza_set_size( GTK_PIZZA(m_parent->m_wxwindow), m_widget, x, y, width, height );
2670}
2daa0ce9 2671
1e6feb95 2672void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
c801d85f 2673{
223d09f6 2674 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
1e6feb95 2675 wxASSERT_MSG( (m_parent != NULL), wxT("wxWindowGTK::SetSize requires parent.\n") );
8bbe427f 2676
33611ebb 2677/*
f94fca1b 2678 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
33611ebb
RR
2679*/
2680
e27ce4e9 2681 if (m_resizing) return; /* I don't like recursions */
fb1585ae 2682 m_resizing = TRUE;
1e6feb95 2683
b9f29261
VS
2684 int currentX, currentY;
2685 GetPosition(&currentX, &currentY);
2686 if (x == -1)
2687 x = currentX;
a200c35e 2688 if (y == -1)
b9f29261 2689 y = currentY;
a200c35e
VS
2690 AdjustForParentClientOrigin(x, y, sizeFlags);
2691
a2053b27 2692 if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
fb1585ae 2693 {
e27ce4e9 2694 /* don't set the size for children of wxNotebook, just take the values. */
fb1585ae
RR
2695 m_x = x;
2696 m_y = y;
2697 m_width = width;
ba4e3652 2698 m_height = height;
fb1585ae 2699 }
ba4e3652 2700 else
fb1585ae 2701 {
da048e3d 2702 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
148cd9b6 2703
85ad5eb5 2704 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
ba4e3652 2705 {
da048e3d
RR
2706 if (x != -1) m_x = x + pizza->xoffset;
2707 if (y != -1) m_y = y + pizza->yoffset;
ba4e3652
RR
2708 if (width != -1) m_width = width;
2709 if (height != -1) m_height = height;
2710 }
2711 else
2712 {
da048e3d
RR
2713 m_x = x + pizza->xoffset;
2714 m_y = y + pizza->yoffset;
ba4e3652
RR
2715 m_width = width;
2716 m_height = height;
2717 }
47d67540 2718
ba4e3652
RR
2719 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
2720 {
2721 if (width == -1) m_width = 80;
2722 }
2723
2724 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
2725 {
2726 if (height == -1) m_height = 26;
2727 }
8bbe427f 2728
e7dda1ff
VS
2729 int minWidth = GetMinWidth(),
2730 minHeight = GetMinHeight(),
2731 maxWidth = GetMaxWidth(),
2732 maxHeight = GetMaxHeight();
2733
2734 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
2735 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
2736 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
2737 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
47d67540 2738
a2053b27 2739 int border = 0;
c50f1fb9 2740 int bottom_border = 0;
f03fc89f 2741
29f538ce 2742 if (GTK_WIDGET_CAN_DEFAULT(m_widget))
c50f1fb9
VZ
2743 {
2744 /* the default button has a border around it */
2745 border = 6;
2746 bottom_border = 5;
2747 }
2748
23efdd02
RR
2749 DoMoveWindow( m_x-border,
2750 m_y-border,
2751 m_width+2*border,
2752 m_height+border+bottom_border );
54517652 2753 }
148cd9b6 2754
5b8a521e
RR
2755 if (m_hasScrolling)
2756 {
1e6feb95 2757 /* Sometimes the client area changes size without the
b6fa52db
RR
2758 whole windows's size changing, but if the whole
2759 windows's size doesn't change, no wxSizeEvent will
2760 normally be sent. Here we add an extra test if
2761 the client test has been changed and this will
2762 be used then. */
5b8a521e
RR
2763 GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
2764 }
2765
54517652 2766/*
6d693bb4
RR
2767 wxPrintf( "OnSize sent from " );
2768 if (GetClassInfo() && GetClassInfo()->GetClassName())
2769 wxPrintf( GetClassInfo()->GetClassName() );
2770 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2771*/
2772
30760ce7
RR
2773 if (!m_nativeSizeEvent)
2774 {
2775 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
2776 event.SetEventObject( this );
2777 GetEventHandler()->ProcessEvent( event );
2778 }
6d693bb4 2779
fb1585ae 2780 m_resizing = FALSE;
362c6693 2781}
c801d85f 2782
1e6feb95 2783void wxWindowGTK::OnInternalIdle()
9390a202 2784{
beab25bd
RR
2785 // Update invalidated regions.
2786 Update();
2787
2788 // Synthetize activate events.
148cd9b6
VZ
2789 if ( g_sendActivateEvent != -1 )
2790 {
2791 bool activate = g_sendActivateEvent != 0;
2792
2793 // do it only once
2794 g_sendActivateEvent = -1;
2795
1e6feb95 2796 wxTheApp->SetActive(activate, (wxWindow *)g_focusWindowLast);
148cd9b6
VZ
2797 }
2798
e8c12a53
VS
2799 if ( g_activeFrameLostFocus )
2800 {
2801 if ( g_activeFrame )
2802 {
45eb5249 2803 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame);
e8c12a53
VS
2804 wxActivateEvent event(wxEVT_ACTIVATE, FALSE, g_activeFrame->GetId());
2805 event.SetEventObject(g_activeFrame);
2806 g_activeFrame->GetEventHandler()->ProcessEvent(event);
2807 g_activeFrame = NULL;
2808 }
2809 g_activeFrameLostFocus = FALSE;
2810 }
2811
9146082c
RR
2812 wxCursor cursor = m_cursor;
2813 if (g_globalCursor.Ok()) cursor = g_globalCursor;
c50f1fb9 2814
f7a11f8c 2815 if (cursor.Ok())
9146082c 2816 {
3017f78d 2817 /* I now set the cursor anew in every OnInternalIdle call
b02da6b1
VZ
2818 as setting the cursor in a parent window also effects the
2819 windows above so that checking for the current cursor is
2820 not possible. */
148cd9b6 2821
9146082c 2822 if (m_wxwindow)
6a008b33 2823 {
da048e3d 2824 GdkWindow *window = GTK_PIZZA(m_wxwindow)->bin_window;
6a008b33 2825 if (window)
c50f1fb9 2826 gdk_window_set_cursor( window, cursor.GetCursor() );
6a008b33
VZ
2827
2828 if (!g_globalCursor.Ok())
2829 cursor = *wxSTANDARD_CURSOR;
2830
2831 window = m_widget->window;
5e014a0c 2832 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
9146082c 2833 gdk_window_set_cursor( window, cursor.GetCursor() );
5e014a0c 2834
6a008b33
VZ
2835 }
2836 else
2837 {
5e014a0c 2838
9146082c 2839 GdkWindow *window = m_widget->window;
5e014a0c 2840 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
9146082c 2841 gdk_window_set_cursor( window, cursor.GetCursor() );
5e014a0c 2842
6a008b33 2843 }
9146082c 2844 }
6a008b33 2845
9390a202
RR
2846 UpdateWindowUI();
2847}
2848
1e6feb95 2849void wxWindowGTK::DoGetSize( int *width, int *height ) const
c801d85f 2850{
223d09f6 2851 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 2852
fb1585ae
RR
2853 if (width) (*width) = m_width;
2854 if (height) (*height) = m_height;
362c6693 2855}
c801d85f 2856
1e6feb95 2857void wxWindowGTK::DoSetClientSize( int width, int height )
c801d85f 2858{
223d09f6 2859 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 2860
1ecc4d80 2861 if (!m_wxwindow)
c801d85f 2862 {
1ecc4d80 2863 SetSize( width, height );
c801d85f
KB
2864 }
2865 else
2866 {
1ecc4d80
RR
2867 int dw = 0;
2868 int dh = 0;
2869
1e6feb95 2870#ifndef __WXUNIVERSAL__
98d3fdbe
RR
2871 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
2872 {
5e014a0c 2873 /* when using GTK 1.2 we set the shadow border size to 2 */
6a008b33 2874 dw += 2 * 2;
98d3fdbe
RR
2875 dh += 2 * 2;
2876 }
5e014a0c
RR
2877 if (HasFlag(wxSIMPLE_BORDER))
2878 {
2879 /* when using GTK 1.2 we set the simple border size to 1 */
2880 dw += 1 * 2;
2881 dh += 1 * 2;
2882 }
1e6feb95 2883#endif // __WXUNIVERSAL__
034be888 2884
5b8a521e 2885 if (m_hasScrolling)
98d3fdbe 2886 {
324dbfec 2887 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2daa0ce9 2888
9000c624
RR
2889 GtkRequisition vscroll_req;
2890 vscroll_req.width = 2;
2891 vscroll_req.height = 2;
dd00f3f6 2892 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
9000c624 2893 (scroll_window->vscrollbar, &vscroll_req );
2daa0ce9 2894
9000c624
RR
2895 GtkRequisition hscroll_req;
2896 hscroll_req.width = 2;
2897 hscroll_req.height = 2;
dd00f3f6 2898 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
9000c624
RR
2899 (scroll_window->hscrollbar, &hscroll_req );
2900
dd00f3f6 2901 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
324dbfec 2902
1ecc4d80
RR
2903 if (scroll_window->vscrollbar_visible)
2904 {
9000c624 2905 dw += vscroll_req.width;
1ecc4d80
RR
2906 dw += scroll_class->scrollbar_spacing;
2907 }
2908
2909 if (scroll_window->hscrollbar_visible)
2910 {
9000c624 2911 dh += hscroll_req.height;
63cc5d9d 2912 dh += scroll_class->scrollbar_spacing;
1ecc4d80 2913 }
9000c624 2914 }
1ecc4d80 2915
034be888 2916 SetSize( width+dw, height+dh );
1ecc4d80 2917 }
362c6693 2918}
c801d85f 2919
1e6feb95 2920void wxWindowGTK::DoGetClientSize( int *width, int *height ) const
c801d85f 2921{
223d09f6 2922 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 2923
1ecc4d80
RR
2924 if (!m_wxwindow)
2925 {
2926 if (width) (*width) = m_width;
2927 if (height) (*height) = m_height;
c801d85f
KB
2928 }
2929 else
2930 {
1ecc4d80
RR
2931 int dw = 0;
2932 int dh = 0;
2933
1e6feb95 2934#ifndef __WXUNIVERSAL__
98d3fdbe
RR
2935 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
2936 {
5e014a0c 2937 /* when using GTK 1.2 we set the shadow border size to 2 */
6a008b33 2938 dw += 2 * 2;
98d3fdbe
RR
2939 dh += 2 * 2;
2940 }
5e014a0c
RR
2941 if (HasFlag(wxSIMPLE_BORDER))
2942 {
2943 /* when using GTK 1.2 we set the simple border size to 1 */
2944 dw += 1 * 2;
2945 dh += 1 * 2;
2946 }
1e6feb95 2947#endif // __WXUNIVERSAL__
9000c624 2948
5b8a521e 2949 if (m_hasScrolling)
98d3fdbe 2950 {
6a008b33 2951 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2daa0ce9 2952
9000c624
RR
2953 GtkRequisition vscroll_req;
2954 vscroll_req.width = 2;
2955 vscroll_req.height = 2;
dd00f3f6 2956 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
9000c624 2957 (scroll_window->vscrollbar, &vscroll_req );
2daa0ce9 2958
9000c624
RR
2959 GtkRequisition hscroll_req;
2960 hscroll_req.width = 2;
2961 hscroll_req.height = 2;
dd00f3f6 2962 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
9000c624
RR
2963 (scroll_window->hscrollbar, &hscroll_req );
2964
dd00f3f6 2965 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
6a008b33 2966
1ecc4d80
RR
2967 if (scroll_window->vscrollbar_visible)
2968 {
9000c624 2969 dw += vscroll_req.width;
1ecc4d80
RR
2970 dw += scroll_class->scrollbar_spacing;
2971 }
2972
2973 if (scroll_window->hscrollbar_visible)
2974 {
9000c624 2975 dh += hscroll_req.height;
1ecc4d80
RR
2976 dh += scroll_class->scrollbar_spacing;
2977 }
6a008b33 2978 }
47d67540 2979
1ecc4d80
RR
2980 if (width) (*width) = m_width - dw;
2981 if (height) (*height) = m_height - dh;
2982 }
1e6feb95 2983
f94fca1b
RR
2984/*
2985 printf( "GetClientSize, name %s ", GetName().c_str() );
2986 if (width) printf( " width = %d", (*width) );
2987 if (height) printf( " height = %d", (*height) );
2988 printf( "\n" );
2989*/
362c6693 2990}
c801d85f 2991
1e6feb95 2992void wxWindowGTK::DoGetPosition( int *x, int *y ) const
c801d85f 2993{
223d09f6 2994 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 2995
bf0c00c6
RR
2996 int dx = 0;
2997 int dy = 0;
2998 if (m_parent && m_parent->m_wxwindow)
2999 {
da048e3d 3000 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
b02da6b1
VZ
3001 dx = pizza->xoffset;
3002 dy = pizza->yoffset;
bf0c00c6 3003 }
94633ad9 3004
496beb3f
VS
3005 if (x) (*x) = m_x - dx;
3006 if (y) (*y) = m_y - dy;
362c6693 3007}
c801d85f 3008
1e6feb95 3009void wxWindowGTK::DoClientToScreen( int *x, int *y ) const
c801d85f 3010{
223d09f6 3011 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3012
a2053b27
RR
3013 if (!m_widget->window) return;
3014
43a18898
RR
3015 GdkWindow *source = (GdkWindow *) NULL;
3016 if (m_wxwindow)
da048e3d 3017 source = GTK_PIZZA(m_wxwindow)->bin_window;
43a18898
RR
3018 else
3019 source = m_widget->window;
47d67540 3020
43a18898
RR
3021 int org_x = 0;
3022 int org_y = 0;
3023 gdk_window_get_origin( source, &org_x, &org_y );
c801d85f 3024
43a18898 3025 if (!m_wxwindow)
c801d85f 3026 {
43a18898
RR
3027 if (GTK_WIDGET_NO_WINDOW (m_widget))
3028 {
3029 org_x += m_widget->allocation.x;
3030 org_y += m_widget->allocation.y;
3031 }
362c6693 3032 }
47d67540 3033
43a18898
RR
3034 if (x) *x += org_x;
3035 if (y) *y += org_y;
362c6693 3036}
c801d85f 3037
1e6feb95 3038void wxWindowGTK::DoScreenToClient( int *x, int *y ) const
c801d85f 3039{
223d09f6 3040 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3041
a2053b27
RR
3042 if (!m_widget->window) return;
3043
1ecc4d80
RR
3044 GdkWindow *source = (GdkWindow *) NULL;
3045 if (m_wxwindow)
da048e3d 3046 source = GTK_PIZZA(m_wxwindow)->bin_window;
1ecc4d80
RR
3047 else
3048 source = m_widget->window;
47d67540 3049
1ecc4d80
RR
3050 int org_x = 0;
3051 int org_y = 0;
3052 gdk_window_get_origin( source, &org_x, &org_y );
c801d85f 3053
1ecc4d80 3054 if (!m_wxwindow)
c801d85f 3055 {
1ecc4d80
RR
3056 if (GTK_WIDGET_NO_WINDOW (m_widget))
3057 {
3058 org_x += m_widget->allocation.x;
3059 org_y += m_widget->allocation.y;
3060 }
362c6693 3061 }
47d67540 3062
1ecc4d80
RR
3063 if (x) *x -= org_x;
3064 if (y) *y -= org_y;
362c6693 3065}
c801d85f 3066
1e6feb95 3067bool wxWindowGTK::Show( bool show )
c801d85f 3068{
223d09f6 3069 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
47d67540 3070
739730ca
RR
3071 if (!wxWindowBase::Show(show))
3072 {
3073 // nothing to do
f03fc89f 3074 return FALSE;
739730ca 3075 }
8bbe427f 3076
f03fc89f
VZ
3077 if (show)
3078 gtk_widget_show( m_widget );
1ecc4d80 3079 else
f03fc89f 3080 gtk_widget_hide( m_widget );
8bbe427f 3081
f03fc89f 3082 return TRUE;
362c6693 3083}
c801d85f 3084
3379ed37 3085static void wxWindowNotifyEnable(wxWindowGTK* win, bool enable)
fdca68a6
JS
3086{
3087 win->OnParentEnable(enable);
3088
3089 // Recurse, so that children have the opportunity to Do The Right Thing
3090 // and reset colours that have been messed up by a parent's (really ancestor's)
3091 // Enable call
3092 for ( wxWindowList::Node *node = win->GetChildren().GetFirst();
3093 node;
3094 node = node->GetNext() )
3095 {
3096 wxWindow *child = node->GetData();
3097 if (!child->IsKindOf(CLASSINFO(wxDialog)) && !child->IsKindOf(CLASSINFO(wxFrame)))
3098 wxWindowNotifyEnable(child, enable);
3099 }
3100}
3101
3379ed37 3102bool wxWindowGTK::Enable( bool enable )
c801d85f 3103{
223d09f6 3104 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
5e0aa05a 3105
739730ca
RR
3106 if (!wxWindowBase::Enable(enable))
3107 {
3108 // nothing to do
f03fc89f 3109 return FALSE;
739730ca 3110 }
1ecc4d80 3111
f03fc89f
VZ
3112 gtk_widget_set_sensitive( m_widget, enable );
3113 if ( m_wxwindow )
3114 gtk_widget_set_sensitive( m_wxwindow, enable );
ff8bfdbb 3115
fdca68a6 3116 wxWindowNotifyEnable(this, enable);
513903c4 3117
f03fc89f 3118 return TRUE;
362c6693 3119}
c801d85f 3120
1e6feb95 3121int wxWindowGTK::GetCharHeight() const
2f2aa628 3122{
223d09f6 3123 wxCHECK_MSG( (m_widget != NULL), 12, wxT("invalid window") );
47d67540 3124
223d09f6 3125 wxCHECK_MSG( m_font.Ok(), 12, wxT("invalid font") );
2f2aa628 3126
f03fc89f
VZ
3127 GdkFont *font = m_font.GetInternalFont( 1.0 );
3128
3129 return font->ascent + font->descent;
362c6693 3130}
c801d85f 3131
1e6feb95 3132int wxWindowGTK::GetCharWidth() const
c33c4050 3133{
223d09f6 3134 wxCHECK_MSG( (m_widget != NULL), 8, wxT("invalid window") );
47d67540 3135
223d09f6 3136 wxCHECK_MSG( m_font.Ok(), 8, wxT("invalid font") );
47d67540 3137
463c1fa1 3138 GdkFont *font = m_font.GetInternalFont( 1.0 );
ff8bfdbb 3139
463c1fa1 3140 return gdk_string_width( font, "H" );
c33c4050
RR
3141}
3142
1e6feb95 3143void wxWindowGTK::GetTextExtent( const wxString& string,
f03fc89f
VZ
3144 int *x,
3145 int *y,
3146 int *descent,
3147 int *externalLeading,
3148 const wxFont *theFont ) const
c33c4050 3149{
463c1fa1
RR
3150 wxFont fontToUse = m_font;
3151 if (theFont) fontToUse = *theFont;
47d67540 3152
223d09f6 3153 wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
47d67540 3154
463c1fa1 3155 GdkFont *font = fontToUse.GetInternalFont( 1.0 );
05939a81 3156 if (x) (*x) = gdk_string_width( font, string.mbc_str() );
463c1fa1
RR
3157 if (y) (*y) = font->ascent + font->descent;
3158 if (descent) (*descent) = font->descent;
3159 if (externalLeading) (*externalLeading) = 0; // ??
c33c4050
RR
3160}
3161
1e6feb95 3162void wxWindowGTK::SetFocus()
c801d85f 3163{
223d09f6 3164 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2daa0ce9 3165
780bb874
RR
3166#if 0
3167 wxPrintf( "SetFocus from " );
3168 if (GetClassInfo() && GetClassInfo()->GetClassName())
3169 wxPrintf( GetClassInfo()->GetClassName() );
3170 wxPrintf( ".\n" );
3171#endif
3172
354aa1e3
RR
3173 if (m_wxwindow)
3174 {
173348db 3175 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
b231914f
VZ
3176 {
3177 // see comment in gtk_window_focus_out_callback()
3178 gs_widgetLastFocus = m_wxwindow;
173348db 3179 gtk_widget_grab_focus (m_wxwindow);
b231914f 3180 }
354aa1e3 3181 }
b231914f 3182 else if (m_widget)
c801d85f 3183 {
173348db 3184 if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
463c1fa1 3185 {
354aa1e3 3186 gtk_widget_grab_focus (m_widget);
463c1fa1 3187 }
354aa1e3 3188 else if (GTK_IS_CONTAINER(m_widget))
ff8bfdbb 3189 {
354aa1e3 3190 gtk_container_focus( GTK_CONTAINER(m_widget), GTK_DIR_TAB_FORWARD );
ff8bfdbb
VZ
3191 }
3192 else
3193 {
b02da6b1 3194 // ?
ff8bfdbb 3195 }
362c6693 3196 }
94633ad9 3197
780bb874
RR
3198#if 0
3199 wxPrintf( "SetFocus finished in " );
3200 if (GetClassInfo() && GetClassInfo()->GetClassName())
3201 wxPrintf( GetClassInfo()->GetClassName() );
3202 wxPrintf( ".\n" );
3203#endif
3204
362c6693 3205}
c801d85f 3206
1e6feb95 3207bool wxWindowGTK::AcceptsFocus() const
b292e2f5 3208{
f03fc89f 3209 return m_acceptsFocus && wxWindowBase::AcceptsFocus();
b292e2f5
RR
3210}
3211
1e6feb95 3212bool wxWindowGTK::Reparent( wxWindowBase *newParentBase )
463c1fa1 3213{
223d09f6 3214 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
c50f1fb9 3215
1e6feb95
VZ
3216 wxWindowGTK *oldParent = m_parent,
3217 *newParent = (wxWindowGTK *)newParentBase;
a2053b27 3218
5fd11f09
RR
3219 wxASSERT( GTK_IS_WIDGET(m_widget) );
3220
f03fc89f
VZ
3221 if ( !wxWindowBase::Reparent(newParent) )
3222 return FALSE;
8bbe427f 3223
5fd11f09
RR
3224 wxASSERT( GTK_IS_WIDGET(m_widget) );
3225
3226 /* prevent GTK from deleting the widget arbitrarily */
3227 gtk_widget_ref( m_widget );
3228
8ce63e9d
RR
3229 if (oldParent)
3230 {
3017f78d 3231 gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget );
8ce63e9d 3232 }
c50f1fb9 3233
5fd11f09
RR
3234 wxASSERT( GTK_IS_WIDGET(m_widget) );
3235
8ce63e9d
RR
3236 if (newParent)
3237 {
3238 /* insert GTK representation */
3239 (*(newParent->m_insertCallback))(newParent, this);
3240 }
c50f1fb9 3241
5fd11f09
RR
3242 /* reverse: prevent GTK from deleting the widget arbitrarily */
3243 gtk_widget_unref( m_widget );
148cd9b6 3244
f03fc89f 3245 return TRUE;
362c6693 3246}
c801d85f 3247
1e6feb95 3248void wxWindowGTK::DoAddChild(wxWindowGTK *child)
ddb6bc71 3249{
223d09f6 3250 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
ddb6bc71 3251
223d09f6 3252 wxASSERT_MSG( (child != NULL), wxT("invalid child window") );
ddb6bc71 3253
223d09f6 3254 wxASSERT_MSG( (m_insertCallback != NULL), wxT("invalid child insertion function") );
c50f1fb9 3255
ddb6bc71
RR
3256 /* add to list */
3257 AddChild( child );
c50f1fb9 3258
ddb6bc71
RR
3259 /* insert GTK representation */
3260 (*m_insertCallback)(this, child);
3261}
3262
1e6feb95 3263void wxWindowGTK::Raise()
362c6693 3264{
223d09f6 3265 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3266
a2053b27
RR
3267 if (!m_widget->window) return;
3268
f03fc89f 3269 gdk_window_raise( m_widget->window );
362c6693
RR
3270}
3271
1e6feb95 3272void wxWindowGTK::Lower()
362c6693 3273{
223d09f6 3274 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3275
a2053b27
RR
3276 if (!m_widget->window) return;
3277
f03fc89f 3278 gdk_window_lower( m_widget->window );
362c6693 3279}
c801d85f 3280
1e6feb95 3281bool wxWindowGTK::SetCursor( const wxCursor &cursor )
86b29a61 3282{
223d09f6 3283 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
86b29a61 3284
f6bcfd97
BP
3285 if (cursor == m_cursor)
3286 return FALSE;
3287
3288 if (g_isIdle)
3289 wxapp_install_idle_handler();
1e6feb95 3290
f6bcfd97
BP
3291 if (cursor == wxNullCursor)
3292 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR );
3293 else
3294 return wxWindowBase::SetCursor( cursor );
362c6693 3295}
c801d85f 3296
1e6feb95 3297void wxWindowGTK::WarpPointer( int x, int y )
4f22cf8d 3298{
223d09f6 3299 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
85eb36c2 3300
3bcc8d15
RR
3301 // We provide this function ourselves as it is
3302 // missing in GDK (top of this file).
148cd9b6 3303
ed673c6a
RR
3304 GdkWindow *window = (GdkWindow*) NULL;
3305 if (m_wxwindow)
da048e3d 3306 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a
RR
3307 else
3308 window = GetConnectWidget()->window;
148cd9b6 3309
ed673c6a
RR
3310 if (window)
3311 gdk_window_warp_pointer( window, x, y );
4f22cf8d
RR
3312}
3313
1e6feb95 3314void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
c801d85f 3315{
f2593d0d 3316 if (!m_widget) return;
a2053b27
RR
3317 if (!m_widget->window) return;
3318
1e6feb95
VZ
3319 // temporarily hide the caret to avoid nasty interactions between caret
3320 // drawing and the window contents redraw
3321#if 0 // def wxUSE_CARET -- doesn't seem to help :-(
3322 wxCaretSuspend cs((wxWindow *)this);
3323#endif // wxUSE_CARET
3324
139adb6a 3325 if (eraseBackground && m_wxwindow && m_wxwindow->window)
c801d85f 3326 {
139adb6a
RR
3327 if (rect)
3328 {
3bcc8d15
RR
3329 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3330 m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height );
139adb6a
RR
3331 }
3332 else
3333 {
3bcc8d15
RR
3334 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3335 m_clearRegion.Clear();
3336 m_clearRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
139adb6a
RR
3337 }
3338 }
ff8bfdbb 3339
3bcc8d15 3340 if (rect)
139adb6a
RR
3341 {
3342 if (m_wxwindow)
b02da6b1 3343 {
23716407 3344 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3bcc8d15 3345 m_updateRegion.Union( rect->x, rect->y, rect->width, rect->height );
b02da6b1 3346 }
ff8bfdbb 3347 else
b6fa52db 3348 {
3bcc8d15
RR
3349 GdkRectangle gdk_rect;
3350 gdk_rect.x = rect->x;
3351 gdk_rect.y = rect->y;
3352 gdk_rect.width = rect->width;
3353 gdk_rect.height = rect->height;
3354 gtk_widget_draw( m_widget, &gdk_rect );
b6fa52db 3355 }
362c6693 3356 }
c801d85f 3357 else
139adb6a 3358 {
139adb6a 3359 if (m_wxwindow)
b02da6b1 3360 {
23716407 3361 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3bcc8d15
RR
3362 m_updateRegion.Clear();
3363 m_updateRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
b02da6b1 3364 }
139adb6a 3365 else
b6fa52db 3366 {
3bcc8d15 3367 gtk_widget_draw( m_widget, (GdkRectangle*) NULL );
b6fa52db 3368 }
139adb6a 3369 }
362c6693 3370}
c801d85f 3371
beab25bd
RR
3372void wxWindowGTK::Update()
3373{
3374 if (!m_updateRegion.IsEmpty())
3375 {
23716407 3376 GtkSendPaintEvents();
beab25bd
RR
3377 }
3378}
3379
3380void wxWindowGTK::GtkSendPaintEvents()
3381{
3bcc8d15
RR
3382 if (!m_wxwindow)
3383 {
3384 m_clearRegion.Clear();
3385 m_updateRegion.Clear();
3386 return;
3387 }
beab25bd 3388
3bcc8d15 3389 m_clipPaintRegion = TRUE;
beab25bd 3390
3bcc8d15 3391 if (!m_clearRegion.IsEmpty())
beab25bd 3392 {
3bcc8d15
RR
3393 wxWindowDC dc( (wxWindow*)this );
3394 dc.SetClippingRegion( m_clearRegion );
3395
3396 wxEraseEvent erase_event( GetId(), &dc );
3397 erase_event.SetEventObject( this );
3398
beab25bd
RR
3399 if (!GetEventHandler()->ProcessEvent(erase_event))
3400 {
3bcc8d15 3401 wxRegionIterator upd( m_clearRegion );
beab25bd
RR
3402 while (upd)
3403 {
3bcc8d15
RR
3404 gdk_window_clear_area( GTK_PIZZA(m_wxwindow)->bin_window,
3405 upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
beab25bd
RR
3406 upd ++;
3407 }
3408 }
3bcc8d15 3409 m_clearRegion.Clear();
beab25bd 3410 }
beab25bd
RR
3411
3412 wxNcPaintEvent nc_paint_event( GetId() );
3413 nc_paint_event.SetEventObject( this );
3414 GetEventHandler()->ProcessEvent( nc_paint_event );
3415
3416 wxPaintEvent paint_event( GetId() );
3417 paint_event.SetEventObject( this );
3418 GetEventHandler()->ProcessEvent( paint_event );
3419
beab25bd 3420 m_clipPaintRegion = FALSE;
c89f5c02 3421
8f3e7ecc
RR
3422#ifndef __WXUNIVERSAL__
3423 // The following code will result in all window-less widgets
3424 // being redrawn because the wxWindows class is allowed to
3425 // paint over the window-less widgets.
3426
c89f5c02 3427 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
8f3e7ecc
RR
3428
3429 GList *children = pizza->children;
3430 while (children)
c89f5c02 3431 {
8f3e7ecc
RR
3432 GtkPizzaChild *child = (GtkPizzaChild*) children->data;
3433 children = children->next;
c89f5c02 3434
8f3e7ecc
RR
3435 if (GTK_WIDGET_NO_WINDOW (child->widget) &&
3436 GTK_WIDGET_DRAWABLE (child->widget))
3437 {
3438 // Get intersection of widget area and update region
3439 wxRegion region( m_updateRegion );
3440
3441 GdkEventExpose gdk_event;
3442 gdk_event.type = GDK_EXPOSE;
3443 gdk_event.window = pizza->bin_window;
3444 gdk_event.count = 0;
3445
3446 wxRegionIterator upd( m_updateRegion );
3447 while (upd)
c89f5c02 3448 {
8f3e7ecc
RR
3449 GdkRectangle rect;
3450 rect.x = upd.GetX();
3451 rect.y = upd.GetY();
3452 rect.width = upd.GetWidth();
3453 rect.height = upd.GetHeight();
c89f5c02 3454
8f3e7ecc
RR
3455 if (gtk_widget_intersect (child->widget, &rect, &gdk_event.area))
3456 {
3457 gtk_widget_event (child->widget, (GdkEvent*) &gdk_event);
3458 }
3459
3460 upd ++;
c89f5c02
RR
3461 }
3462 }
3463 }
8f3e7ecc 3464#endif
c89f5c02
RR
3465
3466 m_updateRegion.Clear();
beab25bd
RR
3467}
3468
1e6feb95 3469void wxWindowGTK::Clear()
c801d85f 3470{
223d09f6 3471 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
47d67540 3472
a2053b27
RR
3473 if (!m_widget->window) return;
3474
f234c60c
RR
3475 if (m_wxwindow && m_wxwindow->window)
3476 {
c916e13b 3477// gdk_window_clear( m_wxwindow->window );
f234c60c 3478 }
362c6693 3479}
c801d85f 3480
ff8bfdbb 3481#if wxUSE_TOOLTIPS
1e6feb95 3482void wxWindowGTK::DoSetToolTip( wxToolTip *tip )
b1170810 3483{
f03fc89f 3484 wxWindowBase::DoSetToolTip(tip);
ff8bfdbb 3485
f03fc89f 3486 if (m_tooltip)
3379ed37 3487 m_tooltip->Apply( (wxWindow *)this );
b1170810
RR
3488}
3489
1e6feb95 3490void wxWindowGTK::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
b1170810 3491{
dcf924a3 3492 gtk_tooltips_set_tip( tips, GetConnectWidget(), wxConvCurrent->cWX2MB(tip), (gchar*) NULL );
301cd871 3493}
ff8bfdbb 3494#endif // wxUSE_TOOLTIPS
b1170810 3495
1e6feb95 3496bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
c801d85f 3497{
223d09f6 3498 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
8bbe427f 3499
739730ca
RR
3500 if (!wxWindowBase::SetBackgroundColour(colour))
3501 {
3502 // don't leave if the GTK widget has just
3503 // been realized
3504 if (!m_delayedBackgroundColour) return FALSE;
3505 }
c50f1fb9 3506
ed673c6a
RR
3507 GdkWindow *window = (GdkWindow*) NULL;
3508 if (m_wxwindow)
da048e3d 3509 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a
RR
3510 else
3511 window = GetConnectWidget()->window;
148cd9b6 3512
ed673c6a 3513 if (!window)
739730ca
RR
3514 {
3515 // indicate that a new style has been set
c50f1fb9
VZ
3516 // but it couldn't get applied as the
3517 // widget hasn't been realized yet.
3518 m_delayedBackgroundColour = TRUE;
739730ca 3519 }
ca298c88 3520
0f2f4986 3521 if ((m_wxwindow) &&
103aab26 3522 (m_wxwindow->window) &&
a756f210 3523 (m_backgroundColour != wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)))
3bc755fc 3524 {
a2053b27
RR
3525 /* wxMSW doesn't clear the window here. I don't do that either to
3526 provide compatibility. call Clear() to do the job. */
ca298c88 3527
ed673c6a
RR
3528 m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
3529 gdk_window_set_background( window, m_backgroundColour.GetColor() );
3bc755fc 3530 }
8bbe427f 3531
0f2f4986 3532 ApplyWidgetStyle();
c801d85f 3533
f03fc89f 3534 return TRUE;
6de97a3b
RR
3535}
3536
1e6feb95 3537bool wxWindowGTK::SetForegroundColour( const wxColour &colour )
6de97a3b 3538{
223d09f6 3539 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
8bbe427f 3540
739730ca
RR
3541 if (!wxWindowBase::SetForegroundColour(colour))
3542 {
3543 // don't leave if the GTK widget has just
3544 // been realized
3545 if (!m_delayedForegroundColour) return FALSE;
3546 }
c50f1fb9 3547
ed673c6a
RR
3548 GdkWindow *window = (GdkWindow*) NULL;
3549 if (m_wxwindow)
da048e3d 3550 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a
RR
3551 else
3552 window = GetConnectWidget()->window;
148cd9b6 3553
ed673c6a 3554 if (!window)
739730ca
RR
3555 {
3556 // indicate that a new style has been set
c50f1fb9
VZ
3557 // but it couldn't get applied as the
3558 // widget hasn't been realized yet.
3559 m_delayedForegroundColour = TRUE;
739730ca 3560 }
2b07d713 3561
0f2f4986 3562 ApplyWidgetStyle();
f03fc89f
VZ
3563
3564 return TRUE;
58614078
RR
3565}
3566
1e6feb95 3567GtkStyle *wxWindowGTK::GetWidgetStyle()
58614078 3568{
103aab26
RR
3569 if (m_widgetStyle)
3570 {
3571 GtkStyle *remake = gtk_style_copy( m_widgetStyle );
dd00f3f6
OK
3572#ifdef __WXGTK20__
3573 /* FIXME: is this necessary? */
3574 _G_TYPE_IGC(remake, GtkObjectClass) = _G_TYPE_IGC(m_widgetStyle, GtkObjectClass);
3575#else
103aab26 3576 remake->klass = m_widgetStyle->klass;
dd00f3f6 3577#endif
2daa0ce9 3578
103aab26
RR
3579 gtk_style_unref( m_widgetStyle );
3580 m_widgetStyle = remake;
3581 }
3582 else
3583 {
3584 GtkStyle *def = gtk_rc_get_style( m_widget );
e6527f9d 3585
103aab26
RR
3586 if (!def)
3587 def = gtk_widget_get_default_style();
e6527f9d 3588
103aab26 3589 m_widgetStyle = gtk_style_copy( def );
dd00f3f6
OK
3590#ifdef __WXGTK20__
3591 /* FIXME: is this necessary? */
3592 _G_TYPE_IGC(m_widgetStyle, GtkObjectClass) = _G_TYPE_IGC(def, GtkObjectClass);
3593#else
103aab26 3594 m_widgetStyle->klass = def->klass;
dd00f3f6 3595#endif
103aab26 3596 }
8bbe427f 3597
1ecc4d80 3598 return m_widgetStyle;
58614078
RR
3599}
3600
1e6feb95 3601void wxWindowGTK::SetWidgetStyle()
58614078 3602{
8f3e7ecc 3603#if DISABLE_STYLE_IF_BROKEN_THEME
fb65642c
RR
3604 if (m_widget->style->engine_data)
3605 {
3606 static bool s_warningPrinted = FALSE;
3607 if (!s_warningPrinted)
3608 {
3609 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3610 s_warningPrinted = TRUE;
3611 }
3612 m_widgetStyle = m_widget->style;
3613 return;
3614 }
a56fcaaf 3615#endif
fb65642c 3616
1ecc4d80
RR
3617 GtkStyle *style = GetWidgetStyle();
3618
a756f210 3619 if (m_font != wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ))
db434467
RR
3620 {
3621 gdk_font_unref( style->font );
3622 style->font = gdk_font_ref( m_font.GetInternalFont( 1.0 ) );
3623 }
1ecc4d80
RR
3624
3625 if (m_foregroundColour.Ok())
3626 {
454e2a22 3627 m_foregroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
a756f210 3628 if (m_foregroundColour != wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT))
db434467
RR
3629 {
3630 style->fg[GTK_STATE_NORMAL] = *m_foregroundColour.GetColor();
3631 style->fg[GTK_STATE_PRELIGHT] = *m_foregroundColour.GetColor();
3632 style->fg[GTK_STATE_ACTIVE] = *m_foregroundColour.GetColor();
3633 }
1e6feb95 3634 else
f6bcfd97
BP
3635 {
3636 // Try to restore the gtk default style. This is still a little
3637 // oversimplified for what is probably really needed here for controls
3638 // other than buttons, but is better than not being able to (re)set a
3639 // control's foreground colour to *wxBLACK -- RL
3640 GtkStyle *def = gtk_rc_get_style( m_widget );
3641
3642 if (!def)
3643 def = gtk_widget_get_default_style();
3644
3645 style->fg[GTK_STATE_NORMAL] = def->fg[GTK_STATE_NORMAL];
3646 style->fg[GTK_STATE_PRELIGHT] = def->fg[GTK_STATE_PRELIGHT];
3647 style->fg[GTK_STATE_ACTIVE] = def->fg[GTK_STATE_ACTIVE];
3648 }
1ecc4d80
RR
3649 }
3650
3651 if (m_backgroundColour.Ok())
3652 {
454e2a22 3653 m_backgroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
a756f210 3654 if (m_backgroundColour != wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE))
db434467
RR
3655 {
3656 style->bg[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
3657 style->base[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
3658 style->bg[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
3659 style->base[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
3660 style->bg[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
3661 style->base[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
3662 style->bg[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
3663 style->base[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
f6bcfd97
BP
3664 }
3665 else
3666 {
3667 // Try to restore the gtk default style. This is still a little
3668 // oversimplified for what is probably really needed here for controls
3669 // other than buttons, but is better than not being able to (re)set a
3670 // control's background colour to default grey and means resetting a
1e6feb95 3671 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
f6bcfd97
BP
3672 // behavior -- RL
3673 GtkStyle *def = gtk_rc_get_style( m_widget );
3674
3675 if (!def)
3676 def = gtk_widget_get_default_style();
3677
3678 style->bg[GTK_STATE_NORMAL] = def->bg[GTK_STATE_NORMAL];
3679 style->base[GTK_STATE_NORMAL] = def->base[GTK_STATE_NORMAL];
3680 style->bg[GTK_STATE_PRELIGHT] = def->bg[GTK_STATE_PRELIGHT];
3681 style->base[GTK_STATE_PRELIGHT] = def->base[GTK_STATE_PRELIGHT];
3682 style->bg[GTK_STATE_ACTIVE] = def->bg[GTK_STATE_ACTIVE];
3683 style->base[GTK_STATE_ACTIVE] = def->base[GTK_STATE_ACTIVE];
3684 style->bg[GTK_STATE_INSENSITIVE] = def->bg[GTK_STATE_INSENSITIVE];
3685 style->base[GTK_STATE_INSENSITIVE] = def->base[GTK_STATE_INSENSITIVE];
3686 }
1ecc4d80 3687 }
a81258be
RR
3688}
3689
1e6feb95 3690void wxWindowGTK::ApplyWidgetStyle()
a81258be 3691{
6de97a3b
RR
3692}
3693
2259e007
RR
3694//-----------------------------------------------------------------------------
3695// Pop-up menu stuff
3696//-----------------------------------------------------------------------------
3697
6522713c 3698#if wxUSE_MENUS_NATIVE
1e6feb95 3699
90350682
VZ
3700extern "C"
3701void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting )
2259e007
RR
3702{
3703 *is_waiting = FALSE;
3704}
3705
1e6feb95 3706static void SetInvokingWindow( wxMenu *menu, wxWindowGTK *win )
30dea054 3707{
1ecc4d80 3708 menu->SetInvokingWindow( win );
1987af7e 3709 wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
1ecc4d80
RR
3710 while (node)
3711 {
1987af7e 3712 wxMenuItem *menuitem = node->GetData();
1ecc4d80
RR
3713 if (menuitem->IsSubMenu())
3714 {
ff8bfdbb
VZ
3715 SetInvokingWindow( menuitem->GetSubMenu(), win );
3716 }
1987af7e
VZ
3717
3718 node = node->GetNext();
1ecc4d80 3719 }
362c6693 3720}
30dea054 3721
e3473203
VZ
3722// used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
3723// wxPopupMenuPositionCallback()
3724//
3725// should be safe even in the MT case as the user can hardly popup 2 menus
3726// simultaneously, can he?
0c77152e
RR
3727static gint gs_pop_x = 0;
3728static gint gs_pop_y = 0;
3729
295272bd
VZ
3730extern "C" void wxPopupMenuPositionCallback( GtkMenu *menu,
3731 gint *x, gint *y,
3732 gpointer WXUNUSED(user_data) )
0c77152e 3733{
e3473203
VZ
3734 // ensure that the menu appears entirely on screen
3735 GtkRequisition req;
3736 gtk_widget_get_child_requisition(GTK_WIDGET(menu), &req);
3737
3738 wxSize sizeScreen = wxGetDisplaySize();
3739
3740 gint xmax = sizeScreen.x - req.width,
3741 ymax = sizeScreen.y - req.height;
3742
3743 *x = gs_pop_x < xmax ? gs_pop_x : xmax;
3744 *y = gs_pop_y < ymax ? gs_pop_y : ymax;
0c77152e
RR
3745}
3746
1e6feb95 3747bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
30dea054 3748{
223d09f6 3749 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
47d67540 3750
223d09f6 3751 wxCHECK_MSG( menu != NULL, FALSE, wxT("invalid popup-menu") );
8bbe427f 3752
1ecc4d80 3753 SetInvokingWindow( menu, this );
ff8bfdbb 3754
631f1bfe
JS
3755 menu->UpdateUI();
3756
0c77152e
RR
3757 gs_pop_x = x;
3758 gs_pop_y = y;
e3473203 3759 ClientToScreen( &gs_pop_x, &gs_pop_y );
ff8bfdbb 3760
2259e007 3761 bool is_waiting = TRUE;
148cd9b6 3762
90350682
VZ
3763 gtk_signal_connect( GTK_OBJECT(menu->m_menu),
3764 "hide",
3765 GTK_SIGNAL_FUNC(gtk_pop_hide_callback),
3766 (gpointer)&is_waiting );
2259e007 3767
1ecc4d80 3768 gtk_menu_popup(
47d67540 3769 GTK_MENU(menu->m_menu),
e3473203
VZ
3770 (GtkWidget *) NULL, // parent menu shell
3771 (GtkWidget *) NULL, // parent menu item
3772 wxPopupMenuPositionCallback, // function to position it
3773 NULL, // client data
3774 0, // button used to activate it
3775 gs_timeLastClick // the time of activation
47d67540 3776 );
148cd9b6 3777
956dbab1
RR
3778 while (is_waiting)
3779 {
3780 while (gtk_events_pending())
3781 gtk_main_iteration();
3782 }
2259e007 3783
1ecc4d80 3784 return TRUE;
30dea054
RR
3785}
3786
6522713c 3787#endif // wxUSE_MENUS_NATIVE
1e6feb95 3788
06cfab17 3789#if wxUSE_DRAG_AND_DROP
ac57418f 3790
1e6feb95 3791void wxWindowGTK::SetDropTarget( wxDropTarget *dropTarget )
c801d85f 3792{
223d09f6 3793 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
47d67540 3794
1ecc4d80 3795 GtkWidget *dnd_widget = GetConnectWidget();
47d67540 3796
1ecc4d80 3797 if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
47d67540 3798
1ecc4d80
RR
3799 if (m_dropTarget) delete m_dropTarget;
3800 m_dropTarget = dropTarget;
47d67540 3801
1ecc4d80 3802 if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
362c6693 3803}
c801d85f 3804
f03fc89f 3805#endif // wxUSE_DRAG_AND_DROP
ac57418f 3806
1e6feb95 3807GtkWidget* wxWindowGTK::GetConnectWidget()
e3e65dac 3808{
1ecc4d80
RR
3809 GtkWidget *connect_widget = m_widget;
3810 if (m_wxwindow) connect_widget = m_wxwindow;
47d67540 3811
1ecc4d80 3812 return connect_widget;
e3e65dac 3813}
47d67540 3814
1e6feb95 3815bool wxWindowGTK::IsOwnGtkWindow( GdkWindow *window )
903f689b 3816{
148cd9b6 3817 if (m_wxwindow)
da048e3d 3818 return (window == GTK_PIZZA(m_wxwindow)->bin_window);
148cd9b6 3819
1ecc4d80 3820 return (window == m_widget->window);
903f689b
RR
3821}
3822
1e6feb95 3823bool wxWindowGTK::SetFont( const wxFont &font )
c801d85f 3824{
223d09f6 3825 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
c801d85f 3826
739730ca
RR
3827 if (!wxWindowBase::SetFont(font))
3828 {
454e2a22 3829 return FALSE;
739730ca 3830 }
9c288e4d 3831
a756f210 3832 wxColour sysbg = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
f03fc89f 3833 if ( sysbg == m_backgroundColour )
ae0bdb01
RR
3834 {
3835 m_backgroundColour = wxNullColour;
3836 ApplyWidgetStyle();
ff8bfdbb
VZ
3837 m_backgroundColour = sysbg;
3838 }
ae0bdb01
RR
3839 else
3840 {
3841 ApplyWidgetStyle();
3842 }
c801d85f 3843
f03fc89f 3844 return TRUE;
362c6693 3845}
c801d85f 3846
94633ad9 3847void wxWindowGTK::DoCaptureMouse()
c801d85f 3848{
b231914f
VZ
3849 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3850
ed673c6a 3851 GdkWindow *window = (GdkWindow*) NULL;
b231914f
VZ
3852 if (m_wxwindow)
3853 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a 3854 else
b231914f 3855 window = GetConnectWidget()->window;
148cd9b6 3856
e4606ed9 3857 wxCHECK_RET( window, _T("CaptureMouse() failed") );
c50f1fb9 3858
b231914f 3859 wxCursor* cursor = & m_cursor;
cca602ac
JS
3860 if (!cursor->Ok())
3861 cursor = wxSTANDARD_CURSOR;
3862
ed673c6a 3863 gdk_pointer_grab( window, FALSE,
1ecc4d80
RR
3864 (GdkEventMask)
3865 (GDK_BUTTON_PRESS_MASK |
3866 GDK_BUTTON_RELEASE_MASK |
148cd9b6 3867 GDK_POINTER_MOTION_HINT_MASK |
1ecc4d80 3868 GDK_POINTER_MOTION_MASK),
ff8bfdbb 3869 (GdkWindow *) NULL,
cca602ac 3870 cursor->GetCursor(),
b02da6b1 3871 (guint32)GDK_CURRENT_TIME );
b231914f 3872 g_captureWindow = this;
1e6feb95 3873 g_captureWindowHasMouse = TRUE;
362c6693 3874}
c801d85f 3875
94633ad9 3876void wxWindowGTK::DoReleaseMouse()
c801d85f 3877{
b231914f
VZ
3878 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3879
e4606ed9 3880 wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") );
47d67540 3881
c43430bb
VS
3882 g_captureWindow = (wxWindowGTK*) NULL;
3883
ed673c6a 3884 GdkWindow *window = (GdkWindow*) NULL;
b231914f
VZ
3885 if (m_wxwindow)
3886 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a 3887 else
b231914f 3888 window = GetConnectWidget()->window;
148cd9b6 3889
b02da6b1
VZ
3890 if (!window)
3891 return;
c50f1fb9 3892
b02da6b1 3893 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
362c6693 3894}
c801d85f 3895
1e6feb95
VZ
3896/* static */
3897wxWindow *wxWindowBase::GetCapture()
3898{
3899 return (wxWindow *)g_captureWindow;
3900}
3901
3902bool wxWindowGTK::IsRetained() const
c801d85f 3903{
1ecc4d80 3904 return FALSE;
362c6693 3905}
c801d85f 3906
1e6feb95 3907void wxWindowGTK::SetScrollbar( int orient, int pos, int thumbVisible,
cb43b372 3908 int range, bool refresh )
c801d85f 3909{
223d09f6 3910 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
8bbe427f 3911
223d09f6 3912 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
c801d85f 3913
1ecc4d80 3914 m_hasScrolling = TRUE;
47d67540 3915
1ecc4d80 3916 if (orient == wxHORIZONTAL)
cb43b372 3917 {
1ecc4d80
RR
3918 float fpos = (float)pos;
3919 float frange = (float)range;
3920 float fthumb = (float)thumbVisible;
3921 if (fpos > frange-fthumb) fpos = frange-fthumb;
3922 if (fpos < 0.0) fpos = 0.0;
3923
3924 if ((fabs(frange-m_hAdjust->upper) < 0.2) &&
3925 (fabs(fthumb-m_hAdjust->page_size) < 0.2))
3926 {
3927 SetScrollPos( orient, pos, refresh );
3928 return;
3929 }
47d67540 3930
1ecc4d80 3931 m_oldHorizontalPos = fpos;
47d67540 3932
1ecc4d80
RR
3933 m_hAdjust->lower = 0.0;
3934 m_hAdjust->upper = frange;
3935 m_hAdjust->value = fpos;
3936 m_hAdjust->step_increment = 1.0;
3937 m_hAdjust->page_increment = (float)(wxMax(fthumb,0));
3938 m_hAdjust->page_size = fthumb;
cb43b372 3939 }
1ecc4d80
RR
3940 else
3941 {
3942 float fpos = (float)pos;
3943 float frange = (float)range;
3944 float fthumb = (float)thumbVisible;
3945 if (fpos > frange-fthumb) fpos = frange-fthumb;
3946 if (fpos < 0.0) fpos = 0.0;
3947
3948 if ((fabs(frange-m_vAdjust->upper) < 0.2) &&
3949 (fabs(fthumb-m_vAdjust->page_size) < 0.2))
3950 {
3951 SetScrollPos( orient, pos, refresh );
3952 return;
3953 }
47d67540 3954
1ecc4d80 3955 m_oldVerticalPos = fpos;
47d67540 3956
1ecc4d80
RR
3957 m_vAdjust->lower = 0.0;
3958 m_vAdjust->upper = frange;
3959 m_vAdjust->value = fpos;
3960 m_vAdjust->step_increment = 1.0;
3961 m_vAdjust->page_increment = (float)(wxMax(fthumb,0));
3962 m_vAdjust->page_size = fthumb;
3963 }
47d67540 3964
eb082a08
RR
3965 if (orient == wxHORIZONTAL)
3966 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
3967 else
3968 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
362c6693 3969}
c801d85f 3970
1e6feb95 3971void wxWindowGTK::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
c801d85f 3972{
223d09f6 3973 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
1ecc4d80 3974
223d09f6 3975 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
1ecc4d80
RR
3976
3977 if (orient == wxHORIZONTAL)
3978 {
3979 float fpos = (float)pos;
3980 if (fpos > m_hAdjust->upper - m_hAdjust->page_size) fpos = m_hAdjust->upper - m_hAdjust->page_size;
3981 if (fpos < 0.0) fpos = 0.0;
3982 m_oldHorizontalPos = fpos;
3983
3984 if (fabs(fpos-m_hAdjust->value) < 0.2) return;
3985 m_hAdjust->value = fpos;
3986 }
3987 else
3988 {
3989 float fpos = (float)pos;
3990 if (fpos > m_vAdjust->upper - m_vAdjust->page_size) fpos = m_vAdjust->upper - m_vAdjust->page_size;
3991 if (fpos < 0.0) fpos = 0.0;
3992 m_oldVerticalPos = fpos;
ff8bfdbb 3993
1ecc4d80
RR
3994 if (fabs(fpos-m_vAdjust->value) < 0.2) return;
3995 m_vAdjust->value = fpos;
3996 }
47d67540 3997
5b8a521e 3998 if (m_wxwindow->window)
47d67540 3999 {
5b8a521e 4000 if (orient == wxHORIZONTAL)
473d087e
RR
4001 {
4002 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust),
4003 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
2daa0ce9 4004
5b8a521e 4005 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
2daa0ce9 4006
473d087e
RR
4007 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
4008 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
4009 }
5b8a521e 4010 else
473d087e
RR
4011 {
4012 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust),
4013 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
2daa0ce9 4014
5b8a521e 4015 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
473d087e
RR
4016
4017 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
4018 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
4019 }
cb43b372 4020 }
362c6693 4021}
c801d85f 4022
1e6feb95 4023int wxWindowGTK::GetScrollThumb( int orient ) const
c801d85f 4024{
223d09f6 4025 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
47d67540 4026
223d09f6 4027 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
47d67540 4028
1ecc4d80
RR
4029 if (orient == wxHORIZONTAL)
4030 return (int)(m_hAdjust->page_size+0.5);
4031 else
4032 return (int)(m_vAdjust->page_size+0.5);
362c6693 4033}
c801d85f 4034
1e6feb95 4035int wxWindowGTK::GetScrollPos( int orient ) const
c801d85f 4036{
223d09f6 4037 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
47d67540 4038
223d09f6 4039 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
c801d85f 4040
1ecc4d80
RR
4041 if (orient == wxHORIZONTAL)
4042 return (int)(m_hAdjust->value+0.5);
4043 else
4044 return (int)(m_vAdjust->value+0.5);
362c6693 4045}
c801d85f 4046
1e6feb95 4047int wxWindowGTK::GetScrollRange( int orient ) const
c801d85f 4048{
223d09f6 4049 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
47d67540 4050
223d09f6 4051 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
c801d85f 4052
1ecc4d80
RR
4053 if (orient == wxHORIZONTAL)
4054 return (int)(m_hAdjust->upper+0.5);
4055 else
4056 return (int)(m_vAdjust->upper+0.5);
362c6693 4057}
c801d85f 4058
1e6feb95 4059void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
c801d85f 4060{
223d09f6 4061 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
47d67540 4062
223d09f6 4063 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
1e6feb95 4064
f47ae6e7 4065 // No scrolling requested.
8e217128 4066 if ((dx == 0) && (dy == 0)) return;
f47ae6e7 4067
35917d22
RR
4068 if (!m_updateRegion.IsEmpty())
4069 {
4070 m_updateRegion.Offset( dx, dy );
4071
4072 int cw = 0;
4073 int ch = 0;
4074 GetClientSize( &cw, &ch );
4075 m_updateRegion.Intersect( 0, 0, cw, ch );
4076 }
4077
3bcc8d15
RR
4078 if (!m_clearRegion.IsEmpty())
4079 {
4080 m_clearRegion.Offset( dx, dy );
4081
4082 int cw = 0;
4083 int ch = 0;
4084 GetClientSize( &cw, &ch );
4085 m_clearRegion.Intersect( 0, 0, cw, ch );
4086 }
4087
f47ae6e7 4088#if 1
c801d85f 4089
b6fa52db 4090 m_clipPaintRegion = TRUE;
f47ae6e7 4091
da048e3d 4092 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
f47ae6e7 4093
b6fa52db 4094 m_clipPaintRegion = FALSE;
1e6feb95 4095
f47ae6e7
RR
4096#else
4097
8e217128
RR
4098 if (m_children.GetCount() > 0)
4099 {
4100 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
4101 }
4102 else
4103 {
4104 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
1e6feb95 4105
8e217128
RR
4106 pizza->xoffset -= dx;
4107 pizza->yoffset -= dy;
1e6feb95 4108
8e217128
RR
4109 GdkGC *m_scrollGC = gdk_gc_new( pizza->bin_window );
4110 gdk_gc_set_exposures( m_scrollGC, TRUE );
4111
4112 int cw = 0;
4113 int ch = 0;
4114 GetClientSize( &cw, &ch );
4115 int w = cw - abs(dx);
4116 int h = ch - abs(dy);
4117
4118 if ((h < 0) || (w < 0))
4119 {
4120 Refresh();
1e6feb95 4121 }
8e217128
RR
4122 else
4123 {
4124 int s_x = 0;
4125 int s_y = 0;
4126 if (dx < 0) s_x = -dx;
4127 if (dy < 0) s_y = -dy;
4128 int d_x = 0;
4129 int d_y = 0;
4130 if (dx > 0) d_x = dx;
4131 if (dy > 0) d_y = dy;
4132
4133 gdk_window_copy_area( pizza->bin_window, m_scrollGC, d_x, d_y,
4134 pizza->bin_window, s_x, s_y, w, h );
4135
4136 wxRect rect;
4137 if (dx < 0) rect.x = cw+dx; else rect.x = 0;
4138 if (dy < 0) rect.y = ch+dy; else rect.y = 0;
4139 if (dy != 0) rect.width = cw; else rect.width = abs(dx);
4140 if (dx != 0) rect.height = ch; else rect.height = abs(dy);
4141
4142 Refresh( TRUE, &rect );
4143 }
1e6feb95 4144
8e217128
RR
4145 gdk_gc_unref( m_scrollGC );
4146 }
f47ae6e7 4147#endif
c801d85f 4148}
3723b7b1 4149
3723b7b1
JS
4150// Find the wxWindow at the current mouse position, also returning the mouse
4151// position.
4152wxWindow* wxFindWindowAtPointer(wxPoint& pt)
4153{
59a12e90
JS
4154 pt = wxGetMousePosition();
4155 wxWindow* found = wxFindWindowAtPoint(pt);
4156 return found;
3723b7b1
JS
4157}
4158
4159// Get the current mouse position.
4160wxPoint wxGetMousePosition()
4161{
59a12e90
JS
4162 /* This crashes when used within wxHelpContext,
4163 so we have to use the X-specific implementation below.
4164 gint x, y;
4165 GdkModifierType *mask;
4166 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4167
4168 return wxPoint(x, y);
4169 */
4170
3723b7b1
JS
4171 int x, y;
4172 GdkWindow* windowAtPtr = gdk_window_at_pointer(& x, & y);
57591e0e
JS
4173 if (!windowAtPtr)
4174 return wxPoint(-999, -999);
59a12e90
JS
4175
4176 Display *display = GDK_WINDOW_XDISPLAY(windowAtPtr);
4177 Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
4178 Window rootReturn, childReturn;
4179 int rootX, rootY, winX, winY;
4180 unsigned int maskReturn;
4181
4182 XQueryPointer (display,
5cd09f0b
RR
4183 rootWindow,
4184 &rootReturn,
59a12e90
JS
4185 &childReturn,
4186 &rootX, &rootY, &winX, &winY, &maskReturn);
4187 return wxPoint(rootX, rootY);
4188
3723b7b1
JS
4189}
4190