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