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