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