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