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