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