]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/window.cpp
Smartphone menus.
[wxWidgets.git] / src / gtk / 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
148 wxStatitText class handles only a GtkLabel widget a pointer to which you
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
RR
2309
2310 if (win->m_delayedBackgroundColour && !win->GetThemeEnabled())
ea323db3 2311 win->GtkSetBackgroundColour( win->GetBackgroundColour() );
a2053b27 2312
2b904684 2313 if (win->m_delayedForegroundColour && !win->GetThemeEnabled())
ea323db3 2314 win->GtkSetForegroundColour( win->GetForegroundColour() );
a2053b27 2315
2b5f62a0
VZ
2316#ifdef __WXGTK20__
2317 if (win->m_imContext)
2318 {
2319 GtkPizza *pizza = GTK_PIZZA( m_widget );
2320 gtk_im_context_set_client_window( (GtkIMContext*) win->m_imContext, pizza->bin_window );
2321 }
2322#endif
2323
3c679789
RR
2324 wxWindowCreateEvent event( win );
2325 event.SetEventObject( win );
2326 win->GetEventHandler()->ProcessEvent( event );
1e6feb95 2327
a2053b27
RR
2328 return FALSE;
2329}
2330
b79395c5
RR
2331//-----------------------------------------------------------------------------
2332// "size_allocate"
2333//-----------------------------------------------------------------------------
2334
8f75cb6c 2335static
adc1999b
RR
2336void gtk_window_size_callback( GtkWidget *WXUNUSED(widget),
2337 GtkAllocation *WXUNUSED(alloc),
8f75cb6c
RR
2338 wxWindow *win )
2339{
2340 if (g_isIdle)
2341 wxapp_install_idle_handler();
2daa0ce9 2342
5b8a521e 2343 if (!win->m_hasScrolling) return;
2daa0ce9 2344
5b8a521e
RR
2345 int client_width = 0;
2346 int client_height = 0;
2347 win->GetClientSize( &client_width, &client_height );
2348 if ((client_width == win->m_oldClientWidth) && (client_height == win->m_oldClientHeight))
2349 return;
2daa0ce9 2350
5b8a521e
RR
2351 win->m_oldClientWidth = client_width;
2352 win->m_oldClientHeight = client_height;
2daa0ce9 2353
5b8a521e
RR
2354 if (!win->m_nativeSizeEvent)
2355 {
2356 wxSizeEvent event( win->GetSize(), win->GetId() );
2357 event.SetEventObject( win );
2358 win->GetEventHandler()->ProcessEvent( event );
2359 }
8f75cb6c
RR
2360}
2361
2362
3ed2e7ce
VZ
2363#ifdef HAVE_XIM
2364 #define WXUNUSED_UNLESS_XIM(param) param
2365#else
2366 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2367#endif
2368
b79395c5
RR
2369/* Resize XIM window */
2370
3ed2e7ce 2371static
8f75cb6c
RR
2372void gtk_wxwindow_size_callback( GtkWidget* WXUNUSED_UNLESS_XIM(widget),
2373 GtkAllocation* WXUNUSED_UNLESS_XIM(alloc),
1e6feb95 2374 wxWindowGTK* WXUNUSED_UNLESS_XIM(win) )
b79395c5
RR
2375{
2376 if (g_isIdle)
2377 wxapp_install_idle_handler();
2daa0ce9 2378
9a8c7620 2379#ifdef HAVE_XIM
b79395c5
RR
2380 if (!win->m_ic)
2381 return;
2382
b79395c5
RR
2383 if (gdk_ic_get_style (win->m_ic) & GDK_IM_PREEDIT_POSITION)
2384 {
2385 gint width, height;
2386
3ed2e7ce 2387 gdk_window_get_size (widget->window, &width, &height);
b79395c5
RR
2388 win->m_icattr->preedit_area.width = width;
2389 win->m_icattr->preedit_area.height = height;
2390 gdk_ic_set_attr (win->m_ic, win->m_icattr, GDK_IC_PREEDIT_AREA);
2391 }
9a8c7620 2392#endif // HAVE_XIM
b79395c5
RR
2393}
2394
63081513
RR
2395//-----------------------------------------------------------------------------
2396// "realize" from m_wxwindow
2397//-----------------------------------------------------------------------------
2398
2399/* Initialize XIM support */
2400
2401static gint
3ed2e7ce 2402gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget),
1e6feb95 2403 wxWindowGTK * WXUNUSED_UNLESS_XIM(win) )
63081513
RR
2404{
2405 if (g_isIdle)
2406 wxapp_install_idle_handler();
2407
d06800f1 2408#ifdef HAVE_XIM
63081513
RR
2409 if (win->m_ic) return FALSE;
2410 if (!widget) return FALSE;
2411 if (!gdk_im_ready()) return FALSE;
2412
2413 win->m_icattr = gdk_ic_attr_new();
2414 if (!win->m_icattr) return FALSE;
2daa0ce9 2415
63081513
RR
2416 gint width, height;
2417 GdkEventMask mask;
2418 GdkColormap *colormap;
2419 GdkICAttr *attr = win->m_icattr;
b58b1dfc 2420 unsigned attrmask = GDK_IC_ALL_REQ;
63081513 2421 GdkIMStyle style;
b79395c5
RR
2422 GdkIMStyle supported_style = (GdkIMStyle)
2423 (GDK_IM_PREEDIT_NONE |
1e6feb95
VZ
2424 GDK_IM_PREEDIT_NOTHING |
2425 GDK_IM_PREEDIT_POSITION |
2426 GDK_IM_STATUS_NONE |
2427 GDK_IM_STATUS_NOTHING);
63081513
RR
2428
2429 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
1e6feb95 2430 supported_style = (GdkIMStyle)(supported_style & ~GDK_IM_PREEDIT_POSITION);
63081513
RR
2431
2432 attr->style = style = gdk_im_decide_style (supported_style);
2433 attr->client_window = widget->window;
2434
2435 if ((colormap = gtk_widget_get_colormap (widget)) !=
1e6feb95 2436 gtk_widget_get_default_colormap ())
63081513 2437 {
5cd09f0b
RR
2438 attrmask |= GDK_IC_PREEDIT_COLORMAP;
2439 attr->preedit_colormap = colormap;
63081513 2440 }
2daa0ce9 2441
63081513
RR
2442 attrmask |= GDK_IC_PREEDIT_FOREGROUND;
2443 attrmask |= GDK_IC_PREEDIT_BACKGROUND;
2444 attr->preedit_foreground = widget->style->fg[GTK_STATE_NORMAL];
2445 attr->preedit_background = widget->style->base[GTK_STATE_NORMAL];
2446
2447 switch (style & GDK_IM_PREEDIT_MASK)
2448 {
1e6feb95
VZ
2449 case GDK_IM_PREEDIT_POSITION:
2450 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
2451 {
2452 g_warning ("over-the-spot style requires fontset");
2453 break;
2454 }
63081513 2455
1e6feb95 2456 gdk_window_get_size (widget->window, &width, &height);
63081513 2457
1e6feb95
VZ
2458 attrmask |= GDK_IC_PREEDIT_POSITION_REQ;
2459 attr->spot_location.x = 0;
2460 attr->spot_location.y = height;
2461 attr->preedit_area.x = 0;
2462 attr->preedit_area.y = 0;
2463 attr->preedit_area.width = width;
2464 attr->preedit_area.height = height;
2465 attr->preedit_fontset = widget->style->font;
63081513 2466
1e6feb95 2467 break;
b79395c5 2468 }
2daa0ce9 2469
b58b1dfc 2470 win->m_ic = gdk_ic_new (attr, (GdkICAttributesType)attrmask);
2daa0ce9 2471
63081513 2472 if (win->m_ic == NULL)
1e6feb95 2473 g_warning ("Can't create input context.");
63081513 2474 else
1e6feb95
VZ
2475 {
2476 mask = gdk_window_get_events (widget->window);
2477 mask = (GdkEventMask)(mask | gdk_ic_get_events (win->m_ic));
2478 gdk_window_set_events (widget->window, mask);
2479
2480 if (GTK_WIDGET_HAS_FOCUS(widget))
2481 gdk_im_begin (win->m_ic, widget->window);
2482 }
2483#endif // HAVE_XIM
63081513
RR
2484
2485 return FALSE;
2486}
2487
6ca41e57 2488//-----------------------------------------------------------------------------
1e6feb95 2489// InsertChild for wxWindowGTK.
6ca41e57
RR
2490//-----------------------------------------------------------------------------
2491
1e6feb95 2492/* Callback for wxWindowGTK. This very strange beast has to be used because
b1170810
RR
2493 * C++ has no virtual methods in a constructor. We have to emulate a
2494 * virtual function here as wxNotebook requires a different way to insert
2495 * a child in it. I had opted for creating a wxNotebookPage window class
2496 * which would have made this superfluous (such in the MDI window system),
2497 * but no-one was listening to me... */
6ca41e57 2498
1e6feb95 2499static void wxInsertChildInWindow( wxWindowGTK* parent, wxWindowGTK* child )
6ca41e57 2500{
bf0c00c6
RR
2501 /* the window might have been scrolled already, do we
2502 have to adapt the position */
da048e3d
RR
2503 GtkPizza *pizza = GTK_PIZZA(parent->m_wxwindow);
2504 child->m_x += pizza->xoffset;
2505 child->m_y += pizza->yoffset;
148cd9b6 2506
da048e3d 2507 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
a2053b27
RR
2508 GTK_WIDGET(child->m_widget),
2509 child->m_x,
2510 child->m_y,
2511 child->m_width,
2512 child->m_height );
6ca41e57
RR
2513}
2514
bbe0af5b
RR
2515//-----------------------------------------------------------------------------
2516// global functions
2517//-----------------------------------------------------------------------------
2518
1e6feb95 2519wxWindow *wxGetActiveWindow()
bbe0af5b 2520{
6cad4f1b 2521 return wxWindow::FindFocus();
bbe0af5b
RR
2522}
2523
c801d85f 2524//-----------------------------------------------------------------------------
1e6feb95 2525// wxWindowGTK
c801d85f
KB
2526//-----------------------------------------------------------------------------
2527
6522713c
VZ
2528// in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2529// method
1e6feb95 2530#ifdef __WXUNIVERSAL__
6522713c
VZ
2531 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK, wxWindowBase)
2532#else // __WXGTK__
1e6feb95 2533 IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
6522713c 2534#endif // __WXUNIVERSAL__/__WXGTK__
c801d85f 2535
1e6feb95 2536void wxWindowGTK::Init()
c801d85f 2537{
f03fc89f 2538 // GTK specific
a2053b27 2539 m_widget = (GtkWidget *) NULL;
e380f72b 2540 m_wxwindow = (GtkWidget *) NULL;
76fcf0f2 2541 m_focusWidget = (GtkWidget *) NULL;
8bbe427f 2542
f03fc89f 2543 // position/size
a2053b27
RR
2544 m_x = 0;
2545 m_y = 0;
2546 m_width = 0;
e380f72b 2547 m_height = 0;
8bbe427f 2548
e380f72b
RR
2549 m_sizeSet = FALSE;
2550 m_hasVMT = FALSE;
2551 m_needParent = TRUE;
31c6b4fc 2552 m_isBeingDeleted = FALSE;
148cd9b6 2553
147bc491 2554 m_noExpose = FALSE;
30760ce7 2555 m_nativeSizeEvent = FALSE;
94633ad9 2556
a2053b27 2557 m_hasScrolling = FALSE;
846e1424 2558 m_isScrolling = FALSE;
f03fc89f 2559
a2053b27 2560 m_hAdjust = (GtkAdjustment*) NULL;
e380f72b 2561 m_vAdjust = (GtkAdjustment*) NULL;
815ac4a7 2562 m_oldHorizontalPos =
e380f72b 2563 m_oldVerticalPos = 0.0;
815ac4a7
VZ
2564 m_oldClientWidth =
2565 m_oldClientHeight = 0;
8bbe427f 2566
e380f72b 2567 m_resizing = FALSE;
8bbe427f 2568
ddb6bc71 2569 m_insertCallback = (wxInsertChildFunction) NULL;
8bbe427f 2570
b292e2f5 2571 m_acceptsFocus = FALSE;
6cad4f1b 2572 m_hasFocus = FALSE;
148cd9b6 2573
b6fa52db 2574 m_clipPaintRegion = FALSE;
b6fa52db 2575
5e014a0c 2576 m_cursor = *wxSTANDARD_CURSOR;
2daa0ce9 2577
f6bcfd97
BP
2578 m_delayedForegroundColour = FALSE;
2579 m_delayedBackgroundColour = FALSE;
1e6feb95 2580
2b5f62a0
VZ
2581#ifdef __WXGTK20__
2582 m_imContext = NULL;
2583 m_x11Context = NULL;
2584#else
63081513
RR
2585#ifdef HAVE_XIM
2586 m_ic = (GdkIC*) NULL;
2587 m_icattr = (GdkICAttr*) NULL;
2588#endif
2b5f62a0 2589#endif
362c6693 2590}
c801d85f 2591
1e6feb95 2592wxWindowGTK::wxWindowGTK()
68995f26
VZ
2593{
2594 Init();
2595}
2596
1e6feb95
VZ
2597wxWindowGTK::wxWindowGTK( wxWindow *parent,
2598 wxWindowID id,
2599 const wxPoint &pos,
2600 const wxSize &size,
2601 long style,
2602 const wxString &name )
6ca41e57 2603{
68995f26
VZ
2604 Init();
2605
e380f72b 2606 Create( parent, id, pos, size, style, name );
6ca41e57 2607}
8bbe427f 2608
1e6feb95
VZ
2609bool wxWindowGTK::Create( wxWindow *parent,
2610 wxWindowID id,
2611 const wxPoint &pos,
2612 const wxSize &size,
2613 long style,
2614 const wxString &name )
c801d85f 2615{
4dcaf11a
RR
2616 if (!PreCreation( parent, pos, size ) ||
2617 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
2618 {
1e6feb95 2619 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
b02da6b1 2620 return FALSE;
4dcaf11a 2621 }
47d67540 2622
ddb6bc71 2623 m_insertCallback = wxInsertChildInWindow;
2b5f62a0 2624
994bc575 2625 // always needed for background clearing
2b5f62a0 2626 m_delayedBackgroundColour = TRUE;
1e6feb95 2627
e380f72b 2628 m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
38c7b3d3 2629 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
ff8bfdbb 2630
f03fc89f 2631 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
47d67540 2632
dd00f3f6 2633 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
e380f72b 2634 scroll_class->scrollbar_spacing = 0;
47d67540 2635
f03fc89f 2636 gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
47d67540 2637
f03fc89f
VZ
2638 m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->hscrollbar) );
2639 m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->vscrollbar) );
47d67540 2640
da048e3d 2641 m_wxwindow = gtk_pizza_new();
0fc5dbf5 2642
1e6feb95 2643#ifndef __WXUNIVERSAL__
da048e3d 2644 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
b292e2f5 2645
f03fc89f 2646 if (HasFlag(wxRAISED_BORDER))
034be888 2647 {
da048e3d 2648 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_OUT );
034be888 2649 }
f03fc89f 2650 else if (HasFlag(wxSUNKEN_BORDER))
034be888 2651 {
da048e3d 2652 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_IN );
5e014a0c
RR
2653 }
2654 else if (HasFlag(wxSIMPLE_BORDER))
2655 {
da048e3d 2656 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_THIN );
034be888
RR
2657 }
2658 else
2659 {
da048e3d 2660 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_NONE );
034be888 2661 }
1e6feb95 2662#endif // __WXUNIVERSAL__
47d67540 2663
4e5a4c69
RR
2664 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
2665
3da17724
RR
2666 GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
2667 m_acceptsFocus = TRUE;
ca298c88 2668
e380f72b 2669 // I _really_ don't want scrollbars in the beginning
a2053b27
RR
2670 m_vAdjust->lower = 0.0;
2671 m_vAdjust->upper = 1.0;
2672 m_vAdjust->value = 0.0;
2673 m_vAdjust->step_increment = 1.0;
2674 m_vAdjust->page_increment = 1.0;
2675 m_vAdjust->page_size = 5.0;
2676 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
2677 m_hAdjust->lower = 0.0;
2678 m_hAdjust->upper = 1.0;
2679 m_hAdjust->value = 0.0;
2680 m_hAdjust->step_increment = 1.0;
2681 m_hAdjust->page_increment = 1.0;
2682 m_hAdjust->page_size = 5.0;
2683 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
f03fc89f
VZ
2684
2685 // these handlers block mouse events to any window during scrolling such as
77ffb593 2686 // motion events and prevent GTK and wxWidgets from fighting over where the
f03fc89f
VZ
2687 // slider should be
2688
2689 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_press_event",
76ed8f8d
RR
2690 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2691
f03fc89f 2692 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_press_event",
76ed8f8d
RR
2693 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2694
f03fc89f 2695 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_release_event",
76ed8f8d
RR
2696 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2697
f03fc89f 2698 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_release_event",
76ed8f8d 2699 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
8bbe427f 2700
034be888 2701 // these handlers get notified when screen updates are required either when
76ed8f8d
RR
2702 // scrolling or when the window size (and therefore scrollbar configuration)
2703 // has changed
2704
2705 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
2706 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
2707 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
2708 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
2709
2b5f62a0
VZ
2710#ifdef __WXGTK20__
2711 // Create input method handler
2712 m_imContext = (GtkIMMulticontext*) gtk_im_multicontext_new ();
2713
2714 // Cannot handle drawing preedited text yet
2715 gtk_im_context_set_use_preedit( (GtkIMContext*) m_imContext, FALSE );
2716
2717 g_signal_connect (G_OBJECT (m_imContext), "commit",
2718 G_CALLBACK (gtk_wxwindow_commit_cb), this);
2719#endif
2720
f03fc89f 2721 gtk_widget_show( m_wxwindow );
47d67540 2722
f03fc89f
VZ
2723 if (m_parent)
2724 m_parent->DoAddChild( this );
94633ad9 2725
76fcf0f2 2726 m_focusWidget = m_wxwindow;
8bbe427f 2727
e380f72b 2728 PostCreation();
8bbe427f 2729
e380f72b 2730 return TRUE;
362c6693 2731}
c801d85f 2732
1e6feb95 2733wxWindowGTK::~wxWindowGTK()
c801d85f 2734{
7de59551
RD
2735 SendDestroyEvent();
2736
44cd54c2
JS
2737 if (g_focusWindow == this)
2738 g_focusWindow = NULL;
2739
e8c12a53
VS
2740 if (g_activeFrame == this)
2741 g_activeFrame = NULL;
2742
3e679f01
VZ
2743 if ( g_delayedFocus == this )
2744 g_delayedFocus = NULL;
2745
31c6b4fc 2746 m_isBeingDeleted = TRUE;
43a18898 2747 m_hasVMT = FALSE;
47d67540 2748
f03fc89f
VZ
2749 if (m_widget)
2750 Show( FALSE );
8bbe427f 2751
a2053b27
RR
2752 DestroyChildren();
2753
63081513
RR
2754#ifdef HAVE_XIM
2755 if (m_ic)
2756 gdk_ic_destroy (m_ic);
2757 if (m_icattr)
2758 gdk_ic_attr_destroy (m_icattr);
2759#endif
2760
f03fc89f 2761 if (m_wxwindow)
a2053b27 2762 {
f03fc89f 2763 gtk_widget_destroy( m_wxwindow );
c50f1fb9 2764 m_wxwindow = (GtkWidget*) NULL;
a2053b27 2765 }
8bbe427f 2766
f03fc89f 2767 if (m_widget)
a2053b27 2768 {
f03fc89f 2769 gtk_widget_destroy( m_widget );
c50f1fb9 2770 m_widget = (GtkWidget*) NULL;
a2053b27 2771 }
362c6693 2772}
c801d85f 2773
1e6feb95 2774bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos, const wxSize &size )
c801d85f 2775{
223d09f6 2776 wxCHECK_MSG( !m_needParent || parent, FALSE, wxT("Need complete parent.") );
8bbe427f 2777
a7c26d10
RD
2778 // Use either the given size, or the default if -1 is given.
2779 // See wxWindowBase for these functions.
3013a903 2780 m_width = WidthDefault(size.x) ;
f03fc89f 2781 m_height = HeightDefault(size.y);
8bbe427f 2782
43a18898
RR
2783 m_x = (int)pos.x;
2784 m_y = (int)pos.y;
8bbe427f 2785
4dcaf11a 2786 return TRUE;
c801d85f
KB
2787}
2788
1e6feb95 2789void wxWindowGTK::PostCreation()
c801d85f 2790{
82b978d7
RD
2791 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2792
43a18898
RR
2793 if (m_wxwindow)
2794 {
147bc491 2795 if (!m_noExpose)
b02da6b1 2796 {
77ffb593 2797 // these get reported to wxWidgets -> wxPaintEvent
1e6feb95 2798
b420fb6a
RR
2799 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow), TRUE );
2800
147bc491
RR
2801 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
2802 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
2803
4e5a4c69 2804#ifndef __WXGTK20__
147bc491
RR
2805 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
2806 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
0fc5dbf5 2807
e441e1f4 2808 if (!HasFlag(wxFULL_REPAINT_ON_RESIZE))
e22454be
RR
2809 {
2810 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "event",
2811 GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this );
2812 }
4e5a4c69 2813#else
e441e1f4 2814 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2b5f62a0
VZ
2815#endif
2816
2817#ifdef __WXGTK20__
2818 // Create input method handler
2819 m_imContext = (GtkIMMulticontext*) gtk_im_multicontext_new ();
2820
2821 // Cannot handle drawing preedited text yet
2822 gtk_im_context_set_use_preedit( (GtkIMContext*) m_imContext, FALSE );
2823
2824 g_signal_connect (G_OBJECT (m_imContext), "commit",
2825 G_CALLBACK (gtk_wxwindow_commit_cb), this);
4e5a4c69 2826#endif
b02da6b1 2827 }
148cd9b6 2828
67d78217 2829 // these are called when the "sunken" or "raised" borders are drawn
034be888
RR
2830 gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
2831 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
2832
4e5a4c69 2833#ifndef __WXGTK20__
034be888
RR
2834 gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
2835 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
4e5a4c69 2836#endif
43a18898 2837 }
47d67540 2838
76fcf0f2 2839 // focus handling
63081513 2840
76fcf0f2
RR
2841 if (m_focusWidget == NULL)
2842 m_focusWidget = m_widget;
2daa0ce9 2843
76fcf0f2
RR
2844 gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_in_event",
2845 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
2846
2847 gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_out_event",
2848 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
2849
2850 // connect to the various key and mouse handlers
63081513 2851
a2053b27 2852 GtkWidget *connect_widget = GetConnectWidget();
f03fc89f 2853
a2053b27 2854 ConnectWidget( connect_widget );
47d67540 2855
63081513 2856 /* We cannot set colours, fonts and cursors before the widget has
a2053b27
RR
2857 been realized, so we do this directly after realization */
2858 gtk_signal_connect( GTK_OBJECT(connect_widget), "realize",
c50f1fb9 2859 GTK_SIGNAL_FUNC(gtk_window_realized_callback), (gpointer) this );
2daa0ce9 2860
63081513
RR
2861 if (m_wxwindow)
2862 {
47c93b63 2863 // Catch native resize events
8f75cb6c
RR
2864 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2865 GTK_SIGNAL_FUNC(gtk_window_size_callback), (gpointer)this );
2daa0ce9 2866
47c93b63 2867 // Initialize XIM support
63081513
RR
2868 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "realize",
2869 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback), (gpointer) this );
8f75cb6c 2870
47c93b63 2871 // And resize XIM window
b79395c5
RR
2872 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2873 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this );
63081513 2874 }
2daa0ce9 2875
e1f448ee 2876 if ( !GTK_IS_COMBO(m_widget))
47c93b63
RR
2877 {
2878 // This is needed if we want to add our windows into native
2879 // GTK control, such as the toolbar. With this callback, the
2880 // toolbar gets to know the correct size (the one set by the
2881 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2882 // when moving to GTK 2.0.
2883 gtk_signal_connect( GTK_OBJECT(m_widget), "size_request",
e1f448ee
VZ
2884 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback),
2885 (gpointer) this );
47c93b63 2886 }
1e6feb95 2887
43a18898 2888 m_hasVMT = TRUE;
a433fbd5
VZ
2889
2890 // unless the window was created initially hidden (i.e. Hide() had been
2891 // called before Create()), we should show it at GTK+ level as well
2892 if ( IsShown() )
2893 gtk_widget_show( m_widget );
b4071e91
RR
2894}
2895
1e6feb95 2896void wxWindowGTK::ConnectWidget( GtkWidget *widget )
b4071e91 2897{
43a18898
RR
2898 gtk_signal_connect( GTK_OBJECT(widget), "key_press_event",
2899 GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this );
c801d85f 2900
b666df2c
RR
2901 gtk_signal_connect( GTK_OBJECT(widget), "key_release_event",
2902 GTK_SIGNAL_FUNC(gtk_window_key_release_callback), (gpointer)this );
2903
43a18898
RR
2904 gtk_signal_connect( GTK_OBJECT(widget), "button_press_event",
2905 GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
47d67540 2906
43a18898
RR
2907 gtk_signal_connect( GTK_OBJECT(widget), "button_release_event",
2908 GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
47d67540 2909
43a18898
RR
2910 gtk_signal_connect( GTK_OBJECT(widget), "motion_notify_event",
2911 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
47d67540 2912
557c9f5b
JS
2913#ifdef __WXGTK20__
2914 gtk_signal_connect( GTK_OBJECT(widget), "scroll_event",
2915 GTK_SIGNAL_FUNC(gtk_window_wheel_callback), (gpointer)this );
2916#endif
2917
43a18898
RR
2918 gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event",
2919 GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
47d67540 2920
43a18898
RR
2921 gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
2922 GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
362c6693 2923}
c801d85f 2924
1e6feb95 2925bool wxWindowGTK::Destroy()
c801d85f 2926{
82b978d7 2927 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
47d67540 2928
43a18898 2929 m_hasVMT = FALSE;
c801d85f 2930
f03fc89f 2931 return wxWindowBase::Destroy();
362c6693 2932}
c801d85f 2933
1e6feb95 2934void wxWindowGTK::DoMoveWindow(int x, int y, int width, int height)
23efdd02
RR
2935{
2936 gtk_pizza_set_size( GTK_PIZZA(m_parent->m_wxwindow), m_widget, x, y, width, height );
2937}
2daa0ce9 2938
1e6feb95 2939void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
c801d85f 2940{
82b978d7 2941 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
1e6feb95 2942 wxASSERT_MSG( (m_parent != NULL), wxT("wxWindowGTK::SetSize requires parent.\n") );
8bbe427f 2943
33611ebb 2944/*
f94fca1b 2945 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
33611ebb
RR
2946*/
2947
e27ce4e9 2948 if (m_resizing) return; /* I don't like recursions */
fb1585ae 2949 m_resizing = TRUE;
1e6feb95 2950
b9f29261
VS
2951 int currentX, currentY;
2952 GetPosition(&currentX, &currentY);
443c834d 2953 if (x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
b9f29261 2954 x = currentX;
443c834d 2955 if (y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
b9f29261 2956 y = currentY;
a200c35e
VS
2957 AdjustForParentClientOrigin(x, y, sizeFlags);
2958
a2053b27 2959 if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
fb1585ae 2960 {
e27ce4e9 2961 /* don't set the size for children of wxNotebook, just take the values. */
fb1585ae
RR
2962 m_x = x;
2963 m_y = y;
2964 m_width = width;
ba4e3652 2965 m_height = height;
fb1585ae 2966 }
ba4e3652 2967 else
fb1585ae 2968 {
da048e3d 2969 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
85ad5eb5 2970 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
ba4e3652 2971 {
da048e3d
RR
2972 if (x != -1) m_x = x + pizza->xoffset;
2973 if (y != -1) m_y = y + pizza->yoffset;
ba4e3652
RR
2974 }
2975 else
2976 {
da048e3d
RR
2977 m_x = x + pizza->xoffset;
2978 m_y = y + pizza->yoffset;
ba4e3652 2979 }
47d67540 2980
a63d48fa 2981 // calculate the best size if we should auto size the window
c7e111cd
VZ
2982 if ( ((sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1) ||
2983 ((sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1) )
ba4e3652 2984 {
a63d48fa 2985 const wxSize sizeBest = GetBestSize();
c7e111cd 2986 if ( (sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1 )
a63d48fa 2987 width = sizeBest.x;
c7e111cd 2988 if ( (sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1 )
a63d48fa 2989 height = sizeBest.y;
ba4e3652
RR
2990 }
2991
a63d48fa
VZ
2992 if (width != -1)
2993 m_width = width;
2994 if (height != -1)
2995 m_height = height;
8bbe427f 2996
e7dda1ff
VS
2997 int minWidth = GetMinWidth(),
2998 minHeight = GetMinHeight(),
2999 maxWidth = GetMaxWidth(),
3000 maxHeight = GetMaxHeight();
3001
3002 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
3003 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
3004 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
3005 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
47d67540 3006
a2053b27 3007 int border = 0;
c50f1fb9 3008 int bottom_border = 0;
f03fc89f 3009
eb9e6a00 3010#ifndef __WXGTK20__
29f538ce 3011 if (GTK_WIDGET_CAN_DEFAULT(m_widget))
c50f1fb9
VZ
3012 {
3013 /* the default button has a border around it */
3014 border = 6;
3015 bottom_border = 5;
3016 }
67d78217 3017#endif
c50f1fb9 3018
23efdd02
RR
3019 DoMoveWindow( m_x-border,
3020 m_y-border,
3021 m_width+2*border,
3022 m_height+border+bottom_border );
54517652 3023 }
148cd9b6 3024
5b8a521e
RR
3025 if (m_hasScrolling)
3026 {
1e6feb95 3027 /* Sometimes the client area changes size without the
b6fa52db
RR
3028 whole windows's size changing, but if the whole
3029 windows's size doesn't change, no wxSizeEvent will
3030 normally be sent. Here we add an extra test if
3031 the client test has been changed and this will
3032 be used then. */
5b8a521e
RR
3033 GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
3034 }
3035
54517652 3036/*
6d693bb4
RR
3037 wxPrintf( "OnSize sent from " );
3038 if (GetClassInfo() && GetClassInfo()->GetClassName())
3039 wxPrintf( GetClassInfo()->GetClassName() );
3040 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3041*/
3042
30760ce7
RR
3043 if (!m_nativeSizeEvent)
3044 {
3045 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
3046 event.SetEventObject( this );
3047 GetEventHandler()->ProcessEvent( event );
3048 }
6d693bb4 3049
fb1585ae 3050 m_resizing = FALSE;
362c6693 3051}
c801d85f 3052
1e6feb95 3053void wxWindowGTK::OnInternalIdle()
9390a202 3054{
beab25bd 3055 // Update invalidated regions.
010afced 3056 GtkUpdate();
0fc5dbf5 3057
beab25bd 3058 // Synthetize activate events.
148cd9b6
VZ
3059 if ( g_sendActivateEvent != -1 )
3060 {
3061 bool activate = g_sendActivateEvent != 0;
3062
3063 // do it only once
3064 g_sendActivateEvent = -1;
3065
1e6feb95 3066 wxTheApp->SetActive(activate, (wxWindow *)g_focusWindowLast);
148cd9b6
VZ
3067 }
3068
e8c12a53
VS
3069 if ( g_activeFrameLostFocus )
3070 {
3071 if ( g_activeFrame )
3072 {
45eb5249 3073 wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame);
e8c12a53
VS
3074 wxActivateEvent event(wxEVT_ACTIVATE, FALSE, g_activeFrame->GetId());
3075 event.SetEventObject(g_activeFrame);
3076 g_activeFrame->GetEventHandler()->ProcessEvent(event);
3077 g_activeFrame = NULL;
3078 }
3079 g_activeFrameLostFocus = FALSE;
3080 }
2b5f62a0 3081
9146082c
RR
3082 wxCursor cursor = m_cursor;
3083 if (g_globalCursor.Ok()) cursor = g_globalCursor;
c50f1fb9 3084
f7a11f8c 3085 if (cursor.Ok())
9146082c 3086 {
3017f78d 3087 /* I now set the cursor anew in every OnInternalIdle call
b02da6b1
VZ
3088 as setting the cursor in a parent window also effects the
3089 windows above so that checking for the current cursor is
3090 not possible. */
148cd9b6 3091
9146082c 3092 if (m_wxwindow)
6a008b33 3093 {
da048e3d 3094 GdkWindow *window = GTK_PIZZA(m_wxwindow)->bin_window;
6a008b33 3095 if (window)
c50f1fb9 3096 gdk_window_set_cursor( window, cursor.GetCursor() );
6a008b33
VZ
3097
3098 if (!g_globalCursor.Ok())
3099 cursor = *wxSTANDARD_CURSOR;
3100
3101 window = m_widget->window;
5e014a0c 3102 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
9146082c 3103 gdk_window_set_cursor( window, cursor.GetCursor() );
5e014a0c 3104
6a008b33
VZ
3105 }
3106 else
3107 {
5e014a0c 3108
9146082c 3109 GdkWindow *window = m_widget->window;
5e014a0c 3110 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
9146082c 3111 gdk_window_set_cursor( window, cursor.GetCursor() );
5e014a0c 3112
6a008b33 3113 }
9146082c 3114 }
6a008b33 3115
e39af974
JS
3116 if (wxUpdateUIEvent::CanUpdate(this))
3117 UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
9390a202
RR
3118}
3119
1e6feb95 3120void wxWindowGTK::DoGetSize( int *width, int *height ) const
c801d85f 3121{
82b978d7 3122 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3123
fb1585ae
RR
3124 if (width) (*width) = m_width;
3125 if (height) (*height) = m_height;
362c6693 3126}
c801d85f 3127
1e6feb95 3128void wxWindowGTK::DoSetClientSize( int width, int height )
c801d85f 3129{
82b978d7
RD
3130 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3131
1ecc4d80 3132 if (!m_wxwindow)
c801d85f 3133 {
1ecc4d80 3134 SetSize( width, height );
c801d85f
KB
3135 }
3136 else
3137 {
1ecc4d80
RR
3138 int dw = 0;
3139 int dh = 0;
3140
1e6feb95 3141#ifndef __WXUNIVERSAL__
98d3fdbe
RR
3142 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
3143 {
5e014a0c 3144 /* when using GTK 1.2 we set the shadow border size to 2 */
6a008b33 3145 dw += 2 * 2;
98d3fdbe
RR
3146 dh += 2 * 2;
3147 }
5e014a0c
RR
3148 if (HasFlag(wxSIMPLE_BORDER))
3149 {
3150 /* when using GTK 1.2 we set the simple border size to 1 */
3151 dw += 1 * 2;
3152 dh += 1 * 2;
3153 }
1e6feb95 3154#endif // __WXUNIVERSAL__
034be888 3155
5b8a521e 3156 if (m_hasScrolling)
98d3fdbe 3157 {
324dbfec 3158 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2daa0ce9 3159
9000c624
RR
3160 GtkRequisition vscroll_req;
3161 vscroll_req.width = 2;
3162 vscroll_req.height = 2;
dd00f3f6 3163 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
9000c624 3164 (scroll_window->vscrollbar, &vscroll_req );
2daa0ce9 3165
9000c624
RR
3166 GtkRequisition hscroll_req;
3167 hscroll_req.width = 2;
3168 hscroll_req.height = 2;
dd00f3f6 3169 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
9000c624
RR
3170 (scroll_window->hscrollbar, &hscroll_req );
3171
dd00f3f6 3172 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
324dbfec 3173
1ecc4d80
RR
3174 if (scroll_window->vscrollbar_visible)
3175 {
9000c624 3176 dw += vscroll_req.width;
1ecc4d80
RR
3177 dw += scroll_class->scrollbar_spacing;
3178 }
3179
3180 if (scroll_window->hscrollbar_visible)
3181 {
9000c624 3182 dh += hscroll_req.height;
63cc5d9d 3183 dh += scroll_class->scrollbar_spacing;
1ecc4d80 3184 }
9000c624 3185 }
1ecc4d80 3186
034be888 3187 SetSize( width+dw, height+dh );
1ecc4d80 3188 }
362c6693 3189}
c801d85f 3190
1e6feb95 3191void wxWindowGTK::DoGetClientSize( int *width, int *height ) const
c801d85f 3192{
82b978d7 3193 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3194
1ecc4d80
RR
3195 if (!m_wxwindow)
3196 {
3197 if (width) (*width) = m_width;
3198 if (height) (*height) = m_height;
c801d85f
KB
3199 }
3200 else
3201 {
1ecc4d80
RR
3202 int dw = 0;
3203 int dh = 0;
3204
1e6feb95 3205#ifndef __WXUNIVERSAL__
98d3fdbe
RR
3206 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
3207 {
5e014a0c 3208 /* when using GTK 1.2 we set the shadow border size to 2 */
6a008b33 3209 dw += 2 * 2;
98d3fdbe
RR
3210 dh += 2 * 2;
3211 }
5e014a0c
RR
3212 if (HasFlag(wxSIMPLE_BORDER))
3213 {
3214 /* when using GTK 1.2 we set the simple border size to 1 */
3215 dw += 1 * 2;
3216 dh += 1 * 2;
3217 }
1e6feb95 3218#endif // __WXUNIVERSAL__
9000c624 3219
5b8a521e 3220 if (m_hasScrolling)
98d3fdbe 3221 {
6a008b33 3222 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2daa0ce9 3223
9000c624
RR
3224 GtkRequisition vscroll_req;
3225 vscroll_req.width = 2;
3226 vscroll_req.height = 2;
dd00f3f6 3227 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
9000c624 3228 (scroll_window->vscrollbar, &vscroll_req );
2daa0ce9 3229
9000c624
RR
3230 GtkRequisition hscroll_req;
3231 hscroll_req.width = 2;
3232 hscroll_req.height = 2;
dd00f3f6 3233 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
9000c624
RR
3234 (scroll_window->hscrollbar, &hscroll_req );
3235
dd00f3f6 3236 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
6a008b33 3237
1ecc4d80
RR
3238 if (scroll_window->vscrollbar_visible)
3239 {
9000c624 3240 dw += vscroll_req.width;
1ecc4d80
RR
3241 dw += scroll_class->scrollbar_spacing;
3242 }
3243
3244 if (scroll_window->hscrollbar_visible)
3245 {
9000c624 3246 dh += hscroll_req.height;
1ecc4d80
RR
3247 dh += scroll_class->scrollbar_spacing;
3248 }
6a008b33 3249 }
47d67540 3250
1ecc4d80
RR
3251 if (width) (*width) = m_width - dw;
3252 if (height) (*height) = m_height - dh;
3253 }
1e6feb95 3254
f94fca1b
RR
3255/*
3256 printf( "GetClientSize, name %s ", GetName().c_str() );
3257 if (width) printf( " width = %d", (*width) );
3258 if (height) printf( " height = %d", (*height) );
3259 printf( "\n" );
3260*/
362c6693 3261}
c801d85f 3262
1e6feb95 3263void wxWindowGTK::DoGetPosition( int *x, int *y ) const
c801d85f 3264{
82b978d7 3265 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3266
bf0c00c6
RR
3267 int dx = 0;
3268 int dy = 0;
3269 if (m_parent && m_parent->m_wxwindow)
3270 {
da048e3d 3271 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
b02da6b1
VZ
3272 dx = pizza->xoffset;
3273 dy = pizza->yoffset;
bf0c00c6 3274 }
94633ad9 3275
496beb3f
VS
3276 if (x) (*x) = m_x - dx;
3277 if (y) (*y) = m_y - dy;
362c6693 3278}
c801d85f 3279
1e6feb95 3280void wxWindowGTK::DoClientToScreen( int *x, int *y ) const
c801d85f 3281{
82b978d7 3282 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3283
a2053b27
RR
3284 if (!m_widget->window) return;
3285
43a18898
RR
3286 GdkWindow *source = (GdkWindow *) NULL;
3287 if (m_wxwindow)
da048e3d 3288 source = GTK_PIZZA(m_wxwindow)->bin_window;
43a18898
RR
3289 else
3290 source = m_widget->window;
47d67540 3291
43a18898
RR
3292 int org_x = 0;
3293 int org_y = 0;
3294 gdk_window_get_origin( source, &org_x, &org_y );
c801d85f 3295
43a18898 3296 if (!m_wxwindow)
c801d85f 3297 {
43a18898
RR
3298 if (GTK_WIDGET_NO_WINDOW (m_widget))
3299 {
3300 org_x += m_widget->allocation.x;
3301 org_y += m_widget->allocation.y;
3302 }
362c6693 3303 }
47d67540 3304
43a18898
RR
3305 if (x) *x += org_x;
3306 if (y) *y += org_y;
362c6693 3307}
c801d85f 3308
1e6feb95 3309void wxWindowGTK::DoScreenToClient( int *x, int *y ) const
c801d85f 3310{
82b978d7 3311 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3312
a2053b27
RR
3313 if (!m_widget->window) return;
3314
1ecc4d80
RR
3315 GdkWindow *source = (GdkWindow *) NULL;
3316 if (m_wxwindow)
da048e3d 3317 source = GTK_PIZZA(m_wxwindow)->bin_window;
1ecc4d80
RR
3318 else
3319 source = m_widget->window;
47d67540 3320
1ecc4d80
RR
3321 int org_x = 0;
3322 int org_y = 0;
3323 gdk_window_get_origin( source, &org_x, &org_y );
c801d85f 3324
1ecc4d80 3325 if (!m_wxwindow)
c801d85f 3326 {
1ecc4d80
RR
3327 if (GTK_WIDGET_NO_WINDOW (m_widget))
3328 {
3329 org_x += m_widget->allocation.x;
3330 org_y += m_widget->allocation.y;
3331 }
362c6693 3332 }
47d67540 3333
1ecc4d80
RR
3334 if (x) *x -= org_x;
3335 if (y) *y -= org_y;
362c6693 3336}
c801d85f 3337
1e6feb95 3338bool wxWindowGTK::Show( bool show )
c801d85f 3339{
82b978d7 3340 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
47d67540 3341
739730ca
RR
3342 if (!wxWindowBase::Show(show))
3343 {
3344 // nothing to do
f03fc89f 3345 return FALSE;
739730ca 3346 }
8bbe427f 3347
f03fc89f
VZ
3348 if (show)
3349 gtk_widget_show( m_widget );
1ecc4d80 3350 else
f03fc89f 3351 gtk_widget_hide( m_widget );
8bbe427f 3352
2b5f62a0
VZ
3353 wxShowEvent eventShow(GetId(), show);
3354 eventShow.m_eventObject = this;
3355
3356 GetEventHandler()->ProcessEvent(eventShow);
3357
f03fc89f 3358 return TRUE;
362c6693 3359}
c801d85f 3360
3379ed37 3361static void wxWindowNotifyEnable(wxWindowGTK* win, bool enable)
fdca68a6
JS
3362{
3363 win->OnParentEnable(enable);
3364
3365 // Recurse, so that children have the opportunity to Do The Right Thing
3366 // and reset colours that have been messed up by a parent's (really ancestor's)
3367 // Enable call
222ed1d6 3368 for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
fdca68a6
JS
3369 node;
3370 node = node->GetNext() )
3371 {
3372 wxWindow *child = node->GetData();
3373 if (!child->IsKindOf(CLASSINFO(wxDialog)) && !child->IsKindOf(CLASSINFO(wxFrame)))
3374 wxWindowNotifyEnable(child, enable);
3375 }
3376}
3377
3379ed37 3378bool wxWindowGTK::Enable( bool enable )
c801d85f 3379{
82b978d7
RD
3380 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3381
739730ca
RR
3382 if (!wxWindowBase::Enable(enable))
3383 {
3384 // nothing to do
f03fc89f 3385 return FALSE;
739730ca 3386 }
1ecc4d80 3387
f03fc89f
VZ
3388 gtk_widget_set_sensitive( m_widget, enable );
3389 if ( m_wxwindow )
3390 gtk_widget_set_sensitive( m_wxwindow, enable );
ff8bfdbb 3391
fdca68a6 3392 wxWindowNotifyEnable(this, enable);
513903c4 3393
f03fc89f 3394 return TRUE;
362c6693 3395}
c801d85f 3396
1e6feb95 3397int wxWindowGTK::GetCharHeight() const
2f2aa628 3398{
82b978d7 3399 wxCHECK_MSG( (m_widget != NULL), 12, wxT("invalid window") );
47d67540 3400
cc402e64
VZ
3401 wxFont font = GetFont();
3402 wxCHECK_MSG( font.Ok(), 12, wxT("invalid font") );
2f2aa628 3403
bbd006c0
RR
3404#ifdef __WXGTK20__
3405 PangoContext *context = NULL;
3406 if (m_widget)
3407 context = gtk_widget_get_pango_context( m_widget );
3408
3409 if (!context)
3410 return 0;
3411
cc402e64 3412 PangoFontDescription *desc = font.GetNativeFontInfo()->description;
bbd006c0
RR
3413 PangoLayout *layout = pango_layout_new(context);
3414 pango_layout_set_font_description(layout, desc);
3415 pango_layout_set_text(layout, "H", 1);
3416 PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
3417
3418 PangoRectangle rect;
3419 pango_layout_line_get_extents(line, NULL, &rect);
3420
3421 g_object_unref( G_OBJECT( layout ) );
7de59551 3422
bbd006c0
RR
3423 return (int) (rect.height / PANGO_SCALE);
3424#else
cc402e64 3425 GdkFont *gfont = font.GetInternalFont( 1.0 );
f03fc89f 3426
cc402e64 3427 return gfont->ascent + gfont->descent;
bbd006c0 3428#endif
362c6693 3429}
c801d85f 3430
1e6feb95 3431int wxWindowGTK::GetCharWidth() const
c33c4050 3432{
82b978d7 3433 wxCHECK_MSG( (m_widget != NULL), 8, wxT("invalid window") );
47d67540 3434
cc402e64
VZ
3435 wxFont font = GetFont();
3436 wxCHECK_MSG( font.Ok(), 8, wxT("invalid font") );
47d67540 3437
bbd006c0
RR
3438#ifdef __WXGTK20__
3439 PangoContext *context = NULL;
3440 if (m_widget)
3441 context = gtk_widget_get_pango_context( m_widget );
3442
3443 if (!context)
3444 return 0;
3445
cc402e64 3446 PangoFontDescription *desc = font.GetNativeFontInfo()->description;
bbd006c0
RR
3447 PangoLayout *layout = pango_layout_new(context);
3448 pango_layout_set_font_description(layout, desc);
95c430aa 3449 pango_layout_set_text(layout, "g", 1);
bbd006c0
RR
3450 PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
3451
3452 PangoRectangle rect;
3453 pango_layout_line_get_extents(line, NULL, &rect);
3454
3455 g_object_unref( G_OBJECT( layout ) );
7de59551 3456
bbd006c0
RR
3457 return (int) (rect.width / PANGO_SCALE);
3458#else
cc402e64 3459 GdkFont *gfont = font.GetInternalFont( 1.0 );
ff8bfdbb 3460
cc402e64 3461 return gdk_string_width( gfont, "g" );
bbd006c0 3462#endif
c33c4050
RR
3463}
3464
1e6feb95 3465void wxWindowGTK::GetTextExtent( const wxString& string,
f03fc89f
VZ
3466 int *x,
3467 int *y,
3468 int *descent,
3469 int *externalLeading,
3470 const wxFont *theFont ) const
c33c4050 3471{
cc402e64 3472 wxFont fontToUse = theFont ? *theFont : GetFont();
47d67540 3473
223d09f6 3474 wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
2b5f62a0 3475
48d011c8
RR
3476 if (string.IsEmpty())
3477 {
b15ed747
RR
3478 if (x) (*x) = 0;
3479 if (y) (*y) = 0;
48d011c8
RR
3480 return;
3481 }
47d67540 3482
2b5f62a0 3483#ifdef __WXGTK20__
48d011c8
RR
3484 PangoContext *context = NULL;
3485 if (m_widget)
2b5f62a0
VZ
3486 context = gtk_widget_get_pango_context( m_widget );
3487
48d011c8
RR
3488 if (!context)
3489 {
b15ed747
RR
3490 if (x) (*x) = 0;
3491 if (y) (*y) = 0;
48d011c8
RR
3492 return;
3493 }
2b5f62a0 3494
48d011c8
RR
3495 PangoFontDescription *desc = fontToUse.GetNativeFontInfo()->description;
3496 PangoLayout *layout = pango_layout_new(context);
3497 pango_layout_set_font_description(layout, desc);
3498 {
fb3ed106 3499#if wxUSE_UNICODE
48d011c8
RR
3500 const wxCharBuffer data = wxConvUTF8.cWC2MB( string );
3501 pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data ));
fb3ed106
RR
3502#else
3503 const wxWCharBuffer wdata = wxConvLocal.cMB2WC( string );
3504 const wxCharBuffer data = wxConvUTF8.cWC2MB( wdata );
3505 pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data ));
3506#endif
48d011c8
RR
3507 }
3508 PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
2b5f62a0 3509
48d011c8
RR
3510 PangoRectangle rect;
3511 pango_layout_line_get_extents(line, NULL, &rect);
2b5f62a0 3512
b15ed747
RR
3513 if (x) (*x) = (wxCoord) (rect.width / PANGO_SCALE);
3514 if (y) (*y) = (wxCoord) (rect.height / PANGO_SCALE);
48d011c8
RR
3515 if (descent)
3516 {
3517 // Do something about metrics here
3518 (*descent) = 0;
3519 }
3520 if (externalLeading) (*externalLeading) = 0; // ??
2b5f62a0 3521
48d011c8
RR
3522 g_object_unref( G_OBJECT( layout ) );
3523#else
463c1fa1 3524 GdkFont *font = fontToUse.GetInternalFont( 1.0 );
fab591c5 3525 if (x) (*x) = gdk_string_width( font, wxGTK_CONV( string ) );
463c1fa1
RR
3526 if (y) (*y) = font->ascent + font->descent;
3527 if (descent) (*descent) = font->descent;
3528 if (externalLeading) (*externalLeading) = 0; // ??
48d011c8 3529#endif
c33c4050
RR
3530}
3531
1e6feb95 3532void wxWindowGTK::SetFocus()
c801d85f 3533{
82b978d7 3534 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
6cad4f1b
VZ
3535
3536 if ( m_hasFocus )
3537 {
3538 // don't do anything if we already have focus
3539 return;
3540 }
2daa0ce9 3541
354aa1e3
RR
3542 if (m_wxwindow)
3543 {
173348db 3544 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
b231914f 3545 {
173348db 3546 gtk_widget_grab_focus (m_wxwindow);
b231914f 3547 }
354aa1e3 3548 }
b231914f 3549 else if (m_widget)
c801d85f 3550 {
173348db 3551 if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
463c1fa1 3552 {
d7fa7eaa 3553 if (!GTK_WIDGET_REALIZED(m_widget))
6aeb6f2a 3554 {
6cad4f1b
VZ
3555 // we can't set the focus to the widget now so we remember that
3556 // it should be focused and will do it later, during the idle
3557 // time, as soon as we can
3558 wxLogTrace(TRACE_FOCUS,
3559 _T("Delaying setting focus to %s(%s)"),
6aeb6f2a
VZ
3560 GetClassInfo()->GetClassName(), GetLabel().c_str());
3561
d7fa7eaa 3562 g_delayedFocus = this;
6aeb6f2a 3563 }
d7fa7eaa 3564 else
6aeb6f2a 3565 {
6cad4f1b
VZ
3566 wxLogTrace(TRACE_FOCUS,
3567 _T("Setting focus to %s(%s)"),
6aeb6f2a
VZ
3568 GetClassInfo()->GetClassName(), GetLabel().c_str());
3569
d7fa7eaa 3570 gtk_widget_grab_focus (m_widget);
6aeb6f2a 3571 }
463c1fa1 3572 }
354aa1e3 3573 else if (GTK_IS_CONTAINER(m_widget))
ff8bfdbb 3574 {
9e691f46 3575 SET_CONTAINER_FOCUS( m_widget, GTK_DIR_TAB_FORWARD );
ff8bfdbb
VZ
3576 }
3577 else
3578 {
6cad4f1b
VZ
3579 wxLogTrace(TRACE_FOCUS,
3580 _T("Can't set focus to %s(%s)"),
3581 GetClassInfo()->GetClassName(), GetLabel().c_str());
ff8bfdbb 3582 }
362c6693 3583 }
362c6693 3584}
c801d85f 3585
1e6feb95 3586bool wxWindowGTK::AcceptsFocus() const
b292e2f5 3587{
f03fc89f 3588 return m_acceptsFocus && wxWindowBase::AcceptsFocus();
b292e2f5
RR
3589}
3590
1e6feb95 3591bool wxWindowGTK::Reparent( wxWindowBase *newParentBase )
463c1fa1 3592{
82b978d7 3593 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
c50f1fb9 3594
1e6feb95
VZ
3595 wxWindowGTK *oldParent = m_parent,
3596 *newParent = (wxWindowGTK *)newParentBase;
a2053b27 3597
5fd11f09
RR
3598 wxASSERT( GTK_IS_WIDGET(m_widget) );
3599
f03fc89f
VZ
3600 if ( !wxWindowBase::Reparent(newParent) )
3601 return FALSE;
8bbe427f 3602
5fd11f09
RR
3603 wxASSERT( GTK_IS_WIDGET(m_widget) );
3604
3605 /* prevent GTK from deleting the widget arbitrarily */
3606 gtk_widget_ref( m_widget );
3607
8ce63e9d
RR
3608 if (oldParent)
3609 {
3017f78d 3610 gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget );
8ce63e9d 3611 }
c50f1fb9 3612
5fd11f09
RR
3613 wxASSERT( GTK_IS_WIDGET(m_widget) );
3614
8ce63e9d
RR
3615 if (newParent)
3616 {
3617 /* insert GTK representation */
3618 (*(newParent->m_insertCallback))(newParent, this);
3619 }
c50f1fb9 3620
5fd11f09
RR
3621 /* reverse: prevent GTK from deleting the widget arbitrarily */
3622 gtk_widget_unref( m_widget );
148cd9b6 3623
f03fc89f 3624 return TRUE;
362c6693 3625}
c801d85f 3626
1e6feb95 3627void wxWindowGTK::DoAddChild(wxWindowGTK *child)
ddb6bc71 3628{
223d09f6 3629 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
ddb6bc71 3630
223d09f6 3631 wxASSERT_MSG( (child != NULL), wxT("invalid child window") );
ddb6bc71 3632
223d09f6 3633 wxASSERT_MSG( (m_insertCallback != NULL), wxT("invalid child insertion function") );
c50f1fb9 3634
ddb6bc71
RR
3635 /* add to list */
3636 AddChild( child );
c50f1fb9 3637
ddb6bc71
RR
3638 /* insert GTK representation */
3639 (*m_insertCallback)(this, child);
3640}
3641
1e6feb95 3642void wxWindowGTK::Raise()
362c6693 3643{
82b978d7
RD
3644 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3645
a2053b27
RR
3646 if (!m_widget->window) return;
3647
f03fc89f 3648 gdk_window_raise( m_widget->window );
362c6693
RR
3649}
3650
1e6feb95 3651void wxWindowGTK::Lower()
362c6693 3652{
82b978d7
RD
3653 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3654
a2053b27
RR
3655 if (!m_widget->window) return;
3656
f03fc89f 3657 gdk_window_lower( m_widget->window );
362c6693 3658}
c801d85f 3659
1e6feb95 3660bool wxWindowGTK::SetCursor( const wxCursor &cursor )
86b29a61 3661{
82b978d7 3662 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
86b29a61 3663
f6bcfd97
BP
3664 if (cursor == m_cursor)
3665 return FALSE;
3666
3667 if (g_isIdle)
3668 wxapp_install_idle_handler();
1e6feb95 3669
f6bcfd97
BP
3670 if (cursor == wxNullCursor)
3671 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR );
3672 else
3673 return wxWindowBase::SetCursor( cursor );
362c6693 3674}
c801d85f 3675
1e6feb95 3676void wxWindowGTK::WarpPointer( int x, int y )
4f22cf8d 3677{
82b978d7
RD
3678 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3679
3bcc8d15
RR
3680 // We provide this function ourselves as it is
3681 // missing in GDK (top of this file).
148cd9b6 3682
ed673c6a
RR
3683 GdkWindow *window = (GdkWindow*) NULL;
3684 if (m_wxwindow)
da048e3d 3685 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a
RR
3686 else
3687 window = GetConnectWidget()->window;
148cd9b6 3688
ed673c6a
RR
3689 if (window)
3690 gdk_window_warp_pointer( window, x, y );
4f22cf8d
RR
3691}
3692
3013a903 3693
1e6feb95 3694void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
c801d85f 3695{
f2593d0d 3696 if (!m_widget) return;
a2053b27 3697 if (!m_widget->window) return;
2b5f62a0 3698
4e5a4c69 3699#ifndef __WXGTK20__
ea323db3
RR
3700 if (g_isIdle)
3701 wxapp_install_idle_handler();
2b5f62a0 3702
75625d79
SN
3703 wxRect myRect(0,0,0,0);
3704 if (m_wxwindow && rect)
3705 {
3706 myRect.SetSize(wxSize( m_wxwindow->allocation.width,
3707 m_wxwindow->allocation.height));
3708 myRect.Intersect(*rect);
3709 if (!myRect.width || !myRect.height)
3710 // nothing to do, rectangle is empty
3711 return;
3712 rect = &myRect;
3713 }
3714
139adb6a 3715 if (eraseBackground && m_wxwindow && m_wxwindow->window)
c801d85f 3716 {
139adb6a
RR
3717 if (rect)
3718 {
3bcc8d15
RR
3719 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3720 m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height );
139adb6a
RR
3721 }
3722 else
3723 {
3bcc8d15
RR
3724 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3725 m_clearRegion.Clear();
3726 m_clearRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
139adb6a
RR
3727 }
3728 }
ff8bfdbb 3729
3bcc8d15 3730 if (rect)
139adb6a
RR
3731 {
3732 if (m_wxwindow)
b02da6b1 3733 {
23716407 3734 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3bcc8d15 3735 m_updateRegion.Union( rect->x, rect->y, rect->width, rect->height );
b02da6b1 3736 }
ff8bfdbb 3737 else
b6fa52db 3738 {
3bcc8d15
RR
3739 GdkRectangle gdk_rect;
3740 gdk_rect.x = rect->x;
3741 gdk_rect.y = rect->y;
3742 gdk_rect.width = rect->width;
3743 gdk_rect.height = rect->height;
3744 gtk_widget_draw( m_widget, &gdk_rect );
b6fa52db 3745 }
362c6693 3746 }
c801d85f 3747 else
139adb6a 3748 {
139adb6a 3749 if (m_wxwindow)
b02da6b1 3750 {
23716407 3751 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3bcc8d15
RR
3752 m_updateRegion.Clear();
3753 m_updateRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
b02da6b1 3754 }
139adb6a 3755 else
b6fa52db 3756 {
3bcc8d15 3757 gtk_widget_draw( m_widget, (GdkRectangle*) NULL );
b6fa52db 3758 }
139adb6a 3759 }
4e5a4c69
RR
3760#else
3761 if (m_wxwindow)
3762 {
3763 if (rect)
3764 {
3765 GdkRectangle gdk_rect;
3766 gdk_rect.x = rect->x;
3767 gdk_rect.y = rect->y;
3768 gdk_rect.width = rect->width;
3769 gdk_rect.height = rect->height;
3770 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow)->bin_window, &gdk_rect, TRUE );
3771 }
3772 else
3773 {
3774 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow)->bin_window, NULL, TRUE );
3775 }
3776 }
3777#endif
362c6693 3778}
c801d85f 3779
beab25bd 3780void wxWindowGTK::Update()
010afced
RR
3781{
3782 GtkUpdate();
3783}
3784
3785void wxWindowGTK::GtkUpdate()
beab25bd 3786{
4e5a4c69
RR
3787#ifdef __WXGTK20__
3788 if (m_wxwindow && GTK_PIZZA(m_wxwindow)->bin_window)
3789 gdk_window_process_updates( GTK_PIZZA(m_wxwindow)->bin_window, FALSE );
b15ed747 3790#else
beab25bd 3791 if (!m_updateRegion.IsEmpty())
23716407 3792 GtkSendPaintEvents();
b15ed747 3793#endif
beab25bd
RR
3794}
3795
3796void wxWindowGTK::GtkSendPaintEvents()
3797{
3bcc8d15
RR
3798 if (!m_wxwindow)
3799 {
2b5f62a0 3800#ifndef __WXGTK20__
3bcc8d15 3801 m_clearRegion.Clear();
b15ed747 3802#endif
3bcc8d15
RR
3803 m_updateRegion.Clear();
3804 return;
3805 }
beab25bd 3806
f90566f5 3807 // Clip to paint region in wxClientDC
3bcc8d15 3808 m_clipPaintRegion = TRUE;
fab591c5 3809
b15ed747
RR
3810 // widget to draw on
3811 GtkPizza *pizza = GTK_PIZZA (m_wxwindow);
2b5f62a0 3812
f90566f5
RR
3813 if (GetThemeEnabled())
3814 {
3815 // find ancestor from which to steal background
3816 wxWindow *parent = GetParent();
3817 while (parent && !parent->IsTopLevel())
3818 parent = parent->GetParent();
3819 if (!parent)
cc06fe74 3820 parent = (wxWindow*)this;
2b5f62a0 3821
f90566f5
RR
3822 wxRegionIterator upd( m_updateRegion );
3823 while (upd)
3824 {
3825 GdkRectangle rect;
3826 rect.x = upd.GetX();
3827 rect.y = upd.GetY();
3828 rect.width = upd.GetWidth();
3829 rect.height = upd.GetHeight();
2b5f62a0 3830
f90566f5
RR
3831 gtk_paint_flat_box( parent->m_widget->style,
3832 pizza->bin_window,
90b85bfc 3833 (GtkStateType)GTK_WIDGET_STATE(m_wxwindow),
f90566f5
RR
3834 GTK_SHADOW_NONE,
3835 &rect,
3836 parent->m_widget,
3837 (char *)"base",
3838 0, 0, -1, -1 );
2b5f62a0 3839
f90566f5
RR
3840 upd ++;
3841 }
3842 }
3843 else
b15ed747
RR
3844
3845#ifdef __WXGTK20__
3846 {
3847 wxWindowDC dc( (wxWindow*)this );
3848 dc.SetClippingRegion( m_updateRegion );
3849
3850 wxEraseEvent erase_event( GetId(), &dc );
3851 erase_event.SetEventObject( this );
3852
3853 GetEventHandler()->ProcessEvent(erase_event);
3854 }
3855#else
3856 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
beab25bd 3857 {
3bcc8d15 3858 wxWindowDC dc( (wxWindow*)this );
62cb3cd8
RR
3859 if (m_clearRegion.IsEmpty())
3860 dc.SetClippingRegion( m_updateRegion );
3861 else
3862 dc.SetClippingRegion( m_clearRegion );
0fc5dbf5 3863
3bcc8d15
RR
3864 wxEraseEvent erase_event( GetId(), &dc );
3865 erase_event.SetEventObject( this );
0fc5dbf5 3866
beab25bd
RR
3867 if (!GetEventHandler()->ProcessEvent(erase_event))
3868 {
994bc575
RR
3869 if (!g_eraseGC)
3870 {
f90566f5 3871 g_eraseGC = gdk_gc_new( pizza->bin_window );
994bc575
RR
3872 gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
3873 }
1cd3409d 3874 gdk_gc_set_foreground( g_eraseGC, GetBackgroundColour().GetColor() );
0fc5dbf5 3875
3bcc8d15 3876 wxRegionIterator upd( m_clearRegion );
beab25bd
RR
3877 while (upd)
3878 {
f90566f5
RR
3879 gdk_draw_rectangle( pizza->bin_window, g_eraseGC, 1,
3880 upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
beab25bd
RR
3881 upd ++;
3882 }
3883 }
3bcc8d15 3884 m_clearRegion.Clear();
beab25bd 3885 }
b15ed747 3886#endif
beab25bd
RR
3887
3888 wxNcPaintEvent nc_paint_event( GetId() );
3889 nc_paint_event.SetEventObject( this );
3890 GetEventHandler()->ProcessEvent( nc_paint_event );
3891
3892 wxPaintEvent paint_event( GetId() );
3893 paint_event.SetEventObject( this );
3894 GetEventHandler()->ProcessEvent( paint_event );
3895
beab25bd 3896 m_clipPaintRegion = FALSE;
c89f5c02 3897
8f3e7ecc 3898#ifndef __WXUNIVERSAL__
4e5a4c69 3899#ifndef __WXGTK20__
8f3e7ecc 3900 // The following code will result in all window-less widgets
77ffb593 3901 // being redrawn because the wxWidgets class is allowed to
8f3e7ecc 3902 // paint over the window-less widgets.
0fc5dbf5 3903
8f3e7ecc
RR
3904 GList *children = pizza->children;
3905 while (children)
c89f5c02 3906 {
8f3e7ecc
RR
3907 GtkPizzaChild *child = (GtkPizzaChild*) children->data;
3908 children = children->next;
2b5f62a0 3909
8f3e7ecc
RR
3910 if (GTK_WIDGET_NO_WINDOW (child->widget) &&
3911 GTK_WIDGET_DRAWABLE (child->widget))
3912 {
3913 // Get intersection of widget area and update region
3914 wxRegion region( m_updateRegion );
0fc5dbf5 3915
8f3e7ecc
RR
3916 GdkEventExpose gdk_event;
3917 gdk_event.type = GDK_EXPOSE;
3918 gdk_event.window = pizza->bin_window;
3919 gdk_event.count = 0;
0fc5dbf5 3920
8f3e7ecc
RR
3921 wxRegionIterator upd( m_updateRegion );
3922 while (upd)
c89f5c02 3923 {
8f3e7ecc
RR
3924 GdkRectangle rect;
3925 rect.x = upd.GetX();
3926 rect.y = upd.GetY();
3927 rect.width = upd.GetWidth();
3928 rect.height = upd.GetHeight();
0fc5dbf5 3929
8f3e7ecc
RR
3930 if (gtk_widget_intersect (child->widget, &rect, &gdk_event.area))
3931 {
3932 gtk_widget_event (child->widget, (GdkEvent*) &gdk_event);
3933 }
0fc5dbf5 3934
8f3e7ecc 3935 upd ++;
c89f5c02
RR
3936 }
3937 }
3938 }
4e5a4c69 3939#endif
8f3e7ecc 3940#endif
c89f5c02
RR
3941
3942 m_updateRegion.Clear();
beab25bd
RR
3943}
3944
596f1d11 3945void wxWindowGTK::ClearBackground()
c801d85f 3946{
82b978d7
RD
3947 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3948
b15ed747 3949#ifndef __WXGTK20__
f234c60c
RR
3950 if (m_wxwindow && m_wxwindow->window)
3951 {
d7fa7eaa
RR
3952 m_clearRegion.Clear();
3953 wxSize size( GetClientSize() );
3954 m_clearRegion.Union( 0,0,size.x,size.y );
2b5f62a0 3955
d7fa7eaa 3956 // Better do this in idle?
010afced 3957 GtkUpdate();
f234c60c 3958 }
b15ed747 3959#endif
362c6693 3960}
c801d85f 3961
ff8bfdbb 3962#if wxUSE_TOOLTIPS
1e6feb95 3963void wxWindowGTK::DoSetToolTip( wxToolTip *tip )
b1170810 3964{
f03fc89f 3965 wxWindowBase::DoSetToolTip(tip);
ff8bfdbb 3966
f03fc89f 3967 if (m_tooltip)
3379ed37 3968 m_tooltip->Apply( (wxWindow *)this );
b1170810
RR
3969}
3970
1e6feb95 3971void wxWindowGTK::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
b1170810 3972{
aa154cb1
RR
3973 wxString tmp( tip );
3974 gtk_tooltips_set_tip( tips, GetConnectWidget(), wxGTK_CONV(tmp), (gchar*) NULL );
301cd871 3975}
ff8bfdbb 3976#endif // wxUSE_TOOLTIPS
b1170810 3977
ea323db3
RR
3978void wxWindowGTK::GtkSetBackgroundColour( const wxColour &colour )
3979{
3980 GdkWindow *window = (GdkWindow*) NULL;
3981 if (m_wxwindow)
3982 window = GTK_PIZZA(m_wxwindow)->bin_window;
3983 else
3984 window = GetConnectWidget()->window;
3985
3986 wxASSERT( window );
2b5f62a0 3987
ea323db3
RR
3988 // We need the pixel value e.g. for background clearing.
3989 m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
2b5f62a0 3990
f90566f5 3991 if (m_wxwindow)
ea323db3 3992 {
f90566f5 3993 // wxMSW doesn't clear the window here, either.
ea323db3
RR
3994 gdk_window_set_background( window, m_backgroundColour.GetColor() );
3995 }
3996
3997 ApplyWidgetStyle();
3998}
3999
1e6feb95 4000bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
c801d85f 4001{
82b978d7 4002 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
8bbe427f 4003
739730ca 4004 if (!wxWindowBase::SetBackgroundColour(colour))
ea323db3 4005 return FALSE;
c50f1fb9 4006
ed673c6a
RR
4007 GdkWindow *window = (GdkWindow*) NULL;
4008 if (m_wxwindow)
da048e3d 4009 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a
RR
4010 else
4011 window = GetConnectWidget()->window;
148cd9b6 4012
ed673c6a 4013 if (!window)
739730ca
RR
4014 {
4015 // indicate that a new style has been set
c50f1fb9
VZ
4016 // but it couldn't get applied as the
4017 // widget hasn't been realized yet.
4018 m_delayedBackgroundColour = TRUE;
ea323db3 4019 return TRUE;
739730ca 4020 }
ea323db3 4021 else
994bc575 4022 {
ea323db3 4023 GtkSetBackgroundColour( colour );
994bc575 4024 }
ca298c88 4025
ea323db3
RR
4026 return TRUE;
4027}
8bbe427f 4028
ea323db3
RR
4029void wxWindowGTK::GtkSetForegroundColour( const wxColour &colour )
4030{
4031 GdkWindow *window = (GdkWindow*) NULL;
4032 if (m_wxwindow)
4033 window = GTK_PIZZA(m_wxwindow)->bin_window;
4034 else
4035 window = GetConnectWidget()->window;
c801d85f 4036
ea323db3
RR
4037 wxASSERT( window );
4038
4039 ApplyWidgetStyle();
6de97a3b
RR
4040}
4041
1e6feb95 4042bool wxWindowGTK::SetForegroundColour( const wxColour &colour )
6de97a3b 4043{
82b978d7 4044 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
8bbe427f 4045
739730ca
RR
4046 if (!wxWindowBase::SetForegroundColour(colour))
4047 {
4048 // don't leave if the GTK widget has just
4049 // been realized
4050 if (!m_delayedForegroundColour) return FALSE;
4051 }
c50f1fb9 4052
ed673c6a
RR
4053 GdkWindow *window = (GdkWindow*) NULL;
4054 if (m_wxwindow)
da048e3d 4055 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a
RR
4056 else
4057 window = GetConnectWidget()->window;
148cd9b6 4058
ed673c6a 4059 if (!window)
739730ca
RR
4060 {
4061 // indicate that a new style has been set
c50f1fb9
VZ
4062 // but it couldn't get applied as the
4063 // widget hasn't been realized yet.
4064 m_delayedForegroundColour = TRUE;
739730ca 4065 }
ea323db3
RR
4066 else
4067 {
4068 GtkSetForegroundColour( colour );
4069 }
f03fc89f
VZ
4070
4071 return TRUE;
58614078
RR
4072}
4073
2b5f62a0
VZ
4074#ifdef __WXGTK20__
4075PangoContext *wxWindowGTK::GtkGetPangoDefaultContext()
4076{
4077 return gtk_widget_get_pango_context( m_widget );
4078}
4079
4080PangoContext *wxWindowGTK::GtkGetPangoX11Context()
4081{
4082 if (!m_x11Context)
4083 m_x11Context = pango_x_get_context( gdk_display );
4084
4085 return m_x11Context;
4086}
4087#endif
f40fdaa3
VS
4088
4089GtkRcStyle *wxWindowGTK::CreateWidgetStyle()
58614078 4090{
f40fdaa3
VS
4091 // do we need to apply any changes at all?
4092 if ( !m_hasFont && !m_hasFgCol &&
4093 (!m_hasBgCol || !m_backgroundColour.Ok()) )
fb65642c 4094 {
f40fdaa3 4095 return NULL;
fb65642c
RR
4096 }
4097
f40fdaa3 4098 GtkRcStyle *style = gtk_rc_style_new();
1ecc4d80 4099
40452e05 4100 if ( m_hasFont )
db434467 4101 {
288059b2 4102#ifdef __WXGTK20__
f40fdaa3
VS
4103 style->font_desc =
4104 pango_font_description_copy( m_font.GetNativeFontInfo()->description );
288059b2 4105#else
f40fdaa3
VS
4106 wxString xfontname = m_font.GetNativeFontInfo()->GetXFontName();
4107 style->fontset_name = g_strdup(xfontname.c_str());
cfcc3932 4108#endif
288059b2 4109 }
1ecc4d80 4110
40452e05 4111 if ( m_hasFgCol )
1ecc4d80 4112 {
454e2a22 4113 m_foregroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
f40fdaa3
VS
4114
4115 style->fg[GTK_STATE_NORMAL] = *m_foregroundColour.GetColor();
4116 style->color_flags[GTK_STATE_NORMAL] = GTK_RC_FG;
4117
4118 style->fg[GTK_STATE_PRELIGHT] = *m_foregroundColour.GetColor();
4119 style->color_flags[GTK_STATE_PRELIGHT] = GTK_RC_FG;
4120
4121 style->fg[GTK_STATE_ACTIVE] = *m_foregroundColour.GetColor();
4122 style->color_flags[GTK_STATE_ACTIVE] = GTK_RC_FG;
1ecc4d80
RR
4123 }
4124
57fbd435 4125 if ( m_hasBgCol && m_backgroundColour.Ok() )
1ecc4d80 4126 {
454e2a22 4127 m_backgroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
f40fdaa3
VS
4128
4129 style->bg[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
4130 style->base[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
4131 style->color_flags[GTK_STATE_NORMAL] = (GtkRcFlags)
4132 (style->color_flags[GTK_STATE_NORMAL] | GTK_RC_BG | GTK_RC_BASE);
4133
4134 style->bg[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
4135 style->base[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
4136 style->color_flags[GTK_STATE_PRELIGHT] = (GtkRcFlags)
4137 (style->color_flags[GTK_STATE_PRELIGHT] | GTK_RC_BG | GTK_RC_BASE);
4138
4139 style->bg[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
4140 style->base[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
4141 style->color_flags[GTK_STATE_ACTIVE] = (GtkRcFlags)
4142 (style->color_flags[GTK_STATE_ACTIVE] | GTK_RC_BG | GTK_RC_BASE);
4143
4144 style->bg[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
4145 style->base[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
4146 style->color_flags[GTK_STATE_INSENSITIVE] = (GtkRcFlags)
4147 (style->color_flags[GTK_STATE_INSENSITIVE] | GTK_RC_BG | GTK_RC_BASE);
1ecc4d80 4148 }
f40fdaa3
VS
4149
4150 return style;
a81258be
RR
4151}
4152
1e6feb95 4153void wxWindowGTK::ApplyWidgetStyle()
a81258be 4154{
6de97a3b
RR
4155}
4156
2259e007
RR
4157//-----------------------------------------------------------------------------
4158// Pop-up menu stuff
4159//-----------------------------------------------------------------------------
4160
6522713c 4161#if wxUSE_MENUS_NATIVE
1e6feb95 4162
90350682
VZ
4163extern "C"
4164void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting )
2259e007
RR
4165{
4166 *is_waiting = FALSE;
4167}
4168
1e6feb95 4169static void SetInvokingWindow( wxMenu *menu, wxWindowGTK *win )
30dea054 4170{
1ecc4d80 4171 menu->SetInvokingWindow( win );
222ed1d6 4172 wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst();
1ecc4d80
RR
4173 while (node)
4174 {
1987af7e 4175 wxMenuItem *menuitem = node->GetData();
1ecc4d80
RR
4176 if (menuitem->IsSubMenu())
4177 {
ff8bfdbb
VZ
4178 SetInvokingWindow( menuitem->GetSubMenu(), win );
4179 }
1987af7e
VZ
4180
4181 node = node->GetNext();
1ecc4d80 4182 }
362c6693 4183}
30dea054 4184
295272bd
VZ
4185extern "C" void wxPopupMenuPositionCallback( GtkMenu *menu,
4186 gint *x, gint *y,
9e691f46
VZ
4187#ifdef __WXGTK20__
4188 gboolean * WXUNUSED(whatever),
4189#endif
39b44a39 4190 gpointer user_data )
0c77152e 4191{
e3473203
VZ
4192 // ensure that the menu appears entirely on screen
4193 GtkRequisition req;
4194 gtk_widget_get_child_requisition(GTK_WIDGET(menu), &req);
4195
4196 wxSize sizeScreen = wxGetDisplaySize();
39b44a39 4197 wxPoint *pos = (wxPoint*)user_data;
e3473203
VZ
4198
4199 gint xmax = sizeScreen.x - req.width,
4200 ymax = sizeScreen.y - req.height;
4201
39b44a39
VS
4202 *x = pos->x < xmax ? pos->x : xmax;
4203 *y = pos->y < ymax ? pos->y : ymax;
0c77152e
RR
4204}
4205
1e6feb95 4206bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
30dea054 4207{
971562cb 4208 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
47d67540 4209
971562cb 4210 wxCHECK_MSG( menu != NULL, false, wxT("invalid popup-menu") );
8bbe427f 4211
1ecc4d80 4212 SetInvokingWindow( menu, this );
ff8bfdbb 4213
631f1bfe
JS
4214 menu->UpdateUI();
4215
971562cb 4216 bool is_waiting = true;
148cd9b6 4217
90350682
VZ
4218 gtk_signal_connect( GTK_OBJECT(menu->m_menu),
4219 "hide",
4220 GTK_SIGNAL_FUNC(gtk_pop_hide_callback),
4221 (gpointer)&is_waiting );
2259e007 4222
971562cb
VS
4223 wxPoint pos;
4224 gpointer userdata;
4225 GtkMenuPositionFunc posfunc;
4226 if ( x == -1 && y == -1 )
4227 {
4228 // use GTK's default positioning algorithm
4229 userdata = NULL;
4230 posfunc = NULL;
4231 }
4232 else
4233 {
4234 pos = ClientToScreen(wxPoint(x, y));
4235 userdata = &pos;
4236 posfunc = wxPopupMenuPositionCallback;
4237 }
4238
1ecc4d80 4239 gtk_menu_popup(
47d67540 4240 GTK_MENU(menu->m_menu),
e3473203
VZ
4241 (GtkWidget *) NULL, // parent menu shell
4242 (GtkWidget *) NULL, // parent menu item
971562cb
VS
4243 posfunc, // function to position it
4244 userdata, // client data
4245 0, // button used to activate it
34791896
RR
4246#ifdef __WXGTK20__
4247 gtk_get_current_event_time()
4248#else
34adc954 4249 gs_timeLastClick // the time of activation
34791896 4250#endif
47d67540 4251 );
148cd9b6 4252
956dbab1
RR
4253 while (is_waiting)
4254 {
a03cac3f 4255 gtk_main_iteration();
956dbab1 4256 }
2259e007 4257
971562cb 4258 return true;
30dea054
RR
4259}
4260
6522713c 4261#endif // wxUSE_MENUS_NATIVE
1e6feb95 4262
06cfab17 4263#if wxUSE_DRAG_AND_DROP
ac57418f 4264
1e6feb95 4265void wxWindowGTK::SetDropTarget( wxDropTarget *dropTarget )
c801d85f 4266{
82b978d7
RD
4267 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4268
1ecc4d80 4269 GtkWidget *dnd_widget = GetConnectWidget();
47d67540 4270
1ecc4d80 4271 if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
47d67540 4272
1ecc4d80
RR
4273 if (m_dropTarget) delete m_dropTarget;
4274 m_dropTarget = dropTarget;
47d67540 4275
1ecc4d80 4276 if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
362c6693 4277}
c801d85f 4278
f03fc89f 4279#endif // wxUSE_DRAG_AND_DROP
ac57418f 4280
1e6feb95 4281GtkWidget* wxWindowGTK::GetConnectWidget()
e3e65dac 4282{
1ecc4d80
RR
4283 GtkWidget *connect_widget = m_widget;
4284 if (m_wxwindow) connect_widget = m_wxwindow;
47d67540 4285
1ecc4d80 4286 return connect_widget;
e3e65dac 4287}
47d67540 4288
1e6feb95 4289bool wxWindowGTK::IsOwnGtkWindow( GdkWindow *window )
903f689b 4290{
148cd9b6 4291 if (m_wxwindow)
da048e3d 4292 return (window == GTK_PIZZA(m_wxwindow)->bin_window);
148cd9b6 4293
1ecc4d80 4294 return (window == m_widget->window);
903f689b
RR
4295}
4296
1e6feb95 4297bool wxWindowGTK::SetFont( const wxFont &font )
c801d85f 4298{
133fb2a3 4299 if (!wxWindowBase::SetFont(font) || !m_widget)
739730ca 4300 {
454e2a22 4301 return FALSE;
739730ca 4302 }
9c288e4d 4303
a756f210 4304 wxColour sysbg = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
f03fc89f 4305 if ( sysbg == m_backgroundColour )
ae0bdb01
RR
4306 {
4307 m_backgroundColour = wxNullColour;
4308 ApplyWidgetStyle();
ff8bfdbb
VZ
4309 m_backgroundColour = sysbg;
4310 }
ae0bdb01
RR
4311 else
4312 {
4313 ApplyWidgetStyle();
4314 }
c801d85f 4315
f03fc89f 4316 return TRUE;
362c6693 4317}
c801d85f 4318
94633ad9 4319void wxWindowGTK::DoCaptureMouse()
c801d85f 4320{
82b978d7
RD
4321 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4322
ed673c6a 4323 GdkWindow *window = (GdkWindow*) NULL;
b231914f
VZ
4324 if (m_wxwindow)
4325 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a 4326 else
b231914f 4327 window = GetConnectWidget()->window;
148cd9b6 4328
e4606ed9 4329 wxCHECK_RET( window, _T("CaptureMouse() failed") );
c50f1fb9 4330
b231914f 4331 wxCursor* cursor = & m_cursor;
cca602ac
JS
4332 if (!cursor->Ok())
4333 cursor = wxSTANDARD_CURSOR;
4334
ed673c6a 4335 gdk_pointer_grab( window, FALSE,
1ecc4d80
RR
4336 (GdkEventMask)
4337 (GDK_BUTTON_PRESS_MASK |
4338 GDK_BUTTON_RELEASE_MASK |
148cd9b6 4339 GDK_POINTER_MOTION_HINT_MASK |
1ecc4d80 4340 GDK_POINTER_MOTION_MASK),
ff8bfdbb 4341 (GdkWindow *) NULL,
cca602ac 4342 cursor->GetCursor(),
b02da6b1 4343 (guint32)GDK_CURRENT_TIME );
b231914f 4344 g_captureWindow = this;
1e6feb95 4345 g_captureWindowHasMouse = TRUE;
362c6693 4346}
c801d85f 4347
94633ad9 4348void wxWindowGTK::DoReleaseMouse()
c801d85f 4349{
82b978d7
RD
4350 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4351
e4606ed9 4352 wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") );
47d67540 4353
c43430bb
VS
4354 g_captureWindow = (wxWindowGTK*) NULL;
4355
ed673c6a 4356 GdkWindow *window = (GdkWindow*) NULL;
b231914f
VZ
4357 if (m_wxwindow)
4358 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a 4359 else
b231914f 4360 window = GetConnectWidget()->window;
148cd9b6 4361
b02da6b1
VZ
4362 if (!window)
4363 return;
c50f1fb9 4364
b02da6b1 4365 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
362c6693 4366}
c801d85f 4367
1e6feb95
VZ
4368/* static */
4369wxWindow *wxWindowBase::GetCapture()
4370{
4371 return (wxWindow *)g_captureWindow;
4372}
4373
4374bool wxWindowGTK::IsRetained() const
c801d85f 4375{
1ecc4d80 4376 return FALSE;
362c6693 4377}
c801d85f 4378
1e6feb95 4379void wxWindowGTK::SetScrollbar( int orient, int pos, int thumbVisible,
cb43b372 4380 int range, bool refresh )
c801d85f 4381{
82b978d7
RD
4382 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4383
223d09f6 4384 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
c801d85f 4385
1ecc4d80 4386 m_hasScrolling = TRUE;
47d67540 4387
1ecc4d80 4388 if (orient == wxHORIZONTAL)
cb43b372 4389 {
1ecc4d80
RR
4390 float fpos = (float)pos;
4391 float frange = (float)range;
4392 float fthumb = (float)thumbVisible;
4393 if (fpos > frange-fthumb) fpos = frange-fthumb;
4394 if (fpos < 0.0) fpos = 0.0;
4395
4396 if ((fabs(frange-m_hAdjust->upper) < 0.2) &&
4397 (fabs(fthumb-m_hAdjust->page_size) < 0.2))
4398 {
4399 SetScrollPos( orient, pos, refresh );
4400 return;
4401 }
47d67540 4402
1ecc4d80 4403 m_oldHorizontalPos = fpos;
47d67540 4404
1ecc4d80
RR
4405 m_hAdjust->lower = 0.0;
4406 m_hAdjust->upper = frange;
4407 m_hAdjust->value = fpos;
4408 m_hAdjust->step_increment = 1.0;
4409 m_hAdjust->page_increment = (float)(wxMax(fthumb,0));
4410 m_hAdjust->page_size = fthumb;
cb43b372 4411 }
1ecc4d80
RR
4412 else
4413 {
4414 float fpos = (float)pos;
4415 float frange = (float)range;
4416 float fthumb = (float)thumbVisible;
4417 if (fpos > frange-fthumb) fpos = frange-fthumb;
4418 if (fpos < 0.0) fpos = 0.0;
4419
4420 if ((fabs(frange-m_vAdjust->upper) < 0.2) &&
4421 (fabs(fthumb-m_vAdjust->page_size) < 0.2))
4422 {
4423 SetScrollPos( orient, pos, refresh );
4424 return;
4425 }
47d67540 4426
1ecc4d80 4427 m_oldVerticalPos = fpos;
47d67540 4428
1ecc4d80
RR
4429 m_vAdjust->lower = 0.0;
4430 m_vAdjust->upper = frange;
4431 m_vAdjust->value = fpos;
4432 m_vAdjust->step_increment = 1.0;
4433 m_vAdjust->page_increment = (float)(wxMax(fthumb,0));
4434 m_vAdjust->page_size = fthumb;
4435 }
47d67540 4436
eb082a08
RR
4437 if (orient == wxHORIZONTAL)
4438 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
4439 else
4440 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
362c6693 4441}
c801d85f 4442
1e6feb95 4443void wxWindowGTK::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
c801d85f 4444{
82b978d7 4445 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
1ecc4d80 4446
223d09f6 4447 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
1ecc4d80
RR
4448
4449 if (orient == wxHORIZONTAL)
4450 {
4451 float fpos = (float)pos;
4452 if (fpos > m_hAdjust->upper - m_hAdjust->page_size) fpos = m_hAdjust->upper - m_hAdjust->page_size;
4453 if (fpos < 0.0) fpos = 0.0;
4454 m_oldHorizontalPos = fpos;
4455
4456 if (fabs(fpos-m_hAdjust->value) < 0.2) return;
4457 m_hAdjust->value = fpos;
4458 }
4459 else
4460 {
4461 float fpos = (float)pos;
4462 if (fpos > m_vAdjust->upper - m_vAdjust->page_size) fpos = m_vAdjust->upper - m_vAdjust->page_size;
4463 if (fpos < 0.0) fpos = 0.0;
4464 m_oldVerticalPos = fpos;
ff8bfdbb 4465
1ecc4d80
RR
4466 if (fabs(fpos-m_vAdjust->value) < 0.2) return;
4467 m_vAdjust->value = fpos;
4468 }
47d67540 4469
5b8a521e 4470 if (m_wxwindow->window)
47d67540 4471 {
5b8a521e 4472 if (orient == wxHORIZONTAL)
473d087e
RR
4473 {
4474 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust),
4475 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
2daa0ce9 4476
5b8a521e 4477 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
2daa0ce9 4478
473d087e
RR
4479 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
4480 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
4481 }
5b8a521e 4482 else
473d087e
RR
4483 {
4484 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust),
4485 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
2daa0ce9 4486
5b8a521e 4487 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
473d087e
RR
4488
4489 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
4490 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
4491 }
cb43b372 4492 }
362c6693 4493}
c801d85f 4494
1e6feb95 4495int wxWindowGTK::GetScrollThumb( int orient ) const
c801d85f 4496{
82b978d7
RD
4497 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
4498
223d09f6 4499 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
47d67540 4500
1ecc4d80
RR
4501 if (orient == wxHORIZONTAL)
4502 return (int)(m_hAdjust->page_size+0.5);
4503 else
4504 return (int)(m_vAdjust->page_size+0.5);
362c6693 4505}
c801d85f 4506
1e6feb95 4507int wxWindowGTK::GetScrollPos( int orient ) const
c801d85f 4508{
82b978d7 4509 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
47d67540 4510
223d09f6 4511 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
c801d85f 4512
1ecc4d80
RR
4513 if (orient == wxHORIZONTAL)
4514 return (int)(m_hAdjust->value+0.5);
4515 else
4516 return (int)(m_vAdjust->value+0.5);
362c6693 4517}
c801d85f 4518
1e6feb95 4519int wxWindowGTK::GetScrollRange( int orient ) const
c801d85f 4520{
82b978d7 4521 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
47d67540 4522
223d09f6 4523 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
c801d85f 4524
1ecc4d80
RR
4525 if (orient == wxHORIZONTAL)
4526 return (int)(m_hAdjust->upper+0.5);
4527 else
4528 return (int)(m_vAdjust->upper+0.5);
362c6693 4529}
c801d85f 4530
1e6feb95 4531void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
c801d85f 4532{
82b978d7
RD
4533 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4534
223d09f6 4535 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
2b5f62a0 4536
f47ae6e7 4537 // No scrolling requested.
8e217128 4538 if ((dx == 0) && (dy == 0)) return;
0fc5dbf5 4539
4e5a4c69 4540#ifndef __WXGTK20__
35917d22
RR
4541 if (!m_updateRegion.IsEmpty())
4542 {
4543 m_updateRegion.Offset( dx, dy );
0fc5dbf5 4544
35917d22
RR
4545 int cw = 0;
4546 int ch = 0;
4547 GetClientSize( &cw, &ch );
4548 m_updateRegion.Intersect( 0, 0, cw, ch );
4549 }
0fc5dbf5 4550
3bcc8d15
RR
4551 if (!m_clearRegion.IsEmpty())
4552 {
4553 m_clearRegion.Offset( dx, dy );
0fc5dbf5 4554
3bcc8d15
RR
4555 int cw = 0;
4556 int ch = 0;
4557 GetClientSize( &cw, &ch );
4558 m_clearRegion.Intersect( 0, 0, cw, ch );
4559 }
3fc6e5fa
RR
4560#endif
4561
b6fa52db 4562 m_clipPaintRegion = TRUE;
0fc5dbf5 4563
da048e3d 4564 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
0fc5dbf5 4565
b6fa52db 4566 m_clipPaintRegion = FALSE;
c801d85f 4567}
3723b7b1 4568
4e5a4c69 4569
3723b7b1
JS
4570// Find the wxWindow at the current mouse position, also returning the mouse
4571// position.
4572wxWindow* wxFindWindowAtPointer(wxPoint& pt)
4573{
59a12e90
JS
4574 pt = wxGetMousePosition();
4575 wxWindow* found = wxFindWindowAtPoint(pt);
4576 return found;
3723b7b1
JS
4577}
4578
4579// Get the current mouse position.
4580wxPoint wxGetMousePosition()
4581{
59a12e90
JS
4582 /* This crashes when used within wxHelpContext,
4583 so we have to use the X-specific implementation below.
4584 gint x, y;
4585 GdkModifierType *mask;
4586 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4587
4588 return wxPoint(x, y);
4589 */
4590
3723b7b1
JS
4591 int x, y;
4592 GdkWindow* windowAtPtr = gdk_window_at_pointer(& x, & y);
59a12e90 4593
37d81cc2 4594 Display *display = windowAtPtr ? GDK_WINDOW_XDISPLAY(windowAtPtr) : GDK_DISPLAY();
59a12e90
JS
4595 Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
4596 Window rootReturn, childReturn;
4597 int rootX, rootY, winX, winY;
4598 unsigned int maskReturn;
4599
4600 XQueryPointer (display,
5cd09f0b
RR
4601 rootWindow,
4602 &rootReturn,
59a12e90
JS
4603 &childReturn,
4604 &rootX, &rootY, &winX, &winY, &maskReturn);
4605 return wxPoint(rootX, rootY);
4606
3723b7b1
JS
4607}
4608
4e5a4c69
RR
4609// ----------------------------------------------------------------------------
4610// wxDCModule
4611// ----------------------------------------------------------------------------
4612
4613class wxWinModule : public wxModule
4614{
4615public:
4616 bool OnInit();
4617 void OnExit();
4618
4619private:
4620 DECLARE_DYNAMIC_CLASS(wxWinModule)
4621};
4622
4623IMPLEMENT_DYNAMIC_CLASS(wxWinModule, wxModule)
4624
4625bool wxWinModule::OnInit()
4626{
994bc575
RR
4627 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4628 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
0fc5dbf5 4629
4e5a4c69
RR
4630 return TRUE;
4631}
4632
4633void wxWinModule::OnExit()
4634{
994bc575
RR
4635 if (g_eraseGC)
4636 gdk_gc_unref( g_eraseGC );
4e5a4c69
RR
4637}
4638
6728fb61 4639// vi:sts=4:sw=4:et