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