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