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