]> git.saurik.com Git - wxWidgets.git/blame - src/gtk1/window.cpp
Compile fixes for the const patch
[wxWidgets.git] / src / gtk1 / window.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
f6bcfd97 2// Name: gtk/window.cpp
c801d85f
KB
3// Purpose:
4// Author: Robert Roebling
c67d8618 5// Id: $Id$
01111366 6// Copyright: (c) 1998 Robert Roebling, Julian Smart
65571936 7// Licence: wxWindows licence
c801d85f
KB
8/////////////////////////////////////////////////////////////////////////////
9
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
f6551618
MW
2904#ifdef __WXGTK20__
2905 // delete before the widgets to avoid a crash on solaris
2906 delete m_imData;
2907#endif
2908
f03fc89f 2909 if (m_wxwindow)
a2053b27 2910 {
f03fc89f 2911 gtk_widget_destroy( m_wxwindow );
c50f1fb9 2912 m_wxwindow = (GtkWidget*) NULL;
a2053b27 2913 }
8bbe427f 2914
f03fc89f 2915 if (m_widget)
a2053b27 2916 {
f03fc89f 2917 gtk_widget_destroy( m_widget );
c50f1fb9 2918 m_widget = (GtkWidget*) NULL;
a2053b27 2919 }
362c6693 2920}
c801d85f 2921
1e6feb95 2922bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos, const wxSize &size )
c801d85f 2923{
0a164d4c 2924 wxCHECK_MSG( !m_needParent || parent, false, wxT("Need complete parent.") );
8bbe427f 2925
a7c26d10
RD
2926 // Use either the given size, or the default if -1 is given.
2927 // See wxWindowBase for these functions.
3013a903 2928 m_width = WidthDefault(size.x) ;
f03fc89f 2929 m_height = HeightDefault(size.y);
8bbe427f 2930
43a18898
RR
2931 m_x = (int)pos.x;
2932 m_y = (int)pos.y;
8bbe427f 2933
0a164d4c 2934 return true;
c801d85f
KB
2935}
2936
1e6feb95 2937void wxWindowGTK::PostCreation()
c801d85f 2938{
82b978d7
RD
2939 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2940
43a18898
RR
2941 if (m_wxwindow)
2942 {
147bc491 2943 if (!m_noExpose)
b02da6b1 2944 {
77ffb593 2945 // these get reported to wxWidgets -> wxPaintEvent
1e6feb95 2946
b420fb6a
RR
2947 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow), TRUE );
2948
147bc491
RR
2949 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
2950 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
2951
4e5a4c69 2952#ifndef __WXGTK20__
147bc491
RR
2953 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
2954 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
0fc5dbf5 2955
e441e1f4 2956 if (!HasFlag(wxFULL_REPAINT_ON_RESIZE))
e22454be
RR
2957 {
2958 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "event",
2959 GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this );
2960 }
4e5a4c69 2961#else
e441e1f4 2962 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2b5f62a0 2963#endif
93d23d8f 2964 }
2b5f62a0
VZ
2965
2966#ifdef __WXGTK20__
ed56a258
JS
2967 // Create input method handler
2968 m_imData = new wxGtkIMData;
2969
2b5f62a0 2970 // Cannot handle drawing preedited text yet
a3c15d89 2971 gtk_im_context_set_use_preedit( m_imData->context, FALSE );
2b5f62a0 2972
a3c15d89 2973 g_signal_connect (G_OBJECT (m_imData->context), "commit",
da210120 2974 G_CALLBACK (gtk_wxwindow_commit_cb), this);
4e5a4c69 2975#endif
148cd9b6 2976
67d78217 2977 // these are called when the "sunken" or "raised" borders are drawn
034be888
RR
2978 gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
2979 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
2980
4e5a4c69 2981#ifndef __WXGTK20__
034be888
RR
2982 gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
2983 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
4e5a4c69 2984#endif
43a18898 2985 }
47d67540 2986
76fcf0f2 2987 // focus handling
63081513 2988
06fda9e8
RR
2989 if (!GTK_IS_WINDOW(m_widget))
2990 {
2991 if (m_focusWidget == NULL)
2992 m_focusWidget = m_widget;
0a164d4c 2993
06fda9e8
RR
2994 gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_in_event",
2995 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
76fcf0f2 2996
4ecd9342 2997 gtk_signal_connect_after( GTK_OBJECT(m_focusWidget), "focus_out_event",
06fda9e8
RR
2998 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
2999 }
76fcf0f2
RR
3000
3001 // connect to the various key and mouse handlers
63081513 3002
a2053b27 3003 GtkWidget *connect_widget = GetConnectWidget();
f03fc89f 3004
a2053b27 3005 ConnectWidget( connect_widget );
47d67540 3006
63081513 3007 /* We cannot set colours, fonts and cursors before the widget has
a2053b27
RR
3008 been realized, so we do this directly after realization */
3009 gtk_signal_connect( GTK_OBJECT(connect_widget), "realize",
c50f1fb9 3010 GTK_SIGNAL_FUNC(gtk_window_realized_callback), (gpointer) this );
2daa0ce9 3011
63081513
RR
3012 if (m_wxwindow)
3013 {
47c93b63 3014 // Catch native resize events
8f75cb6c
RR
3015 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
3016 GTK_SIGNAL_FUNC(gtk_window_size_callback), (gpointer)this );
2daa0ce9 3017
47c93b63 3018 // Initialize XIM support
63081513
RR
3019 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "realize",
3020 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback), (gpointer) this );
8f75cb6c 3021
47c93b63 3022 // And resize XIM window
b79395c5
RR
3023 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
3024 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this );
63081513 3025 }
2daa0ce9 3026
024e9a4c
RR
3027 if (GTK_IS_COMBO(m_widget))
3028 {
3029 GtkCombo *gcombo = GTK_COMBO(m_widget);
0a164d4c 3030
024e9a4c
RR
3031 gtk_signal_connect( GTK_OBJECT(gcombo->entry), "size_request",
3032 GTK_SIGNAL_FUNC(wxgtk_combo_size_request_callback),
3033 (gpointer) this );
3034 }
3035 else
47c93b63
RR
3036 {
3037 // This is needed if we want to add our windows into native
024e9a4c 3038 // GTK controls, such as the toolbar. With this callback, the
47c93b63 3039 // toolbar gets to know the correct size (the one set by the
024e9a4c 3040 // programmer). Sadly, it misbehaves for wxComboBox.
47c93b63 3041 gtk_signal_connect( GTK_OBJECT(m_widget), "size_request",
e1f448ee
VZ
3042 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback),
3043 (gpointer) this );
47c93b63 3044 }
1e6feb95 3045
40bab631
VS
3046 InheritAttributes();
3047
0a164d4c 3048 m_hasVMT = true;
a433fbd5
VZ
3049
3050 // unless the window was created initially hidden (i.e. Hide() had been
3051 // called before Create()), we should show it at GTK+ level as well
3052 if ( IsShown() )
3053 gtk_widget_show( m_widget );
b4071e91
RR
3054}
3055
1e6feb95 3056void wxWindowGTK::ConnectWidget( GtkWidget *widget )
b4071e91 3057{
43a18898
RR
3058 gtk_signal_connect( GTK_OBJECT(widget), "key_press_event",
3059 GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this );
c801d85f 3060
b666df2c
RR
3061 gtk_signal_connect( GTK_OBJECT(widget), "key_release_event",
3062 GTK_SIGNAL_FUNC(gtk_window_key_release_callback), (gpointer)this );
3063
43a18898
RR
3064 gtk_signal_connect( GTK_OBJECT(widget), "button_press_event",
3065 GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
47d67540 3066
43a18898
RR
3067 gtk_signal_connect( GTK_OBJECT(widget), "button_release_event",
3068 GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
47d67540 3069
43a18898
RR
3070 gtk_signal_connect( GTK_OBJECT(widget), "motion_notify_event",
3071 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
47d67540 3072
557c9f5b
JS
3073#ifdef __WXGTK20__
3074 gtk_signal_connect( GTK_OBJECT(widget), "scroll_event",
3075 GTK_SIGNAL_FUNC(gtk_window_wheel_callback), (gpointer)this );
ac103441
RR
3076 g_signal_connect(widget, "popup_menu",
3077 G_CALLBACK(wxgtk_window_popup_menu_callback), this);
557c9f5b
JS
3078#endif
3079
43a18898
RR
3080 gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event",
3081 GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
47d67540 3082
43a18898
RR
3083 gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
3084 GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
362c6693 3085}
c801d85f 3086
1e6feb95 3087bool wxWindowGTK::Destroy()
c801d85f 3088{
82b978d7 3089 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
47d67540 3090
0a164d4c 3091 m_hasVMT = false;
c801d85f 3092
f03fc89f 3093 return wxWindowBase::Destroy();
362c6693 3094}
c801d85f 3095
1e6feb95 3096void wxWindowGTK::DoMoveWindow(int x, int y, int width, int height)
23efdd02
RR
3097{
3098 gtk_pizza_set_size( GTK_PIZZA(m_parent->m_wxwindow), m_widget, x, y, width, height );
3099}
2daa0ce9 3100
1e6feb95 3101void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
c801d85f 3102{
82b978d7 3103 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
1e6feb95 3104 wxASSERT_MSG( (m_parent != NULL), wxT("wxWindowGTK::SetSize requires parent.\n") );
8bbe427f 3105
33611ebb 3106/*
f94fca1b 3107 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
33611ebb
RR
3108*/
3109
e27ce4e9 3110 if (m_resizing) return; /* I don't like recursions */
0a164d4c 3111 m_resizing = true;
1e6feb95 3112
b9f29261
VS
3113 int currentX, currentY;
3114 GetPosition(&currentX, &currentY);
443c834d 3115 if (x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
b9f29261 3116 x = currentX;
443c834d 3117 if (y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
b9f29261 3118 y = currentY;
a200c35e
VS
3119 AdjustForParentClientOrigin(x, y, sizeFlags);
3120
a2053b27 3121 if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
fb1585ae 3122 {
e27ce4e9 3123 /* don't set the size for children of wxNotebook, just take the values. */
fb1585ae
RR
3124 m_x = x;
3125 m_y = y;
3126 m_width = width;
ba4e3652 3127 m_height = height;
fb1585ae 3128 }
ba4e3652 3129 else
fb1585ae 3130 {
da048e3d 3131 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
85ad5eb5 3132 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
ba4e3652 3133 {
da048e3d
RR
3134 if (x != -1) m_x = x + pizza->xoffset;
3135 if (y != -1) m_y = y + pizza->yoffset;
ba4e3652
RR
3136 }
3137 else
3138 {
da048e3d
RR
3139 m_x = x + pizza->xoffset;
3140 m_y = y + pizza->yoffset;
ba4e3652 3141 }
47d67540 3142
a63d48fa 3143 // calculate the best size if we should auto size the window
c7e111cd
VZ
3144 if ( ((sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1) ||
3145 ((sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1) )
ba4e3652 3146 {
a63d48fa 3147 const wxSize sizeBest = GetBestSize();
c7e111cd 3148 if ( (sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1 )
a63d48fa 3149 width = sizeBest.x;
c7e111cd 3150 if ( (sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1 )
a63d48fa 3151 height = sizeBest.y;
ba4e3652
RR
3152 }
3153
a63d48fa
VZ
3154 if (width != -1)
3155 m_width = width;
3156 if (height != -1)
3157 m_height = height;
8bbe427f 3158
e7dda1ff
VS
3159 int minWidth = GetMinWidth(),
3160 minHeight = GetMinHeight(),
3161 maxWidth = GetMaxWidth(),
3162 maxHeight = GetMaxHeight();
3163
3164 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
3165 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
3166 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
3167 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
47d67540 3168
863e0817
RR
3169 int left_border = 0;
3170 int right_border = 0;
3171 int top_border = 0;
c50f1fb9 3172 int bottom_border = 0;
f03fc89f 3173
863e0817 3174 /* the default button has a border around it */
29f538ce 3175 if (GTK_WIDGET_CAN_DEFAULT(m_widget))
c50f1fb9 3176 {
863e0817 3177#ifdef __WXGTK20__
f893066b
RR
3178 GtkBorder *default_border = NULL;
3179 gtk_widget_style_get( m_widget, "default_border", &default_border, NULL );
3180 if (default_border)
863e0817 3181 {
f893066b
RR
3182 left_border += default_border->left;
3183 right_border += default_border->right;
3184 top_border += default_border->top;
3185 bottom_border += default_border->bottom;
3186 g_free( default_border );
863e0817
RR
3187 }
3188#else
3189 left_border = 6;
3190 right_border = 6;
3191 top_border = 6;
c50f1fb9 3192 bottom_border = 5;
67d78217 3193#endif
863e0817 3194 }
c50f1fb9 3195
863e0817
RR
3196 DoMoveWindow( m_x-top_border,
3197 m_y-left_border,
3198 m_width+left_border+right_border,
3199 m_height+top_border+bottom_border );
54517652 3200 }
148cd9b6 3201
5b8a521e
RR
3202 if (m_hasScrolling)
3203 {
1e6feb95 3204 /* Sometimes the client area changes size without the
b6fa52db
RR
3205 whole windows's size changing, but if the whole
3206 windows's size doesn't change, no wxSizeEvent will
3207 normally be sent. Here we add an extra test if
3208 the client test has been changed and this will
3209 be used then. */
5b8a521e
RR
3210 GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
3211 }
3212
54517652 3213/*
6d693bb4
RR
3214 wxPrintf( "OnSize sent from " );
3215 if (GetClassInfo() && GetClassInfo()->GetClassName())
3216 wxPrintf( GetClassInfo()->GetClassName() );
3217 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3218*/
3219
30760ce7
RR
3220 if (!m_nativeSizeEvent)
3221 {
3222 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
3223 event.SetEventObject( this );
3224 GetEventHandler()->ProcessEvent( event );
3225 }
6d693bb4 3226
0a164d4c 3227 m_resizing = false;
362c6693 3228}
c801d85f 3229
1e6feb95 3230void wxWindowGTK::OnInternalIdle()
9390a202 3231{
a589495e
VS
3232#ifdef __WXGTK20__
3233 if ( m_dirtyTabOrder )
3234 RealizeTabOrder();
3235#endif
c7382f91
JS
3236 // Update style if the window was not yet realized
3237 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
3238 if (m_needsStyleChange)
3239 {
3240 SetBackgroundStyle(GetBackgroundStyle());
3241 m_needsStyleChange = false;
3242 }
a589495e 3243
beab25bd 3244 // Update invalidated regions.
010afced 3245 GtkUpdate();
0fc5dbf5 3246
9146082c
RR
3247 wxCursor cursor = m_cursor;
3248 if (g_globalCursor.Ok()) cursor = g_globalCursor;
c50f1fb9 3249
f7a11f8c 3250 if (cursor.Ok())
9146082c 3251 {
3017f78d 3252 /* I now set the cursor anew in every OnInternalIdle call
b02da6b1
VZ
3253 as setting the cursor in a parent window also effects the
3254 windows above so that checking for the current cursor is
3255 not possible. */
148cd9b6 3256
9146082c 3257 if (m_wxwindow)
6a008b33 3258 {
da048e3d 3259 GdkWindow *window = GTK_PIZZA(m_wxwindow)->bin_window;
6a008b33 3260 if (window)
c50f1fb9 3261 gdk_window_set_cursor( window, cursor.GetCursor() );
6a008b33
VZ
3262
3263 if (!g_globalCursor.Ok())
3264 cursor = *wxSTANDARD_CURSOR;
3265
3266 window = m_widget->window;
5e014a0c 3267 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
9146082c 3268 gdk_window_set_cursor( window, cursor.GetCursor() );
5e014a0c 3269
6a008b33
VZ
3270 }
3271 else
3272 {
5e014a0c 3273
9146082c 3274 GdkWindow *window = m_widget->window;
5e014a0c 3275 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
9146082c 3276 gdk_window_set_cursor( window, cursor.GetCursor() );
5e014a0c 3277
6a008b33 3278 }
9146082c 3279 }
6a008b33 3280
e39af974
JS
3281 if (wxUpdateUIEvent::CanUpdate(this))
3282 UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
9390a202
RR
3283}
3284
1e6feb95 3285void wxWindowGTK::DoGetSize( int *width, int *height ) const
c801d85f 3286{
82b978d7 3287 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3288
fb1585ae
RR
3289 if (width) (*width) = m_width;
3290 if (height) (*height) = m_height;
362c6693 3291}
c801d85f 3292
1e6feb95 3293void wxWindowGTK::DoSetClientSize( int width, int height )
c801d85f 3294{
82b978d7
RD
3295 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3296
1ecc4d80 3297 if (!m_wxwindow)
c801d85f 3298 {
1ecc4d80 3299 SetSize( width, height );
c801d85f
KB
3300 }
3301 else
3302 {
1ecc4d80
RR
3303 int dw = 0;
3304 int dh = 0;
3305
1e6feb95 3306#ifndef __WXUNIVERSAL__
98d3fdbe
RR
3307 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
3308 {
5e014a0c 3309 /* when using GTK 1.2 we set the shadow border size to 2 */
6a008b33 3310 dw += 2 * 2;
98d3fdbe
RR
3311 dh += 2 * 2;
3312 }
5e014a0c
RR
3313 if (HasFlag(wxSIMPLE_BORDER))
3314 {
3315 /* when using GTK 1.2 we set the simple border size to 1 */
3316 dw += 1 * 2;
3317 dh += 1 * 2;
3318 }
1e6feb95 3319#endif // __WXUNIVERSAL__
034be888 3320
5b8a521e 3321 if (m_hasScrolling)
98d3fdbe 3322 {
324dbfec 3323 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2daa0ce9 3324
9000c624
RR
3325 GtkRequisition vscroll_req;
3326 vscroll_req.width = 2;
3327 vscroll_req.height = 2;
dd00f3f6 3328 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
9000c624 3329 (scroll_window->vscrollbar, &vscroll_req );
2daa0ce9 3330
9000c624
RR
3331 GtkRequisition hscroll_req;
3332 hscroll_req.width = 2;
3333 hscroll_req.height = 2;
dd00f3f6 3334 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
9000c624
RR
3335 (scroll_window->hscrollbar, &hscroll_req );
3336
dd00f3f6 3337 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
324dbfec 3338
1ecc4d80
RR
3339 if (scroll_window->vscrollbar_visible)
3340 {
9000c624 3341 dw += vscroll_req.width;
1ecc4d80
RR
3342 dw += scroll_class->scrollbar_spacing;
3343 }
3344
3345 if (scroll_window->hscrollbar_visible)
3346 {
9000c624 3347 dh += hscroll_req.height;
63cc5d9d 3348 dh += scroll_class->scrollbar_spacing;
1ecc4d80 3349 }
9000c624 3350 }
1ecc4d80 3351
034be888 3352 SetSize( width+dw, height+dh );
1ecc4d80 3353 }
362c6693 3354}
c801d85f 3355
1e6feb95 3356void wxWindowGTK::DoGetClientSize( int *width, int *height ) const
c801d85f 3357{
82b978d7 3358 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3359
1ecc4d80
RR
3360 if (!m_wxwindow)
3361 {
3362 if (width) (*width) = m_width;
3363 if (height) (*height) = m_height;
c801d85f
KB
3364 }
3365 else
3366 {
1ecc4d80
RR
3367 int dw = 0;
3368 int dh = 0;
3369
1e6feb95 3370#ifndef __WXUNIVERSAL__
98d3fdbe
RR
3371 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
3372 {
5e014a0c 3373 /* when using GTK 1.2 we set the shadow border size to 2 */
6a008b33 3374 dw += 2 * 2;
98d3fdbe
RR
3375 dh += 2 * 2;
3376 }
5e014a0c
RR
3377 if (HasFlag(wxSIMPLE_BORDER))
3378 {
3379 /* when using GTK 1.2 we set the simple border size to 1 */
3380 dw += 1 * 2;
3381 dh += 1 * 2;
3382 }
1e6feb95 3383#endif // __WXUNIVERSAL__
9000c624 3384
5b8a521e 3385 if (m_hasScrolling)
98d3fdbe 3386 {
6a008b33 3387 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2daa0ce9 3388
9000c624
RR
3389 GtkRequisition vscroll_req;
3390 vscroll_req.width = 2;
3391 vscroll_req.height = 2;
dd00f3f6 3392 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
9000c624 3393 (scroll_window->vscrollbar, &vscroll_req );
2daa0ce9 3394
9000c624
RR
3395 GtkRequisition hscroll_req;
3396 hscroll_req.width = 2;
3397 hscroll_req.height = 2;
dd00f3f6 3398 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
9000c624
RR
3399 (scroll_window->hscrollbar, &hscroll_req );
3400
dd00f3f6 3401 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
6a008b33 3402
1ecc4d80
RR
3403 if (scroll_window->vscrollbar_visible)
3404 {
9000c624 3405 dw += vscroll_req.width;
1ecc4d80
RR
3406 dw += scroll_class->scrollbar_spacing;
3407 }
3408
3409 if (scroll_window->hscrollbar_visible)
3410 {
9000c624 3411 dh += hscroll_req.height;
1ecc4d80
RR
3412 dh += scroll_class->scrollbar_spacing;
3413 }
6a008b33 3414 }
47d67540 3415
1ecc4d80
RR
3416 if (width) (*width) = m_width - dw;
3417 if (height) (*height) = m_height - dh;
3418 }
1e6feb95 3419
f94fca1b
RR
3420/*
3421 printf( "GetClientSize, name %s ", GetName().c_str() );
3422 if (width) printf( " width = %d", (*width) );
3423 if (height) printf( " height = %d", (*height) );
3424 printf( "\n" );
3425*/
362c6693 3426}
c801d85f 3427
1e6feb95 3428void wxWindowGTK::DoGetPosition( int *x, int *y ) const
c801d85f 3429{
82b978d7 3430 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3431
bf0c00c6
RR
3432 int dx = 0;
3433 int dy = 0;
3434 if (m_parent && m_parent->m_wxwindow)
3435 {
da048e3d 3436 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
b02da6b1
VZ
3437 dx = pizza->xoffset;
3438 dy = pizza->yoffset;
bf0c00c6 3439 }
94633ad9 3440
496beb3f
VS
3441 if (x) (*x) = m_x - dx;
3442 if (y) (*y) = m_y - dy;
362c6693 3443}
c801d85f 3444
1e6feb95 3445void wxWindowGTK::DoClientToScreen( int *x, int *y ) const
c801d85f 3446{
82b978d7 3447 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3448
a2053b27
RR
3449 if (!m_widget->window) return;
3450
43a18898
RR
3451 GdkWindow *source = (GdkWindow *) NULL;
3452 if (m_wxwindow)
da048e3d 3453 source = GTK_PIZZA(m_wxwindow)->bin_window;
43a18898
RR
3454 else
3455 source = m_widget->window;
47d67540 3456
43a18898
RR
3457 int org_x = 0;
3458 int org_y = 0;
3459 gdk_window_get_origin( source, &org_x, &org_y );
c801d85f 3460
43a18898 3461 if (!m_wxwindow)
c801d85f 3462 {
43a18898
RR
3463 if (GTK_WIDGET_NO_WINDOW (m_widget))
3464 {
3465 org_x += m_widget->allocation.x;
3466 org_y += m_widget->allocation.y;
3467 }
362c6693 3468 }
47d67540 3469
43a18898
RR
3470 if (x) *x += org_x;
3471 if (y) *y += org_y;
362c6693 3472}
c801d85f 3473
1e6feb95 3474void wxWindowGTK::DoScreenToClient( int *x, int *y ) const
c801d85f 3475{
82b978d7 3476 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3477
a2053b27
RR
3478 if (!m_widget->window) return;
3479
1ecc4d80
RR
3480 GdkWindow *source = (GdkWindow *) NULL;
3481 if (m_wxwindow)
da048e3d 3482 source = GTK_PIZZA(m_wxwindow)->bin_window;
1ecc4d80
RR
3483 else
3484 source = m_widget->window;
47d67540 3485
1ecc4d80
RR
3486 int org_x = 0;
3487 int org_y = 0;
3488 gdk_window_get_origin( source, &org_x, &org_y );
c801d85f 3489
1ecc4d80 3490 if (!m_wxwindow)
c801d85f 3491 {
1ecc4d80
RR
3492 if (GTK_WIDGET_NO_WINDOW (m_widget))
3493 {
3494 org_x += m_widget->allocation.x;
3495 org_y += m_widget->allocation.y;
3496 }
362c6693 3497 }
47d67540 3498
1ecc4d80
RR
3499 if (x) *x -= org_x;
3500 if (y) *y -= org_y;
362c6693 3501}
c801d85f 3502
1e6feb95 3503bool wxWindowGTK::Show( bool show )
c801d85f 3504{
0a164d4c 3505 wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
47d67540 3506
739730ca
RR
3507 if (!wxWindowBase::Show(show))
3508 {
3509 // nothing to do
0a164d4c 3510 return false;
739730ca 3511 }
8bbe427f 3512
f03fc89f
VZ
3513 if (show)
3514 gtk_widget_show( m_widget );
1ecc4d80 3515 else
f03fc89f 3516 gtk_widget_hide( m_widget );
8bbe427f 3517
2b5f62a0 3518 wxShowEvent eventShow(GetId(), show);
687706f5 3519 eventShow.SetEventObject(this);
2b5f62a0
VZ
3520
3521 GetEventHandler()->ProcessEvent(eventShow);
3522
0a164d4c 3523 return true;
362c6693 3524}
c801d85f 3525
3379ed37 3526static void wxWindowNotifyEnable(wxWindowGTK* win, bool enable)
fdca68a6
JS
3527{
3528 win->OnParentEnable(enable);
3529
3530 // Recurse, so that children have the opportunity to Do The Right Thing
3531 // and reset colours that have been messed up by a parent's (really ancestor's)
3532 // Enable call
222ed1d6 3533 for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
fdca68a6
JS
3534 node;
3535 node = node->GetNext() )
3536 {
3537 wxWindow *child = node->GetData();
3538 if (!child->IsKindOf(CLASSINFO(wxDialog)) && !child->IsKindOf(CLASSINFO(wxFrame)))
3539 wxWindowNotifyEnable(child, enable);
3540 }
3541}
3542
3379ed37 3543bool wxWindowGTK::Enable( bool enable )
c801d85f 3544{
0a164d4c 3545 wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
82b978d7 3546
739730ca
RR
3547 if (!wxWindowBase::Enable(enable))
3548 {
3549 // nothing to do
0a164d4c 3550 return false;
739730ca 3551 }
1ecc4d80 3552
f03fc89f
VZ
3553 gtk_widget_set_sensitive( m_widget, enable );
3554 if ( m_wxwindow )
3555 gtk_widget_set_sensitive( m_wxwindow, enable );
ff8bfdbb 3556
fdca68a6 3557 wxWindowNotifyEnable(this, enable);
513903c4 3558
0a164d4c 3559 return true;
362c6693 3560}
c801d85f 3561
1e6feb95 3562int wxWindowGTK::GetCharHeight() const
2f2aa628 3563{
82b978d7 3564 wxCHECK_MSG( (m_widget != NULL), 12, wxT("invalid window") );
47d67540 3565
cc402e64
VZ
3566 wxFont font = GetFont();
3567 wxCHECK_MSG( font.Ok(), 12, wxT("invalid font") );
2f2aa628 3568
bbd006c0
RR
3569#ifdef __WXGTK20__
3570 PangoContext *context = NULL;
3571 if (m_widget)
3572 context = gtk_widget_get_pango_context( m_widget );
3573
3574 if (!context)
3575 return 0;
3576
cc402e64 3577 PangoFontDescription *desc = font.GetNativeFontInfo()->description;
bbd006c0
RR
3578 PangoLayout *layout = pango_layout_new(context);
3579 pango_layout_set_font_description(layout, desc);
3580 pango_layout_set_text(layout, "H", 1);
3581 PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
3582
3583 PangoRectangle rect;
3584 pango_layout_line_get_extents(line, NULL, &rect);
3585
3586 g_object_unref( G_OBJECT( layout ) );
7de59551 3587
f69e2009 3588 return (int) PANGO_PIXELS(rect.height);
bbd006c0 3589#else
cc402e64 3590 GdkFont *gfont = font.GetInternalFont( 1.0 );
f03fc89f 3591
cc402e64 3592 return gfont->ascent + gfont->descent;
bbd006c0 3593#endif
362c6693 3594}
c801d85f 3595
1e6feb95 3596int wxWindowGTK::GetCharWidth() const
c33c4050 3597{
82b978d7 3598 wxCHECK_MSG( (m_widget != NULL), 8, wxT("invalid window") );
47d67540 3599
cc402e64
VZ
3600 wxFont font = GetFont();
3601 wxCHECK_MSG( font.Ok(), 8, wxT("invalid font") );
47d67540 3602
bbd006c0
RR
3603#ifdef __WXGTK20__
3604 PangoContext *context = NULL;
3605 if (m_widget)
3606 context = gtk_widget_get_pango_context( m_widget );
3607
3608 if (!context)
3609 return 0;
3610
cc402e64 3611 PangoFontDescription *desc = font.GetNativeFontInfo()->description;
bbd006c0
RR
3612 PangoLayout *layout = pango_layout_new(context);
3613 pango_layout_set_font_description(layout, desc);
95c430aa 3614 pango_layout_set_text(layout, "g", 1);
bbd006c0
RR
3615 PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
3616
3617 PangoRectangle rect;
3618 pango_layout_line_get_extents(line, NULL, &rect);
3619
3620 g_object_unref( G_OBJECT( layout ) );
7de59551 3621
f69e2009 3622 return (int) PANGO_PIXELS(rect.width);
bbd006c0 3623#else
cc402e64 3624 GdkFont *gfont = font.GetInternalFont( 1.0 );
ff8bfdbb 3625
cc402e64 3626 return gdk_string_width( gfont, "g" );
bbd006c0 3627#endif
c33c4050
RR
3628}
3629
1e6feb95 3630void wxWindowGTK::GetTextExtent( const wxString& string,
0a164d4c
WS
3631 int *x,
3632 int *y,
3633 int *descent,
3634 int *externalLeading,
3635 const wxFont *theFont ) const
c33c4050 3636{
cc402e64 3637 wxFont fontToUse = theFont ? *theFont : GetFont();
47d67540 3638
223d09f6 3639 wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
2b5f62a0 3640
0a164d4c 3641 if (string.empty())
48d011c8 3642 {
b15ed747
RR
3643 if (x) (*x) = 0;
3644 if (y) (*y) = 0;
48d011c8
RR
3645 return;
3646 }
47d67540 3647
2b5f62a0 3648#ifdef __WXGTK20__
48d011c8
RR
3649 PangoContext *context = NULL;
3650 if (m_widget)
2b5f62a0
VZ
3651 context = gtk_widget_get_pango_context( m_widget );
3652
48d011c8
RR
3653 if (!context)
3654 {
b15ed747
RR
3655 if (x) (*x) = 0;
3656 if (y) (*y) = 0;
48d011c8
RR
3657 return;
3658 }
2b5f62a0 3659
48d011c8
RR
3660 PangoFontDescription *desc = fontToUse.GetNativeFontInfo()->description;
3661 PangoLayout *layout = pango_layout_new(context);
3662 pango_layout_set_font_description(layout, desc);
3663 {
fb3ed106 3664#if wxUSE_UNICODE
48d011c8
RR
3665 const wxCharBuffer data = wxConvUTF8.cWC2MB( string );
3666 pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data ));
fb3ed106
RR
3667#else
3668 const wxWCharBuffer wdata = wxConvLocal.cMB2WC( string );
3669 const wxCharBuffer data = wxConvUTF8.cWC2MB( wdata );
3670 pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data ));
3671#endif
48d011c8 3672 }
2b5f62a0 3673
48d011c8 3674 PangoRectangle rect;
fd43b1b3 3675 pango_layout_get_extents(layout, NULL, &rect);
2b5f62a0 3676
f69e2009
VS
3677 if (x) (*x) = (wxCoord) PANGO_PIXELS(rect.width);
3678 if (y) (*y) = (wxCoord) PANGO_PIXELS(rect.height);
48d011c8
RR
3679 if (descent)
3680 {
f69e2009
VS
3681 PangoLayoutIter *iter = pango_layout_get_iter(layout);
3682 int baseline = pango_layout_iter_get_baseline(iter);
3683 pango_layout_iter_free(iter);
3684 *descent = *y - PANGO_PIXELS(baseline);
48d011c8
RR
3685 }
3686 if (externalLeading) (*externalLeading) = 0; // ??
2b5f62a0 3687
48d011c8
RR
3688 g_object_unref( G_OBJECT( layout ) );
3689#else
463c1fa1 3690 GdkFont *font = fontToUse.GetInternalFont( 1.0 );
fab591c5 3691 if (x) (*x) = gdk_string_width( font, wxGTK_CONV( string ) );
463c1fa1
RR
3692 if (y) (*y) = font->ascent + font->descent;
3693 if (descent) (*descent) = font->descent;
3694 if (externalLeading) (*externalLeading) = 0; // ??
48d011c8 3695#endif
c33c4050
RR
3696}
3697
1e6feb95 3698void wxWindowGTK::SetFocus()
c801d85f 3699{
82b978d7 3700 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
6cad4f1b
VZ
3701 if ( m_hasFocus )
3702 {
3703 // don't do anything if we already have focus
3704 return;
3705 }
2daa0ce9 3706
354aa1e3
RR
3707 if (m_wxwindow)
3708 {
173348db 3709 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
b231914f 3710 {
173348db 3711 gtk_widget_grab_focus (m_wxwindow);
b231914f 3712 }
354aa1e3 3713 }
b231914f 3714 else if (m_widget)
c801d85f 3715 {
eccd5602
RR
3716#ifdef __WXGTK20__
3717 if (GTK_IS_CONTAINER(m_widget))
3718 {
3719 gtk_widget_child_focus( m_widget, GTK_DIR_TAB_FORWARD );
3720 }
3721 else
3722#endif
173348db 3723 if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
463c1fa1 3724 {
0a164d4c 3725
d7fa7eaa 3726 if (!GTK_WIDGET_REALIZED(m_widget))
6aeb6f2a 3727 {
6cad4f1b
VZ
3728 // we can't set the focus to the widget now so we remember that
3729 // it should be focused and will do it later, during the idle
3730 // time, as soon as we can
3731 wxLogTrace(TRACE_FOCUS,
3732 _T("Delaying setting focus to %s(%s)"),
6aeb6f2a
VZ
3733 GetClassInfo()->GetClassName(), GetLabel().c_str());
3734
d7fa7eaa 3735 g_delayedFocus = this;
6aeb6f2a 3736 }
d7fa7eaa 3737 else
6aeb6f2a 3738 {
6cad4f1b
VZ
3739 wxLogTrace(TRACE_FOCUS,
3740 _T("Setting focus to %s(%s)"),
6aeb6f2a
VZ
3741 GetClassInfo()->GetClassName(), GetLabel().c_str());
3742
d7fa7eaa 3743 gtk_widget_grab_focus (m_widget);
6aeb6f2a 3744 }
463c1fa1 3745 }
0a164d4c 3746 else
eccd5602
RR
3747#ifndef __WXGTK20__
3748 if (GTK_IS_CONTAINER(m_widget))
ff8bfdbb 3749 {
59060b8c 3750 gtk_container_focus( GTK_CONTAINER(m_widget), GTK_DIR_TAB_FORWARD );
ff8bfdbb
VZ
3751 }
3752 else
eccd5602 3753#endif
ff8bfdbb 3754 {
6cad4f1b
VZ
3755 wxLogTrace(TRACE_FOCUS,
3756 _T("Can't set focus to %s(%s)"),
3757 GetClassInfo()->GetClassName(), GetLabel().c_str());
ff8bfdbb 3758 }
362c6693 3759 }
362c6693 3760}
c801d85f 3761
1e6feb95 3762bool wxWindowGTK::AcceptsFocus() const
b292e2f5 3763{
f03fc89f 3764 return m_acceptsFocus && wxWindowBase::AcceptsFocus();
b292e2f5
RR
3765}
3766
1e6feb95 3767bool wxWindowGTK::Reparent( wxWindowBase *newParentBase )
463c1fa1 3768{
0a164d4c 3769 wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
c50f1fb9 3770
1e6feb95
VZ
3771 wxWindowGTK *oldParent = m_parent,
3772 *newParent = (wxWindowGTK *)newParentBase;
a2053b27 3773
5fd11f09
RR
3774 wxASSERT( GTK_IS_WIDGET(m_widget) );
3775
f03fc89f 3776 if ( !wxWindowBase::Reparent(newParent) )
0a164d4c 3777 return false;
8bbe427f 3778
5fd11f09
RR
3779 wxASSERT( GTK_IS_WIDGET(m_widget) );
3780
3781 /* prevent GTK from deleting the widget arbitrarily */
3782 gtk_widget_ref( m_widget );
3783
8ce63e9d
RR
3784 if (oldParent)
3785 {
3017f78d 3786 gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget );
8ce63e9d 3787 }
c50f1fb9 3788
5fd11f09
RR
3789 wxASSERT( GTK_IS_WIDGET(m_widget) );
3790
8ce63e9d
RR
3791 if (newParent)
3792 {
3793 /* insert GTK representation */
3794 (*(newParent->m_insertCallback))(newParent, this);
3795 }
c50f1fb9 3796
5fd11f09
RR
3797 /* reverse: prevent GTK from deleting the widget arbitrarily */
3798 gtk_widget_unref( m_widget );
148cd9b6 3799
0a164d4c 3800 return true;
362c6693 3801}
c801d85f 3802
1e6feb95 3803void wxWindowGTK::DoAddChild(wxWindowGTK *child)
ddb6bc71 3804{
223d09f6 3805 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
ddb6bc71 3806
223d09f6 3807 wxASSERT_MSG( (child != NULL), wxT("invalid child window") );
ddb6bc71 3808
223d09f6 3809 wxASSERT_MSG( (m_insertCallback != NULL), wxT("invalid child insertion function") );
c50f1fb9 3810
ddb6bc71
RR
3811 /* add to list */
3812 AddChild( child );
c50f1fb9 3813
ddb6bc71
RR
3814 /* insert GTK representation */
3815 (*m_insertCallback)(this, child);
3816}
3817
a589495e
VS
3818#ifdef __WXGTK20__
3819
3820void wxWindowGTK::AddChild(wxWindowBase *child)
3821{
3822 wxWindowBase::AddChild(child);
3823 m_dirtyTabOrder = true;
3824 if (g_isIdle)
3825 wxapp_install_idle_handler();
3826}
3827
3828void wxWindowGTK::RemoveChild(wxWindowBase *child)
3829{
3830 wxWindowBase::RemoveChild(child);
3831 m_dirtyTabOrder = true;
3832 if (g_isIdle)
3833 wxapp_install_idle_handler();
3834}
0a164d4c 3835
a589495e
VS
3836void wxWindowGTK::DoMoveInTabOrder(wxWindow *win, MoveKind move)
3837{
3838 wxWindowBase::DoMoveInTabOrder(win, move);
3839 m_dirtyTabOrder = true;
3840 if (g_isIdle)
3841 wxapp_install_idle_handler();
3842}
3843
3844void wxWindowGTK::RealizeTabOrder()
3845{
3846 if (m_wxwindow)
3847 {
3848 if (m_children.size() > 0)
3849 {
3850 GList *chain = NULL;
0a164d4c 3851
a589495e
VS
3852 for (wxWindowList::const_iterator i = m_children.begin();
3853 i != m_children.end(); ++i)
3854 {
3855 chain = g_list_prepend(chain, (*i)->m_widget);
3856 }
0a164d4c 3857
a589495e 3858 chain = g_list_reverse(chain);
0a164d4c 3859
a589495e
VS
3860 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow), chain);
3861 g_list_free(chain);
3862 }
3863 else
3864 {
3865 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow));
3866 }
3867 }
0a164d4c 3868
a589495e
VS
3869 m_dirtyTabOrder = false;
3870}
3871
3872#endif // __WXGTK20__
3873
1e6feb95 3874void wxWindowGTK::Raise()
362c6693 3875{
82b978d7
RD
3876 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3877
fdfb8475
RR
3878 if (m_wxwindow && m_wxwindow->window)
3879 {
3880 gdk_window_raise( m_wxwindow->window );
3881 }
0a164d4c 3882 else if (m_widget->window)
fdfb8475
RR
3883 {
3884 gdk_window_raise( m_widget->window );
3885 }
362c6693
RR
3886}
3887
1e6feb95 3888void wxWindowGTK::Lower()
362c6693 3889{
82b978d7
RD
3890 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3891
fdfb8475
RR
3892 if (m_wxwindow && m_wxwindow->window)
3893 {
3894 gdk_window_lower( m_wxwindow->window );
3895 }
0a164d4c 3896 else if (m_widget->window)
fdfb8475
RR
3897 {
3898 gdk_window_lower( m_widget->window );
3899 }
362c6693 3900}
c801d85f 3901
1e6feb95 3902bool wxWindowGTK::SetCursor( const wxCursor &cursor )
86b29a61 3903{
0a164d4c 3904 wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
86b29a61 3905
f6bcfd97 3906 if (cursor == m_cursor)
0a164d4c 3907 return false;
f6bcfd97
BP
3908
3909 if (g_isIdle)
3910 wxapp_install_idle_handler();
1e6feb95 3911
f6bcfd97
BP
3912 if (cursor == wxNullCursor)
3913 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR );
3914 else
3915 return wxWindowBase::SetCursor( cursor );
362c6693 3916}
c801d85f 3917
1e6feb95 3918void wxWindowGTK::WarpPointer( int x, int y )
4f22cf8d 3919{
82b978d7
RD
3920 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3921
3bcc8d15
RR
3922 // We provide this function ourselves as it is
3923 // missing in GDK (top of this file).
148cd9b6 3924
ed673c6a
RR
3925 GdkWindow *window = (GdkWindow*) NULL;
3926 if (m_wxwindow)
da048e3d 3927 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a
RR
3928 else
3929 window = GetConnectWidget()->window;
148cd9b6 3930
ed673c6a
RR
3931 if (window)
3932 gdk_window_warp_pointer( window, x, y );
4f22cf8d
RR
3933}
3934
3013a903 3935
1e6feb95 3936void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
c801d85f 3937{
a67f1484
VZ
3938 if (!m_widget)
3939 return;
3940 if (!m_widget->window)
3941 return;
2b5f62a0 3942
4e5a4c69 3943#ifndef __WXGTK20__
ea323db3
RR
3944 if (g_isIdle)
3945 wxapp_install_idle_handler();
2b5f62a0 3946
a67f1484 3947 wxRect myRect;
75625d79
SN
3948 if (m_wxwindow && rect)
3949 {
3950 myRect.SetSize(wxSize( m_wxwindow->allocation.width,
3951 m_wxwindow->allocation.height));
a67f1484
VZ
3952 if ( myRect.Intersect(*rect).IsEmpty() )
3953 {
75625d79
SN
3954 // nothing to do, rectangle is empty
3955 return;
a67f1484
VZ
3956 }
3957
75625d79
SN
3958 rect = &myRect;
3959 }
3960
a67f1484 3961 // schedule the area for later updating in GtkUpdate()
139adb6a 3962 if (eraseBackground && m_wxwindow && m_wxwindow->window)
c801d85f 3963 {
139adb6a
RR
3964 if (rect)
3965 {
3bcc8d15 3966 m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height );
139adb6a
RR
3967 }
3968 else
3969 {
3bcc8d15
RR
3970 m_clearRegion.Clear();
3971 m_clearRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
139adb6a
RR
3972 }
3973 }
ff8bfdbb 3974
3bcc8d15 3975 if (rect)
139adb6a
RR
3976 {
3977 if (m_wxwindow)
b02da6b1 3978 {
3bcc8d15 3979 m_updateRegion.Union( rect->x, rect->y, rect->width, rect->height );
b02da6b1 3980 }
ff8bfdbb 3981 else
b6fa52db 3982 {
3bcc8d15
RR
3983 GdkRectangle gdk_rect;
3984 gdk_rect.x = rect->x;
3985 gdk_rect.y = rect->y;
3986 gdk_rect.width = rect->width;
3987 gdk_rect.height = rect->height;
3988 gtk_widget_draw( m_widget, &gdk_rect );
b6fa52db 3989 }
362c6693 3990 }
c801d85f 3991 else
139adb6a 3992 {
139adb6a 3993 if (m_wxwindow)
b02da6b1 3994 {
3bcc8d15
RR
3995 m_updateRegion.Clear();
3996 m_updateRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
b02da6b1 3997 }
139adb6a 3998 else
b6fa52db 3999 {
3bcc8d15 4000 gtk_widget_draw( m_widget, (GdkRectangle*) NULL );
b6fa52db 4001 }
139adb6a 4002 }
a67f1484 4003#else // GTK+ 2
4e5a4c69
RR
4004 if (m_wxwindow)
4005 {
a67f1484
VZ
4006 GdkRectangle gdk_rect,
4007 *p;
4e5a4c69
RR
4008 if (rect)
4009 {
4e5a4c69
RR
4010 gdk_rect.x = rect->x;
4011 gdk_rect.y = rect->y;
4012 gdk_rect.width = rect->width;
4013 gdk_rect.height = rect->height;
a67f1484 4014 p = &gdk_rect;
4e5a4c69 4015 }
a67f1484 4016 else // invalidate everything
4e5a4c69 4017 {
a67f1484 4018 p = NULL;
4e5a4c69 4019 }
a67f1484
VZ
4020
4021 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow)->bin_window, p, TRUE );
4e5a4c69 4022 }
a67f1484 4023#endif // GTK+ 1/2
362c6693 4024}
c801d85f 4025
beab25bd 4026void wxWindowGTK::Update()
010afced
RR
4027{
4028 GtkUpdate();
1b965a9c
VZ
4029
4030 // when we call Update() we really want to update the window immediately on
4031 // screen, even if itmeans flushing the entire queue and hence slowing down
4032 // everything -- but it should still be done, it's just that Update() should
4033 // be called very rarely
4034 gdk_flush();
010afced
RR
4035}
4036
4037void wxWindowGTK::GtkUpdate()
beab25bd 4038{
4e5a4c69
RR
4039#ifdef __WXGTK20__
4040 if (m_wxwindow && GTK_PIZZA(m_wxwindow)->bin_window)
4041 gdk_window_process_updates( GTK_PIZZA(m_wxwindow)->bin_window, FALSE );
b15ed747 4042#else
beab25bd 4043 if (!m_updateRegion.IsEmpty())
23716407 4044 GtkSendPaintEvents();
b15ed747 4045#endif
a67f1484
VZ
4046
4047 // for consistency with other platforms (and also because it's convenient
4048 // to be able to update an entire TLW by calling Update() only once), we
4049 // should also update all our children here
4050 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
4051 node;
4052 node = node->GetNext() )
4053 {
4054 node->GetData()->GtkUpdate();
4055 }
beab25bd
RR
4056}
4057
4058void wxWindowGTK::GtkSendPaintEvents()
4059{
3bcc8d15
RR
4060 if (!m_wxwindow)
4061 {
2b5f62a0 4062#ifndef __WXGTK20__
3bcc8d15 4063 m_clearRegion.Clear();
b15ed747 4064#endif
3bcc8d15
RR
4065 m_updateRegion.Clear();
4066 return;
4067 }
beab25bd 4068
f90566f5 4069 // Clip to paint region in wxClientDC
0a164d4c 4070 m_clipPaintRegion = true;
fab591c5 4071
b15ed747
RR
4072 // widget to draw on
4073 GtkPizza *pizza = GTK_PIZZA (m_wxwindow);
2b5f62a0 4074
aac97549 4075 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM))
f90566f5
RR
4076 {
4077 // find ancestor from which to steal background
cd5e74ba 4078 wxWindow *parent = wxGetTopLevelParent((wxWindow *)this);
f90566f5 4079 if (!parent)
cc06fe74 4080 parent = (wxWindow*)this;
2b5f62a0 4081
822cf31c 4082 if (GTK_WIDGET_MAPPED(parent->m_widget))
f90566f5 4083 {
822cf31c
KH
4084 wxRegionIterator upd( m_updateRegion );
4085 while (upd)
4086 {
4087 GdkRectangle rect;
4088 rect.x = upd.GetX();
4089 rect.y = upd.GetY();
4090 rect.width = upd.GetWidth();
4091 rect.height = upd.GetHeight();
4092
4093 gtk_paint_flat_box( parent->m_widget->style,
4094 pizza->bin_window,
4095 (GtkStateType)GTK_WIDGET_STATE(m_wxwindow),
4096 GTK_SHADOW_NONE,
4097 &rect,
4098 parent->m_widget,
4099 (char *)"base",
4100 0, 0, -1, -1 );
4101
60d8e886 4102 ++upd;
822cf31c 4103 }
f90566f5
RR
4104 }
4105 }
4106 else
b15ed747
RR
4107
4108#ifdef __WXGTK20__
4109 {
4110 wxWindowDC dc( (wxWindow*)this );
4111 dc.SetClippingRegion( m_updateRegion );
4112
4113 wxEraseEvent erase_event( GetId(), &dc );
4114 erase_event.SetEventObject( this );
4115
4116 GetEventHandler()->ProcessEvent(erase_event);
4117 }
4118#else
4119 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
beab25bd 4120 {
3bcc8d15 4121 wxWindowDC dc( (wxWindow*)this );
62cb3cd8
RR
4122 if (m_clearRegion.IsEmpty())
4123 dc.SetClippingRegion( m_updateRegion );
4124 else
4125 dc.SetClippingRegion( m_clearRegion );
0fc5dbf5 4126
3bcc8d15
RR
4127 wxEraseEvent erase_event( GetId(), &dc );
4128 erase_event.SetEventObject( this );
0fc5dbf5 4129
c7382f91 4130 if (!GetEventHandler()->ProcessEvent(erase_event) && GetBackgroundStyle() != wxBG_STYLE_CUSTOM)
beab25bd 4131 {
994bc575
RR
4132 if (!g_eraseGC)
4133 {
f90566f5 4134 g_eraseGC = gdk_gc_new( pizza->bin_window );
994bc575
RR
4135 gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4136 }
1cd3409d 4137 gdk_gc_set_foreground( g_eraseGC, GetBackgroundColour().GetColor() );
0fc5dbf5 4138
3bcc8d15 4139 wxRegionIterator upd( m_clearRegion );
beab25bd
RR
4140 while (upd)
4141 {
f90566f5
RR
4142 gdk_draw_rectangle( pizza->bin_window, g_eraseGC, 1,
4143 upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
beab25bd
RR
4144 upd ++;
4145 }
4146 }
3bcc8d15 4147 m_clearRegion.Clear();
beab25bd 4148 }
b15ed747 4149#endif
beab25bd
RR
4150
4151 wxNcPaintEvent nc_paint_event( GetId() );
4152 nc_paint_event.SetEventObject( this );
4153 GetEventHandler()->ProcessEvent( nc_paint_event );
4154
4155 wxPaintEvent paint_event( GetId() );
4156 paint_event.SetEventObject( this );
4157 GetEventHandler()->ProcessEvent( paint_event );
4158
0a164d4c 4159 m_clipPaintRegion = false;
c89f5c02 4160
4106cebb 4161#if !defined(__WXUNIVERSAL__) && !defined(__WXGTK20__)
8f3e7ecc 4162 // The following code will result in all window-less widgets
77ffb593 4163 // being redrawn because the wxWidgets class is allowed to
8f3e7ecc 4164 // paint over the window-less widgets.
0fc5dbf5 4165
8f3e7ecc
RR
4166 GList *children = pizza->children;
4167 while (children)
c89f5c02 4168 {
8f3e7ecc
RR
4169 GtkPizzaChild *child = (GtkPizzaChild*) children->data;
4170 children = children->next;
2b5f62a0 4171
8f3e7ecc
RR
4172 if (GTK_WIDGET_NO_WINDOW (child->widget) &&
4173 GTK_WIDGET_DRAWABLE (child->widget))
4174 {
4175 // Get intersection of widget area and update region
4176 wxRegion region( m_updateRegion );
0fc5dbf5 4177
8f3e7ecc
RR
4178 GdkEventExpose gdk_event;
4179 gdk_event.type = GDK_EXPOSE;
4180 gdk_event.window = pizza->bin_window;
4181 gdk_event.count = 0;
4106cebb 4182 gdk_event.send_event = TRUE;
0fc5dbf5 4183
8f3e7ecc
RR
4184 wxRegionIterator upd( m_updateRegion );
4185 while (upd)
c89f5c02 4186 {
8f3e7ecc
RR
4187 GdkRectangle rect;
4188 rect.x = upd.GetX();
4189 rect.y = upd.GetY();
4190 rect.width = upd.GetWidth();
4191 rect.height = upd.GetHeight();
0fc5dbf5 4192
8f3e7ecc
RR
4193 if (gtk_widget_intersect (child->widget, &rect, &gdk_event.area))
4194 {
4195 gtk_widget_event (child->widget, (GdkEvent*) &gdk_event);
4196 }
0fc5dbf5 4197
8f3e7ecc 4198 upd ++;
c89f5c02
RR
4199 }
4200 }
4201 }
4106cebb 4202#endif // native GTK 1
c89f5c02
RR
4203
4204 m_updateRegion.Clear();
beab25bd
RR
4205}
4206
596f1d11 4207void wxWindowGTK::ClearBackground()
c801d85f 4208{
82b978d7
RD
4209 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4210
b15ed747 4211#ifndef __WXGTK20__
f234c60c
RR
4212 if (m_wxwindow && m_wxwindow->window)
4213 {
d7fa7eaa
RR
4214 m_clearRegion.Clear();
4215 wxSize size( GetClientSize() );
4216 m_clearRegion.Union( 0,0,size.x,size.y );
2b5f62a0 4217
d7fa7eaa 4218 // Better do this in idle?
010afced 4219 GtkUpdate();
f234c60c 4220 }
b15ed747 4221#endif
362c6693 4222}
c801d85f 4223
ff8bfdbb 4224#if wxUSE_TOOLTIPS
1e6feb95 4225void wxWindowGTK::DoSetToolTip( wxToolTip *tip )
b1170810 4226{
f03fc89f 4227 wxWindowBase::DoSetToolTip(tip);
ff8bfdbb 4228
f03fc89f 4229 if (m_tooltip)
3379ed37 4230 m_tooltip->Apply( (wxWindow *)this );
b1170810
RR
4231}
4232
1e6feb95 4233void wxWindowGTK::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
b1170810 4234{
aa154cb1
RR
4235 wxString tmp( tip );
4236 gtk_tooltips_set_tip( tips, GetConnectWidget(), wxGTK_CONV(tmp), (gchar*) NULL );
301cd871 4237}
ff8bfdbb 4238#endif // wxUSE_TOOLTIPS
b1170810 4239
1e6feb95 4240bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
c801d85f 4241{
0a164d4c 4242 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
8bbe427f 4243
739730ca 4244 if (!wxWindowBase::SetBackgroundColour(colour))
44dfb5ce 4245 return false;
c50f1fb9 4246
5edef14e 4247 if (colour.Ok())
994bc575 4248 {
5edef14e
VS
4249 // We need the pixel value e.g. for background clearing.
4250 m_backgroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
994bc575 4251 }
ca298c88 4252
5edef14e 4253 // apply style change (forceStyle=true so that new style is applied
c7382f91
JS
4254 // even if the bg colour changed from valid to wxNullColour)
4255 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM)
4256 ApplyWidgetStyle(true);
ea323db3 4257
5edef14e 4258 return true;
6de97a3b
RR
4259}
4260
1e6feb95 4261bool wxWindowGTK::SetForegroundColour( const wxColour &colour )
6de97a3b 4262{
0a164d4c 4263 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
8bbe427f 4264
739730ca
RR
4265 if (!wxWindowBase::SetForegroundColour(colour))
4266 {
5edef14e 4267 return false;
739730ca 4268 }
0a164d4c 4269
5edef14e 4270 if (colour.Ok())
ea323db3 4271 {
5edef14e
VS
4272 // We need the pixel value e.g. for background clearing.
4273 m_foregroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
ea323db3 4274 }
f03fc89f 4275
5edef14e
VS
4276 // apply style change (forceStyle=true so that new style is applied
4277 // even if the bg colour changed from valid to wxNullColour):
4278 ApplyWidgetStyle(true);
4279
44dfb5ce 4280 return true;
58614078
RR
4281}
4282
2b5f62a0
VZ
4283#ifdef __WXGTK20__
4284PangoContext *wxWindowGTK::GtkGetPangoDefaultContext()
4285{
4286 return gtk_widget_get_pango_context( m_widget );
4287}
4288
f26623c8 4289// MR: Returns the same as GtkGetPangoDefaultContext until the symbol can be removed in 2.7.x
2b5f62a0
VZ
4290PangoContext *wxWindowGTK::GtkGetPangoX11Context()
4291{
f26623c8 4292 return gtk_widget_get_pango_context( m_widget );
2b5f62a0
VZ
4293}
4294#endif
0a164d4c 4295
5edef14e 4296GtkRcStyle *wxWindowGTK::CreateWidgetStyle(bool forceStyle)
58614078 4297{
f40fdaa3 4298 // do we need to apply any changes at all?
5edef14e 4299 if ( !forceStyle &&
984e8d0b
VS
4300 !m_font.Ok() &&
4301 !m_foregroundColour.Ok() && !m_backgroundColour.Ok() )
fb65642c 4302 {
f40fdaa3 4303 return NULL;
fb65642c
RR
4304 }
4305
f40fdaa3 4306 GtkRcStyle *style = gtk_rc_style_new();
1ecc4d80 4307
984e8d0b 4308 if ( m_font.Ok() )
db434467 4309 {
288059b2 4310#ifdef __WXGTK20__
0a164d4c 4311 style->font_desc =
f40fdaa3 4312 pango_font_description_copy( m_font.GetNativeFontInfo()->description );
288059b2 4313#else
f40fdaa3
VS
4314 wxString xfontname = m_font.GetNativeFontInfo()->GetXFontName();
4315 style->fontset_name = g_strdup(xfontname.c_str());
cfcc3932 4316#endif
288059b2 4317 }
1ecc4d80 4318
fe161a26 4319 if ( m_foregroundColour.Ok() )
1ecc4d80 4320 {
5edef14e 4321 GdkColor *fg = m_foregroundColour.GetColor();
0a164d4c 4322
5edef14e 4323 style->fg[GTK_STATE_NORMAL] = *fg;
f40fdaa3 4324 style->color_flags[GTK_STATE_NORMAL] = GTK_RC_FG;
0a164d4c 4325
5edef14e 4326 style->fg[GTK_STATE_PRELIGHT] = *fg;
f40fdaa3 4327 style->color_flags[GTK_STATE_PRELIGHT] = GTK_RC_FG;
0a164d4c 4328
5edef14e 4329 style->fg[GTK_STATE_ACTIVE] = *fg;
f40fdaa3 4330 style->color_flags[GTK_STATE_ACTIVE] = GTK_RC_FG;
1ecc4d80
RR
4331 }
4332
fe161a26 4333 if ( m_backgroundColour.Ok() )
1ecc4d80 4334 {
5edef14e
VS
4335 GdkColor *bg = m_backgroundColour.GetColor();
4336
4337 style->bg[GTK_STATE_NORMAL] = *bg;
4338 style->base[GTK_STATE_NORMAL] = *bg;
f40fdaa3
VS
4339 style->color_flags[GTK_STATE_NORMAL] = (GtkRcFlags)
4340 (style->color_flags[GTK_STATE_NORMAL] | GTK_RC_BG | GTK_RC_BASE);
0a164d4c 4341
5edef14e
VS
4342 style->bg[GTK_STATE_PRELIGHT] = *bg;
4343 style->base[GTK_STATE_PRELIGHT] = *bg;
f40fdaa3
VS
4344 style->color_flags[GTK_STATE_PRELIGHT] = (GtkRcFlags)
4345 (style->color_flags[GTK_STATE_PRELIGHT] | GTK_RC_BG | GTK_RC_BASE);
0a164d4c 4346
5edef14e
VS
4347 style->bg[GTK_STATE_ACTIVE] = *bg;
4348 style->base[GTK_STATE_ACTIVE] = *bg;
f40fdaa3
VS
4349 style->color_flags[GTK_STATE_ACTIVE] = (GtkRcFlags)
4350 (style->color_flags[GTK_STATE_ACTIVE] | GTK_RC_BG | GTK_RC_BASE);
0a164d4c 4351
5edef14e
VS
4352 style->bg[GTK_STATE_INSENSITIVE] = *bg;
4353 style->base[GTK_STATE_INSENSITIVE] = *bg;
f40fdaa3
VS
4354 style->color_flags[GTK_STATE_INSENSITIVE] = (GtkRcFlags)
4355 (style->color_flags[GTK_STATE_INSENSITIVE] | GTK_RC_BG | GTK_RC_BASE);
1ecc4d80 4356 }
0a164d4c 4357
f40fdaa3 4358 return style;
a81258be
RR
4359}
4360
f8e045e2 4361void wxWindowGTK::ApplyWidgetStyle(bool forceStyle)
a81258be 4362{
f8e045e2
RD
4363 GtkRcStyle *style = CreateWidgetStyle(forceStyle);
4364 if ( style )
4365 {
7074ce35 4366 DoApplyWidgetStyle(style);
f8e045e2
RD
4367 gtk_rc_style_unref(style);
4368 }
6dd18972
VS
4369
4370 // Style change may affect GTK+'s size calculation:
4371 InvalidateBestSize();
6de97a3b
RR
4372}
4373
7074ce35
VS
4374void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle *style)
4375{
4376 if (m_wxwindow)
7074ce35 4377 gtk_widget_modify_style(m_wxwindow, style);
7cb93e45
RR
4378 else
4379 gtk_widget_modify_style(m_widget, style);
7074ce35
VS
4380}
4381
c7382f91
JS
4382bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style)
4383{
4384 wxWindowBase::SetBackgroundStyle(style);
0a164d4c 4385
c7382f91
JS
4386 if (style == wxBG_STYLE_CUSTOM)
4387 {
4388 GdkWindow *window = (GdkWindow*) NULL;
4389 if (m_wxwindow)
4390 window = GTK_PIZZA(m_wxwindow)->bin_window;
4391 else
4392 window = GetConnectWidget()->window;
4393
4394 if (window)
4395 {
4396 // Make sure GDK/X11 doesn't refresh the window
4397 // automatically.
4398 gdk_window_set_back_pixmap( window, None, False );
4399#ifdef __X__
4400 Display* display = GDK_WINDOW_DISPLAY(window);
4401 XFlush(display);
4402#endif
4403 m_needsStyleChange = false;
4404 }
4405 else
4406 // Do in OnIdle, because the window is not yet available
4407 m_needsStyleChange = true;
0a164d4c 4408
c7382f91
JS
4409 // Don't apply widget style, or we get a grey background
4410 }
4411 else
4412 {
4413 // apply style change (forceStyle=true so that new style is applied
4414 // even if the bg colour changed from valid to wxNullColour):
4415 ApplyWidgetStyle(true);
4416 }
4417 return true;
4418}
7074ce35 4419
2259e007
RR
4420//-----------------------------------------------------------------------------
4421// Pop-up menu stuff
4422//-----------------------------------------------------------------------------
4423
6522713c 4424#if wxUSE_MENUS_NATIVE
1e6feb95 4425
20123d49 4426extern "C" WXDLLIMPEXP_CORE
90350682 4427void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting )
2259e007
RR
4428{
4429 *is_waiting = FALSE;
4430}
4431
20123d49 4432WXDLLIMPEXP_CORE void SetInvokingWindow( wxMenu *menu, wxWindow* win )
30dea054 4433{
1ecc4d80 4434 menu->SetInvokingWindow( win );
0a164d4c 4435
222ed1d6 4436 wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst();
1ecc4d80
RR
4437 while (node)
4438 {
1987af7e 4439 wxMenuItem *menuitem = node->GetData();
1ecc4d80
RR
4440 if (menuitem->IsSubMenu())
4441 {
ff8bfdbb
VZ
4442 SetInvokingWindow( menuitem->GetSubMenu(), win );
4443 }
1987af7e
VZ
4444
4445 node = node->GetNext();
1ecc4d80 4446 }
362c6693 4447}
30dea054 4448
20123d49
MW
4449extern "C" WXDLLIMPEXP_CORE
4450void wxPopupMenuPositionCallback( GtkMenu *menu,
4451 gint *x, gint *y,
9e691f46 4452#ifdef __WXGTK20__
20123d49 4453 gboolean * WXUNUSED(whatever),
9e691f46 4454#endif
20123d49 4455 gpointer user_data )
0c77152e 4456{
e3473203
VZ
4457 // ensure that the menu appears entirely on screen
4458 GtkRequisition req;
4459 gtk_widget_get_child_requisition(GTK_WIDGET(menu), &req);
4460
4461 wxSize sizeScreen = wxGetDisplaySize();
39b44a39 4462 wxPoint *pos = (wxPoint*)user_data;
e3473203
VZ
4463
4464 gint xmax = sizeScreen.x - req.width,
4465 ymax = sizeScreen.y - req.height;
4466
39b44a39
VS
4467 *x = pos->x < xmax ? pos->x : xmax;
4468 *y = pos->y < ymax ? pos->y : ymax;
0c77152e
RR
4469}
4470
1e6feb95 4471bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
30dea054 4472{
971562cb 4473 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
47d67540 4474
971562cb 4475 wxCHECK_MSG( menu != NULL, false, wxT("invalid popup-menu") );
8bbe427f 4476
0bd3b8ec
RR
4477 // NOTE: if you change this code, you need to update
4478 // the same code in taskbar.cpp as well. This
4479 // is ugly code duplication, I know,
4480
1ecc4d80 4481 SetInvokingWindow( menu, this );
ff8bfdbb 4482
631f1bfe
JS
4483 menu->UpdateUI();
4484
971562cb 4485 bool is_waiting = true;
148cd9b6 4486
098937b0
VS
4487 gulong handler = gtk_signal_connect( GTK_OBJECT(menu->m_menu),
4488 "hide",
4489 GTK_SIGNAL_FUNC(gtk_pop_hide_callback),
4490 (gpointer)&is_waiting );
2259e007 4491
971562cb
VS
4492 wxPoint pos;
4493 gpointer userdata;
4494 GtkMenuPositionFunc posfunc;
4495 if ( x == -1 && y == -1 )
4496 {
4497 // use GTK's default positioning algorithm
4498 userdata = NULL;
4499 posfunc = NULL;
4500 }
4501 else
4502 {
4503 pos = ClientToScreen(wxPoint(x, y));
4504 userdata = &pos;
4505 posfunc = wxPopupMenuPositionCallback;
4506 }
4507
1ecc4d80 4508 gtk_menu_popup(
47d67540 4509 GTK_MENU(menu->m_menu),
e3473203
VZ
4510 (GtkWidget *) NULL, // parent menu shell
4511 (GtkWidget *) NULL, // parent menu item
971562cb
VS
4512 posfunc, // function to position it
4513 userdata, // client data
4514 0, // button used to activate it
34791896
RR
4515#ifdef __WXGTK20__
4516 gtk_get_current_event_time()
4517#else
34adc954 4518 gs_timeLastClick // the time of activation
34791896 4519#endif
47d67540 4520 );
148cd9b6 4521
956dbab1
RR
4522 while (is_waiting)
4523 {
a03cac3f 4524 gtk_main_iteration();
956dbab1 4525 }
2259e007 4526
098937b0
VS
4527 gtk_signal_disconnect(GTK_OBJECT(menu->m_menu), handler);
4528
971562cb 4529 return true;
30dea054
RR
4530}
4531
6522713c 4532#endif // wxUSE_MENUS_NATIVE
1e6feb95 4533
06cfab17 4534#if wxUSE_DRAG_AND_DROP
ac57418f 4535
1e6feb95 4536void wxWindowGTK::SetDropTarget( wxDropTarget *dropTarget )
c801d85f 4537{
82b978d7
RD
4538 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4539
1ecc4d80 4540 GtkWidget *dnd_widget = GetConnectWidget();
47d67540 4541
1ecc4d80 4542 if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
47d67540 4543
1ecc4d80
RR
4544 if (m_dropTarget) delete m_dropTarget;
4545 m_dropTarget = dropTarget;
47d67540 4546
1ecc4d80 4547 if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
362c6693 4548}
c801d85f 4549
f03fc89f 4550#endif // wxUSE_DRAG_AND_DROP
ac57418f 4551
1e6feb95 4552GtkWidget* wxWindowGTK::GetConnectWidget()
e3e65dac 4553{
1ecc4d80
RR
4554 GtkWidget *connect_widget = m_widget;
4555 if (m_wxwindow) connect_widget = m_wxwindow;
47d67540 4556
1ecc4d80 4557 return connect_widget;
e3e65dac 4558}
47d67540 4559
1e6feb95 4560bool wxWindowGTK::IsOwnGtkWindow( GdkWindow *window )
903f689b 4561{
148cd9b6 4562 if (m_wxwindow)
da048e3d 4563 return (window == GTK_PIZZA(m_wxwindow)->bin_window);
148cd9b6 4564
1ecc4d80 4565 return (window == m_widget->window);
903f689b
RR
4566}
4567
1e6feb95 4568bool wxWindowGTK::SetFont( const wxFont &font )
c801d85f 4569{
0a164d4c 4570 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
9c288e4d 4571
5edef14e
VS
4572 if (!wxWindowBase::SetFont(font))
4573 return false;
c801d85f 4574
5edef14e
VS
4575 // apply style change (forceStyle=true so that new style is applied
4576 // even if the font changed from valid to wxNullFont):
0a164d4c 4577 ApplyWidgetStyle(true);
5edef14e
VS
4578
4579 return true;
362c6693 4580}
c801d85f 4581
94633ad9 4582void wxWindowGTK::DoCaptureMouse()
c801d85f 4583{
82b978d7
RD
4584 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4585
ed673c6a 4586 GdkWindow *window = (GdkWindow*) NULL;
b231914f
VZ
4587 if (m_wxwindow)
4588 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a 4589 else
b231914f 4590 window = GetConnectWidget()->window;
148cd9b6 4591
e4606ed9 4592 wxCHECK_RET( window, _T("CaptureMouse() failed") );
c50f1fb9 4593
b231914f 4594 wxCursor* cursor = & m_cursor;
cca602ac
JS
4595 if (!cursor->Ok())
4596 cursor = wxSTANDARD_CURSOR;
4597
ed673c6a 4598 gdk_pointer_grab( window, FALSE,
1ecc4d80
RR
4599 (GdkEventMask)
4600 (GDK_BUTTON_PRESS_MASK |
4601 GDK_BUTTON_RELEASE_MASK |
148cd9b6 4602 GDK_POINTER_MOTION_HINT_MASK |
1ecc4d80 4603 GDK_POINTER_MOTION_MASK),
ff8bfdbb 4604 (GdkWindow *) NULL,
cca602ac 4605 cursor->GetCursor(),
b02da6b1 4606 (guint32)GDK_CURRENT_TIME );
b231914f 4607 g_captureWindow = this;
0a164d4c 4608 g_captureWindowHasMouse = true;
362c6693 4609}
c801d85f 4610
94633ad9 4611void wxWindowGTK::DoReleaseMouse()
c801d85f 4612{
82b978d7
RD
4613 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4614
e4606ed9 4615 wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") );
47d67540 4616
c43430bb
VS
4617 g_captureWindow = (wxWindowGTK*) NULL;
4618
ed673c6a 4619 GdkWindow *window = (GdkWindow*) NULL;
b231914f
VZ
4620 if (m_wxwindow)
4621 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a 4622 else
b231914f 4623 window = GetConnectWidget()->window;
148cd9b6 4624
b02da6b1
VZ
4625 if (!window)
4626 return;
c50f1fb9 4627
b02da6b1 4628 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
362c6693 4629}
c801d85f 4630
1e6feb95
VZ
4631/* static */
4632wxWindow *wxWindowBase::GetCapture()
4633{
4634 return (wxWindow *)g_captureWindow;
4635}
4636
4637bool wxWindowGTK::IsRetained() const
c801d85f 4638{
0a164d4c 4639 return false;
362c6693 4640}
c801d85f 4641
1e6feb95 4642void wxWindowGTK::SetScrollbar( int orient, int pos, int thumbVisible,
cb43b372 4643 int range, bool refresh )
c801d85f 4644{
82b978d7
RD
4645 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4646
223d09f6 4647 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
c801d85f 4648
0a164d4c 4649 m_hasScrolling = true;
47d67540 4650
1ecc4d80 4651 if (orient == wxHORIZONTAL)
cb43b372 4652 {
1ecc4d80
RR
4653 float fpos = (float)pos;
4654 float frange = (float)range;
4655 float fthumb = (float)thumbVisible;
4656 if (fpos > frange-fthumb) fpos = frange-fthumb;
4657 if (fpos < 0.0) fpos = 0.0;
4658
4659 if ((fabs(frange-m_hAdjust->upper) < 0.2) &&
4660 (fabs(fthumb-m_hAdjust->page_size) < 0.2))
4661 {
4662 SetScrollPos( orient, pos, refresh );
4663 return;
4664 }
47d67540 4665
1ecc4d80 4666 m_oldHorizontalPos = fpos;
47d67540 4667
1ecc4d80
RR
4668 m_hAdjust->lower = 0.0;
4669 m_hAdjust->upper = frange;
4670 m_hAdjust->value = fpos;
4671 m_hAdjust->step_increment = 1.0;
4672 m_hAdjust->page_increment = (float)(wxMax(fthumb,0));
4673 m_hAdjust->page_size = fthumb;
cb43b372 4674 }
1ecc4d80
RR
4675 else
4676 {
4677 float fpos = (float)pos;
4678 float frange = (float)range;
4679 float fthumb = (float)thumbVisible;
4680 if (fpos > frange-fthumb) fpos = frange-fthumb;
4681 if (fpos < 0.0) fpos = 0.0;
4682
4683 if ((fabs(frange-m_vAdjust->upper) < 0.2) &&
4684 (fabs(fthumb-m_vAdjust->page_size) < 0.2))
4685 {
4686 SetScrollPos( orient, pos, refresh );
4687 return;
4688 }
47d67540 4689
1ecc4d80 4690 m_oldVerticalPos = fpos;
47d67540 4691
1ecc4d80
RR
4692 m_vAdjust->lower = 0.0;
4693 m_vAdjust->upper = frange;
4694 m_vAdjust->value = fpos;
4695 m_vAdjust->step_increment = 1.0;
4696 m_vAdjust->page_increment = (float)(wxMax(fthumb,0));
4697 m_vAdjust->page_size = fthumb;
4698 }
47d67540 4699
eb082a08
RR
4700 if (orient == wxHORIZONTAL)
4701 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
4702 else
4703 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
362c6693 4704}
c801d85f 4705
1e6feb95 4706void wxWindowGTK::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
c801d85f 4707{
82b978d7 4708 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
1ecc4d80 4709
223d09f6 4710 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
1ecc4d80
RR
4711
4712 if (orient == wxHORIZONTAL)
4713 {
4714 float fpos = (float)pos;
4715 if (fpos > m_hAdjust->upper - m_hAdjust->page_size) fpos = m_hAdjust->upper - m_hAdjust->page_size;
4716 if (fpos < 0.0) fpos = 0.0;
4717 m_oldHorizontalPos = fpos;
4718
4719 if (fabs(fpos-m_hAdjust->value) < 0.2) return;
4720 m_hAdjust->value = fpos;
4721 }
4722 else
4723 {
4724 float fpos = (float)pos;
4725 if (fpos > m_vAdjust->upper - m_vAdjust->page_size) fpos = m_vAdjust->upper - m_vAdjust->page_size;
4726 if (fpos < 0.0) fpos = 0.0;
4727 m_oldVerticalPos = fpos;
ff8bfdbb 4728
1ecc4d80
RR
4729 if (fabs(fpos-m_vAdjust->value) < 0.2) return;
4730 m_vAdjust->value = fpos;
4731 }
47d67540 4732
5b8a521e 4733 if (m_wxwindow->window)
47d67540 4734 {
5b8a521e 4735 if (orient == wxHORIZONTAL)
473d087e
RR
4736 {
4737 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust),
4738 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
2daa0ce9 4739
5b8a521e 4740 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
2daa0ce9 4741
473d087e
RR
4742 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
4743 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
4744 }
5b8a521e 4745 else
473d087e
RR
4746 {
4747 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust),
4748 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
2daa0ce9 4749
5b8a521e 4750 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
473d087e
RR
4751
4752 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
4753 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
4754 }
cb43b372 4755 }
362c6693 4756}
c801d85f 4757
1e6feb95 4758int wxWindowGTK::GetScrollThumb( int orient ) const
c801d85f 4759{
82b978d7
RD
4760 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
4761
223d09f6 4762 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
47d67540 4763
1ecc4d80
RR
4764 if (orient == wxHORIZONTAL)
4765 return (int)(m_hAdjust->page_size+0.5);
4766 else
4767 return (int)(m_vAdjust->page_size+0.5);
362c6693 4768}
c801d85f 4769
1e6feb95 4770int wxWindowGTK::GetScrollPos( int orient ) const
c801d85f 4771{
82b978d7 4772 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
47d67540 4773
223d09f6 4774 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
c801d85f 4775
1ecc4d80
RR
4776 if (orient == wxHORIZONTAL)
4777 return (int)(m_hAdjust->value+0.5);
4778 else
4779 return (int)(m_vAdjust->value+0.5);
362c6693 4780}
c801d85f 4781
1e6feb95 4782int wxWindowGTK::GetScrollRange( int orient ) const
c801d85f 4783{
82b978d7 4784 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
47d67540 4785
223d09f6 4786 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
c801d85f 4787
1ecc4d80
RR
4788 if (orient == wxHORIZONTAL)
4789 return (int)(m_hAdjust->upper+0.5);
4790 else
4791 return (int)(m_vAdjust->upper+0.5);
362c6693 4792}
c801d85f 4793
1e6feb95 4794void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
c801d85f 4795{
82b978d7
RD
4796 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4797
223d09f6 4798 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
2b5f62a0 4799
f47ae6e7 4800 // No scrolling requested.
8e217128 4801 if ((dx == 0) && (dy == 0)) return;
0fc5dbf5 4802
4e5a4c69 4803#ifndef __WXGTK20__
35917d22
RR
4804 if (!m_updateRegion.IsEmpty())
4805 {
4806 m_updateRegion.Offset( dx, dy );
0fc5dbf5 4807
35917d22
RR
4808 int cw = 0;
4809 int ch = 0;
4810 GetClientSize( &cw, &ch );
4811 m_updateRegion.Intersect( 0, 0, cw, ch );
4812 }
0fc5dbf5 4813
3bcc8d15
RR
4814 if (!m_clearRegion.IsEmpty())
4815 {
4816 m_clearRegion.Offset( dx, dy );
0fc5dbf5 4817
3bcc8d15
RR
4818 int cw = 0;
4819 int ch = 0;
4820 GetClientSize( &cw, &ch );
4821 m_clearRegion.Intersect( 0, 0, cw, ch );
4822 }
3fc6e5fa
RR
4823#endif
4824
0a164d4c 4825 m_clipPaintRegion = true;
0fc5dbf5 4826
da048e3d 4827 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
0fc5dbf5 4828
0a164d4c 4829 m_clipPaintRegion = false;
c801d85f 4830}
3723b7b1 4831
4e5a4c69 4832
3723b7b1
JS
4833// Find the wxWindow at the current mouse position, also returning the mouse
4834// position.
4835wxWindow* wxFindWindowAtPointer(wxPoint& pt)
4836{
59a12e90
JS
4837 pt = wxGetMousePosition();
4838 wxWindow* found = wxFindWindowAtPoint(pt);
4839 return found;
3723b7b1
JS
4840}
4841
4842// Get the current mouse position.
4843wxPoint wxGetMousePosition()
4844{
59a12e90
JS
4845 /* This crashes when used within wxHelpContext,
4846 so we have to use the X-specific implementation below.
4847 gint x, y;
4848 GdkModifierType *mask;
4849 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4850
4851 return wxPoint(x, y);
4852 */
4853
3723b7b1
JS
4854 int x, y;
4855 GdkWindow* windowAtPtr = gdk_window_at_pointer(& x, & y);
59a12e90 4856
37d81cc2 4857 Display *display = windowAtPtr ? GDK_WINDOW_XDISPLAY(windowAtPtr) : GDK_DISPLAY();
59a12e90
JS
4858 Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
4859 Window rootReturn, childReturn;
4860 int rootX, rootY, winX, winY;
4861 unsigned int maskReturn;
4862
4863 XQueryPointer (display,
5cd09f0b
RR
4864 rootWindow,
4865 &rootReturn,
59a12e90
JS
4866 &childReturn,
4867 &rootX, &rootY, &winX, &winY, &maskReturn);
4868 return wxPoint(rootX, rootY);
4869
3723b7b1
JS
4870}
4871
4e5a4c69
RR
4872// ----------------------------------------------------------------------------
4873// wxDCModule
4874// ----------------------------------------------------------------------------
4875
4876class wxWinModule : public wxModule
4877{
4878public:
4879 bool OnInit();
4880 void OnExit();
4881
4882private:
4883 DECLARE_DYNAMIC_CLASS(wxWinModule)
4884};
4885
4886IMPLEMENT_DYNAMIC_CLASS(wxWinModule, wxModule)
4887
4888bool wxWinModule::OnInit()
4889{
994bc575
RR
4890 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4891 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
0fc5dbf5 4892
0a164d4c 4893 return true;
4e5a4c69
RR
4894}
4895
4896void wxWinModule::OnExit()
4897{
994bc575
RR
4898 if (g_eraseGC)
4899 gdk_gc_unref( g_eraseGC );
4e5a4c69
RR
4900}
4901
6728fb61 4902// vi:sts=4:sw=4:et