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