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