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