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