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