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