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