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