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