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