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