]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/window.cpp
changed ar options to reduce build verbosity
[wxWidgets.git] / src / gtk / window.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
f6bcfd97 2// Name: gtk/window.cpp
c801d85f
KB
3// Purpose:
4// Author: Robert Roebling
c67d8618 5// Id: $Id$
01111366 6// Copyright: (c) 1998 Robert Roebling, Julian Smart
5e0aa05a 7// Licence: wxWindows licence
c801d85f
KB
8/////////////////////////////////////////////////////////////////////////////
9
10
11#ifdef __GNUG__
bfc6fde4 12 #pragma implementation "window.h"
c801d85f
KB
13#endif
14
d02af7bb
JJ
15#ifdef __VMS
16#define XWarpPointer XWARPPOINTER
17#endif
18
c801d85f
KB
19#include "wx/defs.h"
20#include "wx/window.h"
33611ebb 21#include "wx/dcclient.h"
c801d85f
KB
22#include "wx/frame.h"
23#include "wx/app.h"
24#include "wx/layout.h"
25#include "wx/utils.h"
26#include "wx/dialog.h"
27#include "wx/msgdlg.h"
bfc6fde4 28
06cfab17 29#if wxUSE_DRAG_AND_DROP
bfc6fde4 30 #include "wx/dnd.h"
ac57418f 31#endif
bfc6fde4 32
cad880f5 33#if wxUSE_TOOLTIPS
bfc6fde4 34 #include "wx/tooltip.h"
cad880f5 35#endif
bfc6fde4 36
f6bcfd97
BP
37#if wxUSE_CARET
38 #include "wx/caret.h"
39#endif // wxUSE_CARET
40
ab93a576
RD
41#if wxUSE_TEXTCTRL
42#include "wx/textctrl.h"
43#endif
44
30dea054 45#include "wx/menu.h"
d4c99d6f 46#include "wx/statusbr.h"
b4071e91 47#include "wx/intl.h"
3bc755fc 48#include "wx/settings.h"
3069ac4e 49#include "wx/log.h"
b4071e91 50
3ac8d3bc
RR
51#ifdef __WXDEBUG__
52 #include "wx/thread.h"
53#endif
54
b4071e91 55#include <math.h>
c801d85f 56
3ac8d3bc
RR
57#include <gdk/gdk.h>
58#include <gtk/gtk.h>
59#include <gdk/gdkprivate.h>
60#include <gdk/gdkkeysyms.h>
3ac8d3bc 61#include <gdk/gdkx.h>
6bc8a1c8 62
8cb9f0d0
RR
63#include <gtk/gtk.h>
64#include <gtk/gtkprivate.h>
65
66#include "wx/gtk/win_gtk.h"
67
868a2826
RR
68//-----------------------------------------------------------------------------
69// documentation on internals
70//-----------------------------------------------------------------------------
71
72/*
73 I have been asked several times about writing some documentation about
74 the GTK port of wxWindows, especially its internal structures. Obviously,
75 you cannot understand wxGTK without knowing a little about the GTK, but
47d67540 76 some more information about what the wxWindow, which is the base class
868a2826 77 for all other window classes, does seems required as well.
47d67540 78
30760ce7
RR
79 I)
80
868a2826 81 What does wxWindow do? It contains the common interface for the following
e380f72b 82 jobs of its descendants:
47d67540 83
868a2826 84 1) Define the rudimentary behaviour common to all window classes, such as
e380f72b
RR
85 resizing, intercepting user input (so as to make it possible to use these
86 events for special purposes in a derived class), window names etc.
868a2826
RR
87
88 2) Provide the possibility to contain and manage children, if the derived
89 class is allowed to contain children, which holds true for those window
e380f72b 90 classes which do not display a native GTK widget. To name them, these
868a2826 91 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
47d67540 92 work classes are a special case and are handled a bit differently from
e380f72b 93 the rest. The same holds true for the wxNotebook class.
47d67540 94
868a2826
RR
95 3) Provide the possibility to draw into a client area of a window. This,
96 too, only holds true for classes that do not display a native GTK widget
97 as above.
47d67540 98
e380f72b
RR
99 4) Provide the entire mechanism for scrolling widgets. This actual inter-
100 face for this is usually in wxScrolledWindow, but the GTK implementation
868a2826 101 is in this class.
47d67540 102
868a2826
RR
103 5) A multitude of helper or extra methods for special purposes, such as
104 Drag'n'Drop, managing validators etc.
47d67540 105
30760ce7
RR
106 6) Display a border (sunken, raised, simple or none).
107
e380f72b
RR
108 Normally one might expect, that one wxWindows window would always correspond
109 to one GTK widget. Under GTK, there is no such allround widget that has all
868a2826
RR
110 the functionality. Moreover, the GTK defines a client area as a different
111 widget from the actual widget you are handling. Last but not least some
112 special classes (e.g. wxFrame) handle different categories of widgets and
113 still have the possibility to draw something in the client area.
114 It was therefore required to write a special purpose GTK widget, that would
115 represent a client area in the sense of wxWindows capable to do the jobs
116 2), 3) and 4). I have written this class and it resides in win_gtk.c of
117 this directory.
47d67540 118
868a2826 119 All windows must have a widget, with which they interact with other under-
e380f72b 120 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
868a2826 121 thw wxWindow class has a member variable called m_widget which holds a
e380f72b
RR
122 pointer to this widget. When the window class represents a GTK native widget,
123 this is (in most cases) the only GTK widget the class manages. E.g. the
124 wxStatitText class handles only a GtkLabel widget a pointer to which you
125 can find in m_widget (defined in wxWindow)
8bbe427f 126
e380f72b 127 When the class has a client area for drawing into and for containing children
da048e3d 128 it has to handle the client area widget (of the type GtkPizza, defined in
8bbe427f
VZ
129 win_gtk.c), but there could be any number of widgets, handled by a class
130 The common rule for all windows is only, that the widget that interacts with
131 the rest of GTK must be referenced in m_widget and all other widgets must be
132 children of this widget on the GTK level. The top-most widget, which also
133 represents the client area, must be in the m_wxwindow field and must be of
da048e3d 134 the type GtkPizza.
47d67540 135
868a2826
RR
136 As I said, the window classes that display a GTK native widget only have
137 one widget, so in the case of e.g. the wxButton class m_widget holds a
138 pointer to a GtkButton widget. But windows with client areas (for drawing
139 and children) have a m_widget field that is a pointer to a GtkScrolled-
da048e3d 140 Window and a m_wxwindow field that is pointer to a GtkPizza and this
868a2826 141 one is (in the GTK sense) a child of the GtkScrolledWindow.
47d67540 142
868a2826
RR
143 If the m_wxwindow field is set, then all input to this widget is inter-
144 cepted and sent to the wxWindows class. If not, all input to the widget
145 that gets pointed to by m_widget gets intercepted and sent to the class.
148cd9b6 146
30760ce7 147 II)
148cd9b6 148
30760ce7
RR
149 The design of scrolling in wxWindows is markedly different from that offered
150 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
151 clicking on a scrollbar belonging to scrolled window will inevitably move
152 the window. In wxWindows, the scrollbar will only emit an event, send this
153 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
da048e3d 154 which actually moves the window and its subchildren. Note that GtkPizza
30760ce7
RR
155 memorizes how much it has been scrolled but that wxWindows forgets this
156 so that the two coordinates systems have to be kept in synch. This is done
da048e3d 157 in various places using the pizza->xoffset and pizza->yoffset values.
148cd9b6
VZ
158
159 III)
160
30760ce7
RR
161 Singularily the most broken code in GTK is the code that is supposes to
162 inform subwindows (child windows) about new positions. Very often, duplicate
163 events are sent without changes in size or position, equally often no
164 events are sent at all (All this is due to a bug in the GtkContainer code
165 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
166 GTK's own system and it simply waits for size events for toplevel windows
167 and then iterates down the respective size events to all window. This has
168 the disadvantage, that windows might get size events before the GTK widget
169 actually has the reported size. This doesn't normally pose any problem, but
3017f78d 170 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
30760ce7
RR
171 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
172 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
173 window that is used for OpenGl output really has that size (as reported by
174 GTK).
175
176 IV)
148cd9b6 177
30760ce7
RR
178 If someone at some point of time feels the immense desire to have a look at,
179 change or attempt to optimse the Refresh() logic, this person will need an
180 intimate understanding of what a "draw" and what an "expose" events are and
181 what there are used for, in particular when used in connection with GTK's
182 own windowless widgets. Beware.
148cd9b6 183
30760ce7 184 V)
148cd9b6 185
30760ce7
RR
186 Cursors, too, have been a constant source of pleasure. The main difficulty
187 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
188 for the parent. To prevent this from doing too much harm, I use idle time
189 to set the cursor over and over again, starting from the toplevel windows
190 and ending with the youngest generation (speaking of parent and child windows).
191 Also don't forget that cursors (like much else) are connected to GdkWindows,
192 not GtkWidgets and that the "window" field of a GtkWidget might very well
148cd9b6 193 point to the GdkWindow of the parent widget (-> "window less widget") and
30760ce7 194 that the two obviously have very different meanings.
868a2826
RR
195
196*/
197
f03fc89f
VZ
198//-----------------------------------------------------------------------------
199// data
200//-----------------------------------------------------------------------------
201
202extern wxList wxPendingDelete;
203extern bool g_blockEventsOnDrag;
204extern bool g_blockEventsOnScroll;
238d735d 205extern wxCursor g_globalCursor;
f68586e5 206
1e6feb95
VZ
207// mouse capture state: the window which has it and if the mouse is currently
208// inside it
209static wxWindowGTK *g_captureWindow = (wxWindowGTK*) NULL;
210static bool g_captureWindowHasMouse = FALSE;
211
212/* extern */ wxWindowGTK *g_focusWindow = (wxWindowGTK*) NULL;
213
214// the last window which had the focus - this is normally never NULL (except
215// if we never had focus at all) as even when g_focusWindow is NULL it still
216// keeps its previous value
217static wxWindowGTK *g_focusWindowLast = (wxWindowGTK *)NULL;
148cd9b6 218
e8c12a53
VS
219// the frame that is currently active (i.e. its child has focus). It is
220// used to generate wxActivateEvents
221static wxWindowGTK *g_activeFrame = (wxWindowGTK *)NULL;
222static bool g_activeFrameLostFocus = FALSE;
223
148cd9b6
VZ
224// if we detect that the app has got/lost the focus, we set this variable to
225// either TRUE or FALSE and an activate event will be sent during the next
226// OnIdle() call and it is reset to -1: this value means that we shouldn't
227// send any activate events at all
228static int g_sendActivateEvent = -1;
f03fc89f
VZ
229
230/* hack: we need something to pass to gtk_menu_popup, so we store the time of
231 the last click here */
232static guint32 gs_timeLastClick = 0;
233
3ac8d3bc
RR
234extern bool g_mainThreadLocked;
235
2e563988
RR
236//-----------------------------------------------------------------------------
237// debug
238//-----------------------------------------------------------------------------
239
d52e91c9 240#ifndef __WXGTK20__
a56fcaaf 241#define DISABLE_STYLE_IF_BROKEN_THEME 1
d52e91c9 242#endif
a56fcaaf 243
2e563988
RR
244#ifdef __WXDEBUG__
245
c6e62f74
KB
246#if wxUSE_THREADS
247# define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
248#else
249# define DEBUG_MAIN_THREAD
250#endif
3ac8d3bc 251
2e563988
RR
252static gint gtk_debug_focus_in_callback( GtkWidget *WXUNUSED(widget),
253 GdkEvent *WXUNUSED(event),
014b0d06 254 const wxChar *WXUNUSED(name) )
2e563988 255{
053dcf1a 256/*
167e3718
VZ
257 static bool s_done = FALSE;
258 if ( !s_done )
259 {
260 wxLog::AddTraceMask("focus");
261 s_done = TRUE;
262 }
223d09f6 263 wxLogTrace(wxT("FOCUS NOW AT: %s"), name);
053dcf1a 264*/
2e563988
RR
265
266 return FALSE;
267}
268
269void debug_focus_in( GtkWidget* widget, const wxChar* name, const wxChar *window )
270{
9a8c7620
VZ
271 // suppress warnings about gtk_debug_focus_in_callback being unused with
272 // this "if ( 0 )"
273 if ( 0 )
274 {
275 wxString tmp = name;
276 tmp += wxT(" FROM ");
277 tmp += window;
2e563988 278
9a8c7620 279 wxChar *s = new wxChar[tmp.Length()+1];
2e563988 280
9a8c7620 281 wxStrcpy( s, tmp );
2e563988 282
9a8c7620
VZ
283 gtk_signal_connect( GTK_OBJECT(widget), "focus_in_event",
284 GTK_SIGNAL_FUNC(gtk_debug_focus_in_callback), (gpointer)s );
285 }
2e563988
RR
286}
287
559d79aa
BJ
288#else
289#define DEBUG_MAIN_THREAD
f03fc89f 290#endif // Debug
ff8bfdbb 291
85eb36c2
RR
292//-----------------------------------------------------------------------------
293// missing gdk functions
294//-----------------------------------------------------------------------------
295
296void
297gdk_window_warp_pointer (GdkWindow *window,
c50f1fb9
VZ
298 gint x,
299 gint y)
85eb36c2 300{
dd00f3f6 301#ifndef __WXGTK20__
85eb36c2 302 GdkWindowPrivate *priv;
dd00f3f6 303#endif
c50f1fb9 304
85eb36c2 305 if (!window)
27df579a 306 window = GDK_ROOT_PARENT();
c50f1fb9 307
dd00f3f6
OK
308#ifdef __WXGTK20__
309 if (!GDK_WINDOW_DESTROYED(window))
310 {
311 XWarpPointer (GDK_WINDOW_XDISPLAY(window),
312 None, /* not source window -> move from anywhere */
313 GDK_WINDOW_XID(window), /* dest window */
314 0, 0, 0, 0, /* not source window -> move from anywhere */
315 x, y );
316 }
317#else
85eb36c2 318 priv = (GdkWindowPrivate*) window;
c50f1fb9 319
85eb36c2
RR
320 if (!priv->destroyed)
321 {
c50f1fb9 322 XWarpPointer (priv->xdisplay,
85eb36c2 323 None, /* not source window -> move from anywhere */
c50f1fb9 324 priv->xwindow, /* dest window */
85eb36c2 325 0, 0, 0, 0, /* not source window -> move from anywhere */
c50f1fb9 326 x, y );
85eb36c2 327 }
dd00f3f6 328#endif
85eb36c2
RR
329}
330
acfd422a 331//-----------------------------------------------------------------------------
a2053b27 332// idle system
acfd422a
RR
333//-----------------------------------------------------------------------------
334
a2053b27
RR
335extern void wxapp_install_idle_handler();
336extern bool g_isIdle;
337
ed673c6a
RR
338//-----------------------------------------------------------------------------
339// local code (see below)
340//-----------------------------------------------------------------------------
341
f6bcfd97 342// returns the child of win which currently has focus or NULL if not found
1e6feb95 343//
fc71ef6e 344// Note: can't be static, needed by textctrl.cpp.
3379ed37 345wxWindow *wxFindFocusedChild(wxWindowGTK *win)
f6bcfd97 346{
3379ed37 347 wxWindow *winFocus = wxWindowGTK::FindFocus();
f6bcfd97 348 if ( !winFocus )
3379ed37 349 return (wxWindow *)NULL;
f6bcfd97
BP
350
351 if ( winFocus == win )
3379ed37 352 return (wxWindow *)win;
f6bcfd97
BP
353
354 for ( wxWindowList::Node *node = win->GetChildren().GetFirst();
355 node;
356 node = node->GetNext() )
357 {
3379ed37 358 wxWindow *child = wxFindFocusedChild(node->GetData());
f6bcfd97
BP
359 if ( child )
360 return child;
361 }
362
3379ed37 363 return (wxWindow *)NULL;
f6bcfd97
BP
364}
365
e8c12a53
VS
366// Returns toplevel grandparent of given window:
367static wxWindowGTK* wxGetTopLevelParent(wxWindowGTK *win)
368{
369 wxWindowGTK *p = win;
370 while (p && !p->IsTopLevel())
371 p = p->GetParent();
372 return p;
373}
374
375
1e6feb95 376static void draw_frame( GtkWidget *widget, wxWindowGTK *win )
ed673c6a 377{
1e6feb95
VZ
378 // wxUniversal widgets draw the borders and scrollbars themselves
379#ifndef __WXUNIVERSAL__
ed673c6a
RR
380 if (!win->m_hasVMT)
381 return;
382
383 int dw = 0;
384 int dh = 0;
385
5b8a521e 386 if (win->m_hasScrolling)
ed673c6a 387 {
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
2daa0ce9
VZ
1211// ----------------------------------------------------------------------------
1212// mouse event processing helper
1213// ----------------------------------------------------------------------------
1214
1215static void AdjustEventButtonState(wxMouseEvent& event)
1216{
1217 // GDK reports the old state of the button for a button press event, but
1218 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1219 // for a LEFT_DOWN event, not FALSE, so we will invert
1220 // left/right/middleDown for the corresponding click events
1e6feb95 1221
1a8caf94
RR
1222 if ((event.GetEventType() == wxEVT_LEFT_DOWN) ||
1223 (event.GetEventType() == wxEVT_LEFT_DCLICK) ||
1224 (event.GetEventType() == wxEVT_LEFT_UP))
1225 {
1226 event.m_leftDown = !event.m_leftDown;
1227 return;
1228 }
1229
1230 if ((event.GetEventType() == wxEVT_MIDDLE_DOWN) ||
1231 (event.GetEventType() == wxEVT_MIDDLE_DCLICK) ||
1232 (event.GetEventType() == wxEVT_MIDDLE_UP))
2daa0ce9 1233 {
1a8caf94
RR
1234 event.m_middleDown = !event.m_middleDown;
1235 return;
1236 }
1237
1238 if ((event.GetEventType() == wxEVT_RIGHT_DOWN) ||
1239 (event.GetEventType() == wxEVT_RIGHT_DCLICK) ||
1240 (event.GetEventType() == wxEVT_RIGHT_UP))
1241 {
1242 event.m_rightDown = !event.m_rightDown;
1243 return;
2daa0ce9
VZ
1244 }
1245}
1246
c801d85f 1247//-----------------------------------------------------------------------------
2f2aa628
RR
1248// "button_press_event"
1249//-----------------------------------------------------------------------------
c801d85f 1250
1e6feb95 1251static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindowGTK *win )
903f689b 1252{
3ac8d3bc
RR
1253 DEBUG_MAIN_THREAD
1254
c50f1fb9 1255 if (g_isIdle)
a2053b27
RR
1256 wxapp_install_idle_handler();
1257
1258/*
223d09f6 1259 wxPrintf( wxT("1) OnButtonPress from ") );
a2053b27
RR
1260 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1261 wxPrintf( win->GetClassInfo()->GetClassName() );
223d09f6 1262 wxPrintf( wxT(".\n") );
a2053b27 1263*/
a2053b27 1264 if (!win->m_hasVMT) return FALSE;
f5e27805 1265 if (g_blockEventsOnDrag) return TRUE;
76ed8f8d 1266 if (g_blockEventsOnScroll) return TRUE;
c801d85f 1267
034be888
RR
1268 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1269
a2053b27 1270 if (win->m_wxwindow)
c801d85f 1271 {
a2053b27 1272 if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow) && !GTK_WIDGET_HAS_FOCUS (win->m_wxwindow) )
f5e27805 1273 {
a2053b27 1274 gtk_widget_grab_focus (win->m_wxwindow);
47d67540 1275
c801d85f 1276/*
223d09f6 1277 wxPrintf( wxT("GrabFocus from ") );
f5e27805 1278 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
a2053b27 1279 wxPrintf( win->GetClassInfo()->GetClassName() );
223d09f6 1280 wxPrintf( wxT(".\n") );
c801d85f 1281*/
47d67540 1282
f5e27805 1283 }
362c6693 1284 }
47d67540 1285
2daa0ce9 1286 wxEventType event_type = wxEVT_NULL;
47d67540 1287
f5e27805 1288 if (gdk_event->button == 1)
c801d85f 1289 {
f5e27805
RR
1290 switch (gdk_event->type)
1291 {
1292 case GDK_BUTTON_PRESS: event_type = wxEVT_LEFT_DOWN; break;
1293 case GDK_2BUTTON_PRESS: event_type = wxEVT_LEFT_DCLICK; break;
1294 default: break;
1295 }
362c6693 1296 }
f5e27805 1297 else if (gdk_event->button == 2)
c801d85f 1298 {
f5e27805
RR
1299 switch (gdk_event->type)
1300 {
1301 case GDK_BUTTON_PRESS: event_type = wxEVT_MIDDLE_DOWN; break;
1302 case GDK_2BUTTON_PRESS: event_type = wxEVT_MIDDLE_DCLICK; break;
1303 default: break;
1304 }
362c6693 1305 }
f5e27805 1306 else if (gdk_event->button == 3)
c801d85f 1307 {
f5e27805
RR
1308 switch (gdk_event->type)
1309 {
1310 case GDK_BUTTON_PRESS: event_type = wxEVT_RIGHT_DOWN; break;
1311 case GDK_2BUTTON_PRESS: event_type = wxEVT_RIGHT_DCLICK; break;
1312 default: break;
1313 }
362c6693 1314 }
47d67540 1315
2daa0ce9
VZ
1316 if ( event_type == wxEVT_NULL )
1317 {
1318 // unknown mouse button or click type
1319 return FALSE;
1320 }
1321
f5e27805 1322 wxMouseEvent event( event_type );
d1367c3d 1323 event.SetTimestamp( gdk_event->time );
f5e27805
RR
1324 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1325 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1326 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1327 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1328 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1329 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1330 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
47d67540 1331
13111b2a
VZ
1332 event.m_x = (wxCoord)gdk_event->x;
1333 event.m_y = (wxCoord)gdk_event->y;
47d67540 1334
2daa0ce9
VZ
1335 AdjustEventButtonState(event);
1336
f5e27805
RR
1337 // Some control don't have their own X window and thus cannot get
1338 // any events.
47d67540 1339
72195a0f 1340 if (!g_captureWindow)
2f2aa628 1341 {
b02da6b1
VZ
1342 wxCoord x = event.m_x;
1343 wxCoord y = event.m_y;
2f073eb2
RR
1344 if (win->m_wxwindow)
1345 {
da048e3d 1346 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
b02da6b1
VZ
1347 x += pizza->xoffset;
1348 y += pizza->yoffset;
2f073eb2
RR
1349 }
1350
db1b4961 1351 wxNode *node = win->GetChildren().First();
f5e27805
RR
1352 while (node)
1353 {
1e6feb95 1354 wxWindowGTK *child = (wxWindowGTK*)node->Data();
148cd9b6 1355
f96ac56a 1356 node = node->Next();
b02da6b1
VZ
1357 if (!child->IsShown())
1358 continue;
ff8bfdbb 1359
a2053b27 1360 if (child->m_isStaticBox)
ff8bfdbb
VZ
1361 {
1362 // wxStaticBox is transparent in the box itself
a2053b27
RR
1363 int xx1 = child->m_x;
1364 int yy1 = child->m_y;
1365 int xx2 = child->m_x + child->m_width;
1366 int yy2 = child->m_x + child->m_height;
ff8bfdbb
VZ
1367
1368 // left
1369 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1370 // right
1371 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1372 // top
1373 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1374 // bottom
1375 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1376 {
1ecc4d80 1377 win = child;
a2053b27
RR
1378 event.m_x -= child->m_x;
1379 event.m_y -= child->m_y;
1ecc4d80 1380 break;
ff8bfdbb
VZ
1381 }
1382
1383 }
1384 else
1385 {
a2053b27 1386 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
2f073eb2
RR
1387 (child->m_x <= x) &&
1388 (child->m_y <= y) &&
1389 (child->m_x+child->m_width >= x) &&
1390 (child->m_y+child->m_height >= y))
1ecc4d80
RR
1391 {
1392 win = child;
a2053b27
RR
1393 event.m_x -= child->m_x;
1394 event.m_y -= child->m_y;
1ecc4d80 1395 break;
ff8bfdbb 1396 }
f5e27805 1397 }
f5e27805 1398 }
2f2aa628 1399 }
ff8bfdbb 1400
f5e27805 1401 event.SetEventObject( win );
47d67540 1402
f5e27805 1403 gs_timeLastClick = gdk_event->time;
47d67540 1404
2f073eb2
RR
1405/*
1406 wxPrintf( wxT("2) OnButtonPress from ") );
1407 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1408 wxPrintf( win->GetClassInfo()->GetClassName() );
1409 wxPrintf( wxT(".\n") );
1410*/
1411
f5e27805 1412 if (win->GetEventHandler()->ProcessEvent( event ))
034be888 1413 {
f5e27805 1414 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_press_event" );
f03fc89f 1415 return TRUE;
034be888 1416 }
47d67540 1417
034be888 1418 return FALSE;
362c6693 1419}
c801d85f
KB
1420
1421//-----------------------------------------------------------------------------
97b3455a 1422// "button_release_event"
2f2aa628 1423//-----------------------------------------------------------------------------
c801d85f 1424
1e6feb95 1425static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindowGTK *win )
47d67540 1426{
3ac8d3bc
RR
1427 DEBUG_MAIN_THREAD
1428
c50f1fb9 1429 if (g_isIdle)
a2053b27
RR
1430 wxapp_install_idle_handler();
1431
1432 if (!win->m_hasVMT) return FALSE;
034be888
RR
1433 if (g_blockEventsOnDrag) return FALSE;
1434 if (g_blockEventsOnScroll) return FALSE;
c801d85f 1435
034be888 1436 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
47d67540 1437
c801d85f 1438/*
f5e27805
RR
1439 printf( "OnButtonRelease from " );
1440 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1441 printf( win->GetClassInfo()->GetClassName() );
1442 printf( ".\n" );
c801d85f 1443*/
47d67540 1444
f5e27805 1445 wxEventType event_type = wxEVT_NULL;
47d67540 1446
f5e27805
RR
1447 switch (gdk_event->button)
1448 {
1449 case 1: event_type = wxEVT_LEFT_UP; break;
1450 case 2: event_type = wxEVT_MIDDLE_UP; break;
1451 case 3: event_type = wxEVT_RIGHT_UP; break;
2daa0ce9 1452 default: return FALSE;
f5e27805 1453 }
47d67540 1454
f5e27805 1455 wxMouseEvent event( event_type );
d1367c3d 1456 event.SetTimestamp( gdk_event->time );
f5e27805
RR
1457 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1458 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1459 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1460 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1461 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1462 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1463 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
13111b2a
VZ
1464 event.m_x = (wxCoord)gdk_event->x;
1465 event.m_y = (wxCoord)gdk_event->y;
f5e27805 1466
2daa0ce9
VZ
1467 AdjustEventButtonState(event);
1468
f5e27805
RR
1469 // Some control don't have their own X window and thus cannot get
1470 // any events.
1471
72195a0f 1472 if (!g_captureWindow)
2f2aa628 1473 {
b02da6b1
VZ
1474 wxCoord x = event.m_x;
1475 wxCoord y = event.m_y;
2f073eb2
RR
1476 if (win->m_wxwindow)
1477 {
da048e3d 1478 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
b02da6b1
VZ
1479 x += pizza->xoffset;
1480 y += pizza->yoffset;
2f073eb2
RR
1481 }
1482
db1b4961 1483 wxNode *node = win->GetChildren().First();
f5e27805
RR
1484 while (node)
1485 {
1e6feb95 1486 wxWindowGTK *child = (wxWindowGTK*)node->Data();
ff8bfdbb 1487
f96ac56a 1488 node = node->Next();
b02da6b1
VZ
1489 if (!child->IsShown())
1490 continue;
f96ac56a 1491
a2053b27 1492 if (child->m_isStaticBox)
ff8bfdbb
VZ
1493 {
1494 // wxStaticBox is transparent in the box itself
a2053b27
RR
1495 int xx1 = child->m_x;
1496 int yy1 = child->m_y;
1497 int xx2 = child->m_x + child->m_width;
1498 int yy2 = child->m_x + child->m_height;
ff8bfdbb
VZ
1499
1500 // left
1501 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1502 // right
1503 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1504 // top
1505 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1506 // bottom
1507 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1508 {
1ecc4d80 1509 win = child;
a2053b27
RR
1510 event.m_x -= child->m_x;
1511 event.m_y -= child->m_y;
1ecc4d80 1512 break;
ff8bfdbb
VZ
1513 }
1514
1515 }
1516 else
1517 {
a2053b27 1518 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
2f073eb2
RR
1519 (child->m_x <= x) &&
1520 (child->m_y <= y) &&
1521 (child->m_x+child->m_width >= x) &&
1522 (child->m_y+child->m_height >= y))
1ecc4d80
RR
1523 {
1524 win = child;
a2053b27
RR
1525 event.m_x -= child->m_x;
1526 event.m_y -= child->m_y;
1ecc4d80 1527 break;
ff8bfdbb 1528 }
f5e27805 1529 }
f5e27805 1530 }
2f2aa628 1531 }
47d67540 1532
f5e27805 1533 event.SetEventObject( win );
47d67540 1534
f5e27805 1535 if (win->GetEventHandler()->ProcessEvent( event ))
034be888 1536 {
f5e27805 1537 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_release_event" );
f03fc89f 1538 return TRUE;
034be888 1539 }
47d67540 1540
034be888 1541 return FALSE;
362c6693 1542}
c801d85f 1543
1e6feb95
VZ
1544// ============================================================================
1545// the mouse events
1546// ============================================================================
1547
1548// init wxMouseEvent with the info from gdk_event
1549#define InitMouseEvent(event, gdk_event) \
1550 event.SetTimestamp( gdk_event->time ); \
1551 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK); \
1552 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK); \
1553 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK); \
1554 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK); \
1555 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK); \
1556 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK); \
1557 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK); \
1558\
1559 event.m_x = (wxCoord)gdk_event->x; \
1560 event.m_y = (wxCoord)gdk_event->y \
1561
c801d85f 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 );
1e6feb95 1599 InitMouseEvent(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);
1613 InitMouseEvent(event, gdk_event);
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 {
1815 wxASSERT_MSG( wxGetTopLevelParent(win) == g_activeFrame, wxT("unfocusing window that haven't gained focus properly") )
1816 g_activeFrameLostFocus = TRUE;
1817 }
1818
148cd9b6
VZ
1819 // if the focus goes out of our app alltogether, OnIdle() will send
1820 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1821 // g_sendActivateEvent to -1
1822 g_sendActivateEvent = 0;
1823
3379ed37 1824 wxWindowGTK *winFocus = wxFindFocusedChild(win);
f6bcfd97
BP
1825 if ( winFocus )
1826 win = winFocus;
1827
1e6feb95 1828 g_focusWindow = (wxWindowGTK *)NULL;
148cd9b6 1829
76fcf0f2
RR
1830#if 0
1831 wxPrintf( "OnKillFocus from " );
e380f72b 1832 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
76fcf0f2
RR
1833 wxPrintf( win->GetClassInfo()->GetClassName() );
1834 wxPrintf( ".\n" );
1835#endif
47d67540 1836
b79395c5
RR
1837#ifdef HAVE_XIM
1838 if (win->m_ic)
1839 gdk_im_end();
1840#endif
1841
1e6feb95 1842#if wxUSE_CARET
f6bcfd97
BP
1843 // caret needs to be informed about focus change
1844 wxCaret *caret = win->GetCaret();
1845 if ( caret )
1846 {
1847 caret->OnKillFocus();
1848 }
1849#endif // wxUSE_CARET
1850
5cd09f0b
RR
1851 wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
1852 event.SetEventObject( win );
1853
1854 if (win->GetEventHandler()->ProcessEvent( event ))
1855 {
1856 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_out_event" );
1857 return TRUE;
034be888 1858 }
ca298c88 1859
034be888 1860 return FALSE;
362c6693 1861}
c801d85f 1862
b4071e91
RR
1863//-----------------------------------------------------------------------------
1864// "enter_notify_event"
1865//-----------------------------------------------------------------------------
1866
1e6feb95 1867static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win )
b4071e91 1868{
3ac8d3bc
RR
1869 DEBUG_MAIN_THREAD
1870
c50f1fb9 1871 if (g_isIdle)
a2053b27 1872 wxapp_install_idle_handler();
ca298c88 1873
a2053b27
RR
1874 if (!win->m_hasVMT) return FALSE;
1875 if (g_blockEventsOnDrag) return FALSE;
47d67540 1876
a2053b27 1877 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
b292e2f5 1878
e380f72b 1879 wxMouseEvent event( wxEVT_ENTER_WINDOW );
d1367c3d 1880 event.SetTimestamp( gdk_event->time );
e380f72b 1881 event.SetEventObject( win );
ff8bfdbb 1882
4a33eba6
RR
1883 int x = 0;
1884 int y = 0;
1885 GdkModifierType state = (GdkModifierType)0;
ff8bfdbb 1886
a2053b27 1887 gdk_window_get_pointer( widget->window, &x, &y, &state );
ff8bfdbb 1888
1e6feb95 1889 InitMouseEvent(event, gdk_event);
4a33eba6 1890
13111b2a
VZ
1891 event.m_x = x;
1892 event.m_y = y;
ff8bfdbb 1893
e380f72b 1894 if (win->GetEventHandler()->ProcessEvent( event ))
034be888 1895 {
e380f72b 1896 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "enter_notify_event" );
034be888
RR
1897 return TRUE;
1898 }
ca298c88 1899
034be888 1900 return FALSE;
b4071e91 1901}
47d67540 1902
b4071e91
RR
1903//-----------------------------------------------------------------------------
1904// "leave_notify_event"
1905//-----------------------------------------------------------------------------
1906
1e6feb95 1907static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win )
b4071e91 1908{
3ac8d3bc
RR
1909 DEBUG_MAIN_THREAD
1910
c50f1fb9 1911 if (g_isIdle)
a2053b27 1912 wxapp_install_idle_handler();
acfd422a 1913
a2053b27
RR
1914 if (!win->m_hasVMT) return FALSE;
1915 if (g_blockEventsOnDrag) return FALSE;
b292e2f5 1916
a2053b27 1917 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
c50f1fb9 1918
e380f72b 1919 wxMouseEvent event( wxEVT_LEAVE_WINDOW );
d1367c3d 1920 event.SetTimestamp( gdk_event->time );
e380f72b 1921 event.SetEventObject( win );
47d67540 1922
4a33eba6
RR
1923 int x = 0;
1924 int y = 0;
1925 GdkModifierType state = (GdkModifierType)0;
ff8bfdbb 1926
4a33eba6 1927 gdk_window_get_pointer( widget->window, &x, &y, &state );
ff8bfdbb 1928
4a33eba6
RR
1929 event.m_shiftDown = (state & GDK_SHIFT_MASK);
1930 event.m_controlDown = (state & GDK_CONTROL_MASK);
1931 event.m_altDown = (state & GDK_MOD1_MASK);
1932 event.m_metaDown = (state & GDK_MOD2_MASK);
1933 event.m_leftDown = (state & GDK_BUTTON1_MASK);
1934 event.m_middleDown = (state & GDK_BUTTON2_MASK);
1935 event.m_rightDown = (state & GDK_BUTTON3_MASK);
1936
13111b2a
VZ
1937 event.m_x = x;
1938 event.m_y = y;
ff8bfdbb 1939
e380f72b 1940 if (win->GetEventHandler()->ProcessEvent( event ))
034be888 1941 {
e380f72b 1942 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "leave_notify_event" );
034be888
RR
1943 return TRUE;
1944 }
ca298c88 1945
034be888 1946 return FALSE;
b4071e91 1947}
47d67540 1948
c801d85f 1949//-----------------------------------------------------------------------------
2f2aa628
RR
1950// "value_changed" from m_vAdjust
1951//-----------------------------------------------------------------------------
c801d85f 1952
1e6feb95 1953static void gtk_window_vscroll_callback( GtkAdjustment *adjust, wxWindowGTK *win )
c801d85f 1954{
3ac8d3bc
RR
1955 DEBUG_MAIN_THREAD
1956
c50f1fb9 1957 if (g_isIdle)
a2053b27 1958 wxapp_install_idle_handler();
c801d85f 1959
a2053b27 1960 if (g_blockEventsOnDrag) return;
47d67540 1961
a2053b27 1962 if (!win->m_hasVMT) return;
148cd9b6 1963
5e014a0c 1964 float diff = adjust->value - win->m_oldVerticalPos;
e380f72b 1965 if (fabs(diff) < 0.2) return;
148cd9b6 1966
5e014a0c 1967 win->m_oldVerticalPos = adjust->value;
47d67540 1968
5e014a0c
RR
1969 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1970 GtkRange *range = GTK_RANGE( scrolledWindow->vscrollbar );
148cd9b6 1971
5e014a0c
RR
1972 wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK;
1973 if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP;
1974 else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN;
1975 else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP;
1976 else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN;
148cd9b6 1977
5e014a0c 1978 int value = (int)(adjust->value+0.5);
c801d85f 1979
c5b42c87 1980 wxScrollWinEvent event( command, value, wxVERTICAL );
e380f72b
RR
1981 event.SetEventObject( win );
1982 win->GetEventHandler()->ProcessEvent( event );
362c6693 1983}
c801d85f
KB
1984
1985//-----------------------------------------------------------------------------
2f2aa628
RR
1986// "value_changed" from m_hAdjust
1987//-----------------------------------------------------------------------------
c801d85f 1988
1e6feb95 1989static void gtk_window_hscroll_callback( GtkAdjustment *adjust, wxWindowGTK *win )
47d67540 1990{
3ac8d3bc
RR
1991 DEBUG_MAIN_THREAD
1992
c50f1fb9 1993 if (g_isIdle)
a2053b27 1994 wxapp_install_idle_handler();
47d67540 1995
a2053b27
RR
1996 if (g_blockEventsOnDrag) return;
1997 if (!win->m_hasVMT) return;
47d67540 1998
5e014a0c 1999 float diff = adjust->value - win->m_oldHorizontalPos;
e380f72b 2000 if (fabs(diff) < 0.2) return;
148cd9b6 2001
5e014a0c 2002 win->m_oldHorizontalPos = adjust->value;
8bbe427f 2003
5e014a0c
RR
2004 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
2005 GtkRange *range = GTK_RANGE( scrolledWindow->hscrollbar );
148cd9b6 2006
5e014a0c
RR
2007 wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK;
2008 if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP;
2009 else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN;
2010 else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP;
2011 else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN;
148cd9b6 2012
5e014a0c 2013 int value = (int)(adjust->value+0.5);
47d67540 2014
c5b42c87 2015 wxScrollWinEvent event( command, value, wxHORIZONTAL );
e380f72b
RR
2016 event.SetEventObject( win );
2017 win->GetEventHandler()->ProcessEvent( event );
362c6693 2018}
c801d85f 2019
cb43b372
RR
2020//-----------------------------------------------------------------------------
2021// "button_press_event" from scrollbar
2022//-----------------------------------------------------------------------------
2023
2a23d363
RR
2024static gint gtk_scrollbar_button_press_callback( GtkRange *widget,
2025 GdkEventButton *gdk_event,
1e6feb95 2026 wxWindowGTK *win)
cb43b372 2027{
3ac8d3bc
RR
2028 DEBUG_MAIN_THREAD
2029
c50f1fb9 2030 if (g_isIdle)
a2053b27
RR
2031 wxapp_install_idle_handler();
2032
d6d26e04 2033
5b8a521e 2034 g_blockEventsOnScroll = TRUE;
2a23d363 2035 win->m_isScrolling = (gdk_event->window == widget->slider);
47d67540 2036
e380f72b 2037 return FALSE;
cb43b372
RR
2038}
2039
2040//-----------------------------------------------------------------------------
2041// "button_release_event" from scrollbar
2042//-----------------------------------------------------------------------------
2043
88413fec 2044static gint gtk_scrollbar_button_release_callback( GtkRange *widget,
8bbe427f 2045 GdkEventButton *WXUNUSED(gdk_event),
1e6feb95 2046 wxWindowGTK *win)
cb43b372 2047{
3ac8d3bc
RR
2048 DEBUG_MAIN_THREAD
2049
1ecc4d80 2050// don't test here as we can release the mouse while being over
5e014a0c 2051// a different window than the slider
76ed8f8d
RR
2052//
2053// if (gdk_event->window != widget->slider) return FALSE;
cb43b372 2054
5b8a521e 2055 g_blockEventsOnScroll = FALSE;
47d67540 2056
2a23d363 2057 if (win->m_isScrolling)
88413fec 2058 {
d6d26e04 2059 wxEventType command = wxEVT_SCROLLWIN_THUMBRELEASE;
2a23d363
RR
2060 int value = -1;
2061 int dir = -1;
2daa0ce9 2062
2a23d363
RR
2063 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
2064 if (widget == GTK_RANGE(scrolledWindow->hscrollbar))
2065 {
2066 value = (int)(win->m_hAdjust->value+0.5);
2067 dir = wxHORIZONTAL;
2068 }
2069 if (widget == GTK_RANGE(scrolledWindow->vscrollbar))
2070 {
2071 value = (int)(win->m_vAdjust->value+0.5);
2072 dir = wxVERTICAL;
2073 }
2daa0ce9 2074
2a23d363 2075 wxScrollWinEvent event( command, value, dir );
2a23d363
RR
2076 event.SetEventObject( win );
2077 win->GetEventHandler()->ProcessEvent( event );
88413fec
RR
2078 }
2079
2a23d363 2080 win->m_isScrolling = FALSE;
2daa0ce9 2081
e380f72b 2082 return FALSE;
cb43b372
RR
2083}
2084
f03fc89f
VZ
2085// ----------------------------------------------------------------------------
2086// this wxWindowBase function is implemented here (in platform-specific file)
2087// because it is static and so couldn't be made virtual
2088// ----------------------------------------------------------------------------
2b07d713 2089
f03fc89f 2090wxWindow *wxWindowBase::FindFocus()
2b07d713 2091{
1e6feb95
VZ
2092 // the cast is necessary when we compile in wxUniversal mode
2093 return (wxWindow *)g_focusWindow;
2b07d713 2094}
ca298c88 2095
a2053b27
RR
2096//-----------------------------------------------------------------------------
2097// "realize" from m_widget
2098//-----------------------------------------------------------------------------
2099
b79395c5
RR
2100/* We cannot set colours and fonts before the widget has
2101 been realized, so we do this directly after realization. */
a2053b27
RR
2102
2103static gint
63081513 2104gtk_window_realized_callback( GtkWidget *WXUNUSED(m_widget), wxWindow *win )
a2053b27 2105{
3ac8d3bc
RR
2106 DEBUG_MAIN_THREAD
2107
c50f1fb9 2108 if (g_isIdle)
a2053b27
RR
2109 wxapp_install_idle_handler();
2110
739730ca
RR
2111 if (win->m_delayedBackgroundColour)
2112 win->SetBackgroundColour( win->GetBackgroundColour() );
a2053b27 2113
739730ca
RR
2114 if (win->m_delayedForegroundColour)
2115 win->SetForegroundColour( win->GetForegroundColour() );
a2053b27 2116
3c679789
RR
2117 wxWindowCreateEvent event( win );
2118 event.SetEventObject( win );
2119 win->GetEventHandler()->ProcessEvent( event );
1e6feb95 2120
a2053b27
RR
2121 return FALSE;
2122}
2123
b79395c5
RR
2124//-----------------------------------------------------------------------------
2125// "size_allocate"
2126//-----------------------------------------------------------------------------
2127
8f75cb6c 2128static
adc1999b
RR
2129void gtk_window_size_callback( GtkWidget *WXUNUSED(widget),
2130 GtkAllocation *WXUNUSED(alloc),
8f75cb6c
RR
2131 wxWindow *win )
2132{
2133 if (g_isIdle)
2134 wxapp_install_idle_handler();
2daa0ce9 2135
5b8a521e 2136 if (!win->m_hasScrolling) return;
2daa0ce9 2137
5b8a521e
RR
2138 int client_width = 0;
2139 int client_height = 0;
2140 win->GetClientSize( &client_width, &client_height );
2141 if ((client_width == win->m_oldClientWidth) && (client_height == win->m_oldClientHeight))
2142 return;
2daa0ce9 2143
5b8a521e
RR
2144 win->m_oldClientWidth = client_width;
2145 win->m_oldClientHeight = client_height;
2daa0ce9 2146
5b8a521e
RR
2147 if (!win->m_nativeSizeEvent)
2148 {
2149 wxSizeEvent event( win->GetSize(), win->GetId() );
2150 event.SetEventObject( win );
2151 win->GetEventHandler()->ProcessEvent( event );
2152 }
8f75cb6c
RR
2153}
2154
2155
3ed2e7ce
VZ
2156#ifdef HAVE_XIM
2157 #define WXUNUSED_UNLESS_XIM(param) param
2158#else
2159 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2160#endif
2161
b79395c5
RR
2162/* Resize XIM window */
2163
3ed2e7ce 2164static
8f75cb6c
RR
2165void gtk_wxwindow_size_callback( GtkWidget* WXUNUSED_UNLESS_XIM(widget),
2166 GtkAllocation* WXUNUSED_UNLESS_XIM(alloc),
1e6feb95 2167 wxWindowGTK* WXUNUSED_UNLESS_XIM(win) )
b79395c5
RR
2168{
2169 if (g_isIdle)
2170 wxapp_install_idle_handler();
2daa0ce9 2171
9a8c7620 2172#ifdef HAVE_XIM
b79395c5
RR
2173 if (!win->m_ic)
2174 return;
2175
b79395c5
RR
2176 if (gdk_ic_get_style (win->m_ic) & GDK_IM_PREEDIT_POSITION)
2177 {
2178 gint width, height;
2179
3ed2e7ce 2180 gdk_window_get_size (widget->window, &width, &height);
b79395c5
RR
2181 win->m_icattr->preedit_area.width = width;
2182 win->m_icattr->preedit_area.height = height;
2183 gdk_ic_set_attr (win->m_ic, win->m_icattr, GDK_IC_PREEDIT_AREA);
2184 }
9a8c7620 2185#endif // HAVE_XIM
b79395c5
RR
2186}
2187
63081513
RR
2188//-----------------------------------------------------------------------------
2189// "realize" from m_wxwindow
2190//-----------------------------------------------------------------------------
2191
2192/* Initialize XIM support */
2193
2194static gint
3ed2e7ce 2195gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget),
1e6feb95 2196 wxWindowGTK * WXUNUSED_UNLESS_XIM(win) )
63081513
RR
2197{
2198 if (g_isIdle)
2199 wxapp_install_idle_handler();
2200
d06800f1 2201#ifdef HAVE_XIM
63081513
RR
2202 if (win->m_ic) return FALSE;
2203 if (!widget) return FALSE;
2204 if (!gdk_im_ready()) return FALSE;
2205
2206 win->m_icattr = gdk_ic_attr_new();
2207 if (!win->m_icattr) return FALSE;
2daa0ce9 2208
63081513
RR
2209 gint width, height;
2210 GdkEventMask mask;
2211 GdkColormap *colormap;
2212 GdkICAttr *attr = win->m_icattr;
b58b1dfc 2213 unsigned attrmask = GDK_IC_ALL_REQ;
63081513 2214 GdkIMStyle style;
b79395c5
RR
2215 GdkIMStyle supported_style = (GdkIMStyle)
2216 (GDK_IM_PREEDIT_NONE |
1e6feb95
VZ
2217 GDK_IM_PREEDIT_NOTHING |
2218 GDK_IM_PREEDIT_POSITION |
2219 GDK_IM_STATUS_NONE |
2220 GDK_IM_STATUS_NOTHING);
63081513
RR
2221
2222 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
1e6feb95 2223 supported_style = (GdkIMStyle)(supported_style & ~GDK_IM_PREEDIT_POSITION);
63081513
RR
2224
2225 attr->style = style = gdk_im_decide_style (supported_style);
2226 attr->client_window = widget->window;
2227
2228 if ((colormap = gtk_widget_get_colormap (widget)) !=
1e6feb95 2229 gtk_widget_get_default_colormap ())
63081513 2230 {
5cd09f0b
RR
2231 attrmask |= GDK_IC_PREEDIT_COLORMAP;
2232 attr->preedit_colormap = colormap;
63081513 2233 }
2daa0ce9 2234
63081513
RR
2235 attrmask |= GDK_IC_PREEDIT_FOREGROUND;
2236 attrmask |= GDK_IC_PREEDIT_BACKGROUND;
2237 attr->preedit_foreground = widget->style->fg[GTK_STATE_NORMAL];
2238 attr->preedit_background = widget->style->base[GTK_STATE_NORMAL];
2239
2240 switch (style & GDK_IM_PREEDIT_MASK)
2241 {
1e6feb95
VZ
2242 case GDK_IM_PREEDIT_POSITION:
2243 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
2244 {
2245 g_warning ("over-the-spot style requires fontset");
2246 break;
2247 }
63081513 2248
1e6feb95 2249 gdk_window_get_size (widget->window, &width, &height);
63081513 2250
1e6feb95
VZ
2251 attrmask |= GDK_IC_PREEDIT_POSITION_REQ;
2252 attr->spot_location.x = 0;
2253 attr->spot_location.y = height;
2254 attr->preedit_area.x = 0;
2255 attr->preedit_area.y = 0;
2256 attr->preedit_area.width = width;
2257 attr->preedit_area.height = height;
2258 attr->preedit_fontset = widget->style->font;
63081513 2259
1e6feb95 2260 break;
b79395c5 2261 }
2daa0ce9 2262
b58b1dfc 2263 win->m_ic = gdk_ic_new (attr, (GdkICAttributesType)attrmask);
2daa0ce9 2264
63081513 2265 if (win->m_ic == NULL)
1e6feb95 2266 g_warning ("Can't create input context.");
63081513 2267 else
1e6feb95
VZ
2268 {
2269 mask = gdk_window_get_events (widget->window);
2270 mask = (GdkEventMask)(mask | gdk_ic_get_events (win->m_ic));
2271 gdk_window_set_events (widget->window, mask);
2272
2273 if (GTK_WIDGET_HAS_FOCUS(widget))
2274 gdk_im_begin (win->m_ic, widget->window);
2275 }
2276#endif // HAVE_XIM
63081513
RR
2277
2278 return FALSE;
2279}
2280
6ca41e57 2281//-----------------------------------------------------------------------------
1e6feb95 2282// InsertChild for wxWindowGTK.
6ca41e57
RR
2283//-----------------------------------------------------------------------------
2284
1e6feb95 2285/* Callback for wxWindowGTK. This very strange beast has to be used because
b1170810
RR
2286 * C++ has no virtual methods in a constructor. We have to emulate a
2287 * virtual function here as wxNotebook requires a different way to insert
2288 * a child in it. I had opted for creating a wxNotebookPage window class
2289 * which would have made this superfluous (such in the MDI window system),
2290 * but no-one was listening to me... */
6ca41e57 2291
1e6feb95 2292static void wxInsertChildInWindow( wxWindowGTK* parent, wxWindowGTK* child )
6ca41e57 2293{
bf0c00c6
RR
2294 /* the window might have been scrolled already, do we
2295 have to adapt the position */
da048e3d
RR
2296 GtkPizza *pizza = GTK_PIZZA(parent->m_wxwindow);
2297 child->m_x += pizza->xoffset;
2298 child->m_y += pizza->yoffset;
148cd9b6 2299
da048e3d 2300 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
a2053b27
RR
2301 GTK_WIDGET(child->m_widget),
2302 child->m_x,
2303 child->m_y,
2304 child->m_width,
2305 child->m_height );
6ca41e57
RR
2306}
2307
bbe0af5b
RR
2308//-----------------------------------------------------------------------------
2309// global functions
2310//-----------------------------------------------------------------------------
2311
1e6feb95 2312wxWindow *wxGetActiveWindow()
bbe0af5b 2313{
1e6feb95
VZ
2314 // the cast is necessary when we compile in wxUniversal mode
2315 return (wxWindow *)g_focusWindow;
bbe0af5b
RR
2316}
2317
c801d85f 2318//-----------------------------------------------------------------------------
1e6feb95 2319// wxWindowGTK
c801d85f
KB
2320//-----------------------------------------------------------------------------
2321
6522713c
VZ
2322// in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2323// method
1e6feb95 2324#ifdef __WXUNIVERSAL__
6522713c
VZ
2325 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK, wxWindowBase)
2326#else // __WXGTK__
1e6feb95 2327 IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
6522713c 2328#endif // __WXUNIVERSAL__/__WXGTK__
c801d85f 2329
1e6feb95 2330void wxWindowGTK::Init()
c801d85f 2331{
f03fc89f
VZ
2332 // common init
2333 InitBase();
68995f26 2334
f03fc89f 2335 // GTK specific
a2053b27 2336 m_widget = (GtkWidget *) NULL;
e380f72b 2337 m_wxwindow = (GtkWidget *) NULL;
76fcf0f2 2338 m_focusWidget = (GtkWidget *) NULL;
8bbe427f 2339
f03fc89f 2340 // position/size
a2053b27
RR
2341 m_x = 0;
2342 m_y = 0;
2343 m_width = 0;
e380f72b 2344 m_height = 0;
8bbe427f 2345
e380f72b
RR
2346 m_sizeSet = FALSE;
2347 m_hasVMT = FALSE;
2348 m_needParent = TRUE;
31c6b4fc 2349 m_isBeingDeleted = FALSE;
148cd9b6 2350
147bc491 2351 m_noExpose = FALSE;
30760ce7 2352 m_nativeSizeEvent = FALSE;
76fcf0f2 2353
a2053b27 2354 m_hasScrolling = FALSE;
846e1424 2355 m_isScrolling = FALSE;
f03fc89f 2356
a2053b27 2357 m_hAdjust = (GtkAdjustment*) NULL;
e380f72b 2358 m_vAdjust = (GtkAdjustment*) NULL;
a2053b27 2359 m_oldHorizontalPos = 0.0;
e380f72b 2360 m_oldVerticalPos = 0.0;
8bbe427f 2361
e380f72b 2362 m_resizing = FALSE;
e380f72b 2363 m_widgetStyle = (GtkStyle*) NULL;
8bbe427f 2364
ddb6bc71 2365 m_insertCallback = (wxInsertChildFunction) NULL;
8bbe427f 2366
1ecc4d80 2367 m_isStaticBox = FALSE;
953704c1 2368 m_isRadioButton = FALSE;
54517652 2369 m_isFrame = FALSE;
b292e2f5 2370 m_acceptsFocus = FALSE;
148cd9b6 2371
b6fa52db 2372 m_clipPaintRegion = FALSE;
b6fa52db 2373
5e014a0c 2374 m_cursor = *wxSTANDARD_CURSOR;
2daa0ce9 2375
f6bcfd97
BP
2376 m_delayedForegroundColour = FALSE;
2377 m_delayedBackgroundColour = FALSE;
1e6feb95 2378
63081513
RR
2379#ifdef HAVE_XIM
2380 m_ic = (GdkIC*) NULL;
2381 m_icattr = (GdkICAttr*) NULL;
2382#endif
362c6693 2383}
c801d85f 2384
1e6feb95 2385wxWindowGTK::wxWindowGTK()
68995f26
VZ
2386{
2387 Init();
2388}
2389
1e6feb95
VZ
2390wxWindowGTK::wxWindowGTK( wxWindow *parent,
2391 wxWindowID id,
2392 const wxPoint &pos,
2393 const wxSize &size,
2394 long style,
2395 const wxString &name )
6ca41e57 2396{
68995f26
VZ
2397 Init();
2398
e380f72b 2399 Create( parent, id, pos, size, style, name );
6ca41e57 2400}
8bbe427f 2401
1e6feb95
VZ
2402bool wxWindowGTK::Create( wxWindow *parent,
2403 wxWindowID id,
2404 const wxPoint &pos,
2405 const wxSize &size,
2406 long style,
2407 const wxString &name )
c801d85f 2408{
4dcaf11a
RR
2409 if (!PreCreation( parent, pos, size ) ||
2410 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
2411 {
1e6feb95 2412 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
b02da6b1 2413 return FALSE;
4dcaf11a 2414 }
47d67540 2415
ddb6bc71 2416 m_insertCallback = wxInsertChildInWindow;
1e6feb95 2417
e380f72b 2418 m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
38c7b3d3 2419 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
ff8bfdbb 2420
f03fc89f 2421 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
47d67540 2422
dd00f3f6 2423 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
e380f72b 2424 scroll_class->scrollbar_spacing = 0;
47d67540 2425
f03fc89f 2426 gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
47d67540 2427
f03fc89f
VZ
2428 m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->hscrollbar) );
2429 m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->vscrollbar) );
47d67540 2430
da048e3d 2431 m_wxwindow = gtk_pizza_new();
38c7b3d3 2432
034be888 2433 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
58dea4b0 2434
1e6feb95 2435#ifndef __WXUNIVERSAL__
034be888 2436#if (GTK_MINOR_VERSION > 0)
da048e3d 2437 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
b292e2f5 2438
f03fc89f 2439 if (HasFlag(wxRAISED_BORDER))
034be888 2440 {
da048e3d 2441 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_OUT );
034be888 2442 }
f03fc89f 2443 else if (HasFlag(wxSUNKEN_BORDER))
034be888 2444 {
da048e3d 2445 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_IN );
5e014a0c
RR
2446 }
2447 else if (HasFlag(wxSIMPLE_BORDER))
2448 {
da048e3d 2449 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_THIN );
034be888
RR
2450 }
2451 else
2452 {
da048e3d 2453 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_NONE );
034be888 2454 }
f03fc89f
VZ
2455#else // GTK_MINOR_VERSION == 0
2456 GtkViewport *viewport = GTK_VIEWPORT(scrolledWindow->viewport);
b292e2f5 2457
f03fc89f 2458 if (HasFlag(wxRAISED_BORDER))
e380f72b
RR
2459 {
2460 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_OUT );
2461 }
f03fc89f 2462 else if (HasFlag(wxSUNKEN_BORDER))
e380f72b
RR
2463 {
2464 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_IN );
2465 }
2466 else
2467 {
2468 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_NONE );
2469 }
f03fc89f 2470#endif // GTK_MINOR_VERSION
1e6feb95 2471#endif // __WXUNIVERSAL__
47d67540 2472
3da17724
RR
2473 GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
2474 m_acceptsFocus = TRUE;
ca298c88 2475
034be888 2476#if (GTK_MINOR_VERSION == 0)
e380f72b
RR
2477 // shut the viewport up
2478 gtk_viewport_set_hadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
2479 gtk_viewport_set_vadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
f03fc89f 2480#endif // GTK_MINOR_VERSION == 0
e380f72b
RR
2481
2482 // I _really_ don't want scrollbars in the beginning
a2053b27
RR
2483 m_vAdjust->lower = 0.0;
2484 m_vAdjust->upper = 1.0;
2485 m_vAdjust->value = 0.0;
2486 m_vAdjust->step_increment = 1.0;
2487 m_vAdjust->page_increment = 1.0;
2488 m_vAdjust->page_size = 5.0;
2489 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
2490 m_hAdjust->lower = 0.0;
2491 m_hAdjust->upper = 1.0;
2492 m_hAdjust->value = 0.0;
2493 m_hAdjust->step_increment = 1.0;
2494 m_hAdjust->page_increment = 1.0;
2495 m_hAdjust->page_size = 5.0;
2496 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
f03fc89f
VZ
2497
2498 // these handlers block mouse events to any window during scrolling such as
2499 // motion events and prevent GTK and wxWindows from fighting over where the
2500 // slider should be
2501
2502 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_press_event",
76ed8f8d
RR
2503 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2504
f03fc89f 2505 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_press_event",
76ed8f8d
RR
2506 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2507
f03fc89f 2508 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_release_event",
76ed8f8d
RR
2509 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2510
f03fc89f 2511 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_release_event",
76ed8f8d 2512 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
8bbe427f 2513
034be888 2514 // these handlers get notified when screen updates are required either when
76ed8f8d
RR
2515 // scrolling or when the window size (and therefore scrollbar configuration)
2516 // has changed
2517
2518 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
2519 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
2520 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
2521 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
2522
f03fc89f 2523 gtk_widget_show( m_wxwindow );
47d67540 2524
f03fc89f
VZ
2525 if (m_parent)
2526 m_parent->DoAddChild( this );
76fcf0f2
RR
2527
2528 m_focusWidget = m_wxwindow;
8bbe427f 2529
e380f72b 2530 PostCreation();
8bbe427f 2531
e380f72b 2532 Show( TRUE );
c801d85f 2533
e380f72b 2534 return TRUE;
362c6693 2535}
c801d85f 2536
1e6feb95 2537wxWindowGTK::~wxWindowGTK()
c801d85f 2538{
44cd54c2
JS
2539 if (g_focusWindow == this)
2540 g_focusWindow = NULL;
2541
e8c12a53
VS
2542 if (g_activeFrame == this)
2543 g_activeFrame = NULL;
2544
31c6b4fc 2545 m_isBeingDeleted = TRUE;
43a18898 2546 m_hasVMT = FALSE;
47d67540 2547
f03fc89f
VZ
2548 if (m_widget)
2549 Show( FALSE );
8bbe427f 2550
a2053b27
RR
2551 DestroyChildren();
2552
f03fc89f
VZ
2553 if (m_parent)
2554 m_parent->RemoveChild( this );
c801d85f 2555
63081513
RR
2556#ifdef HAVE_XIM
2557 if (m_ic)
2558 gdk_ic_destroy (m_ic);
2559 if (m_icattr)
2560 gdk_ic_attr_destroy (m_icattr);
2561#endif
2562
f03fc89f 2563 if (m_widgetStyle)
a2053b27 2564 {
a56fcaaf 2565#if DISABLE_STYLE_IF_BROKEN_THEME
bce1406b
RR
2566 // don't delete if it's a pixmap theme style
2567 if (!m_widgetStyle->engine_data)
2568 gtk_style_unref( m_widgetStyle );
1e6feb95 2569#endif
c50f1fb9 2570 m_widgetStyle = (GtkStyle*) NULL;
a2053b27 2571 }
c801d85f 2572
f03fc89f 2573 if (m_wxwindow)
a2053b27 2574 {
f03fc89f 2575 gtk_widget_destroy( m_wxwindow );
c50f1fb9 2576 m_wxwindow = (GtkWidget*) NULL;
a2053b27 2577 }
8bbe427f 2578
f03fc89f 2579 if (m_widget)
a2053b27 2580 {
f03fc89f 2581 gtk_widget_destroy( m_widget );
c50f1fb9 2582 m_widget = (GtkWidget*) NULL;
a2053b27 2583 }
362c6693 2584}
c801d85f 2585
1e6feb95 2586bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos, const wxSize &size )
c801d85f 2587{
223d09f6 2588 wxCHECK_MSG( !m_needParent || parent, FALSE, wxT("Need complete parent.") );
8bbe427f 2589
4dcaf11a
RR
2590 /* this turns -1 into 20 so that a minimal window is
2591 visible even although -1,-1 has been given as the
2592 size of the window. the same trick is used in other
2593 ports and should make debugging easier */
f03fc89f
VZ
2594 m_width = WidthDefault(size.x);
2595 m_height = HeightDefault(size.y);
8bbe427f 2596
43a18898
RR
2597 m_x = (int)pos.x;
2598 m_y = (int)pos.y;
8bbe427f 2599
4dcaf11a 2600 /* some reasonable defaults */
148cd9b6 2601 if (!parent)
6ca41e57 2602 {
43a18898
RR
2603 if (m_x == -1)
2604 {
2605 m_x = (gdk_screen_width () - m_width) / 2;
2606 if (m_x < 10) m_x = 10;
2607 }
2608 if (m_y == -1)
2609 {
2610 m_y = (gdk_screen_height () - m_height) / 2;
2611 if (m_y < 10) m_y = 10;
2612 }
6ca41e57 2613 }
148cd9b6 2614
4dcaf11a 2615 return TRUE;
c801d85f
KB
2616}
2617
1e6feb95 2618void wxWindowGTK::PostCreation()
c801d85f 2619{
223d09f6 2620 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
76fcf0f2 2621
43a18898
RR
2622 if (m_wxwindow)
2623 {
147bc491 2624 if (!m_noExpose)
b02da6b1 2625 {
76fcf0f2 2626 // these get reported to wxWindows -> wxPaintEvent
1e6feb95 2627
b420fb6a
RR
2628 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow), TRUE );
2629
147bc491
RR
2630 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
2631 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
2632
2633 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
2634 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
e22454be
RR
2635
2636 if (HasFlag(wxNO_FULL_REPAINT_ON_RESIZE))
2637 {
2638 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "event",
2639 GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this );
2640 }
b02da6b1 2641 }
148cd9b6 2642
76fcf0f2 2643 // these are called when the "sunken" or "raised" borders are drawn */
034be888
RR
2644 gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
2645 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
2646
2647 gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
2648 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
43a18898 2649 }
47d67540 2650
76fcf0f2 2651 // focus handling
63081513 2652
76fcf0f2
RR
2653 if (m_focusWidget == NULL)
2654 m_focusWidget = m_widget;
2daa0ce9 2655
76fcf0f2
RR
2656#if 0
2657 if (GetClassInfo() && GetClassInfo()->GetClassName())
2658 wxPrintf( GetClassInfo()->GetClassName() );
2659 wxPrintf( ".\n" );
2660#endif
63081513 2661
76fcf0f2
RR
2662 gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_in_event",
2663 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
2664
2665 gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_out_event",
2666 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
2667
2668 // connect to the various key and mouse handlers
63081513 2669
a2053b27 2670 GtkWidget *connect_widget = GetConnectWidget();
f03fc89f 2671
a2053b27 2672 ConnectWidget( connect_widget );
47d67540 2673
63081513 2674 /* We cannot set colours, fonts and cursors before the widget has
a2053b27
RR
2675 been realized, so we do this directly after realization */
2676 gtk_signal_connect( GTK_OBJECT(connect_widget), "realize",
c50f1fb9 2677 GTK_SIGNAL_FUNC(gtk_window_realized_callback), (gpointer) this );
2daa0ce9 2678
63081513
RR
2679 if (m_wxwindow)
2680 {
47c93b63 2681 // Catch native resize events
8f75cb6c
RR
2682 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2683 GTK_SIGNAL_FUNC(gtk_window_size_callback), (gpointer)this );
2daa0ce9 2684
47c93b63 2685 // Initialize XIM support
63081513
RR
2686 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "realize",
2687 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback), (gpointer) this );
8f75cb6c 2688
47c93b63 2689 // And resize XIM window
b79395c5
RR
2690 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2691 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this );
63081513 2692 }
2daa0ce9 2693
47c93b63
RR
2694 if (!GTK_IS_COMBO(m_widget))
2695 {
2696 // This is needed if we want to add our windows into native
2697 // GTK control, such as the toolbar. With this callback, the
2698 // toolbar gets to know the correct size (the one set by the
2699 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2700 // when moving to GTK 2.0.
2701 gtk_signal_connect( GTK_OBJECT(m_widget), "size_request",
2702 GTK_SIGNAL_FUNC(gtk_window_size_request_callback), (gpointer) this );
2703 }
1e6feb95 2704
43a18898 2705 m_hasVMT = TRUE;
b4071e91
RR
2706}
2707
1e6feb95 2708void wxWindowGTK::ConnectWidget( GtkWidget *widget )
b4071e91 2709{
43a18898
RR
2710 gtk_signal_connect( GTK_OBJECT(widget), "key_press_event",
2711 GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this );
c801d85f 2712
b666df2c
RR
2713 gtk_signal_connect( GTK_OBJECT(widget), "key_release_event",
2714 GTK_SIGNAL_FUNC(gtk_window_key_release_callback), (gpointer)this );
2715
43a18898
RR
2716 gtk_signal_connect( GTK_OBJECT(widget), "button_press_event",
2717 GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
47d67540 2718
43a18898
RR
2719 gtk_signal_connect( GTK_OBJECT(widget), "button_release_event",
2720 GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
47d67540 2721
43a18898
RR
2722 gtk_signal_connect( GTK_OBJECT(widget), "motion_notify_event",
2723 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
47d67540 2724
43a18898
RR
2725 gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event",
2726 GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
47d67540 2727
43a18898
RR
2728 gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
2729 GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
362c6693 2730}
c801d85f 2731
1e6feb95 2732bool wxWindowGTK::Destroy()
c801d85f 2733{
223d09f6 2734 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
47d67540 2735
43a18898 2736 m_hasVMT = FALSE;
c801d85f 2737
f03fc89f 2738 return wxWindowBase::Destroy();
362c6693 2739}
c801d85f 2740
1e6feb95 2741void wxWindowGTK::DoMoveWindow(int x, int y, int width, int height)
23efdd02
RR
2742{
2743 gtk_pizza_set_size( GTK_PIZZA(m_parent->m_wxwindow), m_widget, x, y, width, height );
2744}
2daa0ce9 2745
1e6feb95 2746void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
c801d85f 2747{
223d09f6 2748 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
1e6feb95 2749 wxASSERT_MSG( (m_parent != NULL), wxT("wxWindowGTK::SetSize requires parent.\n") );
8bbe427f 2750
33611ebb 2751/*
f94fca1b 2752 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
33611ebb
RR
2753*/
2754
e27ce4e9 2755 if (m_resizing) return; /* I don't like recursions */
fb1585ae 2756 m_resizing = TRUE;
1e6feb95 2757
b9f29261
VS
2758 int currentX, currentY;
2759 GetPosition(&currentX, &currentY);
2760 if (x == -1)
2761 x = currentX;
a200c35e 2762 if (y == -1)
b9f29261 2763 y = currentY;
a200c35e
VS
2764 AdjustForParentClientOrigin(x, y, sizeFlags);
2765
a2053b27 2766 if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
fb1585ae 2767 {
e27ce4e9 2768 /* don't set the size for children of wxNotebook, just take the values. */
fb1585ae
RR
2769 m_x = x;
2770 m_y = y;
2771 m_width = width;
ba4e3652 2772 m_height = height;
fb1585ae 2773 }
ba4e3652 2774 else
fb1585ae 2775 {
da048e3d 2776 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
148cd9b6 2777
85ad5eb5 2778 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
ba4e3652 2779 {
da048e3d
RR
2780 if (x != -1) m_x = x + pizza->xoffset;
2781 if (y != -1) m_y = y + pizza->yoffset;
ba4e3652
RR
2782 if (width != -1) m_width = width;
2783 if (height != -1) m_height = height;
2784 }
2785 else
2786 {
da048e3d
RR
2787 m_x = x + pizza->xoffset;
2788 m_y = y + pizza->yoffset;
ba4e3652
RR
2789 m_width = width;
2790 m_height = height;
2791 }
47d67540 2792
ba4e3652
RR
2793 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
2794 {
2795 if (width == -1) m_width = 80;
2796 }
2797
2798 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
2799 {
2800 if (height == -1) m_height = 26;
2801 }
8bbe427f 2802
ba4e3652
RR
2803 if ((m_minWidth != -1) && (m_width < m_minWidth)) m_width = m_minWidth;
2804 if ((m_minHeight != -1) && (m_height < m_minHeight)) m_height = m_minHeight;
d3b4d113
RR
2805 if ((m_maxWidth != -1) && (m_width > m_maxWidth)) m_width = m_maxWidth;
2806 if ((m_maxHeight != -1) && (m_height > m_maxHeight)) m_height = m_maxHeight;
47d67540 2807
a2053b27 2808 int border = 0;
c50f1fb9 2809 int bottom_border = 0;
f03fc89f 2810
29f538ce 2811 if (GTK_WIDGET_CAN_DEFAULT(m_widget))
c50f1fb9
VZ
2812 {
2813 /* the default button has a border around it */
2814 border = 6;
2815 bottom_border = 5;
2816 }
2817
23efdd02
RR
2818 DoMoveWindow( m_x-border,
2819 m_y-border,
2820 m_width+2*border,
2821 m_height+border+bottom_border );
54517652 2822 }
148cd9b6 2823
5b8a521e
RR
2824 if (m_hasScrolling)
2825 {
1e6feb95 2826 /* Sometimes the client area changes size without the
b6fa52db
RR
2827 whole windows's size changing, but if the whole
2828 windows's size doesn't change, no wxSizeEvent will
2829 normally be sent. Here we add an extra test if
2830 the client test has been changed and this will
2831 be used then. */
5b8a521e
RR
2832 GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
2833 }
2834
54517652 2835/*
6d693bb4
RR
2836 wxPrintf( "OnSize sent from " );
2837 if (GetClassInfo() && GetClassInfo()->GetClassName())
2838 wxPrintf( GetClassInfo()->GetClassName() );
2839 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2840*/
2841
30760ce7
RR
2842 if (!m_nativeSizeEvent)
2843 {
2844 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
2845 event.SetEventObject( this );
2846 GetEventHandler()->ProcessEvent( event );
2847 }
6d693bb4 2848
fb1585ae 2849 m_resizing = FALSE;
362c6693 2850}
c801d85f 2851
1e6feb95 2852void wxWindowGTK::OnInternalIdle()
9390a202 2853{
148cd9b6
VZ
2854 if ( g_sendActivateEvent != -1 )
2855 {
2856 bool activate = g_sendActivateEvent != 0;
2857
2858 // do it only once
2859 g_sendActivateEvent = -1;
2860
1e6feb95 2861 wxTheApp->SetActive(activate, (wxWindow *)g_focusWindowLast);
148cd9b6
VZ
2862 }
2863
e8c12a53
VS
2864 if ( g_activeFrameLostFocus )
2865 {
2866 if ( g_activeFrame )
2867 {
45eb5249 2868 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame);
e8c12a53
VS
2869 wxActivateEvent event(wxEVT_ACTIVATE, FALSE, g_activeFrame->GetId());
2870 event.SetEventObject(g_activeFrame);
2871 g_activeFrame->GetEventHandler()->ProcessEvent(event);
2872 g_activeFrame = NULL;
2873 }
2874 g_activeFrameLostFocus = FALSE;
2875 }
2876
9146082c
RR
2877 wxCursor cursor = m_cursor;
2878 if (g_globalCursor.Ok()) cursor = g_globalCursor;
c50f1fb9 2879
f7a11f8c 2880 if (cursor.Ok())
9146082c 2881 {
3017f78d 2882 /* I now set the cursor anew in every OnInternalIdle call
b02da6b1
VZ
2883 as setting the cursor in a parent window also effects the
2884 windows above so that checking for the current cursor is
2885 not possible. */
148cd9b6 2886
9146082c 2887 if (m_wxwindow)
6a008b33 2888 {
da048e3d 2889 GdkWindow *window = GTK_PIZZA(m_wxwindow)->bin_window;
6a008b33 2890 if (window)
c50f1fb9 2891 gdk_window_set_cursor( window, cursor.GetCursor() );
6a008b33
VZ
2892
2893 if (!g_globalCursor.Ok())
2894 cursor = *wxSTANDARD_CURSOR;
2895
2896 window = m_widget->window;
5e014a0c 2897 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
9146082c 2898 gdk_window_set_cursor( window, cursor.GetCursor() );
5e014a0c 2899
6a008b33
VZ
2900 }
2901 else
2902 {
5e014a0c 2903
9146082c 2904 GdkWindow *window = m_widget->window;
5e014a0c 2905 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
9146082c 2906 gdk_window_set_cursor( window, cursor.GetCursor() );
5e014a0c 2907
6a008b33 2908 }
9146082c 2909 }
6a008b33 2910
9390a202
RR
2911 UpdateWindowUI();
2912}
2913
1e6feb95 2914void wxWindowGTK::DoGetSize( int *width, int *height ) const
c801d85f 2915{
223d09f6 2916 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 2917
fb1585ae
RR
2918 if (width) (*width) = m_width;
2919 if (height) (*height) = m_height;
362c6693 2920}
c801d85f 2921
1e6feb95 2922void wxWindowGTK::DoSetClientSize( int width, int height )
c801d85f 2923{
223d09f6 2924 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 2925
1ecc4d80 2926 if (!m_wxwindow)
c801d85f 2927 {
1ecc4d80 2928 SetSize( width, height );
c801d85f
KB
2929 }
2930 else
2931 {
1ecc4d80
RR
2932 int dw = 0;
2933 int dh = 0;
2934
1e6feb95 2935#ifndef __WXUNIVERSAL__
98d3fdbe
RR
2936 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
2937 {
5e014a0c 2938 /* when using GTK 1.2 we set the shadow border size to 2 */
6a008b33 2939 dw += 2 * 2;
98d3fdbe
RR
2940 dh += 2 * 2;
2941 }
5e014a0c
RR
2942 if (HasFlag(wxSIMPLE_BORDER))
2943 {
2944 /* when using GTK 1.2 we set the simple border size to 1 */
2945 dw += 1 * 2;
2946 dh += 1 * 2;
2947 }
1e6feb95 2948#endif // __WXUNIVERSAL__
034be888 2949
5b8a521e 2950 if (m_hasScrolling)
98d3fdbe 2951 {
324dbfec 2952 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2daa0ce9 2953
9000c624
RR
2954 GtkRequisition vscroll_req;
2955 vscroll_req.width = 2;
2956 vscroll_req.height = 2;
dd00f3f6 2957 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
9000c624 2958 (scroll_window->vscrollbar, &vscroll_req );
2daa0ce9 2959
9000c624
RR
2960 GtkRequisition hscroll_req;
2961 hscroll_req.width = 2;
2962 hscroll_req.height = 2;
dd00f3f6 2963 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
9000c624
RR
2964 (scroll_window->hscrollbar, &hscroll_req );
2965
dd00f3f6 2966 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
324dbfec 2967
1ecc4d80
RR
2968 if (scroll_window->vscrollbar_visible)
2969 {
9000c624 2970 dw += vscroll_req.width;
1ecc4d80
RR
2971 dw += scroll_class->scrollbar_spacing;
2972 }
2973
2974 if (scroll_window->hscrollbar_visible)
2975 {
9000c624 2976 dh += hscroll_req.height;
63cc5d9d 2977 dh += scroll_class->scrollbar_spacing;
1ecc4d80 2978 }
9000c624 2979 }
1ecc4d80 2980
034be888 2981 SetSize( width+dw, height+dh );
1ecc4d80 2982 }
362c6693 2983}
c801d85f 2984
1e6feb95 2985void wxWindowGTK::DoGetClientSize( int *width, int *height ) const
c801d85f 2986{
223d09f6 2987 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 2988
1ecc4d80
RR
2989 if (!m_wxwindow)
2990 {
2991 if (width) (*width) = m_width;
2992 if (height) (*height) = m_height;
c801d85f
KB
2993 }
2994 else
2995 {
1ecc4d80
RR
2996 int dw = 0;
2997 int dh = 0;
2998
1e6feb95 2999#ifndef __WXUNIVERSAL__
98d3fdbe
RR
3000 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
3001 {
5e014a0c 3002 /* when using GTK 1.2 we set the shadow border size to 2 */
6a008b33 3003 dw += 2 * 2;
98d3fdbe
RR
3004 dh += 2 * 2;
3005 }
5e014a0c
RR
3006 if (HasFlag(wxSIMPLE_BORDER))
3007 {
3008 /* when using GTK 1.2 we set the simple border size to 1 */
3009 dw += 1 * 2;
3010 dh += 1 * 2;
3011 }
1e6feb95 3012#endif // __WXUNIVERSAL__
9000c624 3013
5b8a521e 3014 if (m_hasScrolling)
98d3fdbe 3015 {
6a008b33 3016 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2daa0ce9 3017
9000c624
RR
3018 GtkRequisition vscroll_req;
3019 vscroll_req.width = 2;
3020 vscroll_req.height = 2;
dd00f3f6 3021 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
9000c624 3022 (scroll_window->vscrollbar, &vscroll_req );
2daa0ce9 3023
9000c624
RR
3024 GtkRequisition hscroll_req;
3025 hscroll_req.width = 2;
3026 hscroll_req.height = 2;
dd00f3f6 3027 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
9000c624
RR
3028 (scroll_window->hscrollbar, &hscroll_req );
3029
dd00f3f6 3030 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
6a008b33 3031
1ecc4d80
RR
3032 if (scroll_window->vscrollbar_visible)
3033 {
9000c624 3034 dw += vscroll_req.width;
1ecc4d80
RR
3035 dw += scroll_class->scrollbar_spacing;
3036 }
3037
3038 if (scroll_window->hscrollbar_visible)
3039 {
9000c624 3040 dh += hscroll_req.height;
1ecc4d80
RR
3041 dh += scroll_class->scrollbar_spacing;
3042 }
6a008b33 3043 }
47d67540 3044
1ecc4d80
RR
3045 if (width) (*width) = m_width - dw;
3046 if (height) (*height) = m_height - dh;
3047 }
1e6feb95 3048
f94fca1b
RR
3049/*
3050 printf( "GetClientSize, name %s ", GetName().c_str() );
3051 if (width) printf( " width = %d", (*width) );
3052 if (height) printf( " height = %d", (*height) );
3053 printf( "\n" );
3054*/
362c6693 3055}
c801d85f 3056
1e6feb95 3057void wxWindowGTK::DoGetPosition( int *x, int *y ) const
c801d85f 3058{
223d09f6 3059 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3060
bf0c00c6
RR
3061 int dx = 0;
3062 int dy = 0;
3063 if (m_parent && m_parent->m_wxwindow)
3064 {
da048e3d 3065 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
b02da6b1
VZ
3066 dx = pizza->xoffset;
3067 dy = pizza->yoffset;
bf0c00c6 3068 }
b9f29261 3069
496beb3f
VS
3070 if (x) (*x) = m_x - dx;
3071 if (y) (*y) = m_y - dy;
362c6693 3072}
c801d85f 3073
1e6feb95 3074void wxWindowGTK::DoClientToScreen( int *x, int *y ) const
c801d85f 3075{
223d09f6 3076 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3077
a2053b27
RR
3078 if (!m_widget->window) return;
3079
43a18898
RR
3080 GdkWindow *source = (GdkWindow *) NULL;
3081 if (m_wxwindow)
da048e3d 3082 source = GTK_PIZZA(m_wxwindow)->bin_window;
43a18898
RR
3083 else
3084 source = m_widget->window;
47d67540 3085
43a18898
RR
3086 int org_x = 0;
3087 int org_y = 0;
3088 gdk_window_get_origin( source, &org_x, &org_y );
c801d85f 3089
43a18898 3090 if (!m_wxwindow)
c801d85f 3091 {
43a18898
RR
3092 if (GTK_WIDGET_NO_WINDOW (m_widget))
3093 {
3094 org_x += m_widget->allocation.x;
3095 org_y += m_widget->allocation.y;
3096 }
362c6693 3097 }
47d67540 3098
43a18898
RR
3099 if (x) *x += org_x;
3100 if (y) *y += org_y;
362c6693 3101}
c801d85f 3102
1e6feb95 3103void wxWindowGTK::DoScreenToClient( int *x, int *y ) const
c801d85f 3104{
223d09f6 3105 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3106
a2053b27
RR
3107 if (!m_widget->window) return;
3108
1ecc4d80
RR
3109 GdkWindow *source = (GdkWindow *) NULL;
3110 if (m_wxwindow)
da048e3d 3111 source = GTK_PIZZA(m_wxwindow)->bin_window;
1ecc4d80
RR
3112 else
3113 source = m_widget->window;
47d67540 3114
1ecc4d80
RR
3115 int org_x = 0;
3116 int org_y = 0;
3117 gdk_window_get_origin( source, &org_x, &org_y );
c801d85f 3118
1ecc4d80 3119 if (!m_wxwindow)
c801d85f 3120 {
1ecc4d80
RR
3121 if (GTK_WIDGET_NO_WINDOW (m_widget))
3122 {
3123 org_x += m_widget->allocation.x;
3124 org_y += m_widget->allocation.y;
3125 }
362c6693 3126 }
47d67540 3127
1ecc4d80
RR
3128 if (x) *x -= org_x;
3129 if (y) *y -= org_y;
362c6693 3130}
c801d85f 3131
1e6feb95 3132bool wxWindowGTK::Show( bool show )
c801d85f 3133{
223d09f6 3134 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
47d67540 3135
739730ca
RR
3136 if (!wxWindowBase::Show(show))
3137 {
3138 // nothing to do
f03fc89f 3139 return FALSE;
739730ca 3140 }
8bbe427f 3141
f03fc89f
VZ
3142 if (show)
3143 gtk_widget_show( m_widget );
1ecc4d80 3144 else
f03fc89f 3145 gtk_widget_hide( m_widget );
8bbe427f 3146
f03fc89f 3147 return TRUE;
362c6693 3148}
c801d85f 3149
3379ed37 3150static void wxWindowNotifyEnable(wxWindowGTK* win, bool enable)
fdca68a6
JS
3151{
3152 win->OnParentEnable(enable);
3153
3154 // Recurse, so that children have the opportunity to Do The Right Thing
3155 // and reset colours that have been messed up by a parent's (really ancestor's)
3156 // Enable call
3157 for ( wxWindowList::Node *node = win->GetChildren().GetFirst();
3158 node;
3159 node = node->GetNext() )
3160 {
3161 wxWindow *child = node->GetData();
3162 if (!child->IsKindOf(CLASSINFO(wxDialog)) && !child->IsKindOf(CLASSINFO(wxFrame)))
3163 wxWindowNotifyEnable(child, enable);
3164 }
3165}
3166
3379ed37 3167bool wxWindowGTK::Enable( bool enable )
c801d85f 3168{
223d09f6 3169 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
5e0aa05a 3170
739730ca
RR
3171 if (!wxWindowBase::Enable(enable))
3172 {
3173 // nothing to do
f03fc89f 3174 return FALSE;
739730ca 3175 }
1ecc4d80 3176
f03fc89f
VZ
3177 gtk_widget_set_sensitive( m_widget, enable );
3178 if ( m_wxwindow )
3179 gtk_widget_set_sensitive( m_wxwindow, enable );
ff8bfdbb 3180
fdca68a6 3181 wxWindowNotifyEnable(this, enable);
513903c4 3182
f03fc89f 3183 return TRUE;
362c6693 3184}
c801d85f 3185
1e6feb95 3186int wxWindowGTK::GetCharHeight() const
2f2aa628 3187{
223d09f6 3188 wxCHECK_MSG( (m_widget != NULL), 12, wxT("invalid window") );
47d67540 3189
223d09f6 3190 wxCHECK_MSG( m_font.Ok(), 12, wxT("invalid font") );
2f2aa628 3191
f03fc89f
VZ
3192 GdkFont *font = m_font.GetInternalFont( 1.0 );
3193
3194 return font->ascent + font->descent;
362c6693 3195}
c801d85f 3196
1e6feb95 3197int wxWindowGTK::GetCharWidth() const
c33c4050 3198{
223d09f6 3199 wxCHECK_MSG( (m_widget != NULL), 8, wxT("invalid window") );
47d67540 3200
223d09f6 3201 wxCHECK_MSG( m_font.Ok(), 8, wxT("invalid font") );
47d67540 3202
463c1fa1 3203 GdkFont *font = m_font.GetInternalFont( 1.0 );
ff8bfdbb 3204
463c1fa1 3205 return gdk_string_width( font, "H" );
c33c4050
RR
3206}
3207
1e6feb95 3208void wxWindowGTK::GetTextExtent( const wxString& string,
f03fc89f
VZ
3209 int *x,
3210 int *y,
3211 int *descent,
3212 int *externalLeading,
3213 const wxFont *theFont ) const
c33c4050 3214{
463c1fa1
RR
3215 wxFont fontToUse = m_font;
3216 if (theFont) fontToUse = *theFont;
47d67540 3217
223d09f6 3218 wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
47d67540 3219
463c1fa1 3220 GdkFont *font = fontToUse.GetInternalFont( 1.0 );
05939a81 3221 if (x) (*x) = gdk_string_width( font, string.mbc_str() );
463c1fa1
RR
3222 if (y) (*y) = font->ascent + font->descent;
3223 if (descent) (*descent) = font->descent;
3224 if (externalLeading) (*externalLeading) = 0; // ??
c33c4050
RR
3225}
3226
1e6feb95 3227void wxWindowGTK::SetFocus()
c801d85f 3228{
223d09f6 3229 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2daa0ce9 3230
354aa1e3
RR
3231 if (m_wxwindow)
3232 {
173348db 3233 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
b231914f
VZ
3234 {
3235 // see comment in gtk_window_focus_out_callback()
3236 gs_widgetLastFocus = m_wxwindow;
173348db 3237 gtk_widget_grab_focus (m_wxwindow);
b231914f 3238 }
354aa1e3 3239 }
b231914f 3240 else if (m_widget)
c801d85f 3241 {
173348db 3242 if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
463c1fa1 3243 {
354aa1e3 3244 gtk_widget_grab_focus (m_widget);
463c1fa1 3245 }
354aa1e3 3246 else if (GTK_IS_CONTAINER(m_widget))
ff8bfdbb 3247 {
354aa1e3 3248 gtk_container_focus( GTK_CONTAINER(m_widget), GTK_DIR_TAB_FORWARD );
ff8bfdbb
VZ
3249 }
3250 else
3251 {
b02da6b1 3252 // ?
ff8bfdbb 3253 }
362c6693 3254 }
362c6693 3255}
c801d85f 3256
1e6feb95 3257bool wxWindowGTK::AcceptsFocus() const
b292e2f5 3258{
f03fc89f 3259 return m_acceptsFocus && wxWindowBase::AcceptsFocus();
b292e2f5
RR
3260}
3261
1e6feb95 3262bool wxWindowGTK::Reparent( wxWindowBase *newParentBase )
463c1fa1 3263{
223d09f6 3264 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
c50f1fb9 3265
1e6feb95
VZ
3266 wxWindowGTK *oldParent = m_parent,
3267 *newParent = (wxWindowGTK *)newParentBase;
a2053b27 3268
5fd11f09
RR
3269 wxASSERT( GTK_IS_WIDGET(m_widget) );
3270
f03fc89f
VZ
3271 if ( !wxWindowBase::Reparent(newParent) )
3272 return FALSE;
8bbe427f 3273
5fd11f09
RR
3274 wxASSERT( GTK_IS_WIDGET(m_widget) );
3275
3276 /* prevent GTK from deleting the widget arbitrarily */
3277 gtk_widget_ref( m_widget );
3278
8ce63e9d
RR
3279 if (oldParent)
3280 {
3017f78d 3281 gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget );
8ce63e9d 3282 }
c50f1fb9 3283
5fd11f09
RR
3284 wxASSERT( GTK_IS_WIDGET(m_widget) );
3285
8ce63e9d
RR
3286 if (newParent)
3287 {
3288 /* insert GTK representation */
3289 (*(newParent->m_insertCallback))(newParent, this);
3290 }
c50f1fb9 3291
5fd11f09
RR
3292 /* reverse: prevent GTK from deleting the widget arbitrarily */
3293 gtk_widget_unref( m_widget );
148cd9b6 3294
f03fc89f 3295 return TRUE;
362c6693 3296}
c801d85f 3297
1e6feb95 3298void wxWindowGTK::DoAddChild(wxWindowGTK *child)
ddb6bc71 3299{
223d09f6 3300 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
ddb6bc71 3301
223d09f6 3302 wxASSERT_MSG( (child != NULL), wxT("invalid child window") );
ddb6bc71 3303
223d09f6 3304 wxASSERT_MSG( (m_insertCallback != NULL), wxT("invalid child insertion function") );
c50f1fb9 3305
ddb6bc71
RR
3306 /* add to list */
3307 AddChild( child );
c50f1fb9 3308
ddb6bc71
RR
3309 /* insert GTK representation */
3310 (*m_insertCallback)(this, child);
3311}
3312
1e6feb95 3313void wxWindowGTK::Raise()
362c6693 3314{
223d09f6 3315 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3316
a2053b27
RR
3317 if (!m_widget->window) return;
3318
f03fc89f 3319 gdk_window_raise( m_widget->window );
362c6693
RR
3320}
3321
1e6feb95 3322void wxWindowGTK::Lower()
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_lower( m_widget->window );
362c6693 3329}
c801d85f 3330
1e6feb95 3331bool wxWindowGTK::SetCursor( const wxCursor &cursor )
86b29a61 3332{
223d09f6 3333 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
86b29a61 3334
f6bcfd97
BP
3335 if (cursor == m_cursor)
3336 return FALSE;
3337
3338 if (g_isIdle)
3339 wxapp_install_idle_handler();
1e6feb95 3340
f6bcfd97
BP
3341 if (cursor == wxNullCursor)
3342 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR );
3343 else
3344 return wxWindowBase::SetCursor( cursor );
362c6693 3345}
c801d85f 3346
1e6feb95 3347void wxWindowGTK::WarpPointer( int x, int y )
4f22cf8d 3348{
223d09f6 3349 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
85eb36c2 3350
ed673c6a
RR
3351 /* we provide this function ourselves as it is
3352 missing in GDK (top of this file) */
148cd9b6 3353
ed673c6a
RR
3354 GdkWindow *window = (GdkWindow*) NULL;
3355 if (m_wxwindow)
da048e3d 3356 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a
RR
3357 else
3358 window = GetConnectWidget()->window;
148cd9b6 3359
ed673c6a
RR
3360 if (window)
3361 gdk_window_warp_pointer( window, x, y );
4f22cf8d
RR
3362}
3363
1e6feb95 3364void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
c801d85f 3365{
f2593d0d 3366 if (!m_widget) return;
a2053b27
RR
3367 if (!m_widget->window) return;
3368
1e6feb95
VZ
3369 // temporarily hide the caret to avoid nasty interactions between caret
3370 // drawing and the window contents redraw
3371#if 0 // def wxUSE_CARET -- doesn't seem to help :-(
3372 wxCaretSuspend cs((wxWindow *)this);
3373#endif // wxUSE_CARET
3374
139adb6a 3375 if (eraseBackground && m_wxwindow && m_wxwindow->window)
c801d85f 3376 {
139adb6a
RR
3377 if (rect)
3378 {
da048e3d 3379 gdk_window_clear_area( GTK_PIZZA(m_wxwindow)->bin_window,
139adb6a 3380 rect->x, rect->y,
f234c60c 3381 rect->width, rect->height );
139adb6a
RR
3382 }
3383 else
3384 {
da048e3d 3385 gdk_window_clear( GTK_PIZZA(m_wxwindow)->bin_window );
139adb6a
RR
3386 }
3387 }
ff8bfdbb 3388
1b68e0b5 3389 /* there is no GTK equivalent of "draw only, don't clear" so we
da048e3d 3390 invent our own in the GtkPizza widget */
1b68e0b5 3391
139adb6a
RR
3392 if (!rect)
3393 {
3394 if (m_wxwindow)
b02da6b1 3395 {
b6fa52db
RR
3396
3397/*
b02da6b1
VZ
3398 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
3399 gboolean old_clear = pizza->clear_on_draw;
3400 gtk_pizza_set_clear( pizza, FALSE );
1b68e0b5 3401 gtk_widget_draw( m_wxwindow, (GdkRectangle*) NULL );
b02da6b1 3402 gtk_pizza_set_clear( pizza, old_clear );
b6fa52db
RR
3403*/
3404 GdkEventExpose gdk_event;
b4bee866
RR
3405 gdk_event.type = GDK_EXPOSE;
3406 gdk_event.window = GTK_PIZZA(m_wxwindow)->bin_window;
b6fa52db
RR
3407 gdk_event.count = 0;
3408 gdk_event.area.x = 0;
3409 gdk_event.area.y = 0;
3410 gdk_event.area.width = m_wxwindow->allocation.width;
3411 gdk_event.area.height = m_wxwindow->allocation.height;
1e6feb95 3412 gtk_window_expose_callback( m_wxwindow, &gdk_event, (wxWindow *)this );
b02da6b1 3413 }
ff8bfdbb 3414 else
b6fa52db 3415 {
139adb6a 3416 gtk_widget_draw( m_widget, (GdkRectangle*) NULL );
b6fa52db 3417 }
362c6693 3418 }
c801d85f 3419 else
139adb6a 3420 {
139adb6a
RR
3421
3422 if (m_wxwindow)
b02da6b1 3423 {
b6fa52db 3424/*
b02da6b1
VZ
3425 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
3426 gboolean old_clear = pizza->clear_on_draw;
3427 gtk_pizza_set_clear( pizza, FALSE );
148cd9b6 3428
b6fa52db
RR
3429 GdkRectangle gdk_rect;
3430 gdk_rect.x = rect->x;
3431 gdk_rect.y = rect->y;
3432 gdk_rect.width = rect->width;
3433 gdk_rect.height = rect->height;
1b68e0b5 3434 gtk_widget_draw( m_wxwindow, &gdk_rect );
b6fa52db 3435 gtk_window_draw_callback( m_wxwindow, &gdk_rect, this );
148cd9b6 3436
b02da6b1 3437 gtk_pizza_set_clear( pizza, old_clear );
b6fa52db
RR
3438*/
3439 GdkEventExpose gdk_event;
b4bee866
RR
3440 gdk_event.type = GDK_EXPOSE;
3441 gdk_event.window = GTK_PIZZA(m_wxwindow)->bin_window;
b6fa52db
RR
3442 gdk_event.count = 0;
3443 gdk_event.area.x = rect->x;
3444 gdk_event.area.y = rect->y;
3445 gdk_event.area.width = rect->width;
3446 gdk_event.area.height = rect->height;
1e6feb95 3447 gtk_window_expose_callback( m_wxwindow, &gdk_event, (wxWindow *)this );
b02da6b1 3448 }
139adb6a 3449 else
b6fa52db
RR
3450 {
3451 GdkRectangle gdk_rect;
3452 gdk_rect.x = rect->x;
3453 gdk_rect.y = rect->y;
3454 gdk_rect.width = rect->width;
3455 gdk_rect.height = rect->height;
139adb6a 3456 gtk_widget_draw( m_widget, &gdk_rect );
b6fa52db 3457 }
139adb6a 3458 }
362c6693 3459}
c801d85f 3460
1e6feb95 3461void wxWindowGTK::Clear()
c801d85f 3462{
223d09f6 3463 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
47d67540 3464
a2053b27
RR
3465 if (!m_widget->window) return;
3466
f234c60c
RR
3467 if (m_wxwindow && m_wxwindow->window)
3468 {
c916e13b 3469// gdk_window_clear( m_wxwindow->window );
f234c60c 3470 }
362c6693 3471}
c801d85f 3472
ff8bfdbb 3473#if wxUSE_TOOLTIPS
1e6feb95 3474void wxWindowGTK::DoSetToolTip( wxToolTip *tip )
b1170810 3475{
f03fc89f 3476 wxWindowBase::DoSetToolTip(tip);
ff8bfdbb 3477
f03fc89f 3478 if (m_tooltip)
3379ed37 3479 m_tooltip->Apply( (wxWindow *)this );
b1170810
RR
3480}
3481
1e6feb95 3482void wxWindowGTK::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
b1170810 3483{
dcf924a3 3484 gtk_tooltips_set_tip( tips, GetConnectWidget(), wxConvCurrent->cWX2MB(tip), (gchar*) NULL );
301cd871 3485}
ff8bfdbb 3486#endif // wxUSE_TOOLTIPS
b1170810 3487
1e6feb95 3488bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
c801d85f 3489{
223d09f6 3490 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
8bbe427f 3491
739730ca
RR
3492 if (!wxWindowBase::SetBackgroundColour(colour))
3493 {
3494 // don't leave if the GTK widget has just
3495 // been realized
3496 if (!m_delayedBackgroundColour) return FALSE;
3497 }
c50f1fb9 3498
ed673c6a
RR
3499 GdkWindow *window = (GdkWindow*) NULL;
3500 if (m_wxwindow)
da048e3d 3501 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a
RR
3502 else
3503 window = GetConnectWidget()->window;
148cd9b6 3504
ed673c6a 3505 if (!window)
739730ca
RR
3506 {
3507 // indicate that a new style has been set
c50f1fb9
VZ
3508 // but it couldn't get applied as the
3509 // widget hasn't been realized yet.
3510 m_delayedBackgroundColour = TRUE;
739730ca 3511 }
ca298c88 3512
0f2f4986 3513 if ((m_wxwindow) &&
103aab26 3514 (m_wxwindow->window) &&
0f2f4986 3515 (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE)))
3bc755fc 3516 {
a2053b27
RR
3517 /* wxMSW doesn't clear the window here. I don't do that either to
3518 provide compatibility. call Clear() to do the job. */
ca298c88 3519
ed673c6a
RR
3520 m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
3521 gdk_window_set_background( window, m_backgroundColour.GetColor() );
3bc755fc 3522 }
8bbe427f 3523
0f2f4986 3524 ApplyWidgetStyle();
c801d85f 3525
f03fc89f 3526 return TRUE;
6de97a3b
RR
3527}
3528
1e6feb95 3529bool wxWindowGTK::SetForegroundColour( const wxColour &colour )
6de97a3b 3530{
223d09f6 3531 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
8bbe427f 3532
739730ca
RR
3533 if (!wxWindowBase::SetForegroundColour(colour))
3534 {
3535 // don't leave if the GTK widget has just
3536 // been realized
3537 if (!m_delayedForegroundColour) return FALSE;
3538 }
c50f1fb9 3539
ed673c6a
RR
3540 GdkWindow *window = (GdkWindow*) NULL;
3541 if (m_wxwindow)
da048e3d 3542 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a
RR
3543 else
3544 window = GetConnectWidget()->window;
148cd9b6 3545
ed673c6a 3546 if (!window)
739730ca
RR
3547 {
3548 // indicate that a new style has been set
c50f1fb9
VZ
3549 // but it couldn't get applied as the
3550 // widget hasn't been realized yet.
3551 m_delayedForegroundColour = TRUE;
739730ca 3552 }
2b07d713 3553
0f2f4986 3554 ApplyWidgetStyle();
f03fc89f
VZ
3555
3556 return TRUE;
58614078
RR
3557}
3558
1e6feb95 3559GtkStyle *wxWindowGTK::GetWidgetStyle()
58614078 3560{
103aab26
RR
3561 if (m_widgetStyle)
3562 {
3563 GtkStyle *remake = gtk_style_copy( m_widgetStyle );
dd00f3f6
OK
3564#ifdef __WXGTK20__
3565 /* FIXME: is this necessary? */
3566 _G_TYPE_IGC(remake, GtkObjectClass) = _G_TYPE_IGC(m_widgetStyle, GtkObjectClass);
3567#else
103aab26 3568 remake->klass = m_widgetStyle->klass;
dd00f3f6 3569#endif
2daa0ce9 3570
103aab26
RR
3571 gtk_style_unref( m_widgetStyle );
3572 m_widgetStyle = remake;
3573 }
3574 else
3575 {
3576 GtkStyle *def = gtk_rc_get_style( m_widget );
e6527f9d 3577
103aab26
RR
3578 if (!def)
3579 def = gtk_widget_get_default_style();
e6527f9d 3580
103aab26 3581 m_widgetStyle = gtk_style_copy( def );
dd00f3f6
OK
3582#ifdef __WXGTK20__
3583 /* FIXME: is this necessary? */
3584 _G_TYPE_IGC(m_widgetStyle, GtkObjectClass) = _G_TYPE_IGC(def, GtkObjectClass);
3585#else
103aab26 3586 m_widgetStyle->klass = def->klass;
dd00f3f6 3587#endif
103aab26 3588 }
8bbe427f 3589
1ecc4d80 3590 return m_widgetStyle;
58614078
RR
3591}
3592
1e6feb95 3593void wxWindowGTK::SetWidgetStyle()
58614078 3594{
a56fcaaf 3595#if DISABLE_STYLE_IF_BROKEN_THEM
fb65642c
RR
3596 if (m_widget->style->engine_data)
3597 {
3598 static bool s_warningPrinted = FALSE;
3599 if (!s_warningPrinted)
3600 {
3601 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3602 s_warningPrinted = TRUE;
3603 }
3604 m_widgetStyle = m_widget->style;
3605 return;
3606 }
a56fcaaf 3607#endif
fb65642c 3608
1ecc4d80
RR
3609 GtkStyle *style = GetWidgetStyle();
3610
db434467
RR
3611 if (m_font != wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT ))
3612 {
3613 gdk_font_unref( style->font );
3614 style->font = gdk_font_ref( m_font.GetInternalFont( 1.0 ) );
3615 }
1ecc4d80
RR
3616
3617 if (m_foregroundColour.Ok())
3618 {
454e2a22 3619 m_foregroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
db434467
RR
3620 if (m_foregroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNTEXT))
3621 {
3622 style->fg[GTK_STATE_NORMAL] = *m_foregroundColour.GetColor();
3623 style->fg[GTK_STATE_PRELIGHT] = *m_foregroundColour.GetColor();
3624 style->fg[GTK_STATE_ACTIVE] = *m_foregroundColour.GetColor();
3625 }
1e6feb95 3626 else
f6bcfd97
BP
3627 {
3628 // Try to restore the gtk default style. This is still a little
3629 // oversimplified for what is probably really needed here for controls
3630 // other than buttons, but is better than not being able to (re)set a
3631 // control's foreground colour to *wxBLACK -- RL
3632 GtkStyle *def = gtk_rc_get_style( m_widget );
3633
3634 if (!def)
3635 def = gtk_widget_get_default_style();
3636
3637 style->fg[GTK_STATE_NORMAL] = def->fg[GTK_STATE_NORMAL];
3638 style->fg[GTK_STATE_PRELIGHT] = def->fg[GTK_STATE_PRELIGHT];
3639 style->fg[GTK_STATE_ACTIVE] = def->fg[GTK_STATE_ACTIVE];
3640 }
1ecc4d80
RR
3641 }
3642
3643 if (m_backgroundColour.Ok())
3644 {
454e2a22 3645 m_backgroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
db434467
RR
3646 if (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE))
3647 {
3648 style->bg[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
3649 style->base[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
3650 style->bg[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
3651 style->base[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
3652 style->bg[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
3653 style->base[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
3654 style->bg[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
3655 style->base[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
f6bcfd97
BP
3656 }
3657 else
3658 {
3659 // Try to restore the gtk default style. This is still a little
3660 // oversimplified for what is probably really needed here for controls
3661 // other than buttons, but is better than not being able to (re)set a
3662 // control's background colour to default grey and means resetting a
1e6feb95 3663 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
f6bcfd97
BP
3664 // behavior -- RL
3665 GtkStyle *def = gtk_rc_get_style( m_widget );
3666
3667 if (!def)
3668 def = gtk_widget_get_default_style();
3669
3670 style->bg[GTK_STATE_NORMAL] = def->bg[GTK_STATE_NORMAL];
3671 style->base[GTK_STATE_NORMAL] = def->base[GTK_STATE_NORMAL];
3672 style->bg[GTK_STATE_PRELIGHT] = def->bg[GTK_STATE_PRELIGHT];
3673 style->base[GTK_STATE_PRELIGHT] = def->base[GTK_STATE_PRELIGHT];
3674 style->bg[GTK_STATE_ACTIVE] = def->bg[GTK_STATE_ACTIVE];
3675 style->base[GTK_STATE_ACTIVE] = def->base[GTK_STATE_ACTIVE];
3676 style->bg[GTK_STATE_INSENSITIVE] = def->bg[GTK_STATE_INSENSITIVE];
3677 style->base[GTK_STATE_INSENSITIVE] = def->base[GTK_STATE_INSENSITIVE];
3678 }
1ecc4d80 3679 }
a81258be
RR
3680}
3681
1e6feb95 3682void wxWindowGTK::ApplyWidgetStyle()
a81258be 3683{
6de97a3b
RR
3684}
3685
2259e007
RR
3686//-----------------------------------------------------------------------------
3687// Pop-up menu stuff
3688//-----------------------------------------------------------------------------
3689
6522713c 3690#if wxUSE_MENUS_NATIVE
1e6feb95 3691
2259e007
RR
3692static void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting )
3693{
3694 *is_waiting = FALSE;
3695}
3696
1e6feb95 3697static void SetInvokingWindow( wxMenu *menu, wxWindowGTK *win )
30dea054 3698{
1ecc4d80 3699 menu->SetInvokingWindow( win );
1987af7e 3700 wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
1ecc4d80
RR
3701 while (node)
3702 {
1987af7e 3703 wxMenuItem *menuitem = node->GetData();
1ecc4d80
RR
3704 if (menuitem->IsSubMenu())
3705 {
ff8bfdbb
VZ
3706 SetInvokingWindow( menuitem->GetSubMenu(), win );
3707 }
1987af7e
VZ
3708
3709 node = node->GetNext();
1ecc4d80 3710 }
362c6693 3711}
30dea054 3712
0c77152e
RR
3713static gint gs_pop_x = 0;
3714static gint gs_pop_y = 0;
3715
a234a61a
VZ
3716static void pop_pos_callback( GtkMenu * WXUNUSED(menu),
3717 gint *x, gint *y,
1e6feb95 3718 wxWindowGTK *win )
0c77152e
RR
3719{
3720 win->ClientToScreen( &gs_pop_x, &gs_pop_y );
3721 *x = gs_pop_x;
3722 *y = gs_pop_y;
3723}
3724
1e6feb95 3725bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
30dea054 3726{
223d09f6 3727 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
47d67540 3728
223d09f6 3729 wxCHECK_MSG( menu != NULL, FALSE, wxT("invalid popup-menu") );
8bbe427f 3730
1ecc4d80 3731 SetInvokingWindow( menu, this );
ff8bfdbb 3732
631f1bfe
JS
3733 menu->UpdateUI();
3734
0c77152e
RR
3735 gs_pop_x = x;
3736 gs_pop_y = y;
ff8bfdbb 3737
2259e007 3738 bool is_waiting = TRUE;
148cd9b6 3739
2259e007
RR
3740 gtk_signal_connect( GTK_OBJECT(menu->m_menu), "hide",
3741 GTK_SIGNAL_FUNC(gtk_pop_hide_callback), (gpointer)&is_waiting );
3742
1ecc4d80 3743 gtk_menu_popup(
47d67540 3744 GTK_MENU(menu->m_menu),
0c77152e
RR
3745 (GtkWidget *) NULL, // parent menu shell
3746 (GtkWidget *) NULL, // parent menu item
3747 (GtkMenuPositionFunc) pop_pos_callback,
3748 (gpointer) this, // client data
3749 0, // button used to activate it
54517652 3750 gs_timeLastClick // the time of activation
47d67540 3751 );
148cd9b6 3752
956dbab1
RR
3753 while (is_waiting)
3754 {
3755 while (gtk_events_pending())
3756 gtk_main_iteration();
3757 }
2259e007 3758
1ecc4d80 3759 return TRUE;
30dea054
RR
3760}
3761
6522713c 3762#endif // wxUSE_MENUS_NATIVE
1e6feb95 3763
06cfab17 3764#if wxUSE_DRAG_AND_DROP
ac57418f 3765
1e6feb95 3766void wxWindowGTK::SetDropTarget( wxDropTarget *dropTarget )
c801d85f 3767{
223d09f6 3768 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
47d67540 3769
1ecc4d80 3770 GtkWidget *dnd_widget = GetConnectWidget();
47d67540 3771
1ecc4d80 3772 if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
47d67540 3773
1ecc4d80
RR
3774 if (m_dropTarget) delete m_dropTarget;
3775 m_dropTarget = dropTarget;
47d67540 3776
1ecc4d80 3777 if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
362c6693 3778}
c801d85f 3779
f03fc89f 3780#endif // wxUSE_DRAG_AND_DROP
ac57418f 3781
1e6feb95 3782GtkWidget* wxWindowGTK::GetConnectWidget()
e3e65dac 3783{
1ecc4d80
RR
3784 GtkWidget *connect_widget = m_widget;
3785 if (m_wxwindow) connect_widget = m_wxwindow;
47d67540 3786
1ecc4d80 3787 return connect_widget;
e3e65dac 3788}
47d67540 3789
1e6feb95 3790bool wxWindowGTK::IsOwnGtkWindow( GdkWindow *window )
903f689b 3791{
148cd9b6 3792 if (m_wxwindow)
da048e3d 3793 return (window == GTK_PIZZA(m_wxwindow)->bin_window);
148cd9b6 3794
1ecc4d80 3795 return (window == m_widget->window);
903f689b
RR
3796}
3797
1e6feb95 3798bool wxWindowGTK::SetFont( const wxFont &font )
c801d85f 3799{
223d09f6 3800 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
c801d85f 3801
739730ca
RR
3802 if (!wxWindowBase::SetFont(font))
3803 {
454e2a22 3804 return FALSE;
739730ca 3805 }
9c288e4d 3806
ae0bdb01 3807 wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
f03fc89f 3808 if ( sysbg == m_backgroundColour )
ae0bdb01
RR
3809 {
3810 m_backgroundColour = wxNullColour;
3811 ApplyWidgetStyle();
ff8bfdbb
VZ
3812 m_backgroundColour = sysbg;
3813 }
ae0bdb01
RR
3814 else
3815 {
3816 ApplyWidgetStyle();
3817 }
c801d85f 3818
f03fc89f 3819 return TRUE;
362c6693 3820}
c801d85f 3821
b231914f 3822void wxWindowGTK::CaptureMouse()
c801d85f 3823{
b231914f
VZ
3824 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3825
ed673c6a 3826 GdkWindow *window = (GdkWindow*) NULL;
b231914f
VZ
3827 if (m_wxwindow)
3828 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a 3829 else
b231914f 3830 window = GetConnectWidget()->window;
148cd9b6 3831
e4606ed9 3832 wxCHECK_RET( window, _T("CaptureMouse() failed") );
c50f1fb9 3833
b231914f 3834 wxCursor* cursor = & m_cursor;
cca602ac
JS
3835 if (!cursor->Ok())
3836 cursor = wxSTANDARD_CURSOR;
3837
ed673c6a 3838 gdk_pointer_grab( window, FALSE,
1ecc4d80
RR
3839 (GdkEventMask)
3840 (GDK_BUTTON_PRESS_MASK |
3841 GDK_BUTTON_RELEASE_MASK |
148cd9b6 3842 GDK_POINTER_MOTION_HINT_MASK |
1ecc4d80 3843 GDK_POINTER_MOTION_MASK),
ff8bfdbb 3844 (GdkWindow *) NULL,
cca602ac 3845 cursor->GetCursor(),
b02da6b1 3846 (guint32)GDK_CURRENT_TIME );
b231914f 3847 g_captureWindow = this;
1e6feb95 3848 g_captureWindowHasMouse = TRUE;
362c6693 3849}
c801d85f 3850
b231914f 3851void wxWindowGTK::ReleaseMouse()
c801d85f 3852{
b231914f
VZ
3853 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3854
e4606ed9 3855 wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") );
47d67540 3856
ed673c6a 3857 GdkWindow *window = (GdkWindow*) NULL;
b231914f
VZ
3858 if (m_wxwindow)
3859 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a 3860 else
b231914f 3861 window = GetConnectWidget()->window;
148cd9b6 3862
b02da6b1
VZ
3863 if (!window)
3864 return;
c50f1fb9 3865
b02da6b1 3866 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
1e6feb95 3867 g_captureWindow = (wxWindowGTK*) NULL;
362c6693 3868}
c801d85f 3869
1e6feb95
VZ
3870/* static */
3871wxWindow *wxWindowBase::GetCapture()
3872{
3873 return (wxWindow *)g_captureWindow;
3874}
3875
3876bool wxWindowGTK::IsRetained() const
c801d85f 3877{
1ecc4d80 3878 return FALSE;
362c6693 3879}
c801d85f 3880
1e6feb95 3881void wxWindowGTK::SetScrollbar( int orient, int pos, int thumbVisible,
cb43b372 3882 int range, bool refresh )
c801d85f 3883{
223d09f6 3884 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
8bbe427f 3885
223d09f6 3886 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
c801d85f 3887
1ecc4d80 3888 m_hasScrolling = TRUE;
47d67540 3889
1ecc4d80 3890 if (orient == wxHORIZONTAL)
cb43b372 3891 {
1ecc4d80
RR
3892 float fpos = (float)pos;
3893 float frange = (float)range;
3894 float fthumb = (float)thumbVisible;
3895 if (fpos > frange-fthumb) fpos = frange-fthumb;
3896 if (fpos < 0.0) fpos = 0.0;
3897
3898 if ((fabs(frange-m_hAdjust->upper) < 0.2) &&
3899 (fabs(fthumb-m_hAdjust->page_size) < 0.2))
3900 {
3901 SetScrollPos( orient, pos, refresh );
3902 return;
3903 }
47d67540 3904
1ecc4d80 3905 m_oldHorizontalPos = fpos;
47d67540 3906
1ecc4d80
RR
3907 m_hAdjust->lower = 0.0;
3908 m_hAdjust->upper = frange;
3909 m_hAdjust->value = fpos;
3910 m_hAdjust->step_increment = 1.0;
3911 m_hAdjust->page_increment = (float)(wxMax(fthumb,0));
3912 m_hAdjust->page_size = fthumb;
cb43b372 3913 }
1ecc4d80
RR
3914 else
3915 {
3916 float fpos = (float)pos;
3917 float frange = (float)range;
3918 float fthumb = (float)thumbVisible;
3919 if (fpos > frange-fthumb) fpos = frange-fthumb;
3920 if (fpos < 0.0) fpos = 0.0;
3921
3922 if ((fabs(frange-m_vAdjust->upper) < 0.2) &&
3923 (fabs(fthumb-m_vAdjust->page_size) < 0.2))
3924 {
3925 SetScrollPos( orient, pos, refresh );
3926 return;
3927 }
47d67540 3928
1ecc4d80 3929 m_oldVerticalPos = fpos;
47d67540 3930
1ecc4d80
RR
3931 m_vAdjust->lower = 0.0;
3932 m_vAdjust->upper = frange;
3933 m_vAdjust->value = fpos;
3934 m_vAdjust->step_increment = 1.0;
3935 m_vAdjust->page_increment = (float)(wxMax(fthumb,0));
3936 m_vAdjust->page_size = fthumb;
3937 }
47d67540 3938
eb082a08
RR
3939 if (orient == wxHORIZONTAL)
3940 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
3941 else
3942 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
362c6693 3943}
c801d85f 3944
1e6feb95 3945void wxWindowGTK::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
c801d85f 3946{
223d09f6 3947 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
1ecc4d80 3948
223d09f6 3949 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
1ecc4d80
RR
3950
3951 if (orient == wxHORIZONTAL)
3952 {
3953 float fpos = (float)pos;
3954 if (fpos > m_hAdjust->upper - m_hAdjust->page_size) fpos = m_hAdjust->upper - m_hAdjust->page_size;
3955 if (fpos < 0.0) fpos = 0.0;
3956 m_oldHorizontalPos = fpos;
3957
3958 if (fabs(fpos-m_hAdjust->value) < 0.2) return;
3959 m_hAdjust->value = fpos;
3960 }
3961 else
3962 {
3963 float fpos = (float)pos;
3964 if (fpos > m_vAdjust->upper - m_vAdjust->page_size) fpos = m_vAdjust->upper - m_vAdjust->page_size;
3965 if (fpos < 0.0) fpos = 0.0;
3966 m_oldVerticalPos = fpos;
ff8bfdbb 3967
1ecc4d80
RR
3968 if (fabs(fpos-m_vAdjust->value) < 0.2) return;
3969 m_vAdjust->value = fpos;
3970 }
47d67540 3971
5b8a521e 3972 if (m_wxwindow->window)
47d67540 3973 {
5b8a521e 3974 if (orient == wxHORIZONTAL)
473d087e
RR
3975 {
3976 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust),
3977 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
2daa0ce9 3978
5b8a521e 3979 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
2daa0ce9 3980
473d087e
RR
3981 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
3982 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
3983 }
5b8a521e 3984 else
473d087e
RR
3985 {
3986 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust),
3987 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
2daa0ce9 3988
5b8a521e 3989 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
473d087e
RR
3990
3991 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
3992 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
3993 }
cb43b372 3994 }
362c6693 3995}
c801d85f 3996
1e6feb95 3997int wxWindowGTK::GetScrollThumb( int orient ) const
c801d85f 3998{
223d09f6 3999 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
47d67540 4000
223d09f6 4001 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
47d67540 4002
1ecc4d80
RR
4003 if (orient == wxHORIZONTAL)
4004 return (int)(m_hAdjust->page_size+0.5);
4005 else
4006 return (int)(m_vAdjust->page_size+0.5);
362c6693 4007}
c801d85f 4008
1e6feb95 4009int wxWindowGTK::GetScrollPos( int orient ) const
c801d85f 4010{
223d09f6 4011 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
47d67540 4012
223d09f6 4013 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
c801d85f 4014
1ecc4d80
RR
4015 if (orient == wxHORIZONTAL)
4016 return (int)(m_hAdjust->value+0.5);
4017 else
4018 return (int)(m_vAdjust->value+0.5);
362c6693 4019}
c801d85f 4020
1e6feb95 4021int wxWindowGTK::GetScrollRange( int orient ) const
c801d85f 4022{
223d09f6 4023 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
47d67540 4024
223d09f6 4025 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
c801d85f 4026
1ecc4d80
RR
4027 if (orient == wxHORIZONTAL)
4028 return (int)(m_hAdjust->upper+0.5);
4029 else
4030 return (int)(m_vAdjust->upper+0.5);
362c6693 4031}
c801d85f 4032
1e6feb95 4033void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
c801d85f 4034{
223d09f6 4035 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
47d67540 4036
223d09f6 4037 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
1e6feb95 4038
8e217128 4039 if ((dx == 0) && (dy == 0)) return;
c801d85f 4040
b6fa52db 4041 m_clipPaintRegion = TRUE;
da048e3d 4042 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
b6fa52db 4043 m_clipPaintRegion = FALSE;
1e6feb95
VZ
4044
4045/*
8e217128
RR
4046 if (m_children.GetCount() > 0)
4047 {
4048 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
4049 }
4050 else
4051 {
4052 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
1e6feb95 4053
8e217128
RR
4054 pizza->xoffset -= dx;
4055 pizza->yoffset -= dy;
1e6feb95 4056
8e217128
RR
4057 GdkGC *m_scrollGC = gdk_gc_new( pizza->bin_window );
4058 gdk_gc_set_exposures( m_scrollGC, TRUE );
4059
4060 int cw = 0;
4061 int ch = 0;
4062 GetClientSize( &cw, &ch );
4063 int w = cw - abs(dx);
4064 int h = ch - abs(dy);
4065
4066 if ((h < 0) || (w < 0))
4067 {
4068 Refresh();
1e6feb95 4069 }
8e217128
RR
4070 else
4071 {
4072 int s_x = 0;
4073 int s_y = 0;
4074 if (dx < 0) s_x = -dx;
4075 if (dy < 0) s_y = -dy;
4076 int d_x = 0;
4077 int d_y = 0;
4078 if (dx > 0) d_x = dx;
4079 if (dy > 0) d_y = dy;
4080
4081 gdk_window_copy_area( pizza->bin_window, m_scrollGC, d_x, d_y,
4082 pizza->bin_window, s_x, s_y, w, h );
4083
4084 wxRect rect;
4085 if (dx < 0) rect.x = cw+dx; else rect.x = 0;
4086 if (dy < 0) rect.y = ch+dy; else rect.y = 0;
4087 if (dy != 0) rect.width = cw; else rect.width = abs(dx);
4088 if (dx != 0) rect.height = ch; else rect.height = abs(dy);
4089
4090 Refresh( TRUE, &rect );
4091 }
1e6feb95 4092
8e217128
RR
4093 gdk_gc_unref( m_scrollGC );
4094 }
4095*/
c801d85f 4096}
3723b7b1 4097
3723b7b1
JS
4098// Find the wxWindow at the current mouse position, also returning the mouse
4099// position.
4100wxWindow* wxFindWindowAtPointer(wxPoint& pt)
4101{
59a12e90
JS
4102 pt = wxGetMousePosition();
4103 wxWindow* found = wxFindWindowAtPoint(pt);
4104 return found;
3723b7b1
JS
4105}
4106
4107// Get the current mouse position.
4108wxPoint wxGetMousePosition()
4109{
59a12e90
JS
4110 /* This crashes when used within wxHelpContext,
4111 so we have to use the X-specific implementation below.
4112 gint x, y;
4113 GdkModifierType *mask;
4114 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4115
4116 return wxPoint(x, y);
4117 */
4118
3723b7b1
JS
4119 int x, y;
4120 GdkWindow* windowAtPtr = gdk_window_at_pointer(& x, & y);
57591e0e
JS
4121 if (!windowAtPtr)
4122 return wxPoint(-999, -999);
59a12e90
JS
4123
4124 Display *display = GDK_WINDOW_XDISPLAY(windowAtPtr);
4125 Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
4126 Window rootReturn, childReturn;
4127 int rootX, rootY, winX, winY;
4128 unsigned int maskReturn;
4129
4130 XQueryPointer (display,
5cd09f0b
RR
4131 rootWindow,
4132 &rootReturn,
59a12e90
JS
4133 &childReturn,
4134 &rootX, &rootY, &winX, &winY, &maskReturn);
4135 return wxPoint(rootX, rootY);
4136
3723b7b1
JS
4137}
4138