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