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