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