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