]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/window.cpp
moving native format generation into bitmap ref data because of the owner semantics...
[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
a3c15d89
VS
1003 event.m_x = x;
1004 event.m_y = y;
1005 event.SetEventObject( win );
1006}
1007
1008
74710601
VZ
1009static bool
1010wxTranslateGTKKeyEventToWx(wxKeyEvent& event,
1011 wxWindowGTK *win,
1012 GdkEventKey *gdk_event)
47d67540 1013{
1c6896d7
VZ
1014 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
1015 // but only event->keyval which is quite useless to us, so remember
1016 // the last character from GDK_KEY_PRESS and reuse it as last resort
1017 //
1018 // NB: should be MT-safe as we're always called from the main thread only
1019 static struct
1020 {
1021 KeySym keysym;
1022 long keycode;
1023 } s_lastKeyPress = { 0, 0 };
1024
1025 KeySym keysym = gdk_event->keyval;
0a62b197 1026
ada7d2c0 1027 wxLogTrace(TRACE_KEYS, _T("Key %s event: keysym = %ld"),
0a62b197
VZ
1028 event.GetEventType() == wxEVT_KEY_UP ? _T("release")
1029 : _T("press"),
1030 keysym);
1031
1c6896d7
VZ
1032 long key_code = wxTranslateKeySymToWXKey(keysym, FALSE /* !isChar */);
1033
1034 if ( !key_code )
1035 {
1036 // do we have the translation or is it a plain ASCII character?
1037 if ( (gdk_event->length == 1) || wxIsAsciiKeysym(keysym) )
1038 {
1039 // we should use keysym if it is ASCII as X does some translations
1040 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
1041 // which we don't want here (but which we do use for OnChar())
1042 if ( !wxIsAsciiKeysym(keysym) )
1043 {
1044 keysym = (KeySym)gdk_event->string[0];
1045 }
a2053b27 1046
1c6896d7
VZ
1047 // we want to always get the same key code when the same key is
1048 // pressed regardless of the state of the modifies, i.e. on a
1049 // standard US keyboard pressing '5' or '%' ('5' key with
1050 // Shift) should result in the same key code in OnKeyDown():
1051 // '5' (although OnChar() will get either '5' or '%').
1052 //
1053 // to do it we first translate keysym to keycode (== scan code)
1054 // and then back but always using the lower register
1055 Display *dpy = (Display *)wxGetDisplay();
1056 KeyCode keycode = XKeysymToKeycode(dpy, keysym);
0a62b197
VZ
1057
1058 wxLogTrace(TRACE_KEYS, _T("\t-> keycode %d"), keycode);
1059
1c6896d7
VZ
1060 KeySym keysymNormalized = XKeycodeToKeysym(dpy, keycode, 0);
1061
1062 // use the normalized, i.e. lower register, keysym if we've
1063 // got one
1064 key_code = keysymNormalized ? keysymNormalized : keysym;
1065
1066 // as explained above, we want to have lower register key codes
1067 // normally but for the letter keys we want to have the upper ones
1068 //
1069 // NB: don't use XConvertCase() here, we want to do it for letters
1070 // only
1071 key_code = toupper(key_code);
1072 }
1073 else // non ASCII key, what to do?
1074 {
1075 // by default, ignore it
1076 key_code = 0;
1077
1078 // but if we have cached information from the last KEY_PRESS
1079 if ( gdk_event->type == GDK_KEY_RELEASE )
1080 {
1081 // then reuse it
1082 if ( keysym == s_lastKeyPress.keysym )
1083 {
1084 key_code = s_lastKeyPress.keycode;
1085 }
1086 }
1087 }
1088
1089 if ( gdk_event->type == GDK_KEY_PRESS )
1090 {
1091 // remember it to be reused for KEY_UP event later
1092 s_lastKeyPress.keysym = keysym;
1093 s_lastKeyPress.keycode = key_code;
1094 }
1095 }
1096
ada7d2c0 1097 wxLogTrace(TRACE_KEYS, _T("\t-> wxKeyCode %ld"), key_code);
c801d85f 1098
74710601 1099 // sending unknown key events doesn't really make sense
1c6896d7 1100 if ( !key_code )
74710601 1101 return FALSE;
3d6f7261 1102
1c6896d7 1103 // now fill all the other fields
a3c15d89
VS
1104 wxFillOtherKeyEventFields(event, win, gdk_event);
1105
f5e27805 1106 event.m_keyCode = key_code;
74710601
VZ
1107
1108 return TRUE;
1109}
1110
7c5e6fc6 1111
a3c15d89
VS
1112#ifdef __WXGTK20__
1113struct wxGtkIMData
1114{
1115 GtkIMContext *context;
1116 GdkEventKey *lastKeyEvent;
1117
1118 wxGtkIMData()
1119 {
1120 context = gtk_im_multicontext_new();
1121 lastKeyEvent = NULL;
1122 }
1123 ~wxGtkIMData()
1124 {
1125 g_object_unref(context);
1126 }
1127};
1128#endif
1129
74710601
VZ
1130static gint gtk_window_key_press_callback( GtkWidget *widget,
1131 GdkEventKey *gdk_event,
1132 wxWindow *win )
1133{
1134 DEBUG_MAIN_THREAD
1135
1136 if (g_isIdle)
1137 wxapp_install_idle_handler();
1138
1c6896d7
VZ
1139 if (!win->m_hasVMT)
1140 return FALSE;
1141 if (g_blockEventsOnDrag)
1142 return FALSE;
f1272160
RR
1143
1144
1145 wxKeyEvent event( wxEVT_KEY_DOWN );
1146 bool ret = false;
1147 bool return_after_IM = false;
1148
1149 if( wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
1150 {
1151 // Emit KEY_DOWN event
1152 ret = win->GetEventHandler()->ProcessEvent( event );
1153 }
1154 else
1155 {
1156 // Return after IM processing as we cannot do
1157 // anything with it anyhow.
1158 return_after_IM = true;
1159 }
1160
36025bcc 1161#ifdef __WXGTK20__
fdfb8475 1162 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
f1272160 1163 // When we get a key_press event here, it could be originate
f6fca1f8
RR
1164 // from the current widget or its child widgets. However, only the widget
1165 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
1166 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
1167 // originated from its child widgets and shouldn't be passed to IM context.
1168 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
1169 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
1170 // widgets has both IM context and input focus, the event should be filtered
1171 // by gtk_im_context_filter_keypress().
1172 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
f1272160 1173 if ((!ret) && (win->m_imData != NULL) && ( wxWindow::FindFocus() == win ))
f6fca1f8 1174 {
f1272160
RR
1175 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1176 // docs, if IM filter returns true, no further processing should be done.
1177 // we should send the key_down event anyway.
1178 bool intercepted_by_IM = gtk_im_context_filter_keypress(win->m_imData->context, gdk_event);
f6fca1f8 1179 win->m_imData->lastKeyEvent = NULL;
f1272160
RR
1180 if (intercepted_by_IM)
1181 {
f6fca1f8 1182 wxLogTrace(TRACE_KEYS, _T("Key event intercepted by IM"));
f1272160
RR
1183 return true;
1184 }
f6fca1f8 1185 }
a3c15d89 1186#endif
f1272160
RR
1187 if (return_after_IM)
1188 return true;
f6fca1f8 1189
f1272160
RR
1190#ifndef __WXGTK20__
1191 // This is for GTK+ 1.2 only. The char event generatation for GTK+ 2.0 is done
1192 // in the "commit" handler.
1193
fdfb8475
RR
1194 // 2005.02.02 modified by Hong Jen Yee (hzysoft@sina.com.tw).
1195 // In GTK+ 1.2, strings sent by IMs are also regarded as key_press events whose
1196 // keyCodes cannot be recognized by wxWidgets. These MBCS strings, however, are
1197 // composed of more than one character, which means gdk_event->length will always
1198 // greater than one. When gtk_event->length == 1, this may be an ASCII character
1199 // and can be translated by wx. However, when MBCS characters are sent by IM,
1200 // gdk_event->length will >= 2. So neither should we pass it to accelerator table,
1201 // nor should we pass it to controls. The following explanation was excerpted
1202 // from GDK documentation.
1203 // gint length : the length of string.
1204 // gchar *string : a null-terminated multi-byte string containing the composed
1205 // characters resulting from the key press. When text is being input, in a GtkEntry
1206 // for example, it is these characters which should be added to the input buffer.
1207 // When using Input Methods to support internationalized text input, the composed
1208 // characters appear here after the pre-editing has been completed.
1209
ad975781 1210 if ( (!ret) && (gdk_event->length > 1) ) // If this event contains a pre-edited string from IM.
fdfb8475
RR
1211 {
1212 // We should translate this key event into wxEVT_CHAR not wxEVT_KEY_DOWN.
1213 #if wxUSE_UNICODE // GTK+ 1.2 is not UTF-8 based.
1214 const wxWCharBuffer string = wxConvLocal.cMB2WC( gdk_event->string );
ad975781
RR
1215 if( !string )
1216 return false;
fdfb8475
RR
1217 #else
1218 const char* string = gdk_event->string;
1219 #endif
1220
1221 // Implement OnCharHook by checking ancesteror top level windows
f1272160 1222 wxWindow *parent = win;
fdfb8475
RR
1223 while (parent && !parent->IsTopLevel())
1224 parent = parent->GetParent();
1225
f1272160 1226 for( const wxChar* pstr = string; *pstr; pstr++ )
fdfb8475
RR
1227 {
1228 #if wxUSE_UNICODE
1229 event.m_uniChar = *pstr;
1230 // Backward compatible for ISO-8859-1
1231 event.m_keyCode = *pstr < 256 ? event.m_uniChar : 0;
1232 #else
1233 event.m_keyCode = *pstr;
1234 #endif
1235 if (parent)
1236 {
1237 event.SetEventType( wxEVT_CHAR_HOOK );
1238 ret = parent->GetEventHandler()->ProcessEvent( event );
1239 }
1240 if (!ret)
1241 {
1242 event.SetEventType(wxEVT_CHAR);
f1272160 1243 win->GetEventHandler()->ProcessEvent( event );
fdfb8475
RR
1244 }
1245 }
ad975781 1246 return true;
fdfb8475 1247 }
f1272160 1248
4d3ab2a0
RD
1249#endif // #ifndef __WXGTK20__
1250
50b58dec
RD
1251#if wxUSE_ACCEL
1252 if (!ret)
1253 {
1254 wxWindowGTK *ancestor = win;
1255 while (ancestor)
1256 {
1257 int command = ancestor->GetAcceleratorTable()->GetCommand( event );
1258 if (command != -1)
1259 {
1260 wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
1261 ret = ancestor->GetEventHandler()->ProcessEvent( command_event );
1262 break;
1263 }
1264 if (ancestor->IsTopLevel())
1265 break;
1266 ancestor = ancestor->GetParent();
1267 }
1268 }
1269#endif // wxUSE_ACCEL
1270
1ec3a984
RR
1271 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1272 // will only be sent if it is not in an accelerator table.
2dde25b9 1273 if (!ret)
d728dd40 1274 {
7c5e6fc6 1275 long key_code;
1c6896d7 1276 KeySym keysym = gdk_event->keyval;
36025bcc
VS
1277 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1278 key_code = wxTranslateKeySymToWXKey(keysym, TRUE /* isChar */);
1279 if ( !key_code )
1c6896d7 1280 {
0b187670 1281 if ( wxIsAsciiKeysym(keysym) )
1ec3a984 1282 {
36025bcc
VS
1283 // ASCII key
1284 key_code = (unsigned char)keysym;
1285 }
0b187670
RR
1286 // gdk_event->string is actually deprecated
1287 else if ( gdk_event->length == 1 )
1288 {
1289 key_code = (unsigned char)gdk_event->string[0];
1290 }
36025bcc 1291 }
7c5e6fc6 1292
36025bcc
VS
1293 if ( key_code )
1294 {
1295 wxLogTrace(TRACE_KEYS, _T("Char event: %ld"), key_code);
7c5e6fc6 1296
36025bcc 1297 event.m_keyCode = key_code;
7c5e6fc6 1298
36025bcc
VS
1299 // Implement OnCharHook by checking ancesteror top level windows
1300 wxWindow *parent = win;
1301 while (parent && !parent->IsTopLevel())
1302 parent = parent->GetParent();
1303 if (parent)
1304 {
1305 event.SetEventType( wxEVT_CHAR_HOOK );
1306 ret = parent->GetEventHandler()->ProcessEvent( event );
1307 }
1308
1309 if (!ret)
1310 {
1311 event.SetEventType(wxEVT_CHAR);
1312 ret = win->GetEventHandler()->ProcessEvent( event );
1ec3a984 1313 }
f17393f1 1314 }
d728dd40 1315 }
4d3ab2a0 1316
f1272160
RR
1317
1318
f1272160 1319
d728dd40 1320
1ec3a984 1321 // win is a control: tab can be propagated up
f17393f1 1322 if ( !ret &&
5664fc32 1323 ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) &&
f6bcfd97
BP
1324// VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1325// have this style, yet choose not to process this particular TAB in which
1326// case TAB must still work as a navigational character
f5f3247d
JS
1327// JS: enabling again to make consistent with other platforms
1328// (with wxTE_PROCESS_TAB you have to call Navigate to get default
1329// navigation behaviour)
eedc82f4 1330#if wxUSE_TEXTCTRL
8700aedc 1331 (! (win->HasFlag(wxTE_PROCESS_TAB) && win->IsKindOf(CLASSINFO(wxTextCtrl)) )) &&
f5f3247d 1332#endif
f17393f1 1333 win->GetParent() && (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) )
b292e2f5
RR
1334 {
1335 wxNavigationKeyEvent new_event;
8253c7fd 1336 new_event.SetEventObject( win->GetParent() );
1ec3a984 1337 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
5664fc32 1338 new_event.SetDirection( (gdk_event->keyval == GDK_Tab) );
1ec3a984 1339 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
b98d804b 1340 new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) );
b292e2f5 1341 new_event.SetCurrentFocus( win );
8253c7fd 1342 ret = win->GetParent()->GetEventHandler()->ProcessEvent( new_event );
b292e2f5 1343 }
ff8bfdbb 1344
1ec3a984 1345 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
f17393f1 1346 if ( !ret &&
b98d804b
RR
1347 (gdk_event->keyval == GDK_Escape) )
1348 {
6ce16bdb
VZ
1349 // however only do it if we have a Cancel button in the dialog,
1350 // otherwise the user code may get confused by the events from a
1351 // non-existing button and, worse, a wxButton might get button event
1352 // from another button which is not really expected
1353 wxWindow *winForCancel = win,
1354 *btnCancel = NULL;
1355 while ( winForCancel )
1356 {
1357 btnCancel = winForCancel->FindWindow(wxID_CANCEL);
1358 if ( btnCancel )
1359 {
1360 // found a cancel button
1361 break;
1362 }
1363
1364 if ( winForCancel->IsTopLevel() )
1365 {
1366 // no need to look further
1367 break;
1368 }
1369
1370 // maybe our parent has a cancel button?
1371 winForCancel = winForCancel->GetParent();
1372 }
1373
1374 if ( btnCancel )
1375 {
1376 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL);
1377 event.SetEventObject(btnCancel);
1378 ret = btnCancel->GetEventHandler()->ProcessEvent(event);
1379 }
b98d804b 1380 }
c50f1fb9 1381
2b5f62a0 1382 if (ret)
801aa178 1383 {
2b5f62a0
VZ
1384 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
1385 return TRUE;
1386 }
1387
1388 return FALSE;
1389}
2b5f62a0
VZ
1390
1391#ifdef __WXGTK20__
2b5f62a0 1392static void gtk_wxwindow_commit_cb (GtkIMContext *context,
9abbd4a0
RR
1393 const gchar *str,
1394 wxWindow *window)
2b5f62a0 1395{
2b5f62a0
VZ
1396 wxKeyEvent event( wxEVT_KEY_DOWN );
1397
a3c15d89
VS
1398 // take modifiers, cursor position, timestamp etc. from the last
1399 // key_press_event that was fed into Input Method:
1400 if (window->m_imData->lastKeyEvent)
1401 {
1402 wxFillOtherKeyEventFields(event,
1403 window, window->m_imData->lastKeyEvent);
1404 }
1405
2b5f62a0 1406#if wxUSE_UNICODE
5bfaca1b 1407 const wxWCharBuffer data = wxConvUTF8.cMB2WC( (char*)str );
2b5f62a0 1408#else
5bfaca1b
VS
1409 const wxWCharBuffer wdata = wxConvUTF8.cMB2WC( (char*)str );
1410 const wxCharBuffer data = wxConvLocal.cWC2MB( wdata );
a3c15d89 1411#endif // wxUSE_UNICODE
5bfaca1b
VS
1412 if( !(const wxChar*)data )
1413 return;
7c5e6fc6 1414
a3c15d89 1415 bool ret = false;
7c5e6fc6
RD
1416
1417 // Implement OnCharHook by checking ancestor top level windows
1418 wxWindow *parent = window;
1419 while (parent && !parent->IsTopLevel())
2b5f62a0 1420 parent = parent->GetParent();
2b5f62a0 1421
5bfaca1b 1422 for( const wxChar* pstr = data; *pstr; pstr++ )
7c5e6fc6 1423 {
5bfaca1b
VS
1424#if wxUSE_UNICODE
1425 event.m_uniChar = *pstr;
f6fca1f8 1426 // Backward compatible for ISO-8859-1
5bfaca1b
VS
1427 event.m_keyCode = *pstr < 256 ? event.m_uniChar : 0;
1428 wxLogTrace(TRACE_KEYS, _T("IM sent character '%c'"), event.m_uniChar);
1429#else
1430 event.m_keyCode = *pstr;
1431#endif // wxUSE_UNICODE
1432 if (parent)
1433 {
1434 event.SetEventType( wxEVT_CHAR_HOOK );
1435 ret = parent->GetEventHandler()->ProcessEvent( event );
1436 }
1437
1438 if (!ret)
1439 {
1440 event.SetEventType(wxEVT_CHAR);
1441 ret = window->GetEventHandler()->ProcessEvent( event );
1442 }
2b5f62a0
VZ
1443 }
1444}
1445#endif
1446
1447
b666df2c
RR
1448//-----------------------------------------------------------------------------
1449// "key_release_event" from any window
1450//-----------------------------------------------------------------------------
1451
74710601
VZ
1452static gint gtk_window_key_release_callback( GtkWidget *widget,
1453 GdkEventKey *gdk_event,
1454 wxWindowGTK *win )
b666df2c 1455{
3ac8d3bc
RR
1456 DEBUG_MAIN_THREAD
1457
c50f1fb9 1458 if (g_isIdle)
a2053b27
RR
1459 wxapp_install_idle_handler();
1460
74710601
VZ
1461 if (!win->m_hasVMT)
1462 return FALSE;
b666df2c 1463
74710601
VZ
1464 if (g_blockEventsOnDrag)
1465 return FALSE;
b666df2c
RR
1466
1467 wxKeyEvent event( wxEVT_KEY_UP );
74710601 1468 if ( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
b666df2c 1469 {
74710601
VZ
1470 // unknown key pressed, ignore (the event would be useless anyhow
1471 return FALSE;
b666df2c
RR
1472 }
1473
74710601
VZ
1474 if ( !win->GetEventHandler()->ProcessEvent( event ) )
1475 return FALSE;
1476
1477 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_release_event" );
1478 return TRUE;
b666df2c
RR
1479}
1480
c5f9d156
VS
1481// ============================================================================
1482// the mouse events
1483// ============================================================================
1484
d1f2ac45
VZ
1485// ----------------------------------------------------------------------------
1486// mouse event processing helpers
1487// ----------------------------------------------------------------------------
1488
50f00d0c
VS
1489// init wxMouseEvent with the info from GdkEventXXX struct
1490template<typename T> void InitMouseEvent(wxWindowGTK *win,
1491 wxMouseEvent& event,
1492 T *gdk_event)
1493{
1494 event.SetTimestamp( gdk_event->time );
1495 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1496 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1497 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1498 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1499 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1500 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1501 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1502 if (event.GetEventType() == wxEVT_MOUSEWHEEL)
1503 {
1504 event.m_linesPerAction = 3;
60773911 1505 event.m_wheelDelta = 120;
50f00d0c
VS
1506 if (((GdkEventButton*)gdk_event)->button == 4)
1507 event.m_wheelRotation = 120;
1508 else if (((GdkEventButton*)gdk_event)->button == 5)
1509 event.m_wheelRotation = -120;
1510 }
1511
1512 wxPoint pt = win->GetClientAreaOrigin();
1513 event.m_x = (wxCoord)gdk_event->x - pt.x;
1514 event.m_y = (wxCoord)gdk_event->y - pt.y;
1515
1516 event.SetEventObject( win );
1517 event.SetId( win->GetId() );
1518 event.SetTimestamp( gdk_event->time );
1519}
c5f9d156 1520
2daa0ce9
VZ
1521static void AdjustEventButtonState(wxMouseEvent& event)
1522{
1523 // GDK reports the old state of the button for a button press event, but
1524 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1525 // for a LEFT_DOWN event, not FALSE, so we will invert
1526 // left/right/middleDown for the corresponding click events
1e6feb95 1527
1a8caf94
RR
1528 if ((event.GetEventType() == wxEVT_LEFT_DOWN) ||
1529 (event.GetEventType() == wxEVT_LEFT_DCLICK) ||
1530 (event.GetEventType() == wxEVT_LEFT_UP))
1531 {
1532 event.m_leftDown = !event.m_leftDown;
1533 return;
1534 }
1535
1536 if ((event.GetEventType() == wxEVT_MIDDLE_DOWN) ||
1537 (event.GetEventType() == wxEVT_MIDDLE_DCLICK) ||
1538 (event.GetEventType() == wxEVT_MIDDLE_UP))
2daa0ce9 1539 {
1a8caf94
RR
1540 event.m_middleDown = !event.m_middleDown;
1541 return;
1542 }
1543
1544 if ((event.GetEventType() == wxEVT_RIGHT_DOWN) ||
1545 (event.GetEventType() == wxEVT_RIGHT_DCLICK) ||
1546 (event.GetEventType() == wxEVT_RIGHT_UP))
1547 {
1548 event.m_rightDown = !event.m_rightDown;
1549 return;
2daa0ce9
VZ
1550 }
1551}
1552
d1f2ac45
VZ
1553// find the window to send the mouse event too
1554static
1555wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y)
1556{
7d4909b2
RR
1557 wxCoord xx = x;
1558 wxCoord yy = y;
1559
d1f2ac45
VZ
1560 if (win->m_wxwindow)
1561 {
1562 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
7d4909b2
RR
1563 xx += pizza->xoffset;
1564 yy += pizza->yoffset;
d1f2ac45
VZ
1565 }
1566
222ed1d6 1567 wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
d1f2ac45
VZ
1568 while (node)
1569 {
b1d4dd7a 1570 wxWindowGTK *child = node->GetData();
d1f2ac45 1571
b1d4dd7a 1572 node = node->GetNext();
d1f2ac45
VZ
1573 if (!child->IsShown())
1574 continue;
1575
1576 if (child->IsTransparentForMouse())
1577 {
1578 // wxStaticBox is transparent in the box itself
1579 int xx1 = child->m_x;
1580 int yy1 = child->m_y;
1581 int xx2 = child->m_x + child->m_width;
7408cf7f 1582 int yy2 = child->m_y + child->m_height;
d1f2ac45
VZ
1583
1584 // left
7d4909b2 1585 if (((xx >= xx1) && (xx <= xx1+10) && (yy >= yy1) && (yy <= yy2)) ||
d1f2ac45 1586 // right
7d4909b2 1587 ((xx >= xx2-10) && (xx <= xx2) && (yy >= yy1) && (yy <= yy2)) ||
d1f2ac45 1588 // top
7d4909b2 1589 ((xx >= xx1) && (xx <= xx2) && (yy >= yy1) && (yy <= yy1+10)) ||
d1f2ac45 1590 // bottom
7d4909b2 1591 ((xx >= xx1) && (xx <= xx2) && (yy >= yy2-1) && (yy <= yy2)))
d1f2ac45
VZ
1592 {
1593 win = child;
1594 x -= child->m_x;
1595 y -= child->m_y;
1596 break;
1597 }
1598
1599 }
1600 else
1601 {
1602 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
7d4909b2
RR
1603 (child->m_x <= xx) &&
1604 (child->m_y <= yy) &&
af3653dd
RR
1605 (child->m_x+child->m_width >= xx) &&
1606 (child->m_y+child->m_height >= yy))
d1f2ac45
VZ
1607 {
1608 win = child;
1609 x -= child->m_x;
1610 y -= child->m_y;
1611 break;
1612 }
1613 }
1614 }
1615
1616 return win;
1617}
1618
c801d85f 1619//-----------------------------------------------------------------------------
2f2aa628
RR
1620// "button_press_event"
1621//-----------------------------------------------------------------------------
c801d85f 1622
d1f2ac45
VZ
1623static gint gtk_window_button_press_callback( GtkWidget *widget,
1624 GdkEventButton *gdk_event,
1625 wxWindowGTK *win )
903f689b 1626{
3ac8d3bc
RR
1627 DEBUG_MAIN_THREAD
1628
c50f1fb9 1629 if (g_isIdle)
a2053b27
RR
1630 wxapp_install_idle_handler();
1631
1632/*
223d09f6 1633 wxPrintf( wxT("1) OnButtonPress from ") );
a2053b27
RR
1634 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1635 wxPrintf( win->GetClassInfo()->GetClassName() );
223d09f6 1636 wxPrintf( wxT(".\n") );
a2053b27 1637*/
a2053b27 1638 if (!win->m_hasVMT) return FALSE;
f5e27805 1639 if (g_blockEventsOnDrag) return TRUE;
76ed8f8d 1640 if (g_blockEventsOnScroll) return TRUE;
c801d85f 1641
034be888
RR
1642 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1643
afbe906a 1644 if (win->m_wxwindow && (g_focusWindow != win) && win->AcceptsFocus())
c801d85f 1645 {
afbe906a 1646 gtk_widget_grab_focus( win->m_wxwindow );
c801d85f 1647/*
afbe906a
RR
1648 wxPrintf( wxT("GrabFocus from ") );
1649 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1650 wxPrintf( win->GetClassInfo()->GetClassName() );
1651 wxPrintf( wxT(".\n") );
c801d85f 1652*/
362c6693 1653 }
47d67540 1654
2b5f62a0
VZ
1655 // GDK sends surplus button down event
1656 // before a double click event. We
1657 // need to filter these out.
1658 if (gdk_event->type == GDK_BUTTON_PRESS)
1659 {
1660 GdkEvent *peek_event = gdk_event_peek();
1661 if (peek_event)
1662 {
8b8a8e0e
RR
1663 if ((peek_event->type == GDK_2BUTTON_PRESS) ||
1664 (peek_event->type == GDK_3BUTTON_PRESS))
2b5f62a0
VZ
1665 {
1666 gdk_event_free( peek_event );
1667 return TRUE;
1668 }
1669 else
1670 {
1671 gdk_event_free( peek_event );
1672 }
1673 }
1674 }
1675
2daa0ce9 1676 wxEventType event_type = wxEVT_NULL;
47d67540 1677
127304e9
VS
1678 // GdkDisplay is a GTK+ 2.2.0 thing
1679#if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
15475ced
VZ
1680 if ( gdk_event->type == GDK_2BUTTON_PRESS &&
1681 gdk_event->button >= 1 && gdk_event->button <= 3 )
1682 {
1683 // Reset GDK internal timestamp variables in order to disable GDK
1684 // triple click events. GDK will then next time believe no button has
1685 // been clicked just before, and send a normal button click event.
1686 GdkDisplay* display = gtk_widget_get_display (widget);
1687 display->button_click_time[1] = 0;
1688 display->button_click_time[0] = 0;
1689 }
1690#endif // GTK 2+
1691
f5e27805 1692 if (gdk_event->button == 1)
c801d85f 1693 {
f3f0d961 1694 // note that GDK generates triple click events which are not supported
77ffb593 1695 // by wxWidgets but still have to be passed to the app as otherwise
f3f0d961 1696 // clicks would simply go missing
f5e27805
RR
1697 switch (gdk_event->type)
1698 {
15475ced
VZ
1699 // we shouldn't get triple clicks at all for GTK2 because we
1700 // suppress them artificially using the code above but we still
1701 // should map them to something for GTK1 and not just ignore them
1702 // as this would lose clicks
f3f0d961
VZ
1703 case GDK_3BUTTON_PRESS: // we could also map this to DCLICK...
1704 case GDK_BUTTON_PRESS:
1705 event_type = wxEVT_LEFT_DOWN;
1706 break;
1707
1708 case GDK_2BUTTON_PRESS:
1709 event_type = wxEVT_LEFT_DCLICK;
1710 break;
b1f50e65
VZ
1711
1712 default:
1713 // just to silence gcc warnings
1714 ;
f5e27805 1715 }
362c6693 1716 }
f5e27805 1717 else if (gdk_event->button == 2)
c801d85f 1718 {
f5e27805
RR
1719 switch (gdk_event->type)
1720 {
15475ced 1721 case GDK_3BUTTON_PRESS:
f3f0d961
VZ
1722 case GDK_BUTTON_PRESS:
1723 event_type = wxEVT_MIDDLE_DOWN;
1724 break;
1725
1726 case GDK_2BUTTON_PRESS:
1727 event_type = wxEVT_MIDDLE_DCLICK;
1728 break;
b1f50e65
VZ
1729
1730 default:
1731 ;
f5e27805 1732 }
362c6693 1733 }
f5e27805 1734 else if (gdk_event->button == 3)
c801d85f 1735 {
f5e27805
RR
1736 switch (gdk_event->type)
1737 {
15475ced 1738 case GDK_3BUTTON_PRESS:
f3f0d961
VZ
1739 case GDK_BUTTON_PRESS:
1740 event_type = wxEVT_RIGHT_DOWN;
1741 break;
1742
1743 case GDK_2BUTTON_PRESS:
1744 event_type = wxEVT_RIGHT_DCLICK;
1745 break;
b1f50e65
VZ
1746
1747 default:
1748 ;
2b5f62a0
VZ
1749 }
1750 }
f3f0d961 1751 else if (gdk_event->button == 4 || gdk_event->button == 5)
2b5f62a0 1752 {
f3f0d961 1753 if (gdk_event->type == GDK_BUTTON_PRESS )
2b5f62a0 1754 {
f3f0d961 1755 event_type = wxEVT_MOUSEWHEEL;
2b5f62a0
VZ
1756 }
1757 }
47d67540 1758
2daa0ce9
VZ
1759 if ( event_type == wxEVT_NULL )
1760 {
1761 // unknown mouse button or click type
1762 return FALSE;
1763 }
1764
f5e27805 1765 wxMouseEvent event( event_type );
c5f9d156 1766 InitMouseEvent( win, event, gdk_event );
47d67540 1767
2daa0ce9 1768 AdjustEventButtonState(event);
94633ad9 1769
3ae4c570
VZ
1770 // wxListBox actually get mouse events from the item, so we need to give it
1771 // a chance to correct this
1772 win->FixUpMouseEvent(widget, event.m_x, event.m_y);
2daa0ce9 1773
d1f2ac45
VZ
1774 // find the correct window to send the event too: it may be a different one
1775 // from the one which got it at GTK+ level because some control don't have
1776 // their own X window and thus cannot get any events.
1777 if ( !g_captureWindow )
1778 win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
ff8bfdbb 1779
34adc954
VZ
1780 gs_timeLastClick = gdk_event->time;
1781
df135f2b
RR
1782#ifndef __WXGTK20__
1783 if (event_type == wxEVT_LEFT_DCLICK)
1784 {
1785 // GTK 1.2 crashes when intercepting double
1786 // click events from both wxSpinButton and
1787 // wxSpinCtrl
1788 if (GTK_IS_SPIN_BUTTON(win->m_widget))
1789 {
1790 // Just disable this event for now.
1791 return FALSE;
1792 }
1793 }
1794#endif
1795
f5e27805 1796 if (win->GetEventHandler()->ProcessEvent( event ))
034be888 1797 {
f5e27805 1798 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_press_event" );
f03fc89f 1799 return TRUE;
034be888 1800 }
47d67540 1801
ac103441
RR
1802 if (event_type == wxEVT_RIGHT_DOWN)
1803 {
1804 // generate a "context menu" event: this is similar to right mouse
1805 // click under many GUIs except that it is generated differently
1806 // (right up under MSW, ctrl-click under Mac, right down here) and
1807 //
1808 // (a) it's a command event and so is propagated to the parent
1809 // (b) under some ports it can be generated from kbd too
1810 // (c) it uses screen coords (because of (a))
1811 wxContextMenuEvent evtCtx(
1812 wxEVT_CONTEXT_MENU,
1813 win->GetId(),
1814 win->ClientToScreen(event.GetPosition()));
1815 evtCtx.SetEventObject(win);
1816 return win->GetEventHandler()->ProcessEvent(evtCtx);
1817 }
1818
034be888 1819 return FALSE;
362c6693 1820}
c801d85f
KB
1821
1822//-----------------------------------------------------------------------------
97b3455a 1823// "button_release_event"
2f2aa628 1824//-----------------------------------------------------------------------------
c801d85f 1825
2b5f62a0
VZ
1826static gint gtk_window_button_release_callback( GtkWidget *widget,
1827 GdkEventButton *gdk_event,
1828 wxWindowGTK *win )
47d67540 1829{
3ac8d3bc
RR
1830 DEBUG_MAIN_THREAD
1831
c50f1fb9 1832 if (g_isIdle)
a2053b27
RR
1833 wxapp_install_idle_handler();
1834
1835 if (!win->m_hasVMT) return FALSE;
034be888
RR
1836 if (g_blockEventsOnDrag) return FALSE;
1837 if (g_blockEventsOnScroll) return FALSE;
c801d85f 1838
034be888 1839 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
47d67540 1840
f5e27805 1841 wxEventType event_type = wxEVT_NULL;
47d67540 1842
f5e27805
RR
1843 switch (gdk_event->button)
1844 {
2b5f62a0
VZ
1845 case 1:
1846 event_type = wxEVT_LEFT_UP;
1847 break;
1848
1849 case 2:
1850 event_type = wxEVT_MIDDLE_UP;
1851 break;
1852
1853 case 3:
1854 event_type = wxEVT_RIGHT_UP;
1855 break;
1856
1857 default:
1858 // unknwon button, don't process
1859 return FALSE;
f5e27805 1860 }
47d67540 1861
f5e27805 1862 wxMouseEvent event( event_type );
c5f9d156 1863 InitMouseEvent( win, event, gdk_event );
f5e27805 1864
2daa0ce9
VZ
1865 AdjustEventButtonState(event);
1866
3ae4c570
VZ
1867 // same wxListBox hack as above
1868 win->FixUpMouseEvent(widget, event.m_x, event.m_y);
e2762ff0 1869
d1f2ac45
VZ
1870 if ( !g_captureWindow )
1871 win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
47d67540 1872
f5e27805 1873 if (win->GetEventHandler()->ProcessEvent( event ))
034be888 1874 {
f5e27805 1875 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_release_event" );
f03fc89f 1876 return TRUE;
034be888 1877 }
47d67540 1878
034be888 1879 return FALSE;
362c6693 1880}
c801d85f
KB
1881
1882//-----------------------------------------------------------------------------
2f2aa628
RR
1883// "motion_notify_event"
1884//-----------------------------------------------------------------------------
c801d85f 1885
1e6feb95
VZ
1886static gint gtk_window_motion_notify_callback( GtkWidget *widget,
1887 GdkEventMotion *gdk_event,
1888 wxWindowGTK *win )
47d67540 1889{
3ac8d3bc
RR
1890 DEBUG_MAIN_THREAD
1891
c50f1fb9 1892 if (g_isIdle)
a2053b27
RR
1893 wxapp_install_idle_handler();
1894
1895 if (!win->m_hasVMT) return FALSE;
034be888
RR
1896 if (g_blockEventsOnDrag) return FALSE;
1897 if (g_blockEventsOnScroll) return FALSE;
148cd9b6 1898
034be888
RR
1899 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1900
ff8bfdbb 1901 if (gdk_event->is_hint)
aae24d21 1902 {
f7a11f8c
RR
1903 int x = 0;
1904 int y = 0;
1905 GdkModifierType state;
1906 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
1907 gdk_event->x = x;
1908 gdk_event->y = y;
aae24d21 1909 }
ff8bfdbb 1910
c801d85f 1911/*
e380f72b
RR
1912 printf( "OnMotion from " );
1913 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1914 printf( win->GetClassInfo()->GetClassName() );
1915 printf( ".\n" );
aae24d21 1916*/
47d67540 1917
e380f72b 1918 wxMouseEvent event( wxEVT_MOTION );
c5f9d156 1919 InitMouseEvent(win, event, gdk_event);
e380f72b 1920
50382578 1921 if ( g_captureWindow )
2f2aa628 1922 {
1e6feb95
VZ
1923 // synthetize a mouse enter or leave event if needed
1924 GdkWindow *winUnderMouse = gdk_window_at_pointer(NULL, NULL);
7c5e6fc6 1925 // This seems to be necessary and actually been added to
50382578
RR
1926 // GDK itself in version 2.0.X
1927 gdk_flush();
7c5e6fc6 1928
1e6feb95
VZ
1929 bool hasMouse = winUnderMouse == gdk_event->window;
1930 if ( hasMouse != g_captureWindowHasMouse )
1931 {
1932 // the mouse changed window
1933 g_captureWindowHasMouse = hasMouse;
1934
1935 wxMouseEvent event(g_captureWindowHasMouse ? wxEVT_ENTER_WINDOW
1936 : wxEVT_LEAVE_WINDOW);
c5f9d156 1937 InitMouseEvent(win, event, gdk_event);
1e6feb95
VZ
1938 event.SetEventObject(win);
1939 win->GetEventHandler()->ProcessEvent(event);
1940 }
1941 }
1942 else // no capture
1943 {
d1f2ac45 1944 win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
2f2aa628 1945 }
47d67540 1946
e380f72b 1947 if (win->GetEventHandler()->ProcessEvent( event ))
034be888 1948 {
e380f72b 1949 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "motion_notify_event" );
f03fc89f 1950 return TRUE;
034be888 1951 }
47d67540 1952
034be888 1953 return FALSE;
362c6693 1954}
c801d85f 1955
557c9f5b
JS
1956#ifdef __WXGTK20__
1957//-----------------------------------------------------------------------------
1958// "mouse_wheel_event"
1959//-----------------------------------------------------------------------------
1960
1961static gint gtk_window_wheel_callback (GtkWidget * widget,
1962 GdkEventScroll * gdk_event,
1963 wxWindowGTK * win)
1964{
1965 DEBUG_MAIN_THREAD
1966
1967 if (g_isIdle)
1968 wxapp_install_idle_handler();
1969
1970 wxEventType event_type = wxEVT_NULL;
1971 if (gdk_event->direction == GDK_SCROLL_UP)
1972 event_type = wxEVT_MOUSEWHEEL;
1973 else if (gdk_event->direction == GDK_SCROLL_DOWN)
1974 event_type = wxEVT_MOUSEWHEEL;
1975 else
1976 return FALSE;
1977
1978 wxMouseEvent event( event_type );
1979 // Can't use InitMouse macro because scroll events don't have button
1980 event.SetTimestamp( gdk_event->time );
1981 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1982 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1983 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1984 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1985 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1986 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1987 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
58d185f7 1988 event.m_linesPerAction = 3;
60773911 1989 event.m_wheelDelta = 120;
557c9f5b
JS
1990 if (gdk_event->direction == GDK_SCROLL_UP)
1991 event.m_wheelRotation = 120;
1992 else
1993 event.m_wheelRotation = -120;
1994
1995 wxPoint pt = win->GetClientAreaOrigin();
1996 event.m_x = (wxCoord)gdk_event->x - pt.x;
1997 event.m_y = (wxCoord)gdk_event->y - pt.y;
1998
1999 event.SetEventObject( win );
2000 event.SetId( win->GetId() );
2001 event.SetTimestamp( gdk_event->time );
2002
2003 if (win->GetEventHandler()->ProcessEvent( event ))
2004 {
2005 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "scroll_event" );
2006 return TRUE;
2007 }
2008
2009 return FALSE;
2010}
ac103441
RR
2011
2012//-----------------------------------------------------------------------------
2013// "popup-menu"
2014//-----------------------------------------------------------------------------
2015static gboolean wxgtk_window_popup_menu_callback(GtkWidget*, wxWindowGTK* win)
2016{
2017 wxContextMenuEvent event(
2018 wxEVT_CONTEXT_MENU,
2019 win->GetId(),
2020 wxPoint(-1, -1));
2021 event.SetEventObject(win);
2022 return win->GetEventHandler()->ProcessEvent(event);
2023}
2024#endif // __WXGTK20__
557c9f5b 2025
c801d85f 2026//-----------------------------------------------------------------------------
2f2aa628
RR
2027// "focus_in_event"
2028//-----------------------------------------------------------------------------
c801d85f 2029
6aeb6f2a
VZ
2030// send the wxChildFocusEvent and wxFocusEvent, common code of
2031// gtk_window_focus_in_callback() and SetFocus()
2032static bool DoSendFocusEvents(wxWindow *win)
2033{
2034 // Notify the parent keeping track of focus for the kbd navigation
2035 // purposes that we got it.
2036 wxChildFocusEvent eventChildFocus(win);
2037 (void)win->GetEventHandler()->ProcessEvent(eventChildFocus);
2038
2039 wxFocusEvent eventFocus(wxEVT_SET_FOCUS, win->GetId());
2040 eventFocus.SetEventObject(win);
2041
2042 return win->GetEventHandler()->ProcessEvent(eventFocus);
2043}
2044
1e6feb95
VZ
2045static gint gtk_window_focus_in_callback( GtkWidget *widget,
2046 GdkEvent *WXUNUSED(event),
2047 wxWindow *win )
c801d85f 2048{
3ac8d3bc 2049 DEBUG_MAIN_THREAD
06fda9e8 2050
c50f1fb9 2051 if (g_isIdle)
a2053b27
RR
2052 wxapp_install_idle_handler();
2053
4b1ae153 2054#ifdef __WXGTK20__
a3c15d89
VS
2055 if (win->m_imData)
2056 gtk_im_context_focus_in(win->m_imData->context);
4b1ae153
VS
2057#endif
2058
1e6feb95 2059 g_focusWindowLast =
b292e2f5 2060 g_focusWindow = win;
ff8bfdbb 2061
6cad4f1b
VZ
2062 wxLogTrace(TRACE_FOCUS,
2063 _T("%s: focus in"), win->GetName().c_str());
7de59551 2064
b79395c5
RR
2065#ifdef HAVE_XIM
2066 if (win->m_ic)
2067 gdk_im_begin(win->m_ic, win->m_wxwindow->window);
2068#endif
2069
1e6feb95 2070#if wxUSE_CARET
f6bcfd97
BP
2071 // caret needs to be informed about focus change
2072 wxCaret *caret = win->GetCaret();
2073 if ( caret )
2074 {
2075 caret->OnSetFocus();
2076 }
2077#endif // wxUSE_CARET
2078
6cad4f1b
VZ
2079 // does the window itself think that it has the focus?
2080 if ( !win->m_hasFocus )
5cd09f0b 2081 {
6cad4f1b
VZ
2082 // not yet, notify it
2083 win->m_hasFocus = TRUE;
576f7127 2084
6cad4f1b
VZ
2085 if ( DoSendFocusEvents(win) )
2086 {
2087 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
2088 return TRUE;
2089 }
034be888 2090 }
ca298c88 2091
034be888 2092 return FALSE;
362c6693 2093}
c801d85f
KB
2094
2095//-----------------------------------------------------------------------------
2f2aa628
RR
2096// "focus_out_event"
2097//-----------------------------------------------------------------------------
c801d85f 2098
afbe906a 2099static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEventFocus *gdk_event, wxWindowGTK *win )
c801d85f 2100{
3ac8d3bc
RR
2101 DEBUG_MAIN_THREAD
2102
c50f1fb9 2103 if (g_isIdle)
a2053b27
RR
2104 wxapp_install_idle_handler();
2105
4b1ae153 2106#ifdef __WXGTK20__
a3c15d89
VS
2107 if (win->m_imData)
2108 gtk_im_context_focus_out(win->m_imData->context);
4b1ae153
VS
2109#endif
2110
6cad4f1b
VZ
2111 wxLogTrace( TRACE_FOCUS,
2112 _T("%s: focus out"), win->GetName().c_str() );
b231914f 2113
148cd9b6 2114
3379ed37 2115 wxWindowGTK *winFocus = wxFindFocusedChild(win);
f6bcfd97
BP
2116 if ( winFocus )
2117 win = winFocus;
2118
1e6feb95 2119 g_focusWindow = (wxWindowGTK *)NULL;
148cd9b6 2120
b79395c5
RR
2121#ifdef HAVE_XIM
2122 if (win->m_ic)
2123 gdk_im_end();
2124#endif
2125
1e6feb95 2126#if wxUSE_CARET
f6bcfd97
BP
2127 // caret needs to be informed about focus change
2128 wxCaret *caret = win->GetCaret();
2129 if ( caret )
2130 {
2131 caret->OnKillFocus();
2132 }
2133#endif // wxUSE_CARET
2134
6cad4f1b
VZ
2135 // don't send the window a kill focus event if it thinks that it doesn't
2136 // have focus already
2137 if ( win->m_hasFocus )
5cd09f0b 2138 {
6cad4f1b
VZ
2139 win->m_hasFocus = FALSE;
2140
2141 wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
2142 event.SetEventObject( win );
2143
a752b8c4
VZ
2144 // even if we did process the event in wx code, still let GTK itself
2145 // process it too as otherwise bad things happen, especially in GTK2
2146 // where the text control simply aborts the program if it doesn't get
2147 // the matching focus out event
2148 (void)win->GetEventHandler()->ProcessEvent( event );
034be888 2149 }
ca298c88 2150
034be888 2151 return FALSE;
362c6693 2152}
c801d85f 2153
b4071e91
RR
2154//-----------------------------------------------------------------------------
2155// "enter_notify_event"
2156//-----------------------------------------------------------------------------
2157
edc1d330
VZ
2158static
2159gint gtk_window_enter_callback( GtkWidget *widget,
2160 GdkEventCrossing *gdk_event,
2161 wxWindowGTK *win )
b4071e91 2162{
3ac8d3bc
RR
2163 DEBUG_MAIN_THREAD
2164
c50f1fb9 2165 if (g_isIdle)
a2053b27 2166 wxapp_install_idle_handler();
ca298c88 2167
a2053b27
RR
2168 if (!win->m_hasVMT) return FALSE;
2169 if (g_blockEventsOnDrag) return FALSE;
47d67540 2170
7f5f144a
RR
2171 // Event was emitted after a grab
2172 if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
7c5e6fc6 2173
a2053b27 2174 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
b292e2f5 2175
4a33eba6
RR
2176 int x = 0;
2177 int y = 0;
2178 GdkModifierType state = (GdkModifierType)0;
ff8bfdbb 2179
a2053b27 2180 gdk_window_get_pointer( widget->window, &x, &y, &state );
ff8bfdbb 2181
edc1d330 2182 wxMouseEvent event( wxEVT_ENTER_WINDOW );
c5f9d156
VS
2183 InitMouseEvent(win, event, gdk_event);
2184 wxPoint pt = win->GetClientAreaOrigin();
2185 event.m_x = x + pt.x;
2186 event.m_y = y + pt.y;
ff8bfdbb 2187
e380f72b 2188 if (win->GetEventHandler()->ProcessEvent( event ))
034be888 2189 {
e380f72b 2190 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "enter_notify_event" );
034be888
RR
2191 return TRUE;
2192 }
ca298c88 2193
034be888 2194 return FALSE;
b4071e91 2195}
47d67540 2196
b4071e91
RR
2197//-----------------------------------------------------------------------------
2198// "leave_notify_event"
2199//-----------------------------------------------------------------------------
2200
1e6feb95 2201static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win )
b4071e91 2202{
3ac8d3bc
RR
2203 DEBUG_MAIN_THREAD
2204
c50f1fb9 2205 if (g_isIdle)
a2053b27 2206 wxapp_install_idle_handler();
acfd422a 2207
a2053b27
RR
2208 if (!win->m_hasVMT) return FALSE;
2209 if (g_blockEventsOnDrag) return FALSE;
b292e2f5 2210
7f5f144a
RR
2211 // Event was emitted after an ungrab
2212 if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
7c5e6fc6 2213
a2053b27 2214 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
c50f1fb9 2215
e380f72b 2216 wxMouseEvent event( wxEVT_LEAVE_WINDOW );
d1367c3d 2217 event.SetTimestamp( gdk_event->time );
e380f72b 2218 event.SetEventObject( win );
47d67540 2219
4a33eba6
RR
2220 int x = 0;
2221 int y = 0;
2222 GdkModifierType state = (GdkModifierType)0;
ff8bfdbb 2223
4a33eba6 2224 gdk_window_get_pointer( widget->window, &x, &y, &state );
ff8bfdbb 2225
74710601
VZ
2226 event.m_shiftDown = (state & GDK_SHIFT_MASK) != 0;
2227 event.m_controlDown = (state & GDK_CONTROL_MASK) != 0;
2228 event.m_altDown = (state & GDK_MOD1_MASK) != 0;
2229 event.m_metaDown = (state & GDK_MOD2_MASK) != 0;
2230 event.m_leftDown = (state & GDK_BUTTON1_MASK) != 0;
2231 event.m_middleDown = (state & GDK_BUTTON2_MASK) != 0;
2232 event.m_rightDown = (state & GDK_BUTTON3_MASK) != 0;
4a33eba6 2233
c5f9d156
VS
2234 wxPoint pt = win->GetClientAreaOrigin();
2235 event.m_x = x + pt.x;
2236 event.m_y = y + pt.y;
ff8bfdbb 2237
e380f72b 2238 if (win->GetEventHandler()->ProcessEvent( event ))
034be888 2239 {
e380f72b 2240 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "leave_notify_event" );
034be888
RR
2241 return TRUE;
2242 }
ca298c88 2243
034be888 2244 return FALSE;
b4071e91 2245}
47d67540 2246
c801d85f 2247//-----------------------------------------------------------------------------
2f2aa628
RR
2248// "value_changed" from m_vAdjust
2249//-----------------------------------------------------------------------------
c801d85f 2250
9e691f46
VZ
2251static void gtk_window_vscroll_callback( GtkAdjustment *adjust,
2252 SCROLLBAR_CBACK_ARG
2253 wxWindowGTK *win )
c801d85f 2254{
3ac8d3bc
RR
2255 DEBUG_MAIN_THREAD
2256
c50f1fb9 2257 if (g_isIdle)
a2053b27 2258 wxapp_install_idle_handler();
c801d85f 2259
a2053b27 2260 if (g_blockEventsOnDrag) return;
47d67540 2261
a2053b27 2262 if (!win->m_hasVMT) return;
148cd9b6 2263
5e014a0c 2264 float diff = adjust->value - win->m_oldVerticalPos;
e380f72b 2265 if (fabs(diff) < 0.2) return;
148cd9b6 2266
5e014a0c 2267 win->m_oldVerticalPos = adjust->value;
47d67540 2268
a8bf1826 2269#ifndef __WXGTK20__
6728fb61 2270 GtkScrolledWindow *sw = GTK_SCROLLED_WINDOW(win->m_widget);
a8bf1826 2271#endif
6728fb61 2272 wxEventType command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw->vscrollbar));
148cd9b6 2273
5e014a0c 2274 int value = (int)(adjust->value+0.5);
c801d85f 2275
c5b42c87 2276 wxScrollWinEvent event( command, value, wxVERTICAL );
e380f72b
RR
2277 event.SetEventObject( win );
2278 win->GetEventHandler()->ProcessEvent( event );
362c6693 2279}
c801d85f
KB
2280
2281//-----------------------------------------------------------------------------
2f2aa628
RR
2282// "value_changed" from m_hAdjust
2283//-----------------------------------------------------------------------------
c801d85f 2284
9e691f46
VZ
2285static void gtk_window_hscroll_callback( GtkAdjustment *adjust,
2286 SCROLLBAR_CBACK_ARG
2287 wxWindowGTK *win )
47d67540 2288{
3ac8d3bc
RR
2289 DEBUG_MAIN_THREAD
2290
c50f1fb9 2291 if (g_isIdle)
a2053b27 2292 wxapp_install_idle_handler();
47d67540 2293
a2053b27
RR
2294 if (g_blockEventsOnDrag) return;
2295 if (!win->m_hasVMT) return;
47d67540 2296
5e014a0c 2297 float diff = adjust->value - win->m_oldHorizontalPos;
e380f72b 2298 if (fabs(diff) < 0.2) return;
148cd9b6 2299
a8bf1826 2300#ifndef __WXGTK20__
6728fb61 2301 GtkScrolledWindow *sw = GTK_SCROLLED_WINDOW(win->m_widget);
a8bf1826 2302#endif
6728fb61 2303 wxEventType command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw->hscrollbar));
148cd9b6 2304
9e691f46 2305 win->m_oldHorizontalPos = adjust->value;
148cd9b6 2306
5e014a0c 2307 int value = (int)(adjust->value+0.5);
47d67540 2308
c5b42c87 2309 wxScrollWinEvent event( command, value, wxHORIZONTAL );
e380f72b
RR
2310 event.SetEventObject( win );
2311 win->GetEventHandler()->ProcessEvent( event );
362c6693 2312}
c801d85f 2313
cb43b372
RR
2314//-----------------------------------------------------------------------------
2315// "button_press_event" from scrollbar
2316//-----------------------------------------------------------------------------
2317
2a23d363
RR
2318static gint gtk_scrollbar_button_press_callback( GtkRange *widget,
2319 GdkEventButton *gdk_event,
1e6feb95 2320 wxWindowGTK *win)
cb43b372 2321{
3ac8d3bc
RR
2322 DEBUG_MAIN_THREAD
2323
c50f1fb9 2324 if (g_isIdle)
a2053b27
RR
2325 wxapp_install_idle_handler();
2326
d6d26e04 2327
5b8a521e 2328 g_blockEventsOnScroll = TRUE;
9e691f46
VZ
2329
2330 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2331#ifndef __WXGTK20__
2a23d363 2332 win->m_isScrolling = (gdk_event->window == widget->slider);
9e691f46 2333#endif
47d67540 2334
e380f72b 2335 return FALSE;
cb43b372
RR
2336}
2337
2338//-----------------------------------------------------------------------------
2339// "button_release_event" from scrollbar
2340//-----------------------------------------------------------------------------
2341
88413fec 2342static gint gtk_scrollbar_button_release_callback( GtkRange *widget,
8bbe427f 2343 GdkEventButton *WXUNUSED(gdk_event),
1e6feb95 2344 wxWindowGTK *win)
cb43b372 2345{
3ac8d3bc
RR
2346 DEBUG_MAIN_THREAD
2347
1ecc4d80 2348// don't test here as we can release the mouse while being over
5e014a0c 2349// a different window than the slider
76ed8f8d
RR
2350//
2351// if (gdk_event->window != widget->slider) return FALSE;
cb43b372 2352
5b8a521e 2353 g_blockEventsOnScroll = FALSE;
47d67540 2354
2a23d363 2355 if (win->m_isScrolling)
88413fec 2356 {
d6d26e04 2357 wxEventType command = wxEVT_SCROLLWIN_THUMBRELEASE;
2a23d363
RR
2358 int value = -1;
2359 int dir = -1;
2daa0ce9 2360
2a23d363
RR
2361 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
2362 if (widget == GTK_RANGE(scrolledWindow->hscrollbar))
2363 {
2364 value = (int)(win->m_hAdjust->value+0.5);
2365 dir = wxHORIZONTAL;
2366 }
2367 if (widget == GTK_RANGE(scrolledWindow->vscrollbar))
2368 {
2369 value = (int)(win->m_vAdjust->value+0.5);
2370 dir = wxVERTICAL;
2371 }
2daa0ce9 2372
2a23d363 2373 wxScrollWinEvent event( command, value, dir );
2a23d363
RR
2374 event.SetEventObject( win );
2375 win->GetEventHandler()->ProcessEvent( event );
88413fec
RR
2376 }
2377
2a23d363 2378 win->m_isScrolling = FALSE;
2daa0ce9 2379
e380f72b 2380 return FALSE;
cb43b372
RR
2381}
2382
f03fc89f
VZ
2383// ----------------------------------------------------------------------------
2384// this wxWindowBase function is implemented here (in platform-specific file)
2385// because it is static and so couldn't be made virtual
2386// ----------------------------------------------------------------------------
2b07d713 2387
0fe02759 2388wxWindow *wxWindowBase::DoFindFocus()
2b07d713 2389{
1e6feb95
VZ
2390 // the cast is necessary when we compile in wxUniversal mode
2391 return (wxWindow *)g_focusWindow;
2b07d713 2392}
ca298c88 2393
1a685a59 2394
a2053b27
RR
2395//-----------------------------------------------------------------------------
2396// "realize" from m_widget
2397//-----------------------------------------------------------------------------
2398
b79395c5
RR
2399/* We cannot set colours and fonts before the widget has
2400 been realized, so we do this directly after realization. */
a2053b27
RR
2401
2402static gint
2b5f62a0 2403gtk_window_realized_callback( GtkWidget *m_widget, wxWindow *win )
a2053b27 2404{
3ac8d3bc
RR
2405 DEBUG_MAIN_THREAD
2406
c50f1fb9 2407 if (g_isIdle)
a2053b27 2408 wxapp_install_idle_handler();
2b904684 2409
2b5f62a0 2410#ifdef __WXGTK20__
a3c15d89 2411 if (win->m_imData)
2b5f62a0
VZ
2412 {
2413 GtkPizza *pizza = GTK_PIZZA( m_widget );
a3c15d89
VS
2414 gtk_im_context_set_client_window( win->m_imData->context,
2415 pizza->bin_window );
2b5f62a0
VZ
2416 }
2417#endif
2418
3c679789
RR
2419 wxWindowCreateEvent event( win );
2420 event.SetEventObject( win );
2421 win->GetEventHandler()->ProcessEvent( event );
1e6feb95 2422
a2053b27
RR
2423 return FALSE;
2424}
2425
b79395c5
RR
2426//-----------------------------------------------------------------------------
2427// "size_allocate"
2428//-----------------------------------------------------------------------------
2429
8f75cb6c 2430static
adc1999b
RR
2431void gtk_window_size_callback( GtkWidget *WXUNUSED(widget),
2432 GtkAllocation *WXUNUSED(alloc),
8f75cb6c
RR
2433 wxWindow *win )
2434{
2435 if (g_isIdle)
2436 wxapp_install_idle_handler();
2daa0ce9 2437
5b8a521e 2438 if (!win->m_hasScrolling) return;
2daa0ce9 2439
5b8a521e
RR
2440 int client_width = 0;
2441 int client_height = 0;
2442 win->GetClientSize( &client_width, &client_height );
2443 if ((client_width == win->m_oldClientWidth) && (client_height == win->m_oldClientHeight))
2444 return;
2daa0ce9 2445
5b8a521e
RR
2446 win->m_oldClientWidth = client_width;
2447 win->m_oldClientHeight = client_height;
2daa0ce9 2448
5b8a521e
RR
2449 if (!win->m_nativeSizeEvent)
2450 {
2451 wxSizeEvent event( win->GetSize(), win->GetId() );
2452 event.SetEventObject( win );
2453 win->GetEventHandler()->ProcessEvent( event );
2454 }
8f75cb6c
RR
2455}
2456
2457
3ed2e7ce
VZ
2458#ifdef HAVE_XIM
2459 #define WXUNUSED_UNLESS_XIM(param) param
2460#else
2461 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2462#endif
2463
b79395c5
RR
2464/* Resize XIM window */
2465
3ed2e7ce 2466static
8f75cb6c
RR
2467void gtk_wxwindow_size_callback( GtkWidget* WXUNUSED_UNLESS_XIM(widget),
2468 GtkAllocation* WXUNUSED_UNLESS_XIM(alloc),
1e6feb95 2469 wxWindowGTK* WXUNUSED_UNLESS_XIM(win) )
b79395c5
RR
2470{
2471 if (g_isIdle)
2472 wxapp_install_idle_handler();
2daa0ce9 2473
9a8c7620 2474#ifdef HAVE_XIM
b79395c5
RR
2475 if (!win->m_ic)
2476 return;
2477
b79395c5
RR
2478 if (gdk_ic_get_style (win->m_ic) & GDK_IM_PREEDIT_POSITION)
2479 {
2480 gint width, height;
2481
3ed2e7ce 2482 gdk_window_get_size (widget->window, &width, &height);
b79395c5
RR
2483 win->m_icattr->preedit_area.width = width;
2484 win->m_icattr->preedit_area.height = height;
2485 gdk_ic_set_attr (win->m_ic, win->m_icattr, GDK_IC_PREEDIT_AREA);
2486 }
9a8c7620 2487#endif // HAVE_XIM
b79395c5
RR
2488}
2489
63081513
RR
2490//-----------------------------------------------------------------------------
2491// "realize" from m_wxwindow
2492//-----------------------------------------------------------------------------
2493
2494/* Initialize XIM support */
2495
2496static gint
3ed2e7ce 2497gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget),
1e6feb95 2498 wxWindowGTK * WXUNUSED_UNLESS_XIM(win) )
63081513
RR
2499{
2500 if (g_isIdle)
2501 wxapp_install_idle_handler();
2502
d06800f1 2503#ifdef HAVE_XIM
63081513
RR
2504 if (win->m_ic) return FALSE;
2505 if (!widget) return FALSE;
2506 if (!gdk_im_ready()) return FALSE;
2507
2508 win->m_icattr = gdk_ic_attr_new();
2509 if (!win->m_icattr) return FALSE;
2daa0ce9 2510
63081513
RR
2511 gint width, height;
2512 GdkEventMask mask;
2513 GdkColormap *colormap;
2514 GdkICAttr *attr = win->m_icattr;
b58b1dfc 2515 unsigned attrmask = GDK_IC_ALL_REQ;
63081513 2516 GdkIMStyle style;
b79395c5
RR
2517 GdkIMStyle supported_style = (GdkIMStyle)
2518 (GDK_IM_PREEDIT_NONE |
1e6feb95
VZ
2519 GDK_IM_PREEDIT_NOTHING |
2520 GDK_IM_PREEDIT_POSITION |
2521 GDK_IM_STATUS_NONE |
2522 GDK_IM_STATUS_NOTHING);
63081513
RR
2523
2524 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
1e6feb95 2525 supported_style = (GdkIMStyle)(supported_style & ~GDK_IM_PREEDIT_POSITION);
63081513
RR
2526
2527 attr->style = style = gdk_im_decide_style (supported_style);
2528 attr->client_window = widget->window;
2529
2530 if ((colormap = gtk_widget_get_colormap (widget)) !=
1e6feb95 2531 gtk_widget_get_default_colormap ())
63081513 2532 {
5cd09f0b
RR
2533 attrmask |= GDK_IC_PREEDIT_COLORMAP;
2534 attr->preedit_colormap = colormap;
63081513 2535 }
2daa0ce9 2536
63081513
RR
2537 attrmask |= GDK_IC_PREEDIT_FOREGROUND;
2538 attrmask |= GDK_IC_PREEDIT_BACKGROUND;
2539 attr->preedit_foreground = widget->style->fg[GTK_STATE_NORMAL];
2540 attr->preedit_background = widget->style->base[GTK_STATE_NORMAL];
2541
2542 switch (style & GDK_IM_PREEDIT_MASK)
2543 {
1e6feb95
VZ
2544 case GDK_IM_PREEDIT_POSITION:
2545 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
2546 {
2547 g_warning ("over-the-spot style requires fontset");
2548 break;
2549 }
63081513 2550
1e6feb95 2551 gdk_window_get_size (widget->window, &width, &height);
63081513 2552
1e6feb95
VZ
2553 attrmask |= GDK_IC_PREEDIT_POSITION_REQ;
2554 attr->spot_location.x = 0;
2555 attr->spot_location.y = height;
2556 attr->preedit_area.x = 0;
2557 attr->preedit_area.y = 0;
2558 attr->preedit_area.width = width;
2559 attr->preedit_area.height = height;
2560 attr->preedit_fontset = widget->style->font;
63081513 2561
1e6feb95 2562 break;
b79395c5 2563 }
2daa0ce9 2564
b58b1dfc 2565 win->m_ic = gdk_ic_new (attr, (GdkICAttributesType)attrmask);
2daa0ce9 2566
63081513 2567 if (win->m_ic == NULL)
1e6feb95 2568 g_warning ("Can't create input context.");
63081513 2569 else
1e6feb95
VZ
2570 {
2571 mask = gdk_window_get_events (widget->window);
2572 mask = (GdkEventMask)(mask | gdk_ic_get_events (win->m_ic));
2573 gdk_window_set_events (widget->window, mask);
2574
2575 if (GTK_WIDGET_HAS_FOCUS(widget))
2576 gdk_im_begin (win->m_ic, widget->window);
2577 }
2578#endif // HAVE_XIM
63081513
RR
2579
2580 return FALSE;
2581}
2582
6ca41e57 2583//-----------------------------------------------------------------------------
1e6feb95 2584// InsertChild for wxWindowGTK.
6ca41e57
RR
2585//-----------------------------------------------------------------------------
2586
1e6feb95 2587/* Callback for wxWindowGTK. This very strange beast has to be used because
b1170810
RR
2588 * C++ has no virtual methods in a constructor. We have to emulate a
2589 * virtual function here as wxNotebook requires a different way to insert
2590 * a child in it. I had opted for creating a wxNotebookPage window class
2591 * which would have made this superfluous (such in the MDI window system),
2592 * but no-one was listening to me... */
6ca41e57 2593
1e6feb95 2594static void wxInsertChildInWindow( wxWindowGTK* parent, wxWindowGTK* child )
6ca41e57 2595{
bf0c00c6
RR
2596 /* the window might have been scrolled already, do we
2597 have to adapt the position */
da048e3d
RR
2598 GtkPizza *pizza = GTK_PIZZA(parent->m_wxwindow);
2599 child->m_x += pizza->xoffset;
2600 child->m_y += pizza->yoffset;
148cd9b6 2601
da048e3d 2602 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
a2053b27
RR
2603 GTK_WIDGET(child->m_widget),
2604 child->m_x,
2605 child->m_y,
2606 child->m_width,
2607 child->m_height );
6ca41e57
RR
2608}
2609
bbe0af5b
RR
2610//-----------------------------------------------------------------------------
2611// global functions
2612//-----------------------------------------------------------------------------
2613
1e6feb95 2614wxWindow *wxGetActiveWindow()
bbe0af5b 2615{
6cad4f1b 2616 return wxWindow::FindFocus();
bbe0af5b
RR
2617}
2618
c801d85f 2619//-----------------------------------------------------------------------------
1e6feb95 2620// wxWindowGTK
c801d85f
KB
2621//-----------------------------------------------------------------------------
2622
6522713c
VZ
2623// in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2624// method
1e6feb95 2625#ifdef __WXUNIVERSAL__
6522713c
VZ
2626 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK, wxWindowBase)
2627#else // __WXGTK__
1e6feb95 2628 IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
6522713c 2629#endif // __WXUNIVERSAL__/__WXGTK__
c801d85f 2630
1e6feb95 2631void wxWindowGTK::Init()
c801d85f 2632{
f03fc89f 2633 // GTK specific
a2053b27 2634 m_widget = (GtkWidget *) NULL;
e380f72b 2635 m_wxwindow = (GtkWidget *) NULL;
76fcf0f2 2636 m_focusWidget = (GtkWidget *) NULL;
8bbe427f 2637
f03fc89f 2638 // position/size
a2053b27
RR
2639 m_x = 0;
2640 m_y = 0;
2641 m_width = 0;
e380f72b 2642 m_height = 0;
8bbe427f 2643
e380f72b
RR
2644 m_sizeSet = FALSE;
2645 m_hasVMT = FALSE;
2646 m_needParent = TRUE;
31c6b4fc 2647 m_isBeingDeleted = FALSE;
148cd9b6 2648
147bc491 2649 m_noExpose = FALSE;
30760ce7 2650 m_nativeSizeEvent = FALSE;
94633ad9 2651
a2053b27 2652 m_hasScrolling = FALSE;
846e1424 2653 m_isScrolling = FALSE;
f03fc89f 2654
a2053b27 2655 m_hAdjust = (GtkAdjustment*) NULL;
e380f72b 2656 m_vAdjust = (GtkAdjustment*) NULL;
815ac4a7 2657 m_oldHorizontalPos =
e380f72b 2658 m_oldVerticalPos = 0.0;
815ac4a7
VZ
2659 m_oldClientWidth =
2660 m_oldClientHeight = 0;
8bbe427f 2661
e380f72b 2662 m_resizing = FALSE;
8bbe427f 2663
ddb6bc71 2664 m_insertCallback = (wxInsertChildFunction) NULL;
8bbe427f 2665
b292e2f5 2666 m_acceptsFocus = FALSE;
6cad4f1b 2667 m_hasFocus = FALSE;
148cd9b6 2668
b6fa52db 2669 m_clipPaintRegion = FALSE;
b6fa52db 2670
c7382f91
JS
2671 m_needsStyleChange = false;
2672
5e014a0c 2673 m_cursor = *wxSTANDARD_CURSOR;
2daa0ce9 2674
2b5f62a0 2675#ifdef __WXGTK20__
a3c15d89 2676 m_imData = NULL;
2b5f62a0 2677 m_x11Context = NULL;
a589495e 2678 m_dirtyTabOrder = false;
2b5f62a0 2679#else
63081513
RR
2680#ifdef HAVE_XIM
2681 m_ic = (GdkIC*) NULL;
2682 m_icattr = (GdkICAttr*) NULL;
2683#endif
2b5f62a0 2684#endif
362c6693 2685}
c801d85f 2686
1e6feb95 2687wxWindowGTK::wxWindowGTK()
68995f26
VZ
2688{
2689 Init();
2690}
2691
1e6feb95
VZ
2692wxWindowGTK::wxWindowGTK( wxWindow *parent,
2693 wxWindowID id,
2694 const wxPoint &pos,
2695 const wxSize &size,
2696 long style,
2697 const wxString &name )
6ca41e57 2698{
68995f26
VZ
2699 Init();
2700
e380f72b 2701 Create( parent, id, pos, size, style, name );
6ca41e57 2702}
8bbe427f 2703
1e6feb95
VZ
2704bool wxWindowGTK::Create( wxWindow *parent,
2705 wxWindowID id,
2706 const wxPoint &pos,
2707 const wxSize &size,
2708 long style,
2709 const wxString &name )
c801d85f 2710{
4dcaf11a
RR
2711 if (!PreCreation( parent, pos, size ) ||
2712 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
2713 {
1e6feb95 2714 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
b02da6b1 2715 return FALSE;
4dcaf11a 2716 }
47d67540 2717
ddb6bc71 2718 m_insertCallback = wxInsertChildInWindow;
2b5f62a0 2719
e380f72b 2720 m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
38c7b3d3 2721 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
ff8bfdbb 2722
f03fc89f 2723 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
47d67540 2724
dd00f3f6 2725 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
e380f72b 2726 scroll_class->scrollbar_spacing = 0;
47d67540 2727
f03fc89f 2728 gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
47d67540 2729
f03fc89f
VZ
2730 m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->hscrollbar) );
2731 m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->vscrollbar) );
47d67540 2732
da048e3d 2733 m_wxwindow = gtk_pizza_new();
0fc5dbf5 2734
1e6feb95 2735#ifndef __WXUNIVERSAL__
da048e3d 2736 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
b292e2f5 2737
f03fc89f 2738 if (HasFlag(wxRAISED_BORDER))
034be888 2739 {
da048e3d 2740 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_OUT );
034be888 2741 }
f03fc89f 2742 else if (HasFlag(wxSUNKEN_BORDER))
034be888 2743 {
da048e3d 2744 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_IN );
5e014a0c
RR
2745 }
2746 else if (HasFlag(wxSIMPLE_BORDER))
2747 {
da048e3d 2748 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_THIN );
034be888
RR
2749 }
2750 else
2751 {
da048e3d 2752 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_NONE );
034be888 2753 }
1e6feb95 2754#endif // __WXUNIVERSAL__
47d67540 2755
4e5a4c69
RR
2756 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
2757
3da17724
RR
2758 GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
2759 m_acceptsFocus = TRUE;
ca298c88 2760
e380f72b 2761 // I _really_ don't want scrollbars in the beginning
a2053b27
RR
2762 m_vAdjust->lower = 0.0;
2763 m_vAdjust->upper = 1.0;
2764 m_vAdjust->value = 0.0;
2765 m_vAdjust->step_increment = 1.0;
2766 m_vAdjust->page_increment = 1.0;
2767 m_vAdjust->page_size = 5.0;
2768 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
2769 m_hAdjust->lower = 0.0;
2770 m_hAdjust->upper = 1.0;
2771 m_hAdjust->value = 0.0;
2772 m_hAdjust->step_increment = 1.0;
2773 m_hAdjust->page_increment = 1.0;
2774 m_hAdjust->page_size = 5.0;
2775 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
f03fc89f
VZ
2776
2777 // these handlers block mouse events to any window during scrolling such as
77ffb593 2778 // motion events and prevent GTK and wxWidgets from fighting over where the
f03fc89f
VZ
2779 // slider should be
2780
2781 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_press_event",
76ed8f8d
RR
2782 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2783
f03fc89f 2784 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_press_event",
76ed8f8d
RR
2785 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2786
f03fc89f 2787 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_release_event",
76ed8f8d
RR
2788 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2789
f03fc89f 2790 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_release_event",
76ed8f8d 2791 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
8bbe427f 2792
034be888 2793 // these handlers get notified when screen updates are required either when
76ed8f8d
RR
2794 // scrolling or when the window size (and therefore scrollbar configuration)
2795 // has changed
2796
2797 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
2798 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
2799 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
2800 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
2801
f03fc89f 2802 gtk_widget_show( m_wxwindow );
47d67540 2803
f03fc89f
VZ
2804 if (m_parent)
2805 m_parent->DoAddChild( this );
94633ad9 2806
76fcf0f2 2807 m_focusWidget = m_wxwindow;
8bbe427f 2808
e380f72b 2809 PostCreation();
8bbe427f 2810
e380f72b 2811 return TRUE;
362c6693 2812}
c801d85f 2813
1e6feb95 2814wxWindowGTK::~wxWindowGTK()
c801d85f 2815{
7de59551
RD
2816 SendDestroyEvent();
2817
44cd54c2
JS
2818 if (g_focusWindow == this)
2819 g_focusWindow = NULL;
2820
3e679f01
VZ
2821 if ( g_delayedFocus == this )
2822 g_delayedFocus = NULL;
2823
31c6b4fc 2824 m_isBeingDeleted = TRUE;
43a18898 2825 m_hasVMT = FALSE;
47d67540 2826
f03fc89f
VZ
2827 if (m_widget)
2828 Show( FALSE );
8bbe427f 2829
a2053b27
RR
2830 DestroyChildren();
2831
63081513
RR
2832#ifdef HAVE_XIM
2833 if (m_ic)
2834 gdk_ic_destroy (m_ic);
2835 if (m_icattr)
2836 gdk_ic_attr_destroy (m_icattr);
2837#endif
2838
f03fc89f 2839 if (m_wxwindow)
a2053b27 2840 {
f03fc89f 2841 gtk_widget_destroy( m_wxwindow );
c50f1fb9 2842 m_wxwindow = (GtkWidget*) NULL;
a2053b27 2843 }
8bbe427f 2844
f03fc89f 2845 if (m_widget)
a2053b27 2846 {
f03fc89f 2847 gtk_widget_destroy( m_widget );
c50f1fb9 2848 m_widget = (GtkWidget*) NULL;
a2053b27 2849 }
a3c15d89
VS
2850
2851#ifdef __WXGTK20__
2852 delete m_imData;
2853#endif
362c6693 2854}
c801d85f 2855
1e6feb95 2856bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos, const wxSize &size )
c801d85f 2857{
223d09f6 2858 wxCHECK_MSG( !m_needParent || parent, FALSE, wxT("Need complete parent.") );
8bbe427f 2859
a7c26d10
RD
2860 // Use either the given size, or the default if -1 is given.
2861 // See wxWindowBase for these functions.
3013a903 2862 m_width = WidthDefault(size.x) ;
f03fc89f 2863 m_height = HeightDefault(size.y);
8bbe427f 2864
43a18898
RR
2865 m_x = (int)pos.x;
2866 m_y = (int)pos.y;
8bbe427f 2867
4dcaf11a 2868 return TRUE;
c801d85f
KB
2869}
2870
1e6feb95 2871void wxWindowGTK::PostCreation()
c801d85f 2872{
82b978d7
RD
2873 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2874
43a18898
RR
2875 if (m_wxwindow)
2876 {
147bc491 2877 if (!m_noExpose)
b02da6b1 2878 {
77ffb593 2879 // these get reported to wxWidgets -> wxPaintEvent
1e6feb95 2880
b420fb6a
RR
2881 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow), TRUE );
2882
147bc491
RR
2883 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
2884 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
2885
4e5a4c69 2886#ifndef __WXGTK20__
147bc491
RR
2887 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
2888 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
0fc5dbf5 2889
e441e1f4 2890 if (!HasFlag(wxFULL_REPAINT_ON_RESIZE))
e22454be
RR
2891 {
2892 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "event",
2893 GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this );
2894 }
4e5a4c69 2895#else
e441e1f4 2896 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2b5f62a0 2897#endif
93d23d8f 2898 }
2b5f62a0
VZ
2899
2900#ifdef __WXGTK20__
2901 // Create input method handler
a3c15d89 2902 m_imData = new wxGtkIMData;
2b5f62a0
VZ
2903
2904 // Cannot handle drawing preedited text yet
a3c15d89 2905 gtk_im_context_set_use_preedit( m_imData->context, FALSE );
2b5f62a0 2906
a3c15d89 2907 g_signal_connect (G_OBJECT (m_imData->context), "commit",
da210120 2908 G_CALLBACK (gtk_wxwindow_commit_cb), this);
4e5a4c69 2909#endif
148cd9b6 2910
67d78217 2911 // these are called when the "sunken" or "raised" borders are drawn
034be888
RR
2912 gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
2913 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
2914
4e5a4c69 2915#ifndef __WXGTK20__
034be888
RR
2916 gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
2917 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
4e5a4c69 2918#endif
43a18898 2919 }
47d67540 2920
76fcf0f2 2921 // focus handling
63081513 2922
06fda9e8
RR
2923 if (!GTK_IS_WINDOW(m_widget))
2924 {
2925 if (m_focusWidget == NULL)
2926 m_focusWidget = m_widget;
576f7127 2927
06fda9e8
RR
2928 gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_in_event",
2929 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
76fcf0f2 2930
4ecd9342 2931 gtk_signal_connect_after( GTK_OBJECT(m_focusWidget), "focus_out_event",
06fda9e8
RR
2932 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
2933 }
76fcf0f2
RR
2934
2935 // connect to the various key and mouse handlers
63081513 2936
a2053b27 2937 GtkWidget *connect_widget = GetConnectWidget();
f03fc89f 2938
a2053b27 2939 ConnectWidget( connect_widget );
47d67540 2940
63081513 2941 /* We cannot set colours, fonts and cursors before the widget has
a2053b27
RR
2942 been realized, so we do this directly after realization */
2943 gtk_signal_connect( GTK_OBJECT(connect_widget), "realize",
c50f1fb9 2944 GTK_SIGNAL_FUNC(gtk_window_realized_callback), (gpointer) this );
2daa0ce9 2945
63081513
RR
2946 if (m_wxwindow)
2947 {
47c93b63 2948 // Catch native resize events
8f75cb6c
RR
2949 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2950 GTK_SIGNAL_FUNC(gtk_window_size_callback), (gpointer)this );
2daa0ce9 2951
47c93b63 2952 // Initialize XIM support
63081513
RR
2953 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "realize",
2954 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback), (gpointer) this );
8f75cb6c 2955
47c93b63 2956 // And resize XIM window
b79395c5
RR
2957 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2958 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this );
63081513 2959 }
2daa0ce9 2960
024e9a4c
RR
2961 if (GTK_IS_COMBO(m_widget))
2962 {
2963 GtkCombo *gcombo = GTK_COMBO(m_widget);
2964
2965 gtk_signal_connect( GTK_OBJECT(gcombo->entry), "size_request",
2966 GTK_SIGNAL_FUNC(wxgtk_combo_size_request_callback),
2967 (gpointer) this );
2968 }
2969 else
47c93b63
RR
2970 {
2971 // This is needed if we want to add our windows into native
024e9a4c 2972 // GTK controls, such as the toolbar. With this callback, the
47c93b63 2973 // toolbar gets to know the correct size (the one set by the
024e9a4c 2974 // programmer). Sadly, it misbehaves for wxComboBox.
47c93b63 2975 gtk_signal_connect( GTK_OBJECT(m_widget), "size_request",
e1f448ee
VZ
2976 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback),
2977 (gpointer) this );
47c93b63 2978 }
1e6feb95 2979
40bab631
VS
2980 InheritAttributes();
2981
43a18898 2982 m_hasVMT = TRUE;
a433fbd5
VZ
2983
2984 // unless the window was created initially hidden (i.e. Hide() had been
2985 // called before Create()), we should show it at GTK+ level as well
2986 if ( IsShown() )
2987 gtk_widget_show( m_widget );
b4071e91
RR
2988}
2989
1e6feb95 2990void wxWindowGTK::ConnectWidget( GtkWidget *widget )
b4071e91 2991{
43a18898
RR
2992 gtk_signal_connect( GTK_OBJECT(widget), "key_press_event",
2993 GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this );
c801d85f 2994
b666df2c
RR
2995 gtk_signal_connect( GTK_OBJECT(widget), "key_release_event",
2996 GTK_SIGNAL_FUNC(gtk_window_key_release_callback), (gpointer)this );
2997
43a18898
RR
2998 gtk_signal_connect( GTK_OBJECT(widget), "button_press_event",
2999 GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
47d67540 3000
43a18898
RR
3001 gtk_signal_connect( GTK_OBJECT(widget), "button_release_event",
3002 GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
47d67540 3003
43a18898
RR
3004 gtk_signal_connect( GTK_OBJECT(widget), "motion_notify_event",
3005 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
47d67540 3006
557c9f5b
JS
3007#ifdef __WXGTK20__
3008 gtk_signal_connect( GTK_OBJECT(widget), "scroll_event",
3009 GTK_SIGNAL_FUNC(gtk_window_wheel_callback), (gpointer)this );
ac103441
RR
3010 g_signal_connect(widget, "popup_menu",
3011 G_CALLBACK(wxgtk_window_popup_menu_callback), this);
557c9f5b
JS
3012#endif
3013
43a18898
RR
3014 gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event",
3015 GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
47d67540 3016
43a18898
RR
3017 gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
3018 GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
362c6693 3019}
c801d85f 3020
1e6feb95 3021bool wxWindowGTK::Destroy()
c801d85f 3022{
82b978d7 3023 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
47d67540 3024
43a18898 3025 m_hasVMT = FALSE;
c801d85f 3026
f03fc89f 3027 return wxWindowBase::Destroy();
362c6693 3028}
c801d85f 3029
1e6feb95 3030void wxWindowGTK::DoMoveWindow(int x, int y, int width, int height)
23efdd02
RR
3031{
3032 gtk_pizza_set_size( GTK_PIZZA(m_parent->m_wxwindow), m_widget, x, y, width, height );
3033}
2daa0ce9 3034
1e6feb95 3035void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
c801d85f 3036{
82b978d7 3037 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
1e6feb95 3038 wxASSERT_MSG( (m_parent != NULL), wxT("wxWindowGTK::SetSize requires parent.\n") );
8bbe427f 3039
33611ebb 3040/*
f94fca1b 3041 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
33611ebb
RR
3042*/
3043
e27ce4e9 3044 if (m_resizing) return; /* I don't like recursions */
fb1585ae 3045 m_resizing = TRUE;
1e6feb95 3046
b9f29261
VS
3047 int currentX, currentY;
3048 GetPosition(&currentX, &currentY);
443c834d 3049 if (x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
b9f29261 3050 x = currentX;
443c834d 3051 if (y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
b9f29261 3052 y = currentY;
a200c35e
VS
3053 AdjustForParentClientOrigin(x, y, sizeFlags);
3054
a2053b27 3055 if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
fb1585ae 3056 {
e27ce4e9 3057 /* don't set the size for children of wxNotebook, just take the values. */
fb1585ae
RR
3058 m_x = x;
3059 m_y = y;
3060 m_width = width;
ba4e3652 3061 m_height = height;
fb1585ae 3062 }
ba4e3652 3063 else
fb1585ae 3064 {
da048e3d 3065 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
85ad5eb5 3066 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
ba4e3652 3067 {
da048e3d
RR
3068 if (x != -1) m_x = x + pizza->xoffset;
3069 if (y != -1) m_y = y + pizza->yoffset;
ba4e3652
RR
3070 }
3071 else
3072 {
da048e3d
RR
3073 m_x = x + pizza->xoffset;
3074 m_y = y + pizza->yoffset;
ba4e3652 3075 }
47d67540 3076
a63d48fa 3077 // calculate the best size if we should auto size the window
c7e111cd
VZ
3078 if ( ((sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1) ||
3079 ((sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1) )
ba4e3652 3080 {
a63d48fa 3081 const wxSize sizeBest = GetBestSize();
c7e111cd 3082 if ( (sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1 )
a63d48fa 3083 width = sizeBest.x;
c7e111cd 3084 if ( (sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1 )
a63d48fa 3085 height = sizeBest.y;
ba4e3652
RR
3086 }
3087
a63d48fa
VZ
3088 if (width != -1)
3089 m_width = width;
3090 if (height != -1)
3091 m_height = height;
8bbe427f 3092
e7dda1ff
VS
3093 int minWidth = GetMinWidth(),
3094 minHeight = GetMinHeight(),
3095 maxWidth = GetMaxWidth(),
3096 maxHeight = GetMaxHeight();
3097
3098 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
3099 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
3100 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
3101 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
47d67540 3102
a2053b27 3103 int border = 0;
c50f1fb9 3104 int bottom_border = 0;
f03fc89f 3105
eb9e6a00 3106#ifndef __WXGTK20__
29f538ce 3107 if (GTK_WIDGET_CAN_DEFAULT(m_widget))
c50f1fb9
VZ
3108 {
3109 /* the default button has a border around it */
3110 border = 6;
3111 bottom_border = 5;
3112 }
67d78217 3113#endif
c50f1fb9 3114
23efdd02
RR
3115 DoMoveWindow( m_x-border,
3116 m_y-border,
3117 m_width+2*border,
3118 m_height+border+bottom_border );
54517652 3119 }
148cd9b6 3120
5b8a521e
RR
3121 if (m_hasScrolling)
3122 {
1e6feb95 3123 /* Sometimes the client area changes size without the
b6fa52db
RR
3124 whole windows's size changing, but if the whole
3125 windows's size doesn't change, no wxSizeEvent will
3126 normally be sent. Here we add an extra test if
3127 the client test has been changed and this will
3128 be used then. */
5b8a521e
RR
3129 GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
3130 }
3131
54517652 3132/*
6d693bb4
RR
3133 wxPrintf( "OnSize sent from " );
3134 if (GetClassInfo() && GetClassInfo()->GetClassName())
3135 wxPrintf( GetClassInfo()->GetClassName() );
3136 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3137*/
3138
30760ce7
RR
3139 if (!m_nativeSizeEvent)
3140 {
3141 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
3142 event.SetEventObject( this );
3143 GetEventHandler()->ProcessEvent( event );
3144 }
6d693bb4 3145
fb1585ae 3146 m_resizing = FALSE;
362c6693 3147}
c801d85f 3148
1e6feb95 3149void wxWindowGTK::OnInternalIdle()
9390a202 3150{
a589495e
VS
3151#ifdef __WXGTK20__
3152 if ( m_dirtyTabOrder )
3153 RealizeTabOrder();
3154#endif
c7382f91
JS
3155 // Update style if the window was not yet realized
3156 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
3157 if (m_needsStyleChange)
3158 {
3159 SetBackgroundStyle(GetBackgroundStyle());
3160 m_needsStyleChange = false;
3161 }
a589495e 3162
beab25bd 3163 // Update invalidated regions.
010afced 3164 GtkUpdate();
0fc5dbf5 3165
9146082c
RR
3166 wxCursor cursor = m_cursor;
3167 if (g_globalCursor.Ok()) cursor = g_globalCursor;
c50f1fb9 3168
f7a11f8c 3169 if (cursor.Ok())
9146082c 3170 {
3017f78d 3171 /* I now set the cursor anew in every OnInternalIdle call
b02da6b1
VZ
3172 as setting the cursor in a parent window also effects the
3173 windows above so that checking for the current cursor is
3174 not possible. */
148cd9b6 3175
9146082c 3176 if (m_wxwindow)
6a008b33 3177 {
da048e3d 3178 GdkWindow *window = GTK_PIZZA(m_wxwindow)->bin_window;
6a008b33 3179 if (window)
c50f1fb9 3180 gdk_window_set_cursor( window, cursor.GetCursor() );
6a008b33
VZ
3181
3182 if (!g_globalCursor.Ok())
3183 cursor = *wxSTANDARD_CURSOR;
3184
3185 window = m_widget->window;
5e014a0c 3186 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
9146082c 3187 gdk_window_set_cursor( window, cursor.GetCursor() );
5e014a0c 3188
6a008b33
VZ
3189 }
3190 else
3191 {
5e014a0c 3192
9146082c 3193 GdkWindow *window = m_widget->window;
5e014a0c 3194 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
9146082c 3195 gdk_window_set_cursor( window, cursor.GetCursor() );
5e014a0c 3196
6a008b33 3197 }
9146082c 3198 }
6a008b33 3199
e39af974
JS
3200 if (wxUpdateUIEvent::CanUpdate(this))
3201 UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
9390a202
RR
3202}
3203
1e6feb95 3204void wxWindowGTK::DoGetSize( int *width, int *height ) const
c801d85f 3205{
82b978d7 3206 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3207
fb1585ae
RR
3208 if (width) (*width) = m_width;
3209 if (height) (*height) = m_height;
362c6693 3210}
c801d85f 3211
1e6feb95 3212void wxWindowGTK::DoSetClientSize( int width, int height )
c801d85f 3213{
82b978d7
RD
3214 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3215
1ecc4d80 3216 if (!m_wxwindow)
c801d85f 3217 {
1ecc4d80 3218 SetSize( width, height );
c801d85f
KB
3219 }
3220 else
3221 {
1ecc4d80
RR
3222 int dw = 0;
3223 int dh = 0;
3224
1e6feb95 3225#ifndef __WXUNIVERSAL__
98d3fdbe
RR
3226 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
3227 {
5e014a0c 3228 /* when using GTK 1.2 we set the shadow border size to 2 */
6a008b33 3229 dw += 2 * 2;
98d3fdbe
RR
3230 dh += 2 * 2;
3231 }
5e014a0c
RR
3232 if (HasFlag(wxSIMPLE_BORDER))
3233 {
3234 /* when using GTK 1.2 we set the simple border size to 1 */
3235 dw += 1 * 2;
3236 dh += 1 * 2;
3237 }
1e6feb95 3238#endif // __WXUNIVERSAL__
034be888 3239
5b8a521e 3240 if (m_hasScrolling)
98d3fdbe 3241 {
324dbfec 3242 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2daa0ce9 3243
9000c624
RR
3244 GtkRequisition vscroll_req;
3245 vscroll_req.width = 2;
3246 vscroll_req.height = 2;
dd00f3f6 3247 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
9000c624 3248 (scroll_window->vscrollbar, &vscroll_req );
2daa0ce9 3249
9000c624
RR
3250 GtkRequisition hscroll_req;
3251 hscroll_req.width = 2;
3252 hscroll_req.height = 2;
dd00f3f6 3253 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
9000c624
RR
3254 (scroll_window->hscrollbar, &hscroll_req );
3255
dd00f3f6 3256 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
324dbfec 3257
1ecc4d80
RR
3258 if (scroll_window->vscrollbar_visible)
3259 {
9000c624 3260 dw += vscroll_req.width;
1ecc4d80
RR
3261 dw += scroll_class->scrollbar_spacing;
3262 }
3263
3264 if (scroll_window->hscrollbar_visible)
3265 {
9000c624 3266 dh += hscroll_req.height;
63cc5d9d 3267 dh += scroll_class->scrollbar_spacing;
1ecc4d80 3268 }
9000c624 3269 }
1ecc4d80 3270
034be888 3271 SetSize( width+dw, height+dh );
1ecc4d80 3272 }
362c6693 3273}
c801d85f 3274
1e6feb95 3275void wxWindowGTK::DoGetClientSize( int *width, int *height ) const
c801d85f 3276{
82b978d7 3277 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3278
1ecc4d80
RR
3279 if (!m_wxwindow)
3280 {
3281 if (width) (*width) = m_width;
3282 if (height) (*height) = m_height;
c801d85f
KB
3283 }
3284 else
3285 {
1ecc4d80
RR
3286 int dw = 0;
3287 int dh = 0;
3288
1e6feb95 3289#ifndef __WXUNIVERSAL__
98d3fdbe
RR
3290 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
3291 {
5e014a0c 3292 /* when using GTK 1.2 we set the shadow border size to 2 */
6a008b33 3293 dw += 2 * 2;
98d3fdbe
RR
3294 dh += 2 * 2;
3295 }
5e014a0c
RR
3296 if (HasFlag(wxSIMPLE_BORDER))
3297 {
3298 /* when using GTK 1.2 we set the simple border size to 1 */
3299 dw += 1 * 2;
3300 dh += 1 * 2;
3301 }
1e6feb95 3302#endif // __WXUNIVERSAL__
9000c624 3303
5b8a521e 3304 if (m_hasScrolling)
98d3fdbe 3305 {
6a008b33 3306 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2daa0ce9 3307
9000c624
RR
3308 GtkRequisition vscroll_req;
3309 vscroll_req.width = 2;
3310 vscroll_req.height = 2;
dd00f3f6 3311 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
9000c624 3312 (scroll_window->vscrollbar, &vscroll_req );
2daa0ce9 3313
9000c624
RR
3314 GtkRequisition hscroll_req;
3315 hscroll_req.width = 2;
3316 hscroll_req.height = 2;
dd00f3f6 3317 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
9000c624
RR
3318 (scroll_window->hscrollbar, &hscroll_req );
3319
dd00f3f6 3320 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
6a008b33 3321
1ecc4d80
RR
3322 if (scroll_window->vscrollbar_visible)
3323 {
9000c624 3324 dw += vscroll_req.width;
1ecc4d80
RR
3325 dw += scroll_class->scrollbar_spacing;
3326 }
3327
3328 if (scroll_window->hscrollbar_visible)
3329 {
9000c624 3330 dh += hscroll_req.height;
1ecc4d80
RR
3331 dh += scroll_class->scrollbar_spacing;
3332 }
6a008b33 3333 }
47d67540 3334
1ecc4d80
RR
3335 if (width) (*width) = m_width - dw;
3336 if (height) (*height) = m_height - dh;
3337 }
1e6feb95 3338
f94fca1b
RR
3339/*
3340 printf( "GetClientSize, name %s ", GetName().c_str() );
3341 if (width) printf( " width = %d", (*width) );
3342 if (height) printf( " height = %d", (*height) );
3343 printf( "\n" );
3344*/
362c6693 3345}
c801d85f 3346
1e6feb95 3347void wxWindowGTK::DoGetPosition( int *x, int *y ) const
c801d85f 3348{
82b978d7 3349 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3350
bf0c00c6
RR
3351 int dx = 0;
3352 int dy = 0;
3353 if (m_parent && m_parent->m_wxwindow)
3354 {
da048e3d 3355 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
b02da6b1
VZ
3356 dx = pizza->xoffset;
3357 dy = pizza->yoffset;
bf0c00c6 3358 }
94633ad9 3359
496beb3f
VS
3360 if (x) (*x) = m_x - dx;
3361 if (y) (*y) = m_y - dy;
362c6693 3362}
c801d85f 3363
1e6feb95 3364void wxWindowGTK::DoClientToScreen( int *x, int *y ) const
c801d85f 3365{
82b978d7 3366 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3367
a2053b27
RR
3368 if (!m_widget->window) return;
3369
43a18898
RR
3370 GdkWindow *source = (GdkWindow *) NULL;
3371 if (m_wxwindow)
da048e3d 3372 source = GTK_PIZZA(m_wxwindow)->bin_window;
43a18898
RR
3373 else
3374 source = m_widget->window;
47d67540 3375
43a18898
RR
3376 int org_x = 0;
3377 int org_y = 0;
3378 gdk_window_get_origin( source, &org_x, &org_y );
c801d85f 3379
43a18898 3380 if (!m_wxwindow)
c801d85f 3381 {
43a18898
RR
3382 if (GTK_WIDGET_NO_WINDOW (m_widget))
3383 {
3384 org_x += m_widget->allocation.x;
3385 org_y += m_widget->allocation.y;
3386 }
362c6693 3387 }
47d67540 3388
43a18898
RR
3389 if (x) *x += org_x;
3390 if (y) *y += org_y;
362c6693 3391}
c801d85f 3392
1e6feb95 3393void wxWindowGTK::DoScreenToClient( 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
1ecc4d80
RR
3399 GdkWindow *source = (GdkWindow *) NULL;
3400 if (m_wxwindow)
da048e3d 3401 source = GTK_PIZZA(m_wxwindow)->bin_window;
1ecc4d80
RR
3402 else
3403 source = m_widget->window;
47d67540 3404
1ecc4d80
RR
3405 int org_x = 0;
3406 int org_y = 0;
3407 gdk_window_get_origin( source, &org_x, &org_y );
c801d85f 3408
1ecc4d80 3409 if (!m_wxwindow)
c801d85f 3410 {
1ecc4d80
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
1ecc4d80
RR
3418 if (x) *x -= org_x;
3419 if (y) *y -= org_y;
362c6693 3420}
c801d85f 3421
1e6feb95 3422bool wxWindowGTK::Show( bool show )
c801d85f 3423{
82b978d7 3424 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
47d67540 3425
739730ca
RR
3426 if (!wxWindowBase::Show(show))
3427 {
3428 // nothing to do
f03fc89f 3429 return FALSE;
739730ca 3430 }
8bbe427f 3431
f03fc89f
VZ
3432 if (show)
3433 gtk_widget_show( m_widget );
1ecc4d80 3434 else
f03fc89f 3435 gtk_widget_hide( m_widget );
8bbe427f 3436
2b5f62a0 3437 wxShowEvent eventShow(GetId(), show);
687706f5 3438 eventShow.SetEventObject(this);
2b5f62a0
VZ
3439
3440 GetEventHandler()->ProcessEvent(eventShow);
3441
f03fc89f 3442 return TRUE;
362c6693 3443}
c801d85f 3444
3379ed37 3445static void wxWindowNotifyEnable(wxWindowGTK* win, bool enable)
fdca68a6
JS
3446{
3447 win->OnParentEnable(enable);
3448
3449 // Recurse, so that children have the opportunity to Do The Right Thing
3450 // and reset colours that have been messed up by a parent's (really ancestor's)
3451 // Enable call
222ed1d6 3452 for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
fdca68a6
JS
3453 node;
3454 node = node->GetNext() )
3455 {
3456 wxWindow *child = node->GetData();
3457 if (!child->IsKindOf(CLASSINFO(wxDialog)) && !child->IsKindOf(CLASSINFO(wxFrame)))
3458 wxWindowNotifyEnable(child, enable);
3459 }
3460}
3461
3379ed37 3462bool wxWindowGTK::Enable( bool enable )
c801d85f 3463{
82b978d7
RD
3464 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3465
739730ca
RR
3466 if (!wxWindowBase::Enable(enable))
3467 {
3468 // nothing to do
f03fc89f 3469 return FALSE;
739730ca 3470 }
1ecc4d80 3471
f03fc89f
VZ
3472 gtk_widget_set_sensitive( m_widget, enable );
3473 if ( m_wxwindow )
3474 gtk_widget_set_sensitive( m_wxwindow, enable );
ff8bfdbb 3475
fdca68a6 3476 wxWindowNotifyEnable(this, enable);
513903c4 3477
f03fc89f 3478 return TRUE;
362c6693 3479}
c801d85f 3480
1e6feb95 3481int wxWindowGTK::GetCharHeight() const
2f2aa628 3482{
82b978d7 3483 wxCHECK_MSG( (m_widget != NULL), 12, wxT("invalid window") );
47d67540 3484
cc402e64
VZ
3485 wxFont font = GetFont();
3486 wxCHECK_MSG( font.Ok(), 12, wxT("invalid font") );
2f2aa628 3487
bbd006c0
RR
3488#ifdef __WXGTK20__
3489 PangoContext *context = NULL;
3490 if (m_widget)
3491 context = gtk_widget_get_pango_context( m_widget );
3492
3493 if (!context)
3494 return 0;
3495
cc402e64 3496 PangoFontDescription *desc = font.GetNativeFontInfo()->description;
bbd006c0
RR
3497 PangoLayout *layout = pango_layout_new(context);
3498 pango_layout_set_font_description(layout, desc);
3499 pango_layout_set_text(layout, "H", 1);
3500 PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
3501
3502 PangoRectangle rect;
3503 pango_layout_line_get_extents(line, NULL, &rect);
3504
3505 g_object_unref( G_OBJECT( layout ) );
7de59551 3506
f69e2009 3507 return (int) PANGO_PIXELS(rect.height);
bbd006c0 3508#else
cc402e64 3509 GdkFont *gfont = font.GetInternalFont( 1.0 );
f03fc89f 3510
cc402e64 3511 return gfont->ascent + gfont->descent;
bbd006c0 3512#endif
362c6693 3513}
c801d85f 3514
1e6feb95 3515int wxWindowGTK::GetCharWidth() const
c33c4050 3516{
82b978d7 3517 wxCHECK_MSG( (m_widget != NULL), 8, wxT("invalid window") );
47d67540 3518
cc402e64
VZ
3519 wxFont font = GetFont();
3520 wxCHECK_MSG( font.Ok(), 8, wxT("invalid font") );
47d67540 3521
bbd006c0
RR
3522#ifdef __WXGTK20__
3523 PangoContext *context = NULL;
3524 if (m_widget)
3525 context = gtk_widget_get_pango_context( m_widget );
3526
3527 if (!context)
3528 return 0;
3529
cc402e64 3530 PangoFontDescription *desc = font.GetNativeFontInfo()->description;
bbd006c0
RR
3531 PangoLayout *layout = pango_layout_new(context);
3532 pango_layout_set_font_description(layout, desc);
95c430aa 3533 pango_layout_set_text(layout, "g", 1);
bbd006c0
RR
3534 PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
3535
3536 PangoRectangle rect;
3537 pango_layout_line_get_extents(line, NULL, &rect);
3538
3539 g_object_unref( G_OBJECT( layout ) );
7de59551 3540
f69e2009 3541 return (int) PANGO_PIXELS(rect.width);
bbd006c0 3542#else
cc402e64 3543 GdkFont *gfont = font.GetInternalFont( 1.0 );
ff8bfdbb 3544
cc402e64 3545 return gdk_string_width( gfont, "g" );
bbd006c0 3546#endif
c33c4050
RR
3547}
3548
1e6feb95 3549void wxWindowGTK::GetTextExtent( const wxString& string,
f03fc89f
VZ
3550 int *x,
3551 int *y,
3552 int *descent,
3553 int *externalLeading,
3554 const wxFont *theFont ) const
c33c4050 3555{
cc402e64 3556 wxFont fontToUse = theFont ? *theFont : GetFont();
47d67540 3557
223d09f6 3558 wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
2b5f62a0 3559
48d011c8
RR
3560 if (string.IsEmpty())
3561 {
b15ed747
RR
3562 if (x) (*x) = 0;
3563 if (y) (*y) = 0;
48d011c8
RR
3564 return;
3565 }
47d67540 3566
2b5f62a0 3567#ifdef __WXGTK20__
48d011c8
RR
3568 PangoContext *context = NULL;
3569 if (m_widget)
2b5f62a0
VZ
3570 context = gtk_widget_get_pango_context( m_widget );
3571
48d011c8
RR
3572 if (!context)
3573 {
b15ed747
RR
3574 if (x) (*x) = 0;
3575 if (y) (*y) = 0;
48d011c8
RR
3576 return;
3577 }
2b5f62a0 3578
48d011c8
RR
3579 PangoFontDescription *desc = fontToUse.GetNativeFontInfo()->description;
3580 PangoLayout *layout = pango_layout_new(context);
3581 pango_layout_set_font_description(layout, desc);
3582 {
fb3ed106 3583#if wxUSE_UNICODE
48d011c8
RR
3584 const wxCharBuffer data = wxConvUTF8.cWC2MB( string );
3585 pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data ));
fb3ed106
RR
3586#else
3587 const wxWCharBuffer wdata = wxConvLocal.cMB2WC( string );
3588 const wxCharBuffer data = wxConvUTF8.cWC2MB( wdata );
3589 pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data ));
3590#endif
48d011c8 3591 }
2b5f62a0 3592
48d011c8 3593 PangoRectangle rect;
fd43b1b3 3594 pango_layout_get_extents(layout, NULL, &rect);
2b5f62a0 3595
f69e2009
VS
3596 if (x) (*x) = (wxCoord) PANGO_PIXELS(rect.width);
3597 if (y) (*y) = (wxCoord) PANGO_PIXELS(rect.height);
48d011c8
RR
3598 if (descent)
3599 {
f69e2009
VS
3600 PangoLayoutIter *iter = pango_layout_get_iter(layout);
3601 int baseline = pango_layout_iter_get_baseline(iter);
3602 pango_layout_iter_free(iter);
3603 *descent = *y - PANGO_PIXELS(baseline);
48d011c8
RR
3604 }
3605 if (externalLeading) (*externalLeading) = 0; // ??
2b5f62a0 3606
48d011c8
RR
3607 g_object_unref( G_OBJECT( layout ) );
3608#else
463c1fa1 3609 GdkFont *font = fontToUse.GetInternalFont( 1.0 );
fab591c5 3610 if (x) (*x) = gdk_string_width( font, wxGTK_CONV( string ) );
463c1fa1
RR
3611 if (y) (*y) = font->ascent + font->descent;
3612 if (descent) (*descent) = font->descent;
3613 if (externalLeading) (*externalLeading) = 0; // ??
48d011c8 3614#endif
c33c4050
RR
3615}
3616
1e6feb95 3617void wxWindowGTK::SetFocus()
c801d85f 3618{
82b978d7 3619 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
6cad4f1b
VZ
3620 if ( m_hasFocus )
3621 {
3622 // don't do anything if we already have focus
3623 return;
3624 }
2daa0ce9 3625
354aa1e3
RR
3626 if (m_wxwindow)
3627 {
173348db 3628 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
b231914f 3629 {
173348db 3630 gtk_widget_grab_focus (m_wxwindow);
b231914f 3631 }
354aa1e3 3632 }
b231914f 3633 else if (m_widget)
c801d85f 3634 {
eccd5602
RR
3635#ifdef __WXGTK20__
3636 if (GTK_IS_CONTAINER(m_widget))
3637 {
3638 gtk_widget_child_focus( m_widget, GTK_DIR_TAB_FORWARD );
3639 }
3640 else
3641#endif
173348db 3642 if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
463c1fa1 3643 {
eccd5602 3644
d7fa7eaa 3645 if (!GTK_WIDGET_REALIZED(m_widget))
6aeb6f2a 3646 {
6cad4f1b
VZ
3647 // we can't set the focus to the widget now so we remember that
3648 // it should be focused and will do it later, during the idle
3649 // time, as soon as we can
3650 wxLogTrace(TRACE_FOCUS,
3651 _T("Delaying setting focus to %s(%s)"),
6aeb6f2a
VZ
3652 GetClassInfo()->GetClassName(), GetLabel().c_str());
3653
d7fa7eaa 3654 g_delayedFocus = this;
6aeb6f2a 3655 }
d7fa7eaa 3656 else
6aeb6f2a 3657 {
6cad4f1b
VZ
3658 wxLogTrace(TRACE_FOCUS,
3659 _T("Setting focus to %s(%s)"),
6aeb6f2a
VZ
3660 GetClassInfo()->GetClassName(), GetLabel().c_str());
3661
d7fa7eaa 3662 gtk_widget_grab_focus (m_widget);
6aeb6f2a 3663 }
463c1fa1 3664 }
eccd5602
RR
3665 else
3666#ifndef __WXGTK20__
3667 if (GTK_IS_CONTAINER(m_widget))
ff8bfdbb 3668 {
59060b8c 3669 gtk_container_focus( GTK_CONTAINER(m_widget), GTK_DIR_TAB_FORWARD );
ff8bfdbb
VZ
3670 }
3671 else
eccd5602 3672#endif
ff8bfdbb 3673 {
6cad4f1b
VZ
3674 wxLogTrace(TRACE_FOCUS,
3675 _T("Can't set focus to %s(%s)"),
3676 GetClassInfo()->GetClassName(), GetLabel().c_str());
ff8bfdbb 3677 }
362c6693 3678 }
362c6693 3679}
c801d85f 3680
1e6feb95 3681bool wxWindowGTK::AcceptsFocus() const
b292e2f5 3682{
f03fc89f 3683 return m_acceptsFocus && wxWindowBase::AcceptsFocus();
b292e2f5
RR
3684}
3685
1e6feb95 3686bool wxWindowGTK::Reparent( wxWindowBase *newParentBase )
463c1fa1 3687{
82b978d7 3688 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
c50f1fb9 3689
1e6feb95
VZ
3690 wxWindowGTK *oldParent = m_parent,
3691 *newParent = (wxWindowGTK *)newParentBase;
a2053b27 3692
5fd11f09
RR
3693 wxASSERT( GTK_IS_WIDGET(m_widget) );
3694
f03fc89f
VZ
3695 if ( !wxWindowBase::Reparent(newParent) )
3696 return FALSE;
8bbe427f 3697
5fd11f09
RR
3698 wxASSERT( GTK_IS_WIDGET(m_widget) );
3699
3700 /* prevent GTK from deleting the widget arbitrarily */
3701 gtk_widget_ref( m_widget );
3702
8ce63e9d
RR
3703 if (oldParent)
3704 {
3017f78d 3705 gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget );
8ce63e9d 3706 }
c50f1fb9 3707
5fd11f09
RR
3708 wxASSERT( GTK_IS_WIDGET(m_widget) );
3709
8ce63e9d
RR
3710 if (newParent)
3711 {
3712 /* insert GTK representation */
3713 (*(newParent->m_insertCallback))(newParent, this);
3714 }
c50f1fb9 3715
5fd11f09
RR
3716 /* reverse: prevent GTK from deleting the widget arbitrarily */
3717 gtk_widget_unref( m_widget );
148cd9b6 3718
f03fc89f 3719 return TRUE;
362c6693 3720}
c801d85f 3721
1e6feb95 3722void wxWindowGTK::DoAddChild(wxWindowGTK *child)
ddb6bc71 3723{
223d09f6 3724 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
ddb6bc71 3725
223d09f6 3726 wxASSERT_MSG( (child != NULL), wxT("invalid child window") );
ddb6bc71 3727
223d09f6 3728 wxASSERT_MSG( (m_insertCallback != NULL), wxT("invalid child insertion function") );
c50f1fb9 3729
ddb6bc71
RR
3730 /* add to list */
3731 AddChild( child );
c50f1fb9 3732
ddb6bc71
RR
3733 /* insert GTK representation */
3734 (*m_insertCallback)(this, child);
3735}
3736
a589495e
VS
3737#ifdef __WXGTK20__
3738
3739void wxWindowGTK::AddChild(wxWindowBase *child)
3740{
3741 wxWindowBase::AddChild(child);
3742 m_dirtyTabOrder = true;
3743 if (g_isIdle)
3744 wxapp_install_idle_handler();
3745}
3746
3747void wxWindowGTK::RemoveChild(wxWindowBase *child)
3748{
3749 wxWindowBase::RemoveChild(child);
3750 m_dirtyTabOrder = true;
3751 if (g_isIdle)
3752 wxapp_install_idle_handler();
3753}
3754
3755void wxWindowGTK::DoMoveInTabOrder(wxWindow *win, MoveKind move)
3756{
3757 wxWindowBase::DoMoveInTabOrder(win, move);
3758 m_dirtyTabOrder = true;
3759 if (g_isIdle)
3760 wxapp_install_idle_handler();
3761}
3762
3763void wxWindowGTK::RealizeTabOrder()
3764{
3765 if (m_wxwindow)
3766 {
3767 if (m_children.size() > 0)
3768 {
3769 GList *chain = NULL;
3770
3771 for (wxWindowList::const_iterator i = m_children.begin();
3772 i != m_children.end(); ++i)
3773 {
3774 chain = g_list_prepend(chain, (*i)->m_widget);
3775 }
3776
3777 chain = g_list_reverse(chain);
3778
3779 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow), chain);
3780 g_list_free(chain);
3781 }
3782 else
3783 {
3784 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow));
3785 }
3786 }
3787
3788 m_dirtyTabOrder = false;
3789}
3790
3791#endif // __WXGTK20__
3792
1e6feb95 3793void wxWindowGTK::Raise()
362c6693 3794{
82b978d7
RD
3795 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3796
fdfb8475
RR
3797 if (m_wxwindow && m_wxwindow->window)
3798 {
3799 gdk_window_raise( m_wxwindow->window );
3800 }
3801 else if (m_widget->window)
3802 {
3803 gdk_window_raise( m_widget->window );
3804 }
362c6693
RR
3805}
3806
1e6feb95 3807void wxWindowGTK::Lower()
362c6693 3808{
82b978d7
RD
3809 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3810
fdfb8475
RR
3811 if (m_wxwindow && m_wxwindow->window)
3812 {
3813 gdk_window_lower( m_wxwindow->window );
3814 }
3815 else if (m_widget->window)
3816 {
3817 gdk_window_lower( m_widget->window );
3818 }
362c6693 3819}
c801d85f 3820
1e6feb95 3821bool wxWindowGTK::SetCursor( const wxCursor &cursor )
86b29a61 3822{
82b978d7 3823 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
86b29a61 3824
f6bcfd97
BP
3825 if (cursor == m_cursor)
3826 return FALSE;
3827
3828 if (g_isIdle)
3829 wxapp_install_idle_handler();
1e6feb95 3830
f6bcfd97
BP
3831 if (cursor == wxNullCursor)
3832 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR );
3833 else
3834 return wxWindowBase::SetCursor( cursor );
362c6693 3835}
c801d85f 3836
1e6feb95 3837void wxWindowGTK::WarpPointer( int x, int y )
4f22cf8d 3838{
82b978d7
RD
3839 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3840
3bcc8d15
RR
3841 // We provide this function ourselves as it is
3842 // missing in GDK (top of this file).
148cd9b6 3843
ed673c6a
RR
3844 GdkWindow *window = (GdkWindow*) NULL;
3845 if (m_wxwindow)
da048e3d 3846 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a
RR
3847 else
3848 window = GetConnectWidget()->window;
148cd9b6 3849
ed673c6a
RR
3850 if (window)
3851 gdk_window_warp_pointer( window, x, y );
4f22cf8d
RR
3852}
3853
3013a903 3854
1e6feb95 3855void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
c801d85f 3856{
f2593d0d 3857 if (!m_widget) return;
a2053b27 3858 if (!m_widget->window) return;
2b5f62a0 3859
4e5a4c69 3860#ifndef __WXGTK20__
ea323db3
RR
3861 if (g_isIdle)
3862 wxapp_install_idle_handler();
2b5f62a0 3863
75625d79
SN
3864 wxRect myRect(0,0,0,0);
3865 if (m_wxwindow && rect)
3866 {
3867 myRect.SetSize(wxSize( m_wxwindow->allocation.width,
3868 m_wxwindow->allocation.height));
3869 myRect.Intersect(*rect);
3870 if (!myRect.width || !myRect.height)
3871 // nothing to do, rectangle is empty
3872 return;
3873 rect = &myRect;
3874 }
3875
139adb6a 3876 if (eraseBackground && m_wxwindow && m_wxwindow->window)
c801d85f 3877 {
139adb6a
RR
3878 if (rect)
3879 {
3bcc8d15
RR
3880 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3881 m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height );
139adb6a
RR
3882 }
3883 else
3884 {
3bcc8d15
RR
3885 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3886 m_clearRegion.Clear();
3887 m_clearRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
139adb6a
RR
3888 }
3889 }
ff8bfdbb 3890
3bcc8d15 3891 if (rect)
139adb6a
RR
3892 {
3893 if (m_wxwindow)
b02da6b1 3894 {
23716407 3895 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3bcc8d15 3896 m_updateRegion.Union( rect->x, rect->y, rect->width, rect->height );
b02da6b1 3897 }
ff8bfdbb 3898 else
b6fa52db 3899 {
3bcc8d15
RR
3900 GdkRectangle gdk_rect;
3901 gdk_rect.x = rect->x;
3902 gdk_rect.y = rect->y;
3903 gdk_rect.width = rect->width;
3904 gdk_rect.height = rect->height;
3905 gtk_widget_draw( m_widget, &gdk_rect );
b6fa52db 3906 }
362c6693 3907 }
c801d85f 3908 else
139adb6a 3909 {
139adb6a 3910 if (m_wxwindow)
b02da6b1 3911 {
23716407 3912 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3bcc8d15
RR
3913 m_updateRegion.Clear();
3914 m_updateRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
b02da6b1 3915 }
139adb6a 3916 else
b6fa52db 3917 {
3bcc8d15 3918 gtk_widget_draw( m_widget, (GdkRectangle*) NULL );
b6fa52db 3919 }
139adb6a 3920 }
4e5a4c69
RR
3921#else
3922 if (m_wxwindow)
3923 {
3924 if (rect)
3925 {
3926 GdkRectangle gdk_rect;
3927 gdk_rect.x = rect->x;
3928 gdk_rect.y = rect->y;
3929 gdk_rect.width = rect->width;
3930 gdk_rect.height = rect->height;
3931 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow)->bin_window, &gdk_rect, TRUE );
3932 }
3933 else
3934 {
3935 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow)->bin_window, NULL, TRUE );
3936 }
3937 }
3938#endif
362c6693 3939}
c801d85f 3940
beab25bd 3941void wxWindowGTK::Update()
010afced
RR
3942{
3943 GtkUpdate();
1b965a9c
VZ
3944
3945 // when we call Update() we really want to update the window immediately on
3946 // screen, even if itmeans flushing the entire queue and hence slowing down
3947 // everything -- but it should still be done, it's just that Update() should
3948 // be called very rarely
3949 gdk_flush();
010afced
RR
3950}
3951
3952void wxWindowGTK::GtkUpdate()
beab25bd 3953{
4e5a4c69
RR
3954#ifdef __WXGTK20__
3955 if (m_wxwindow && GTK_PIZZA(m_wxwindow)->bin_window)
3956 gdk_window_process_updates( GTK_PIZZA(m_wxwindow)->bin_window, FALSE );
b15ed747 3957#else
beab25bd 3958 if (!m_updateRegion.IsEmpty())
23716407 3959 GtkSendPaintEvents();
b15ed747 3960#endif
beab25bd
RR
3961}
3962
3963void wxWindowGTK::GtkSendPaintEvents()
3964{
3bcc8d15
RR
3965 if (!m_wxwindow)
3966 {
2b5f62a0 3967#ifndef __WXGTK20__
3bcc8d15 3968 m_clearRegion.Clear();
b15ed747 3969#endif
3bcc8d15
RR
3970 m_updateRegion.Clear();
3971 return;
3972 }
beab25bd 3973
f90566f5 3974 // Clip to paint region in wxClientDC
3bcc8d15 3975 m_clipPaintRegion = TRUE;
fab591c5 3976
b15ed747
RR
3977 // widget to draw on
3978 GtkPizza *pizza = GTK_PIZZA (m_wxwindow);
2b5f62a0 3979
aac97549 3980 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM))
f90566f5
RR
3981 {
3982 // find ancestor from which to steal background
aac97549 3983 wxWindow *parent = IsTopLevel() ? this : GetParent();
f90566f5
RR
3984 while (parent && !parent->IsTopLevel())
3985 parent = parent->GetParent();
3986 if (!parent)
cc06fe74 3987 parent = (wxWindow*)this;
2b5f62a0 3988
822cf31c 3989 if (GTK_WIDGET_MAPPED(parent->m_widget))
f90566f5 3990 {
822cf31c
KH
3991 wxRegionIterator upd( m_updateRegion );
3992 while (upd)
3993 {
3994 GdkRectangle rect;
3995 rect.x = upd.GetX();
3996 rect.y = upd.GetY();
3997 rect.width = upd.GetWidth();
3998 rect.height = upd.GetHeight();
3999
4000 gtk_paint_flat_box( parent->m_widget->style,
4001 pizza->bin_window,
4002 (GtkStateType)GTK_WIDGET_STATE(m_wxwindow),
4003 GTK_SHADOW_NONE,
4004 &rect,
4005 parent->m_widget,
4006 (char *)"base",
4007 0, 0, -1, -1 );
4008
4009 upd ++;
4010 }
f90566f5
RR
4011 }
4012 }
4013 else
b15ed747
RR
4014
4015#ifdef __WXGTK20__
4016 {
4017 wxWindowDC dc( (wxWindow*)this );
4018 dc.SetClippingRegion( m_updateRegion );
4019
4020 wxEraseEvent erase_event( GetId(), &dc );
4021 erase_event.SetEventObject( this );
4022
4023 GetEventHandler()->ProcessEvent(erase_event);
4024 }
4025#else
4026 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
beab25bd 4027 {
3bcc8d15 4028 wxWindowDC dc( (wxWindow*)this );
62cb3cd8
RR
4029 if (m_clearRegion.IsEmpty())
4030 dc.SetClippingRegion( m_updateRegion );
4031 else
4032 dc.SetClippingRegion( m_clearRegion );
0fc5dbf5 4033
3bcc8d15
RR
4034 wxEraseEvent erase_event( GetId(), &dc );
4035 erase_event.SetEventObject( this );
0fc5dbf5 4036
c7382f91 4037 if (!GetEventHandler()->ProcessEvent(erase_event) && GetBackgroundStyle() != wxBG_STYLE_CUSTOM)
beab25bd 4038 {
994bc575
RR
4039 if (!g_eraseGC)
4040 {
f90566f5 4041 g_eraseGC = gdk_gc_new( pizza->bin_window );
994bc575
RR
4042 gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4043 }
1cd3409d 4044 gdk_gc_set_foreground( g_eraseGC, GetBackgroundColour().GetColor() );
0fc5dbf5 4045
3bcc8d15 4046 wxRegionIterator upd( m_clearRegion );
beab25bd
RR
4047 while (upd)
4048 {
f90566f5
RR
4049 gdk_draw_rectangle( pizza->bin_window, g_eraseGC, 1,
4050 upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
beab25bd
RR
4051 upd ++;
4052 }
4053 }
3bcc8d15 4054 m_clearRegion.Clear();
beab25bd 4055 }
b15ed747 4056#endif
beab25bd
RR
4057
4058 wxNcPaintEvent nc_paint_event( GetId() );
4059 nc_paint_event.SetEventObject( this );
4060 GetEventHandler()->ProcessEvent( nc_paint_event );
4061
4062 wxPaintEvent paint_event( GetId() );
4063 paint_event.SetEventObject( this );
4064 GetEventHandler()->ProcessEvent( paint_event );
4065
beab25bd 4066 m_clipPaintRegion = FALSE;
c89f5c02 4067
8f3e7ecc 4068#ifndef __WXUNIVERSAL__
4e5a4c69 4069#ifndef __WXGTK20__
8f3e7ecc 4070 // The following code will result in all window-less widgets
77ffb593 4071 // being redrawn because the wxWidgets class is allowed to
8f3e7ecc 4072 // paint over the window-less widgets.
0fc5dbf5 4073
8f3e7ecc
RR
4074 GList *children = pizza->children;
4075 while (children)
c89f5c02 4076 {
8f3e7ecc
RR
4077 GtkPizzaChild *child = (GtkPizzaChild*) children->data;
4078 children = children->next;
2b5f62a0 4079
8f3e7ecc
RR
4080 if (GTK_WIDGET_NO_WINDOW (child->widget) &&
4081 GTK_WIDGET_DRAWABLE (child->widget))
4082 {
4083 // Get intersection of widget area and update region
4084 wxRegion region( m_updateRegion );
0fc5dbf5 4085
8f3e7ecc
RR
4086 GdkEventExpose gdk_event;
4087 gdk_event.type = GDK_EXPOSE;
4088 gdk_event.window = pizza->bin_window;
4089 gdk_event.count = 0;
0fc5dbf5 4090
8f3e7ecc
RR
4091 wxRegionIterator upd( m_updateRegion );
4092 while (upd)
c89f5c02 4093 {
8f3e7ecc
RR
4094 GdkRectangle rect;
4095 rect.x = upd.GetX();
4096 rect.y = upd.GetY();
4097 rect.width = upd.GetWidth();
4098 rect.height = upd.GetHeight();
0fc5dbf5 4099
8f3e7ecc
RR
4100 if (gtk_widget_intersect (child->widget, &rect, &gdk_event.area))
4101 {
4102 gtk_widget_event (child->widget, (GdkEvent*) &gdk_event);
4103 }
0fc5dbf5 4104
8f3e7ecc 4105 upd ++;
c89f5c02
RR
4106 }
4107 }
4108 }
4e5a4c69 4109#endif
8f3e7ecc 4110#endif
c89f5c02
RR
4111
4112 m_updateRegion.Clear();
beab25bd
RR
4113}
4114
596f1d11 4115void wxWindowGTK::ClearBackground()
c801d85f 4116{
82b978d7
RD
4117 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4118
b15ed747 4119#ifndef __WXGTK20__
f234c60c
RR
4120 if (m_wxwindow && m_wxwindow->window)
4121 {
d7fa7eaa
RR
4122 m_clearRegion.Clear();
4123 wxSize size( GetClientSize() );
4124 m_clearRegion.Union( 0,0,size.x,size.y );
2b5f62a0 4125
d7fa7eaa 4126 // Better do this in idle?
010afced 4127 GtkUpdate();
f234c60c 4128 }
b15ed747 4129#endif
362c6693 4130}
c801d85f 4131
ff8bfdbb 4132#if wxUSE_TOOLTIPS
1e6feb95 4133void wxWindowGTK::DoSetToolTip( wxToolTip *tip )
b1170810 4134{
f03fc89f 4135 wxWindowBase::DoSetToolTip(tip);
ff8bfdbb 4136
f03fc89f 4137 if (m_tooltip)
3379ed37 4138 m_tooltip->Apply( (wxWindow *)this );
b1170810
RR
4139}
4140
1e6feb95 4141void wxWindowGTK::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
b1170810 4142{
aa154cb1
RR
4143 wxString tmp( tip );
4144 gtk_tooltips_set_tip( tips, GetConnectWidget(), wxGTK_CONV(tmp), (gchar*) NULL );
301cd871 4145}
ff8bfdbb 4146#endif // wxUSE_TOOLTIPS
b1170810 4147
1e6feb95 4148bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
c801d85f 4149{
5edef14e 4150 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
8bbe427f 4151
739730ca 4152 if (!wxWindowBase::SetBackgroundColour(colour))
44dfb5ce 4153 return false;
c50f1fb9 4154
5edef14e 4155 if (colour.Ok())
994bc575 4156 {
5edef14e
VS
4157 // We need the pixel value e.g. for background clearing.
4158 m_backgroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
994bc575 4159 }
ca298c88 4160
5edef14e 4161 // apply style change (forceStyle=true so that new style is applied
c7382f91
JS
4162 // even if the bg colour changed from valid to wxNullColour)
4163 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM)
4164 ApplyWidgetStyle(true);
ea323db3 4165
5edef14e 4166 return true;
6de97a3b
RR
4167}
4168
1e6feb95 4169bool wxWindowGTK::SetForegroundColour( const wxColour &colour )
6de97a3b 4170{
82b978d7 4171 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
8bbe427f 4172
739730ca
RR
4173 if (!wxWindowBase::SetForegroundColour(colour))
4174 {
5edef14e 4175 return false;
739730ca 4176 }
5edef14e
VS
4177
4178 if (colour.Ok())
ea323db3 4179 {
5edef14e
VS
4180 // We need the pixel value e.g. for background clearing.
4181 m_foregroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
ea323db3 4182 }
f03fc89f 4183
5edef14e
VS
4184 // apply style change (forceStyle=true so that new style is applied
4185 // even if the bg colour changed from valid to wxNullColour):
4186 ApplyWidgetStyle(true);
4187
44dfb5ce 4188 return true;
58614078
RR
4189}
4190
2b5f62a0
VZ
4191#ifdef __WXGTK20__
4192PangoContext *wxWindowGTK::GtkGetPangoDefaultContext()
4193{
4194 return gtk_widget_get_pango_context( m_widget );
4195}
4196
4197PangoContext *wxWindowGTK::GtkGetPangoX11Context()
4198{
4199 if (!m_x11Context)
4200 m_x11Context = pango_x_get_context( gdk_display );
4201
4202 return m_x11Context;
4203}
4204#endif
f40fdaa3 4205
5edef14e 4206GtkRcStyle *wxWindowGTK::CreateWidgetStyle(bool forceStyle)
58614078 4207{
f40fdaa3 4208 // do we need to apply any changes at all?
5edef14e 4209 if ( !forceStyle &&
984e8d0b
VS
4210 !m_font.Ok() &&
4211 !m_foregroundColour.Ok() && !m_backgroundColour.Ok() )
fb65642c 4212 {
f40fdaa3 4213 return NULL;
fb65642c
RR
4214 }
4215
f40fdaa3 4216 GtkRcStyle *style = gtk_rc_style_new();
1ecc4d80 4217
984e8d0b 4218 if ( m_font.Ok() )
db434467 4219 {
288059b2 4220#ifdef __WXGTK20__
f40fdaa3
VS
4221 style->font_desc =
4222 pango_font_description_copy( m_font.GetNativeFontInfo()->description );
288059b2 4223#else
f40fdaa3
VS
4224 wxString xfontname = m_font.GetNativeFontInfo()->GetXFontName();
4225 style->fontset_name = g_strdup(xfontname.c_str());
cfcc3932 4226#endif
288059b2 4227 }
1ecc4d80 4228
fe161a26 4229 if ( m_foregroundColour.Ok() )
1ecc4d80 4230 {
5edef14e 4231 GdkColor *fg = m_foregroundColour.GetColor();
f40fdaa3 4232
5edef14e 4233 style->fg[GTK_STATE_NORMAL] = *fg;
f40fdaa3
VS
4234 style->color_flags[GTK_STATE_NORMAL] = GTK_RC_FG;
4235
5edef14e 4236 style->fg[GTK_STATE_PRELIGHT] = *fg;
f40fdaa3
VS
4237 style->color_flags[GTK_STATE_PRELIGHT] = GTK_RC_FG;
4238
5edef14e 4239 style->fg[GTK_STATE_ACTIVE] = *fg;
f40fdaa3 4240 style->color_flags[GTK_STATE_ACTIVE] = GTK_RC_FG;
1ecc4d80
RR
4241 }
4242
fe161a26 4243 if ( m_backgroundColour.Ok() )
1ecc4d80 4244 {
5edef14e
VS
4245 GdkColor *bg = m_backgroundColour.GetColor();
4246
4247 style->bg[GTK_STATE_NORMAL] = *bg;
4248 style->base[GTK_STATE_NORMAL] = *bg;
f40fdaa3
VS
4249 style->color_flags[GTK_STATE_NORMAL] = (GtkRcFlags)
4250 (style->color_flags[GTK_STATE_NORMAL] | GTK_RC_BG | GTK_RC_BASE);
4251
5edef14e
VS
4252 style->bg[GTK_STATE_PRELIGHT] = *bg;
4253 style->base[GTK_STATE_PRELIGHT] = *bg;
f40fdaa3
VS
4254 style->color_flags[GTK_STATE_PRELIGHT] = (GtkRcFlags)
4255 (style->color_flags[GTK_STATE_PRELIGHT] | GTK_RC_BG | GTK_RC_BASE);
4256
5edef14e
VS
4257 style->bg[GTK_STATE_ACTIVE] = *bg;
4258 style->base[GTK_STATE_ACTIVE] = *bg;
f40fdaa3
VS
4259 style->color_flags[GTK_STATE_ACTIVE] = (GtkRcFlags)
4260 (style->color_flags[GTK_STATE_ACTIVE] | GTK_RC_BG | GTK_RC_BASE);
4261
5edef14e
VS
4262 style->bg[GTK_STATE_INSENSITIVE] = *bg;
4263 style->base[GTK_STATE_INSENSITIVE] = *bg;
f40fdaa3
VS
4264 style->color_flags[GTK_STATE_INSENSITIVE] = (GtkRcFlags)
4265 (style->color_flags[GTK_STATE_INSENSITIVE] | GTK_RC_BG | GTK_RC_BASE);
1ecc4d80 4266 }
f40fdaa3
VS
4267
4268 return style;
a81258be
RR
4269}
4270
f8e045e2 4271void wxWindowGTK::ApplyWidgetStyle(bool forceStyle)
a81258be 4272{
f8e045e2
RD
4273 GtkRcStyle *style = CreateWidgetStyle(forceStyle);
4274 if ( style )
4275 {
7074ce35 4276 DoApplyWidgetStyle(style);
f8e045e2
RD
4277 gtk_rc_style_unref(style);
4278 }
6dd18972
VS
4279
4280 // Style change may affect GTK+'s size calculation:
4281 InvalidateBestSize();
6de97a3b
RR
4282}
4283
7074ce35
VS
4284void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle *style)
4285{
4286 if (m_wxwindow)
7074ce35 4287 gtk_widget_modify_style(m_wxwindow, style);
40bab631 4288 gtk_widget_modify_style(m_widget, style);
7074ce35
VS
4289}
4290
c7382f91
JS
4291bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style)
4292{
4293 wxWindowBase::SetBackgroundStyle(style);
4294
4295 if (style == wxBG_STYLE_CUSTOM)
4296 {
4297 GdkWindow *window = (GdkWindow*) NULL;
4298 if (m_wxwindow)
4299 window = GTK_PIZZA(m_wxwindow)->bin_window;
4300 else
4301 window = GetConnectWidget()->window;
4302
4303 if (window)
4304 {
4305 // Make sure GDK/X11 doesn't refresh the window
4306 // automatically.
4307 gdk_window_set_back_pixmap( window, None, False );
4308#ifdef __X__
4309 Display* display = GDK_WINDOW_DISPLAY(window);
4310 XFlush(display);
4311#endif
4312 m_needsStyleChange = false;
4313 }
4314 else
4315 // Do in OnIdle, because the window is not yet available
4316 m_needsStyleChange = true;
4317
4318 // Don't apply widget style, or we get a grey background
4319 }
4320 else
4321 {
4322 // apply style change (forceStyle=true so that new style is applied
4323 // even if the bg colour changed from valid to wxNullColour):
4324 ApplyWidgetStyle(true);
4325 }
4326 return true;
4327}
7074ce35 4328
2259e007
RR
4329//-----------------------------------------------------------------------------
4330// Pop-up menu stuff
4331//-----------------------------------------------------------------------------
4332
6522713c 4333#if wxUSE_MENUS_NATIVE
1e6feb95 4334
90350682
VZ
4335extern "C"
4336void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting )
2259e007
RR
4337{
4338 *is_waiting = FALSE;
4339}
4340
0bd3b8ec 4341void SetInvokingWindow( wxMenu *menu, wxWindow* win )
30dea054 4342{
1ecc4d80 4343 menu->SetInvokingWindow( win );
0bd3b8ec 4344
222ed1d6 4345 wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst();
1ecc4d80
RR
4346 while (node)
4347 {
1987af7e 4348 wxMenuItem *menuitem = node->GetData();
1ecc4d80
RR
4349 if (menuitem->IsSubMenu())
4350 {
ff8bfdbb
VZ
4351 SetInvokingWindow( menuitem->GetSubMenu(), win );
4352 }
1987af7e
VZ
4353
4354 node = node->GetNext();
1ecc4d80 4355 }
362c6693 4356}
30dea054 4357
295272bd
VZ
4358extern "C" void wxPopupMenuPositionCallback( GtkMenu *menu,
4359 gint *x, gint *y,
9e691f46
VZ
4360#ifdef __WXGTK20__
4361 gboolean * WXUNUSED(whatever),
4362#endif
39b44a39 4363 gpointer user_data )
0c77152e 4364{
e3473203
VZ
4365 // ensure that the menu appears entirely on screen
4366 GtkRequisition req;
4367 gtk_widget_get_child_requisition(GTK_WIDGET(menu), &req);
4368
4369 wxSize sizeScreen = wxGetDisplaySize();
39b44a39 4370 wxPoint *pos = (wxPoint*)user_data;
e3473203
VZ
4371
4372 gint xmax = sizeScreen.x - req.width,
4373 ymax = sizeScreen.y - req.height;
4374
39b44a39
VS
4375 *x = pos->x < xmax ? pos->x : xmax;
4376 *y = pos->y < ymax ? pos->y : ymax;
0c77152e
RR
4377}
4378
1e6feb95 4379bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
30dea054 4380{
971562cb 4381 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
47d67540 4382
971562cb 4383 wxCHECK_MSG( menu != NULL, false, wxT("invalid popup-menu") );
8bbe427f 4384
0bd3b8ec
RR
4385 // NOTE: if you change this code, you need to update
4386 // the same code in taskbar.cpp as well. This
4387 // is ugly code duplication, I know,
4388
1ecc4d80 4389 SetInvokingWindow( menu, this );
ff8bfdbb 4390
631f1bfe
JS
4391 menu->UpdateUI();
4392
971562cb 4393 bool is_waiting = true;
148cd9b6 4394
098937b0
VS
4395 gulong handler = gtk_signal_connect( GTK_OBJECT(menu->m_menu),
4396 "hide",
4397 GTK_SIGNAL_FUNC(gtk_pop_hide_callback),
4398 (gpointer)&is_waiting );
2259e007 4399
971562cb
VS
4400 wxPoint pos;
4401 gpointer userdata;
4402 GtkMenuPositionFunc posfunc;
4403 if ( x == -1 && y == -1 )
4404 {
4405 // use GTK's default positioning algorithm
4406 userdata = NULL;
4407 posfunc = NULL;
4408 }
4409 else
4410 {
4411 pos = ClientToScreen(wxPoint(x, y));
4412 userdata = &pos;
4413 posfunc = wxPopupMenuPositionCallback;
4414 }
4415
1ecc4d80 4416 gtk_menu_popup(
47d67540 4417 GTK_MENU(menu->m_menu),
e3473203
VZ
4418 (GtkWidget *) NULL, // parent menu shell
4419 (GtkWidget *) NULL, // parent menu item
971562cb
VS
4420 posfunc, // function to position it
4421 userdata, // client data
4422 0, // button used to activate it
34791896
RR
4423#ifdef __WXGTK20__
4424 gtk_get_current_event_time()
4425#else
34adc954 4426 gs_timeLastClick // the time of activation
34791896 4427#endif
47d67540 4428 );
148cd9b6 4429
956dbab1
RR
4430 while (is_waiting)
4431 {
a03cac3f 4432 gtk_main_iteration();
956dbab1 4433 }
2259e007 4434
098937b0
VS
4435 gtk_signal_disconnect(GTK_OBJECT(menu->m_menu), handler);
4436
971562cb 4437 return true;
30dea054
RR
4438}
4439
6522713c 4440#endif // wxUSE_MENUS_NATIVE
1e6feb95 4441
06cfab17 4442#if wxUSE_DRAG_AND_DROP
ac57418f 4443
1e6feb95 4444void wxWindowGTK::SetDropTarget( wxDropTarget *dropTarget )
c801d85f 4445{
82b978d7
RD
4446 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4447
1ecc4d80 4448 GtkWidget *dnd_widget = GetConnectWidget();
47d67540 4449
1ecc4d80 4450 if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
47d67540 4451
1ecc4d80
RR
4452 if (m_dropTarget) delete m_dropTarget;
4453 m_dropTarget = dropTarget;
47d67540 4454
1ecc4d80 4455 if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
362c6693 4456}
c801d85f 4457
f03fc89f 4458#endif // wxUSE_DRAG_AND_DROP
ac57418f 4459
1e6feb95 4460GtkWidget* wxWindowGTK::GetConnectWidget()
e3e65dac 4461{
1ecc4d80
RR
4462 GtkWidget *connect_widget = m_widget;
4463 if (m_wxwindow) connect_widget = m_wxwindow;
47d67540 4464
1ecc4d80 4465 return connect_widget;
e3e65dac 4466}
47d67540 4467
1e6feb95 4468bool wxWindowGTK::IsOwnGtkWindow( GdkWindow *window )
903f689b 4469{
148cd9b6 4470 if (m_wxwindow)
da048e3d 4471 return (window == GTK_PIZZA(m_wxwindow)->bin_window);
148cd9b6 4472
1ecc4d80 4473 return (window == m_widget->window);
903f689b
RR
4474}
4475
1e6feb95 4476bool wxWindowGTK::SetFont( const wxFont &font )
c801d85f 4477{
5edef14e 4478 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
9c288e4d 4479
5edef14e
VS
4480 if (!wxWindowBase::SetFont(font))
4481 return false;
c801d85f 4482
5edef14e
VS
4483 // apply style change (forceStyle=true so that new style is applied
4484 // even if the font changed from valid to wxNullFont):
4485 ApplyWidgetStyle(true);
4486
4487 return true;
362c6693 4488}
c801d85f 4489
94633ad9 4490void wxWindowGTK::DoCaptureMouse()
c801d85f 4491{
82b978d7
RD
4492 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4493
ed673c6a 4494 GdkWindow *window = (GdkWindow*) NULL;
b231914f
VZ
4495 if (m_wxwindow)
4496 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a 4497 else
b231914f 4498 window = GetConnectWidget()->window;
148cd9b6 4499
e4606ed9 4500 wxCHECK_RET( window, _T("CaptureMouse() failed") );
c50f1fb9 4501
b231914f 4502 wxCursor* cursor = & m_cursor;
cca602ac
JS
4503 if (!cursor->Ok())
4504 cursor = wxSTANDARD_CURSOR;
4505
ed673c6a 4506 gdk_pointer_grab( window, FALSE,
1ecc4d80
RR
4507 (GdkEventMask)
4508 (GDK_BUTTON_PRESS_MASK |
4509 GDK_BUTTON_RELEASE_MASK |
148cd9b6 4510 GDK_POINTER_MOTION_HINT_MASK |
1ecc4d80 4511 GDK_POINTER_MOTION_MASK),
ff8bfdbb 4512 (GdkWindow *) NULL,
cca602ac 4513 cursor->GetCursor(),
b02da6b1 4514 (guint32)GDK_CURRENT_TIME );
b231914f 4515 g_captureWindow = this;
1e6feb95 4516 g_captureWindowHasMouse = TRUE;
362c6693 4517}
c801d85f 4518
94633ad9 4519void wxWindowGTK::DoReleaseMouse()
c801d85f 4520{
82b978d7
RD
4521 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4522
e4606ed9 4523 wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") );
47d67540 4524
c43430bb
VS
4525 g_captureWindow = (wxWindowGTK*) NULL;
4526
ed673c6a 4527 GdkWindow *window = (GdkWindow*) NULL;
b231914f
VZ
4528 if (m_wxwindow)
4529 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a 4530 else
b231914f 4531 window = GetConnectWidget()->window;
148cd9b6 4532
b02da6b1
VZ
4533 if (!window)
4534 return;
c50f1fb9 4535
b02da6b1 4536 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
362c6693 4537}
c801d85f 4538
1e6feb95
VZ
4539/* static */
4540wxWindow *wxWindowBase::GetCapture()
4541{
4542 return (wxWindow *)g_captureWindow;
4543}
4544
4545bool wxWindowGTK::IsRetained() const
c801d85f 4546{
1ecc4d80 4547 return FALSE;
362c6693 4548}
c801d85f 4549
1e6feb95 4550void wxWindowGTK::SetScrollbar( int orient, int pos, int thumbVisible,
cb43b372 4551 int range, bool refresh )
c801d85f 4552{
82b978d7
RD
4553 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4554
223d09f6 4555 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
c801d85f 4556
1ecc4d80 4557 m_hasScrolling = TRUE;
47d67540 4558
1ecc4d80 4559 if (orient == wxHORIZONTAL)
cb43b372 4560 {
1ecc4d80
RR
4561 float fpos = (float)pos;
4562 float frange = (float)range;
4563 float fthumb = (float)thumbVisible;
4564 if (fpos > frange-fthumb) fpos = frange-fthumb;
4565 if (fpos < 0.0) fpos = 0.0;
4566
4567 if ((fabs(frange-m_hAdjust->upper) < 0.2) &&
4568 (fabs(fthumb-m_hAdjust->page_size) < 0.2))
4569 {
4570 SetScrollPos( orient, pos, refresh );
4571 return;
4572 }
47d67540 4573
1ecc4d80 4574 m_oldHorizontalPos = fpos;
47d67540 4575
1ecc4d80
RR
4576 m_hAdjust->lower = 0.0;
4577 m_hAdjust->upper = frange;
4578 m_hAdjust->value = fpos;
4579 m_hAdjust->step_increment = 1.0;
4580 m_hAdjust->page_increment = (float)(wxMax(fthumb,0));
4581 m_hAdjust->page_size = fthumb;
cb43b372 4582 }
1ecc4d80
RR
4583 else
4584 {
4585 float fpos = (float)pos;
4586 float frange = (float)range;
4587 float fthumb = (float)thumbVisible;
4588 if (fpos > frange-fthumb) fpos = frange-fthumb;
4589 if (fpos < 0.0) fpos = 0.0;
4590
4591 if ((fabs(frange-m_vAdjust->upper) < 0.2) &&
4592 (fabs(fthumb-m_vAdjust->page_size) < 0.2))
4593 {
4594 SetScrollPos( orient, pos, refresh );
4595 return;
4596 }
47d67540 4597
1ecc4d80 4598 m_oldVerticalPos = fpos;
47d67540 4599
1ecc4d80
RR
4600 m_vAdjust->lower = 0.0;
4601 m_vAdjust->upper = frange;
4602 m_vAdjust->value = fpos;
4603 m_vAdjust->step_increment = 1.0;
4604 m_vAdjust->page_increment = (float)(wxMax(fthumb,0));
4605 m_vAdjust->page_size = fthumb;
4606 }
47d67540 4607
eb082a08
RR
4608 if (orient == wxHORIZONTAL)
4609 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
4610 else
4611 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
362c6693 4612}
c801d85f 4613
1e6feb95 4614void wxWindowGTK::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
c801d85f 4615{
82b978d7 4616 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
1ecc4d80 4617
223d09f6 4618 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
1ecc4d80
RR
4619
4620 if (orient == wxHORIZONTAL)
4621 {
4622 float fpos = (float)pos;
4623 if (fpos > m_hAdjust->upper - m_hAdjust->page_size) fpos = m_hAdjust->upper - m_hAdjust->page_size;
4624 if (fpos < 0.0) fpos = 0.0;
4625 m_oldHorizontalPos = fpos;
4626
4627 if (fabs(fpos-m_hAdjust->value) < 0.2) return;
4628 m_hAdjust->value = fpos;
4629 }
4630 else
4631 {
4632 float fpos = (float)pos;
4633 if (fpos > m_vAdjust->upper - m_vAdjust->page_size) fpos = m_vAdjust->upper - m_vAdjust->page_size;
4634 if (fpos < 0.0) fpos = 0.0;
4635 m_oldVerticalPos = fpos;
ff8bfdbb 4636
1ecc4d80
RR
4637 if (fabs(fpos-m_vAdjust->value) < 0.2) return;
4638 m_vAdjust->value = fpos;
4639 }
47d67540 4640
5b8a521e 4641 if (m_wxwindow->window)
47d67540 4642 {
5b8a521e 4643 if (orient == wxHORIZONTAL)
473d087e
RR
4644 {
4645 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust),
4646 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
2daa0ce9 4647
5b8a521e 4648 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
2daa0ce9 4649
473d087e
RR
4650 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
4651 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
4652 }
5b8a521e 4653 else
473d087e
RR
4654 {
4655 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust),
4656 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
2daa0ce9 4657
5b8a521e 4658 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
473d087e
RR
4659
4660 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
4661 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
4662 }
cb43b372 4663 }
362c6693 4664}
c801d85f 4665
1e6feb95 4666int wxWindowGTK::GetScrollThumb( int orient ) const
c801d85f 4667{
82b978d7
RD
4668 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
4669
223d09f6 4670 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
47d67540 4671
1ecc4d80
RR
4672 if (orient == wxHORIZONTAL)
4673 return (int)(m_hAdjust->page_size+0.5);
4674 else
4675 return (int)(m_vAdjust->page_size+0.5);
362c6693 4676}
c801d85f 4677
1e6feb95 4678int wxWindowGTK::GetScrollPos( int orient ) const
c801d85f 4679{
82b978d7 4680 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
47d67540 4681
223d09f6 4682 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
c801d85f 4683
1ecc4d80
RR
4684 if (orient == wxHORIZONTAL)
4685 return (int)(m_hAdjust->value+0.5);
4686 else
4687 return (int)(m_vAdjust->value+0.5);
362c6693 4688}
c801d85f 4689
1e6feb95 4690int wxWindowGTK::GetScrollRange( int orient ) const
c801d85f 4691{
82b978d7 4692 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
47d67540 4693
223d09f6 4694 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
c801d85f 4695
1ecc4d80
RR
4696 if (orient == wxHORIZONTAL)
4697 return (int)(m_hAdjust->upper+0.5);
4698 else
4699 return (int)(m_vAdjust->upper+0.5);
362c6693 4700}
c801d85f 4701
1e6feb95 4702void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
c801d85f 4703{
82b978d7
RD
4704 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4705
223d09f6 4706 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
2b5f62a0 4707
f47ae6e7 4708 // No scrolling requested.
8e217128 4709 if ((dx == 0) && (dy == 0)) return;
0fc5dbf5 4710
4e5a4c69 4711#ifndef __WXGTK20__
35917d22
RR
4712 if (!m_updateRegion.IsEmpty())
4713 {
4714 m_updateRegion.Offset( dx, dy );
0fc5dbf5 4715
35917d22
RR
4716 int cw = 0;
4717 int ch = 0;
4718 GetClientSize( &cw, &ch );
4719 m_updateRegion.Intersect( 0, 0, cw, ch );
4720 }
0fc5dbf5 4721
3bcc8d15
RR
4722 if (!m_clearRegion.IsEmpty())
4723 {
4724 m_clearRegion.Offset( dx, dy );
0fc5dbf5 4725
3bcc8d15
RR
4726 int cw = 0;
4727 int ch = 0;
4728 GetClientSize( &cw, &ch );
4729 m_clearRegion.Intersect( 0, 0, cw, ch );
4730 }
3fc6e5fa
RR
4731#endif
4732
b6fa52db 4733 m_clipPaintRegion = TRUE;
0fc5dbf5 4734
da048e3d 4735 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
0fc5dbf5 4736
b6fa52db 4737 m_clipPaintRegion = FALSE;
c801d85f 4738}
3723b7b1 4739
4e5a4c69 4740
3723b7b1
JS
4741// Find the wxWindow at the current mouse position, also returning the mouse
4742// position.
4743wxWindow* wxFindWindowAtPointer(wxPoint& pt)
4744{
59a12e90
JS
4745 pt = wxGetMousePosition();
4746 wxWindow* found = wxFindWindowAtPoint(pt);
4747 return found;
3723b7b1
JS
4748}
4749
4750// Get the current mouse position.
4751wxPoint wxGetMousePosition()
4752{
59a12e90
JS
4753 /* This crashes when used within wxHelpContext,
4754 so we have to use the X-specific implementation below.
4755 gint x, y;
4756 GdkModifierType *mask;
4757 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4758
4759 return wxPoint(x, y);
4760 */
4761
3723b7b1
JS
4762 int x, y;
4763 GdkWindow* windowAtPtr = gdk_window_at_pointer(& x, & y);
59a12e90 4764
37d81cc2 4765 Display *display = windowAtPtr ? GDK_WINDOW_XDISPLAY(windowAtPtr) : GDK_DISPLAY();
59a12e90
JS
4766 Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
4767 Window rootReturn, childReturn;
4768 int rootX, rootY, winX, winY;
4769 unsigned int maskReturn;
4770
4771 XQueryPointer (display,
5cd09f0b
RR
4772 rootWindow,
4773 &rootReturn,
59a12e90
JS
4774 &childReturn,
4775 &rootX, &rootY, &winX, &winY, &maskReturn);
4776 return wxPoint(rootX, rootY);
4777
3723b7b1
JS
4778}
4779
4e5a4c69
RR
4780// ----------------------------------------------------------------------------
4781// wxDCModule
4782// ----------------------------------------------------------------------------
4783
4784class wxWinModule : public wxModule
4785{
4786public:
4787 bool OnInit();
4788 void OnExit();
4789
4790private:
4791 DECLARE_DYNAMIC_CLASS(wxWinModule)
4792};
4793
4794IMPLEMENT_DYNAMIC_CLASS(wxWinModule, wxModule)
4795
4796bool wxWinModule::OnInit()
4797{
994bc575
RR
4798 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4799 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
0fc5dbf5 4800
4e5a4c69
RR
4801 return TRUE;
4802}
4803
4804void wxWinModule::OnExit()
4805{
994bc575
RR
4806 if (g_eraseGC)
4807 gdk_gc_unref( g_eraseGC );
4e5a4c69
RR
4808}
4809
6728fb61 4810// vi:sts=4:sw=4:et