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