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