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