]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/window.cpp
Fix for bug [ 1351659 ] wxTextValidator::Validate not Unicode safe
[wxWidgets.git] / src / gtk / window.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
f6bcfd97 2// Name: gtk/window.cpp
c801d85f
KB
3// Purpose:
4// Author: Robert Roebling
c67d8618 5// Id: $Id$
01111366 6// Copyright: (c) 1998 Robert Roebling, Julian Smart
65571936 7// Licence: wxWindows licence
c801d85f
KB
8/////////////////////////////////////////////////////////////////////////////
9
14f355c2
VS
10// For compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
12
d02af7bb
JJ
13#ifdef __VMS
14#define XWarpPointer XWARPPOINTER
15#endif
16
c801d85f 17#include "wx/window.h"
33611ebb 18#include "wx/dcclient.h"
c801d85f
KB
19#include "wx/frame.h"
20#include "wx/app.h"
21#include "wx/layout.h"
22#include "wx/utils.h"
23#include "wx/dialog.h"
24#include "wx/msgdlg.h"
0fc5dbf5 25#include "wx/module.h"
024e9a4c 26#include "wx/combobox.h"
bfc6fde4 27
06cfab17 28#if wxUSE_DRAG_AND_DROP
bfc6fde4 29 #include "wx/dnd.h"
ac57418f 30#endif
bfc6fde4 31
cad880f5 32#if wxUSE_TOOLTIPS
bfc6fde4 33 #include "wx/tooltip.h"
cad880f5 34#endif
bfc6fde4 35
f6bcfd97
BP
36#if wxUSE_CARET
37 #include "wx/caret.h"
38#endif // wxUSE_CARET
39
ab93a576 40#if wxUSE_TEXTCTRL
0fc5dbf5 41 #include "wx/textctrl.h"
ab93a576
RD
42#endif
43
30dea054 44#include "wx/menu.h"
d4c99d6f 45#include "wx/statusbr.h"
b4071e91 46#include "wx/intl.h"
3bc755fc 47#include "wx/settings.h"
3069ac4e 48#include "wx/log.h"
48d011c8 49#include "wx/fontutil.h"
b4071e91 50
3ac8d3bc
RR
51#ifdef __WXDEBUG__
52 #include "wx/thread.h"
53#endif
54
463c4d71 55#include "wx/math.h"
fab591c5 56#include <ctype.h>
c801d85f 57
9e691f46 58#include "wx/gtk/private.h"
3ac8d3bc
RR
59#include <gdk/gdkprivate.h>
60#include <gdk/gdkkeysyms.h>
3ac8d3bc 61#include <gdk/gdkx.h>
6bc8a1c8 62
8cb9f0d0
RR
63#include <gtk/gtk.h>
64#include <gtk/gtkprivate.h>
65
66#include "wx/gtk/win_gtk.h"
67
2b5f62a0
VZ
68#ifdef __WXGTK20__
69#include <pango/pangox.h>
70#endif
71
9e691f46 72
4e5a4c69
RR
73#ifdef __WXGTK20__
74 #ifdef HAVE_XIM
75 #undef HAVE_XIM
76 #endif
77#endif
78
af1d24da
RR
79#ifdef __WXGTK20__
80extern GtkContainerClass *pizza_parent_class;
81#endif
82
868a2826
RR
83//-----------------------------------------------------------------------------
84// documentation on internals
85//-----------------------------------------------------------------------------
86
87/*
88 I have been asked several times about writing some documentation about
77ffb593 89 the GTK port of wxWidgets, especially its internal structures. Obviously,
868a2826 90 you cannot understand wxGTK without knowing a little about the GTK, but
47d67540 91 some more information about what the wxWindow, which is the base class
868a2826 92 for all other window classes, does seems required as well.
47d67540 93
30760ce7
RR
94 I)
95
868a2826 96 What does wxWindow do? It contains the common interface for the following
e380f72b 97 jobs of its descendants:
47d67540 98
868a2826 99 1) Define the rudimentary behaviour common to all window classes, such as
e380f72b
RR
100 resizing, intercepting user input (so as to make it possible to use these
101 events for special purposes in a derived class), window names etc.
868a2826
RR
102
103 2) Provide the possibility to contain and manage children, if the derived
104 class is allowed to contain children, which holds true for those window
e380f72b 105 classes which do not display a native GTK widget. To name them, these
868a2826 106 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
47d67540 107 work classes are a special case and are handled a bit differently from
e380f72b 108 the rest. The same holds true for the wxNotebook class.
47d67540 109
868a2826
RR
110 3) Provide the possibility to draw into a client area of a window. This,
111 too, only holds true for classes that do not display a native GTK widget
112 as above.
47d67540 113
e380f72b
RR
114 4) Provide the entire mechanism for scrolling widgets. This actual inter-
115 face for this is usually in wxScrolledWindow, but the GTK implementation
868a2826 116 is in this class.
47d67540 117
868a2826
RR
118 5) A multitude of helper or extra methods for special purposes, such as
119 Drag'n'Drop, managing validators etc.
47d67540 120
30760ce7
RR
121 6) Display a border (sunken, raised, simple or none).
122
77ffb593 123 Normally one might expect, that one wxWidgets window would always correspond
e380f72b 124 to one GTK widget. Under GTK, there is no such allround widget that has all
868a2826
RR
125 the functionality. Moreover, the GTK defines a client area as a different
126 widget from the actual widget you are handling. Last but not least some
127 special classes (e.g. wxFrame) handle different categories of widgets and
128 still have the possibility to draw something in the client area.
129 It was therefore required to write a special purpose GTK widget, that would
77ffb593 130 represent a client area in the sense of wxWidgets capable to do the jobs
868a2826
RR
131 2), 3) and 4). I have written this class and it resides in win_gtk.c of
132 this directory.
47d67540 133
868a2826 134 All windows must have a widget, with which they interact with other under-
e380f72b 135 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
90e572f1 136 the 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
90e572f1 176 Singularily the most broken code in GTK is the code that is supposed to
30760ce7
RR
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
90e572f1 183 the disadvantage that windows might get size events before the GTK widget
30760ce7 184 actually has the reported size. This doesn't normally pose any problem, but
90e572f1 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
90e572f1 188 window that is used for OpenGL output really has that size (as reported by
30760ce7
RR
189 GTK).
190
191 IV)
148cd9b6 192
30760ce7 193 If someone at some point of time feels the immense desire to have a look at,
90e572f1
MR
194 change or attempt to optimise the Refresh() logic, this person will need an
195 intimate understanding of what "draw" and "expose" events are and what
196 they are used for, in particular when used in connection with GTK's
30760ce7 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
90e572f1 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 240// hack: we need something to pass to gtk_menu_popup, so we store the time of
defdd888 241// the last click here (extern: used from gtk/menu.cpp)
17a1ebd1 242#ifndef __WXGTK20__
defdd888 243guint32 wxGtkTimeLastClick = 0;
17a1ebd1 244#endif
34adc954 245
3ac8d3bc
RR
246extern bool g_mainThreadLocked;
247
2e563988
RR
248//-----------------------------------------------------------------------------
249// debug
250//-----------------------------------------------------------------------------
251
252#ifdef __WXDEBUG__
253
c6e62f74
KB
254#if wxUSE_THREADS
255# define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
256#else
257# define DEBUG_MAIN_THREAD
258#endif
559d79aa
BJ
259#else
260#define DEBUG_MAIN_THREAD
f03fc89f 261#endif // Debug
ff8bfdbb 262
6cad4f1b
VZ
263// the trace mask used for the focus debugging messages
264#define TRACE_FOCUS _T("focus")
265
85eb36c2
RR
266//-----------------------------------------------------------------------------
267// missing gdk functions
268//-----------------------------------------------------------------------------
269
270void
271gdk_window_warp_pointer (GdkWindow *window,
c50f1fb9
VZ
272 gint x,
273 gint y)
85eb36c2 274{
dd00f3f6 275#ifndef __WXGTK20__
85eb36c2 276 GdkWindowPrivate *priv;
dd00f3f6 277#endif
c50f1fb9 278
85eb36c2 279 if (!window)
27df579a 280 window = GDK_ROOT_PARENT();
c50f1fb9 281
dd00f3f6
OK
282#ifdef __WXGTK20__
283 if (!GDK_WINDOW_DESTROYED(window))
284 {
285 XWarpPointer (GDK_WINDOW_XDISPLAY(window),
286 None, /* not source window -> move from anywhere */
287 GDK_WINDOW_XID(window), /* dest window */
288 0, 0, 0, 0, /* not source window -> move from anywhere */
289 x, y );
290 }
291#else
85eb36c2 292 priv = (GdkWindowPrivate*) window;
c50f1fb9 293
85eb36c2
RR
294 if (!priv->destroyed)
295 {
c50f1fb9 296 XWarpPointer (priv->xdisplay,
85eb36c2 297 None, /* not source window -> move from anywhere */
c50f1fb9 298 priv->xwindow, /* dest window */
85eb36c2 299 0, 0, 0, 0, /* not source window -> move from anywhere */
c50f1fb9 300 x, y );
85eb36c2 301 }
dd00f3f6 302#endif
85eb36c2
RR
303}
304
acfd422a 305//-----------------------------------------------------------------------------
a2053b27 306// idle system
acfd422a
RR
307//-----------------------------------------------------------------------------
308
a2053b27
RR
309extern void wxapp_install_idle_handler();
310extern bool g_isIdle;
311
ed673c6a
RR
312//-----------------------------------------------------------------------------
313// local code (see below)
314//-----------------------------------------------------------------------------
315
f6bcfd97 316// returns the child of win which currently has focus or NULL if not found
1e6feb95 317//
fc71ef6e 318// Note: can't be static, needed by textctrl.cpp.
3379ed37 319wxWindow *wxFindFocusedChild(wxWindowGTK *win)
f6bcfd97 320{
3379ed37 321 wxWindow *winFocus = wxWindowGTK::FindFocus();
f6bcfd97 322 if ( !winFocus )
3379ed37 323 return (wxWindow *)NULL;
f6bcfd97
BP
324
325 if ( winFocus == win )
3379ed37 326 return (wxWindow *)win;
f6bcfd97 327
222ed1d6 328 for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
f6bcfd97
BP
329 node;
330 node = node->GetNext() )
331 {
3379ed37 332 wxWindow *child = wxFindFocusedChild(node->GetData());
f6bcfd97
BP
333 if ( child )
334 return child;
335 }
336
3379ed37 337 return (wxWindow *)NULL;
f6bcfd97
BP
338}
339
1e6feb95 340static void draw_frame( GtkWidget *widget, wxWindowGTK *win )
ed673c6a 341{
1e6feb95
VZ
342 // wxUniversal widgets draw the borders and scrollbars themselves
343#ifndef __WXUNIVERSAL__
ed673c6a
RR
344 if (!win->m_hasVMT)
345 return;
346
347 int dw = 0;
348 int dh = 0;
349
5b8a521e 350 if (win->m_hasScrolling)
ed673c6a 351 {
beab25bd 352 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(widget);
2daa0ce9 353
beab25bd
RR
354 GtkRequisition vscroll_req;
355 vscroll_req.width = 2;
356 vscroll_req.height = 2;
357 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
358 (scroll_window->vscrollbar, &vscroll_req );
2daa0ce9 359
beab25bd
RR
360 GtkRequisition hscroll_req;
361 hscroll_req.width = 2;
362 hscroll_req.height = 2;
363 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
364 (scroll_window->hscrollbar, &hscroll_req );
9000c624 365
beab25bd 366 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget) );
ed673c6a 367
beab25bd
RR
368 if (scroll_window->vscrollbar_visible)
369 {
370 dw += vscroll_req.width;
371 dw += scroll_class->scrollbar_spacing;
372 }
ed673c6a 373
beab25bd
RR
374 if (scroll_window->hscrollbar_visible)
375 {
376 dh += hscroll_req.height;
377 dh += scroll_class->scrollbar_spacing;
378 }
865bb325 379 }
ed673c6a
RR
380
381 int dx = 0;
382 int dy = 0;
383 if (GTK_WIDGET_NO_WINDOW (widget))
384 {
385 dx += widget->allocation.x;
386 dy += widget->allocation.y;
387 }
388
389 if (win->HasFlag(wxRAISED_BORDER))
390 {
391 gtk_draw_shadow( widget->style,
392 widget->window,
393 GTK_STATE_NORMAL,
394 GTK_SHADOW_OUT,
395 dx, dy,
07f5b19a 396 widget->allocation.width-dw, widget->allocation.height-dh );
ed673c6a
RR
397 return;
398 }
399
400 if (win->HasFlag(wxSUNKEN_BORDER))
401 {
402 gtk_draw_shadow( widget->style,
403 widget->window,
404 GTK_STATE_NORMAL,
405 GTK_SHADOW_IN,
406 dx, dy,
07f5b19a 407 widget->allocation.width-dw, widget->allocation.height-dh );
ed673c6a
RR
408 return;
409 }
148cd9b6 410
ed673c6a
RR
411 if (win->HasFlag(wxSIMPLE_BORDER))
412 {
413 GdkGC *gc;
b02da6b1 414 gc = gdk_gc_new( widget->window );
ed673c6a 415 gdk_gc_set_foreground( gc, &widget->style->black );
148cd9b6 416 gdk_draw_rectangle( widget->window, gc, FALSE,
ed673c6a 417 dx, dy,
07f5b19a 418 widget->allocation.width-dw-1, widget->allocation.height-dh-1 );
ed673c6a
RR
419 gdk_gc_unref( gc );
420 return;
421 }
1e6feb95 422#endif // __WXUNIVERSAL__
ed673c6a
RR
423}
424
425//-----------------------------------------------------------------------------
426// "expose_event" of m_widget
427//-----------------------------------------------------------------------------
428
865bb325
VZ
429extern "C" {
430static gint gtk_window_own_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindowGTK *win )
ed673c6a 431{
b6fa52db 432 if (gdk_event->count > 0) return FALSE;
1e6feb95 433
ed673c6a 434 draw_frame( widget, win );
1e6feb95 435
af1d24da
RR
436#ifdef __WXGTK20__
437
438 (* GTK_WIDGET_CLASS (pizza_parent_class)->expose_event) (widget, gdk_event);
0fc5dbf5
VZ
439
440#endif
b6fa52db 441 return TRUE;
ed673c6a 442}
865bb325 443}
ed673c6a
RR
444
445//-----------------------------------------------------------------------------
147bc491 446// "draw" of m_widget
ed673c6a
RR
447//-----------------------------------------------------------------------------
448
67d78217
RR
449#ifndef __WXGTK20__
450
865bb325 451extern "C" {
1e6feb95 452static void gtk_window_own_draw_callback( GtkWidget *widget, GdkRectangle *WXUNUSED(rect), wxWindowGTK *win )
ed673c6a
RR
453{
454 draw_frame( widget, win );
455}
865bb325 456}
ed673c6a 457
1c6896d7 458#endif // GTK+ < 2.0
c5b42c87 459
47c93b63
RR
460//-----------------------------------------------------------------------------
461// "size_request" of m_widget
462//-----------------------------------------------------------------------------
463
865bb325
VZ
464// make it extern because wxStaticText needs to disconnect this one
465extern "C" {
e1f448ee
VZ
466void wxgtk_window_size_request_callback(GtkWidget *widget,
467 GtkRequisition *requisition,
468 wxWindow *win)
47c93b63 469{
e1f448ee 470 int w, h;
47c93b63 471 win->GetSize( &w, &h );
e1f448ee
VZ
472 if (w < 2)
473 w = 2;
474 if (h < 2)
475 h = 2;
1e6feb95 476
47c93b63
RR
477 requisition->height = h;
478 requisition->width = w;
479}
865bb325 480}
47c93b63 481
865bb325
VZ
482extern "C" {
483static
024e9a4c
RR
484void wxgtk_combo_size_request_callback(GtkWidget *widget,
485 GtkRequisition *requisition,
486 wxComboBox *win)
487{
488 // This callback is actually hooked into the text entry
489 // of the combo box, not the GtkHBox.
0a164d4c 490
024e9a4c
RR
491 int w, h;
492 win->GetSize( &w, &h );
493 if (w < 2)
494 w = 2;
495 if (h < 2)
496 h = 2;
497
498 GtkCombo *gcombo = GTK_COMBO(win->m_widget);
0a164d4c 499
024e9a4c
RR
500 GtkRequisition entry_req;
501 entry_req.width = 2;
502 entry_req.height = 2;
503 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo->button) )->size_request )
504 (gcombo->button, &entry_req );
0a164d4c 505
024e9a4c 506 requisition->width = w - entry_req.width;
bfeb1e58 507 requisition->height = entry_req.height;
024e9a4c 508}
865bb325 509}
024e9a4c 510
c801d85f 511//-----------------------------------------------------------------------------
034be888 512// "expose_event" of m_wxwindow
c801d85f
KB
513//-----------------------------------------------------------------------------
514
865bb325 515extern "C" {
1e6feb95
VZ
516static int gtk_window_expose_callback( GtkWidget *widget,
517 GdkEventExpose *gdk_event,
518 wxWindow *win )
47d67540 519{
3ac8d3bc
RR
520 DEBUG_MAIN_THREAD
521
b6fa52db
RR
522 if (g_isIdle)
523 wxapp_install_idle_handler();
1e6feb95 524
3fc6e5fa
RR
525#ifdef __WXGTK20__
526 // This callback gets called in drawing-idle time under
527 // GTK 2.0, so we don't need to defer anything to idle
528 // time anymore.
2b5f62a0 529
3fc6e5fa
RR
530 GtkPizza *pizza = GTK_PIZZA( widget );
531 if (gdk_event->window != pizza->bin_window) return FALSE;
2b5f62a0 532
9abbd4a0 533#if 0
d7fa7eaa 534 if (win->GetName())
3d2d8da1
RR
535 {
536 wxPrintf( wxT("OnExpose from ") );
537 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
538 wxPrintf( win->GetClassInfo()->GetClassName() );
539 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event->area.x,
540 (int)gdk_event->area.y,
541 (int)gdk_event->area.width,
542 (int)gdk_event->area.height );
543 }
0a164d4c 544
a1696b86
RR
545 gtk_paint_box
546 (
547 win->m_wxwindow->style,
548 pizza->bin_window,
549 GTK_STATE_NORMAL,
550 GTK_SHADOW_OUT,
551 (GdkRectangle*) NULL,
552 win->m_wxwindow,
553 (char *)"button", // const_cast
554 20,20,24,24
555 );
d7fa7eaa 556#endif
1e6feb95 557
b15ed747
RR
558 win->GetUpdateRegion() = wxRegion( gdk_event->region );
559
560 win->GtkSendPaintEvents();
561
2b5f62a0 562
90e572f1 563 // Let parent window draw window-less widgets
b15ed747
RR
564 (* GTK_WIDGET_CLASS (pizza_parent_class)->expose_event) (widget, gdk_event);
565#else
566 // This gets called immediately after an expose event
567 // under GTK 1.2 so we collect the calls and wait for
568 // the idle handler to pick things up.
2b5f62a0 569
2bc6945a
RR
570 win->GetUpdateRegion().Union( gdk_event->area.x,
571 gdk_event->area.y,
572 gdk_event->area.width,
573 gdk_event->area.height );
d665f50b
JS
574 win->m_clearRegion.Union( gdk_event->area.x,
575 gdk_event->area.y,
576 gdk_event->area.width,
577 gdk_event->area.height );
0e09f76e 578
8f3e7ecc 579 // Actual redrawing takes place in idle time.
62cb3cd8 580 // win->GtkUpdate();
0fc5dbf5 581#endif
f7a11f8c 582
3fc6e5fa 583 return FALSE;
b6fa52db 584}
865bb325 585}
b6fa52db
RR
586
587//-----------------------------------------------------------------------------
588// "event" of m_wxwindow
589//-----------------------------------------------------------------------------
590
28fad9e4
VZ
591#ifndef __WXGTK20__
592
beab25bd
RR
593// GTK thinks it is clever and filters out a certain amount of "unneeded"
594// expose events. We need them, of course, so we override the main event
595// procedure in GtkWidget by giving our own handler for all system events.
596// There, we look for expose events ourselves whereas all other events are
597// handled normally.
b6fa52db 598
865bb325
VZ
599extern "C" {
600static
1e6feb95
VZ
601gint gtk_window_event_event_callback( GtkWidget *widget,
602 GdkEventExpose *event,
603 wxWindow *win )
b6fa52db
RR
604{
605 if (event->type == GDK_EXPOSE)
606 {
607 gint ret = gtk_window_expose_callback( widget, event, win );
608 return ret;
609 }
610
b6fa52db 611 return FALSE;
362c6693 612}
865bb325 613}
c801d85f 614
28fad9e4
VZ
615#endif // !GTK+ 2
616
c801d85f 617//-----------------------------------------------------------------------------
034be888 618// "draw" of m_wxwindow
2f2aa628 619//-----------------------------------------------------------------------------
c801d85f 620
67d78217
RR
621#ifndef __WXGTK20__
622
beab25bd 623// This callback is a complete replacement of the gtk_pizza_draw() function,
67d78217 624// which is disabled.
b6fa52db 625
865bb325 626extern "C" {
1e6feb95
VZ
627static void gtk_window_draw_callback( GtkWidget *widget,
628 GdkRectangle *rect,
629 wxWindow *win )
47d67540 630{
3ac8d3bc
RR
631 DEBUG_MAIN_THREAD
632
c50f1fb9 633 if (g_isIdle)
a2053b27 634 wxapp_install_idle_handler();
2d19ad25 635
e441e1f4
VZ
636 // if there are any children we must refresh everything
637 //
638 // VZ: why?
639 if ( !win->HasFlag(wxFULL_REPAINT_ON_RESIZE) &&
640 win->GetChildren().IsEmpty() )
e22454be
RR
641 {
642 return;
643 }
2d19ad25 644
d7fa7eaa
RR
645#if 0
646 if (win->GetName())
3d2d8da1
RR
647 {
648 wxPrintf( wxT("OnDraw from ") );
649 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
650 wxPrintf( win->GetClassInfo()->GetClassName() );
651 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect->x,
652 (int)rect->y,
653 (int)rect->width,
654 (int)rect->height );
655 }
d7fa7eaa 656#endif
1e6feb95 657
2e09dc2d 658#ifndef __WXUNIVERSAL__
b420fb6a 659 GtkPizza *pizza = GTK_PIZZA (widget);
2bc6945a 660
de434621 661 if (win->GetThemeEnabled() && win->GetBackgroundStyle() == wxBG_STYLE_SYSTEM)
789dbcd4 662 {
9cc7121f
RR
663 wxWindow *parent = win->GetParent();
664 while (parent && !parent->IsTopLevel())
789dbcd4 665 parent = parent->GetParent();
9cc7121f
RR
666 if (!parent)
667 parent = win;
668
90350682
VZ
669 gtk_paint_flat_box (parent->m_widget->style,
670 pizza->bin_window,
671 GTK_STATE_NORMAL,
672 GTK_SHADOW_NONE,
673 rect,
674 parent->m_widget,
675 (char *)"base",
676 0, 0, -1, -1);
789dbcd4 677 }
2e09dc2d 678#endif
1e6feb95 679
62cb3cd8 680 win->m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height );
9cc7121f 681 win->GetUpdateRegion().Union( rect->x, rect->y, rect->width, rect->height );
148cd9b6 682
62cb3cd8 683 // Update immediately, not in idle time.
010afced 684 win->GtkUpdate();
1e6feb95 685
8f3e7ecc 686#ifndef __WXUNIVERSAL__
beab25bd 687 // Redraw child widgets
e22454be
RR
688 GList *children = pizza->children;
689 while (children)
690 {
beab25bd
RR
691 GtkPizzaChild *child = (GtkPizzaChild*) children->data;
692 children = children->next;
b420fb6a 693
beab25bd
RR
694 GdkRectangle child_area;
695 if (gtk_widget_intersect (child->widget, rect, &child_area))
696 {
697 gtk_widget_draw (child->widget, &child_area /* (GdkRectangle*) NULL*/ );
698 }
e22454be 699 }
8f3e7ecc 700#endif
362c6693 701}
865bb325 702}
c801d85f 703
67d78217
RR
704#endif
705
c801d85f 706//-----------------------------------------------------------------------------
b292e2f5 707// "key_press_event" from any window
c801d85f 708//-----------------------------------------------------------------------------
c801d85f 709
74710601
VZ
710// set WXTRACE to this to see the key event codes on the console
711#define TRACE_KEYS _T("keyevent")
f17393f1 712
1c6896d7
VZ
713// translates an X key symbol to WXK_XXX value
714//
715// if isChar is true it means that the value returned will be used for EVT_CHAR
716// event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
717// for example, while if it is false it means that the value is going to be
718// used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
719// WXK_NUMPAD_DIVIDE
720static long wxTranslateKeySymToWXKey(KeySym keysym, bool isChar)
721{
722 long key_code;
723
724 switch ( keysym )
725 {
726 // Shift, Control and Alt don't generate the CHAR events at all
727 case GDK_Shift_L:
728 case GDK_Shift_R:
729 key_code = isChar ? 0 : WXK_SHIFT;
730 break;
731 case GDK_Control_L:
732 case GDK_Control_R:
733 key_code = isChar ? 0 : WXK_CONTROL;
734 break;
735 case GDK_Meta_L:
736 case GDK_Meta_R:
737 case GDK_Alt_L:
738 case GDK_Alt_R:
739 case GDK_Super_L:
740 case GDK_Super_R:
741 key_code = isChar ? 0 : WXK_ALT;
742 break;
743
744 // neither do the toggle modifies
745 case GDK_Scroll_Lock:
746 key_code = isChar ? 0 : WXK_SCROLL;
747 break;
748
749 case GDK_Caps_Lock:
750 key_code = isChar ? 0 : WXK_CAPITAL;
751 break;
752
753 case GDK_Num_Lock:
754 key_code = isChar ? 0 : WXK_NUMLOCK;
755 break;
756
757
758 // various other special keys
759 case GDK_Menu:
760 key_code = WXK_MENU;
761 break;
762
763 case GDK_Help:
764 key_code = WXK_HELP;
765 break;
766
767 case GDK_BackSpace:
768 key_code = WXK_BACK;
769 break;
770
771 case GDK_ISO_Left_Tab:
772 case GDK_Tab:
773 key_code = WXK_TAB;
774 break;
775
776 case GDK_Linefeed:
777 case GDK_Return:
778 key_code = WXK_RETURN;
779 break;
780
781 case GDK_Clear:
782 key_code = WXK_CLEAR;
783 break;
784
785 case GDK_Pause:
786 key_code = WXK_PAUSE;
787 break;
788
789 case GDK_Select:
790 key_code = WXK_SELECT;
791 break;
792
793 case GDK_Print:
794 key_code = WXK_PRINT;
795 break;
796
797 case GDK_Execute:
798 key_code = WXK_EXECUTE;
799 break;
800
801 case GDK_Escape:
802 key_code = WXK_ESCAPE;
803 break;
804
805 // cursor and other extended keyboard keys
806 case GDK_Delete:
807 key_code = WXK_DELETE;
808 break;
809
810 case GDK_Home:
811 key_code = WXK_HOME;
812 break;
813
814 case GDK_Left:
815 key_code = WXK_LEFT;
816 break;
817
818 case GDK_Up:
819 key_code = WXK_UP;
820 break;
821
822 case GDK_Right:
823 key_code = WXK_RIGHT;
824 break;
825
826 case GDK_Down:
827 key_code = WXK_DOWN;
828 break;
829
830 case GDK_Prior: // == GDK_Page_Up
831 key_code = WXK_PRIOR;
832 break;
833
834 case GDK_Next: // == GDK_Page_Down
835 key_code = WXK_NEXT;
836 break;
837
838 case GDK_End:
839 key_code = WXK_END;
840 break;
841
842 case GDK_Begin:
843 key_code = WXK_HOME;
844 break;
845
846 case GDK_Insert:
847 key_code = WXK_INSERT;
848 break;
849
850
851 // numpad keys
852 case GDK_KP_0:
853 case GDK_KP_1:
854 case GDK_KP_2:
855 case GDK_KP_3:
856 case GDK_KP_4:
857 case GDK_KP_5:
858 case GDK_KP_6:
859 case GDK_KP_7:
860 case GDK_KP_8:
861 case GDK_KP_9:
862 key_code = (isChar ? '0' : WXK_NUMPAD0) + keysym - GDK_KP_0;
863 break;
864
865 case GDK_KP_Space:
866 key_code = isChar ? ' ' : WXK_NUMPAD_SPACE;
867 break;
868
869 case GDK_KP_Tab:
870 key_code = isChar ? WXK_TAB : WXK_NUMPAD_TAB;
871 break;
872
873 case GDK_KP_Enter:
874 key_code = isChar ? WXK_RETURN : WXK_NUMPAD_ENTER;
875 break;
876
877 case GDK_KP_F1:
878 key_code = isChar ? WXK_F1 : WXK_NUMPAD_F1;
879 break;
880
881 case GDK_KP_F2:
882 key_code = isChar ? WXK_F2 : WXK_NUMPAD_F2;
883 break;
884
885 case GDK_KP_F3:
886 key_code = isChar ? WXK_F3 : WXK_NUMPAD_F3;
887 break;
888
889 case GDK_KP_F4:
890 key_code = isChar ? WXK_F4 : WXK_NUMPAD_F4;
891 break;
892
893 case GDK_KP_Home:
894 key_code = isChar ? WXK_HOME : WXK_NUMPAD_HOME;
895 break;
896
897 case GDK_KP_Left:
898 key_code = isChar ? WXK_LEFT : WXK_NUMPAD_LEFT;
899 break;
900
901 case GDK_KP_Up:
902 key_code = isChar ? WXK_UP : WXK_NUMPAD_UP;
903 break;
904
905 case GDK_KP_Right:
906 key_code = isChar ? WXK_RIGHT : WXK_NUMPAD_RIGHT;
907 break;
908
909 case GDK_KP_Down:
910 key_code = isChar ? WXK_DOWN : WXK_NUMPAD_DOWN;
911 break;
912
913 case GDK_KP_Prior: // == GDK_KP_Page_Up
914 key_code = isChar ? WXK_PRIOR : WXK_NUMPAD_PRIOR;
915 break;
916
917 case GDK_KP_Next: // == GDK_KP_Page_Down
918 key_code = isChar ? WXK_NEXT : WXK_NUMPAD_NEXT;
919 break;
920
921 case GDK_KP_End:
922 key_code = isChar ? WXK_END : WXK_NUMPAD_END;
923 break;
924
925 case GDK_KP_Begin:
926 key_code = isChar ? WXK_HOME : WXK_NUMPAD_BEGIN;
927 break;
928
929 case GDK_KP_Insert:
930 key_code = isChar ? WXK_INSERT : WXK_NUMPAD_INSERT;
931 break;
932
933 case GDK_KP_Delete:
934 key_code = isChar ? WXK_DELETE : WXK_NUMPAD_DELETE;
935 break;
936
937 case GDK_KP_Equal:
938 key_code = isChar ? '=' : WXK_NUMPAD_EQUAL;
939 break;
940
941 case GDK_KP_Multiply:
942 key_code = isChar ? '*' : WXK_NUMPAD_MULTIPLY;
943 break;
944
945 case GDK_KP_Add:
946 key_code = isChar ? '+' : WXK_NUMPAD_ADD;
947 break;
948
949 case GDK_KP_Separator:
950 // FIXME: what is this?
951 key_code = isChar ? '.' : WXK_NUMPAD_SEPARATOR;
952 break;
953
954 case GDK_KP_Subtract:
955 key_code = isChar ? '-' : WXK_NUMPAD_SUBTRACT;
956 break;
957
958 case GDK_KP_Decimal:
959 key_code = isChar ? '.' : WXK_NUMPAD_DECIMAL;
960 break;
961
962 case GDK_KP_Divide:
963 key_code = isChar ? '/' : WXK_NUMPAD_DIVIDE;
964 break;
965
966
967 // function keys
968 case GDK_F1:
969 case GDK_F2:
970 case GDK_F3:
971 case GDK_F4:
972 case GDK_F5:
973 case GDK_F6:
974 case GDK_F7:
975 case GDK_F8:
976 case GDK_F9:
977 case GDK_F10:
978 case GDK_F11:
979 case GDK_F12:
980 key_code = WXK_F1 + keysym - GDK_F1;
981 break;
982
983 default:
984 key_code = 0;
985 }
986
987 return key_code;
988}
989
990static inline bool wxIsAsciiKeysym(KeySym ks)
991{
992 return ks < 256;
993}
994
a3c15d89
VS
995static void wxFillOtherKeyEventFields(wxKeyEvent& event,
996 wxWindowGTK *win,
997 GdkEventKey *gdk_event)
998{
999 int x = 0;
1000 int y = 0;
1001 GdkModifierType state;
1002 if (gdk_event->window)
1003 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
1004
1005 event.SetTimestamp( gdk_event->time );
cfa8c7d6 1006 event.SetId(win->GetId());
a3c15d89
VS
1007 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK) != 0;
1008 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK) != 0;
1009 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK) != 0;
1010 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK) != 0;
1011 event.m_scanCode = gdk_event->keyval;
1012 event.m_rawCode = (wxUint32) gdk_event->keyval;
1013 event.m_rawFlags = 0;
c4d25c01
VS
1014#if wxUSE_UNICODE
1015 event.m_uniChar = gdk_keyval_to_unicode(gdk_event->keyval);
1016#endif
c958d025
RR
1017 wxGetMousePosition( &x, &y );
1018 win->ScreenToClient( &x, &y );
a3c15d89
VS
1019 event.m_x = x;
1020 event.m_y = y;
1021 event.SetEventObject( win );
1022}
1023
1024
74710601
VZ
1025static bool
1026wxTranslateGTKKeyEventToWx(wxKeyEvent& event,
1027 wxWindowGTK *win,
1028 GdkEventKey *gdk_event)
47d67540 1029{
1c6896d7
VZ
1030 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
1031 // but only event->keyval which is quite useless to us, so remember
1032 // the last character from GDK_KEY_PRESS and reuse it as last resort
1033 //
1034 // NB: should be MT-safe as we're always called from the main thread only
1035 static struct
1036 {
1037 KeySym keysym;
1038 long keycode;
1039 } s_lastKeyPress = { 0, 0 };
1040
1041 KeySym keysym = gdk_event->keyval;
0a62b197 1042
ada7d2c0 1043 wxLogTrace(TRACE_KEYS, _T("Key %s event: keysym = %ld"),
0a62b197
VZ
1044 event.GetEventType() == wxEVT_KEY_UP ? _T("release")
1045 : _T("press"),
1046 keysym);
1047
0a164d4c 1048 long key_code = wxTranslateKeySymToWXKey(keysym, false /* !isChar */);
1c6896d7
VZ
1049
1050 if ( !key_code )
1051 {
1052 // do we have the translation or is it a plain ASCII character?
1053 if ( (gdk_event->length == 1) || wxIsAsciiKeysym(keysym) )
1054 {
1055 // we should use keysym if it is ASCII as X does some translations
1056 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
1057 // which we don't want here (but which we do use for OnChar())
1058 if ( !wxIsAsciiKeysym(keysym) )
1059 {
1060 keysym = (KeySym)gdk_event->string[0];
1061 }
a2053b27 1062
1c6896d7 1063 // we want to always get the same key code when the same key is
90e572f1 1064 // pressed regardless of the state of the modifiers, i.e. on a
1c6896d7
VZ
1065 // standard US keyboard pressing '5' or '%' ('5' key with
1066 // Shift) should result in the same key code in OnKeyDown():
1067 // '5' (although OnChar() will get either '5' or '%').
1068 //
1069 // to do it we first translate keysym to keycode (== scan code)
1070 // and then back but always using the lower register
1071 Display *dpy = (Display *)wxGetDisplay();
1072 KeyCode keycode = XKeysymToKeycode(dpy, keysym);
0a62b197
VZ
1073
1074 wxLogTrace(TRACE_KEYS, _T("\t-> keycode %d"), keycode);
1075
1c6896d7
VZ
1076 KeySym keysymNormalized = XKeycodeToKeysym(dpy, keycode, 0);
1077
1078 // use the normalized, i.e. lower register, keysym if we've
1079 // got one
1080 key_code = keysymNormalized ? keysymNormalized : keysym;
1081
1082 // as explained above, we want to have lower register key codes
1083 // normally but for the letter keys we want to have the upper ones
1084 //
1085 // NB: don't use XConvertCase() here, we want to do it for letters
1086 // only
1087 key_code = toupper(key_code);
1088 }
1089 else // non ASCII key, what to do?
1090 {
1091 // by default, ignore it
1092 key_code = 0;
1093
1094 // but if we have cached information from the last KEY_PRESS
1095 if ( gdk_event->type == GDK_KEY_RELEASE )
1096 {
1097 // then reuse it
1098 if ( keysym == s_lastKeyPress.keysym )
1099 {
1100 key_code = s_lastKeyPress.keycode;
1101 }
1102 }
1103 }
1104
1105 if ( gdk_event->type == GDK_KEY_PRESS )
1106 {
1107 // remember it to be reused for KEY_UP event later
1108 s_lastKeyPress.keysym = keysym;
1109 s_lastKeyPress.keycode = key_code;
1110 }
1111 }
1112
ada7d2c0 1113 wxLogTrace(TRACE_KEYS, _T("\t-> wxKeyCode %ld"), key_code);
c801d85f 1114
74710601 1115 // sending unknown key events doesn't really make sense
1c6896d7 1116 if ( !key_code )
0a164d4c 1117 return false;
3d6f7261 1118
1c6896d7 1119 // now fill all the other fields
a3c15d89 1120 wxFillOtherKeyEventFields(event, win, gdk_event);
0a164d4c 1121
f5e27805 1122 event.m_keyCode = key_code;
74710601 1123
0a164d4c 1124 return true;
74710601
VZ
1125}
1126
7c5e6fc6 1127
a3c15d89
VS
1128#ifdef __WXGTK20__
1129struct wxGtkIMData
1130{
1131 GtkIMContext *context;
1132 GdkEventKey *lastKeyEvent;
1133
1134 wxGtkIMData()
1135 {
1136 context = gtk_im_multicontext_new();
1137 lastKeyEvent = NULL;
1138 }
1139 ~wxGtkIMData()
1140 {
1141 g_object_unref(context);
1142 }
1143};
1144#endif
1145
865bb325 1146extern "C" {
74710601
VZ
1147static gint gtk_window_key_press_callback( GtkWidget *widget,
1148 GdkEventKey *gdk_event,
1149 wxWindow *win )
1150{
1151 DEBUG_MAIN_THREAD
1152
1153 if (g_isIdle)
1154 wxapp_install_idle_handler();
1155
1c6896d7
VZ
1156 if (!win->m_hasVMT)
1157 return FALSE;
1158 if (g_blockEventsOnDrag)
1159 return FALSE;
f1272160
RR
1160
1161
1162 wxKeyEvent event( wxEVT_KEY_DOWN );
1163 bool ret = false;
1164 bool return_after_IM = false;
1165
25f182c1 1166 if( wxTranslateGTKKeyEventToWx(event, win, gdk_event) == false )
f1272160
RR
1167 {
1168 // Return after IM processing as we cannot do
1169 // anything with it anyhow.
1170 return_after_IM = true;
1171 }
1172
36025bcc 1173#ifdef __WXGTK20__
fdfb8475 1174 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
f1272160 1175 // When we get a key_press event here, it could be originate
f6fca1f8 1176 // from the current widget or its child widgets. However, only the widget
0a164d4c 1177 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
f6fca1f8
RR
1178 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
1179 // originated from its child widgets and shouldn't be passed to IM context.
1180 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
1181 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
0a164d4c 1182 // widgets has both IM context and input focus, the event should be filtered
f6fca1f8
RR
1183 // by gtk_im_context_filter_keypress().
1184 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
f1272160 1185 if ((!ret) && (win->m_imData != NULL) && ( wxWindow::FindFocus() == win ))
f6fca1f8 1186 {
f1272160
RR
1187 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1188 // docs, if IM filter returns true, no further processing should be done.
0a164d4c 1189 // we should send the key_down event anyway.
f1272160 1190 bool intercepted_by_IM = gtk_im_context_filter_keypress(win->m_imData->context, gdk_event);
f6fca1f8 1191 win->m_imData->lastKeyEvent = NULL;
f1272160
RR
1192 if (intercepted_by_IM)
1193 {
f6fca1f8 1194 wxLogTrace(TRACE_KEYS, _T("Key event intercepted by IM"));
f1272160
RR
1195 return true;
1196 }
f6fca1f8 1197 }
a3c15d89 1198#endif
f1272160 1199 if (return_after_IM)
19874feb 1200 return false;
25f182c1
JS
1201
1202 // Emit KEY_DOWN event
1203 ret = win->GetEventHandler()->ProcessEvent( event );
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
90e572f1 1236 // Implement OnCharHook by checking ancestor 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
90e572f1 1314 // Implement OnCharHook by checking ancestor top level windows
36025bcc
VS
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)) &&
90e572f1 1339// VZ: testing for wxTE_PROCESS_TAB shouldn't be done here - the control may
f6bcfd97
BP
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 {
17a1ebd1
VZ
1391 wxCommandEvent eventClick(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL);
1392 eventClick.SetEventObject(btnCancel);
1393 ret = btnCancel->GetEventHandler()->ProcessEvent(eventClick);
6ce16bdb 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 {
90e572f1 1489 // unknown key pressed, ignore (the event would be useless anyhow)
74710601 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
90e572f1 1676 // GDK sends surplus button down events
2b5f62a0
VZ
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
90e572f1 1792 // wxListBox actually gets mouse events from the item, so we need to give it
3ae4c570
VZ
1793 // a chance to correct this
1794 win->FixUpMouseEvent(widget, event.m_x, event.m_y);
2daa0ce9 1795
90e572f1
MR
1796 // find the correct window to send the event to: it may be a different one
1797 // from the one which got it at GTK+ level because some controls don't have
d1f2ac45
VZ
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
17a1ebd1 1802#ifndef __WXGTK20__
defdd888 1803 wxGtkTimeLastClick = gdk_event->time;
34adc954 1804
df135f2b
RR
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 }
17a1ebd1 1816#endif // !__WXGTK20__
df135f2b 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
17a1ebd1
VZ
1961 wxMouseEvent eventM(g_captureWindowHasMouse ? wxEVT_ENTER_WINDOW
1962 : wxEVT_LEAVE_WINDOW);
1963 InitMouseEvent(win, eventM, gdk_event);
1964 eventM.SetEventObject(win);
1965 win->GetEventHandler()->ProcessEvent(eventM);
1e6feb95
VZ
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
7dd40b6f
RD
2673
2674wxMouseState wxGetMouseState()
2675{
2676 wxMouseState ms;
2677
2678 gint x;
2679 gint y;
2680 GdkModifierType mask;
2681
2682 gdk_window_get_pointer(NULL, &x, &y, &mask);
2683
2684 ms.SetX(x);
2685 ms.SetY(y);
2686 ms.SetLeftDown(mask & GDK_BUTTON1_MASK);
2687 ms.SetMiddleDown(mask & GDK_BUTTON2_MASK);
2688 ms.SetRightDown(mask & GDK_BUTTON3_MASK);
2689
2690 ms.SetControlDown(mask & GDK_CONTROL_MASK);
2691 ms.SetShiftDown(mask & GDK_SHIFT_MASK);
2692 ms.SetAltDown(mask & GDK_MOD1_MASK);
2693 ms.SetMetaDown(mask & GDK_MOD2_MASK);
3d257b8d 2694
7dd40b6f
RD
2695 return ms;
2696}
3d257b8d 2697
c801d85f 2698//-----------------------------------------------------------------------------
1e6feb95 2699// wxWindowGTK
c801d85f
KB
2700//-----------------------------------------------------------------------------
2701
6522713c
VZ
2702// in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2703// method
1e6feb95 2704#ifdef __WXUNIVERSAL__
6522713c
VZ
2705 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK, wxWindowBase)
2706#else // __WXGTK__
1e6feb95 2707 IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
6522713c 2708#endif // __WXUNIVERSAL__/__WXGTK__
c801d85f 2709
1e6feb95 2710void wxWindowGTK::Init()
c801d85f 2711{
f03fc89f 2712 // GTK specific
a2053b27 2713 m_widget = (GtkWidget *) NULL;
e380f72b 2714 m_wxwindow = (GtkWidget *) NULL;
76fcf0f2 2715 m_focusWidget = (GtkWidget *) NULL;
8bbe427f 2716
f03fc89f 2717 // position/size
a2053b27
RR
2718 m_x = 0;
2719 m_y = 0;
2720 m_width = 0;
e380f72b 2721 m_height = 0;
8bbe427f 2722
0a164d4c
WS
2723 m_sizeSet = false;
2724 m_hasVMT = false;
2725 m_needParent = true;
2726 m_isBeingDeleted = false;
148cd9b6 2727
0a164d4c
WS
2728 m_noExpose = false;
2729 m_nativeSizeEvent = false;
94633ad9 2730
0a164d4c
WS
2731 m_hasScrolling = false;
2732 m_isScrolling = false;
f03fc89f 2733
a2053b27 2734 m_hAdjust = (GtkAdjustment*) NULL;
e380f72b 2735 m_vAdjust = (GtkAdjustment*) NULL;
815ac4a7 2736 m_oldHorizontalPos =
e380f72b 2737 m_oldVerticalPos = 0.0;
815ac4a7
VZ
2738 m_oldClientWidth =
2739 m_oldClientHeight = 0;
8bbe427f 2740
0a164d4c 2741 m_resizing = false;
8bbe427f 2742
ddb6bc71 2743 m_insertCallback = (wxInsertChildFunction) NULL;
8bbe427f 2744
0a164d4c
WS
2745 m_acceptsFocus = false;
2746 m_hasFocus = false;
148cd9b6 2747
0a164d4c 2748 m_clipPaintRegion = false;
b6fa52db 2749
c7382f91
JS
2750 m_needsStyleChange = false;
2751
5e014a0c 2752 m_cursor = *wxSTANDARD_CURSOR;
2daa0ce9 2753
2b5f62a0 2754#ifdef __WXGTK20__
a3c15d89 2755 m_imData = NULL;
a589495e 2756 m_dirtyTabOrder = false;
2b5f62a0 2757#else
63081513
RR
2758#ifdef HAVE_XIM
2759 m_ic = (GdkIC*) NULL;
2760 m_icattr = (GdkICAttr*) NULL;
2761#endif
2b5f62a0 2762#endif
362c6693 2763}
c801d85f 2764
1e6feb95 2765wxWindowGTK::wxWindowGTK()
68995f26
VZ
2766{
2767 Init();
2768}
2769
1e6feb95
VZ
2770wxWindowGTK::wxWindowGTK( wxWindow *parent,
2771 wxWindowID id,
2772 const wxPoint &pos,
2773 const wxSize &size,
2774 long style,
2775 const wxString &name )
6ca41e57 2776{
68995f26
VZ
2777 Init();
2778
e380f72b 2779 Create( parent, id, pos, size, style, name );
6ca41e57 2780}
8bbe427f 2781
1e6feb95
VZ
2782bool wxWindowGTK::Create( wxWindow *parent,
2783 wxWindowID id,
2784 const wxPoint &pos,
2785 const wxSize &size,
2786 long style,
2787 const wxString &name )
c801d85f 2788{
4dcaf11a
RR
2789 if (!PreCreation( parent, pos, size ) ||
2790 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
2791 {
1e6feb95 2792 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
0a164d4c 2793 return false;
4dcaf11a 2794 }
47d67540 2795
ddb6bc71 2796 m_insertCallback = wxInsertChildInWindow;
2b5f62a0 2797
e380f72b 2798 m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
38c7b3d3 2799 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
ff8bfdbb 2800
f03fc89f 2801 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
47d67540 2802
dd00f3f6 2803 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
e380f72b 2804 scroll_class->scrollbar_spacing = 0;
47d67540 2805
f03fc89f 2806 gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
47d67540 2807
f03fc89f
VZ
2808 m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->hscrollbar) );
2809 m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->vscrollbar) );
47d67540 2810
da048e3d 2811 m_wxwindow = gtk_pizza_new();
0fc5dbf5 2812
1e6feb95 2813#ifndef __WXUNIVERSAL__
da048e3d 2814 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
b292e2f5 2815
f03fc89f 2816 if (HasFlag(wxRAISED_BORDER))
034be888 2817 {
da048e3d 2818 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_OUT );
034be888 2819 }
f03fc89f 2820 else if (HasFlag(wxSUNKEN_BORDER))
034be888 2821 {
da048e3d 2822 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_IN );
5e014a0c
RR
2823 }
2824 else if (HasFlag(wxSIMPLE_BORDER))
2825 {
da048e3d 2826 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_THIN );
034be888
RR
2827 }
2828 else
2829 {
da048e3d 2830 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_NONE );
034be888 2831 }
1e6feb95 2832#endif // __WXUNIVERSAL__
47d67540 2833
4e5a4c69
RR
2834 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
2835
3da17724 2836 GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
0a164d4c 2837 m_acceptsFocus = true;
ca298c88 2838
e380f72b 2839 // I _really_ don't want scrollbars in the beginning
a2053b27
RR
2840 m_vAdjust->lower = 0.0;
2841 m_vAdjust->upper = 1.0;
2842 m_vAdjust->value = 0.0;
2843 m_vAdjust->step_increment = 1.0;
2844 m_vAdjust->page_increment = 1.0;
2845 m_vAdjust->page_size = 5.0;
2846 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
2847 m_hAdjust->lower = 0.0;
2848 m_hAdjust->upper = 1.0;
2849 m_hAdjust->value = 0.0;
2850 m_hAdjust->step_increment = 1.0;
2851 m_hAdjust->page_increment = 1.0;
2852 m_hAdjust->page_size = 5.0;
2853 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
f03fc89f
VZ
2854
2855 // these handlers block mouse events to any window during scrolling such as
77ffb593 2856 // motion events and prevent GTK and wxWidgets from fighting over where the
f03fc89f
VZ
2857 // slider should be
2858
2859 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_press_event",
76ed8f8d
RR
2860 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2861
f03fc89f 2862 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_press_event",
76ed8f8d
RR
2863 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2864
f03fc89f 2865 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_release_event",
76ed8f8d
RR
2866 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2867
f03fc89f 2868 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_release_event",
76ed8f8d 2869 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
8bbe427f 2870
034be888 2871 // these handlers get notified when screen updates are required either when
76ed8f8d
RR
2872 // scrolling or when the window size (and therefore scrollbar configuration)
2873 // has changed
2874
2875 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
2876 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
2877 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
2878 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
2879
f03fc89f 2880 gtk_widget_show( m_wxwindow );
47d67540 2881
f03fc89f
VZ
2882 if (m_parent)
2883 m_parent->DoAddChild( this );
94633ad9 2884
76fcf0f2 2885 m_focusWidget = m_wxwindow;
8bbe427f 2886
e380f72b 2887 PostCreation();
8bbe427f 2888
0a164d4c 2889 return true;
362c6693 2890}
c801d85f 2891
1e6feb95 2892wxWindowGTK::~wxWindowGTK()
c801d85f 2893{
7de59551
RD
2894 SendDestroyEvent();
2895
44cd54c2
JS
2896 if (g_focusWindow == this)
2897 g_focusWindow = NULL;
2898
3e679f01
VZ
2899 if ( g_delayedFocus == this )
2900 g_delayedFocus = NULL;
2901
0a164d4c
WS
2902 m_isBeingDeleted = true;
2903 m_hasVMT = false;
47d67540 2904
02c3e53b
JS
2905 // destroy children before destroying this window itself
2906 DestroyChildren();
2907
2908 // unhook focus handlers to prevent stray events being
2909 // propagated to this (soon to be) dead object
2910 if (m_focusWidget != NULL)
2911 {
2912 gtk_signal_disconnect_by_func( GTK_OBJECT(m_focusWidget),
2913 (GtkSignalFunc) gtk_window_focus_in_callback, (gpointer) this );
2914 gtk_signal_disconnect_by_func( GTK_OBJECT(m_focusWidget),
2915 (GtkSignalFunc) gtk_window_focus_out_callback, (gpointer) this );
2916 }
2917
f03fc89f 2918 if (m_widget)
0a164d4c 2919 Show( false );
8bbe427f 2920
63081513
RR
2921#ifdef HAVE_XIM
2922 if (m_ic)
2923 gdk_ic_destroy (m_ic);
2924 if (m_icattr)
2925 gdk_ic_attr_destroy (m_icattr);
2926#endif
2927
f6551618
MW
2928#ifdef __WXGTK20__
2929 // delete before the widgets to avoid a crash on solaris
2930 delete m_imData;
2931#endif
2932
f03fc89f 2933 if (m_wxwindow)
a2053b27 2934 {
f03fc89f 2935 gtk_widget_destroy( m_wxwindow );
c50f1fb9 2936 m_wxwindow = (GtkWidget*) NULL;
a2053b27 2937 }
8bbe427f 2938
f03fc89f 2939 if (m_widget)
a2053b27 2940 {
f03fc89f 2941 gtk_widget_destroy( m_widget );
c50f1fb9 2942 m_widget = (GtkWidget*) NULL;
a2053b27 2943 }
362c6693 2944}
c801d85f 2945
1e6feb95 2946bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos, const wxSize &size )
c801d85f 2947{
0a164d4c 2948 wxCHECK_MSG( !m_needParent || parent, false, wxT("Need complete parent.") );
8bbe427f 2949
a7c26d10
RD
2950 // Use either the given size, or the default if -1 is given.
2951 // See wxWindowBase for these functions.
3013a903 2952 m_width = WidthDefault(size.x) ;
f03fc89f 2953 m_height = HeightDefault(size.y);
8bbe427f 2954
43a18898
RR
2955 m_x = (int)pos.x;
2956 m_y = (int)pos.y;
8bbe427f 2957
0a164d4c 2958 return true;
c801d85f
KB
2959}
2960
1e6feb95 2961void wxWindowGTK::PostCreation()
c801d85f 2962{
82b978d7
RD
2963 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2964
43a18898
RR
2965 if (m_wxwindow)
2966 {
147bc491 2967 if (!m_noExpose)
b02da6b1 2968 {
77ffb593 2969 // these get reported to wxWidgets -> wxPaintEvent
1e6feb95 2970
b420fb6a
RR
2971 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow), TRUE );
2972
147bc491
RR
2973 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
2974 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
2975
4e5a4c69 2976#ifndef __WXGTK20__
147bc491
RR
2977 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
2978 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
0fc5dbf5 2979
e441e1f4 2980 if (!HasFlag(wxFULL_REPAINT_ON_RESIZE))
e22454be
RR
2981 {
2982 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "event",
2983 GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this );
2984 }
4e5a4c69 2985#else
e441e1f4 2986 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2b5f62a0 2987#endif
93d23d8f 2988 }
2b5f62a0
VZ
2989
2990#ifdef __WXGTK20__
ed56a258
JS
2991 // Create input method handler
2992 m_imData = new wxGtkIMData;
2993
2b5f62a0 2994 // Cannot handle drawing preedited text yet
a3c15d89 2995 gtk_im_context_set_use_preedit( m_imData->context, FALSE );
2b5f62a0 2996
a3c15d89 2997 g_signal_connect (G_OBJECT (m_imData->context), "commit",
da210120 2998 G_CALLBACK (gtk_wxwindow_commit_cb), this);
4e5a4c69 2999#endif
148cd9b6 3000
67d78217 3001 // these are called when the "sunken" or "raised" borders are drawn
034be888
RR
3002 gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
3003 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
3004
4e5a4c69 3005#ifndef __WXGTK20__
034be888
RR
3006 gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
3007 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
4e5a4c69 3008#endif
43a18898 3009 }
47d67540 3010
76fcf0f2 3011 // focus handling
63081513 3012
06fda9e8
RR
3013 if (!GTK_IS_WINDOW(m_widget))
3014 {
3015 if (m_focusWidget == NULL)
3016 m_focusWidget = m_widget;
0a164d4c 3017
06fda9e8
RR
3018 gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_in_event",
3019 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
76fcf0f2 3020
4ecd9342 3021 gtk_signal_connect_after( GTK_OBJECT(m_focusWidget), "focus_out_event",
06fda9e8
RR
3022 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
3023 }
76fcf0f2
RR
3024
3025 // connect to the various key and mouse handlers
63081513 3026
a2053b27 3027 GtkWidget *connect_widget = GetConnectWidget();
f03fc89f 3028
a2053b27 3029 ConnectWidget( connect_widget );
47d67540 3030
63081513 3031 /* We cannot set colours, fonts and cursors before the widget has
a2053b27
RR
3032 been realized, so we do this directly after realization */
3033 gtk_signal_connect( GTK_OBJECT(connect_widget), "realize",
c50f1fb9 3034 GTK_SIGNAL_FUNC(gtk_window_realized_callback), (gpointer) this );
2daa0ce9 3035
63081513
RR
3036 if (m_wxwindow)
3037 {
47c93b63 3038 // Catch native resize events
8f75cb6c
RR
3039 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
3040 GTK_SIGNAL_FUNC(gtk_window_size_callback), (gpointer)this );
2daa0ce9 3041
47c93b63 3042 // Initialize XIM support
63081513
RR
3043 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "realize",
3044 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback), (gpointer) this );
8f75cb6c 3045
47c93b63 3046 // And resize XIM window
b79395c5
RR
3047 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
3048 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this );
63081513 3049 }
2daa0ce9 3050
024e9a4c
RR
3051 if (GTK_IS_COMBO(m_widget))
3052 {
3053 GtkCombo *gcombo = GTK_COMBO(m_widget);
0a164d4c 3054
024e9a4c
RR
3055 gtk_signal_connect( GTK_OBJECT(gcombo->entry), "size_request",
3056 GTK_SIGNAL_FUNC(wxgtk_combo_size_request_callback),
3057 (gpointer) this );
3058 }
3059 else
47c93b63
RR
3060 {
3061 // This is needed if we want to add our windows into native
024e9a4c 3062 // GTK controls, such as the toolbar. With this callback, the
47c93b63 3063 // toolbar gets to know the correct size (the one set by the
024e9a4c 3064 // programmer). Sadly, it misbehaves for wxComboBox.
47c93b63 3065 gtk_signal_connect( GTK_OBJECT(m_widget), "size_request",
e1f448ee
VZ
3066 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback),
3067 (gpointer) this );
47c93b63 3068 }
1e6feb95 3069
40bab631
VS
3070 InheritAttributes();
3071
0a164d4c 3072 m_hasVMT = true;
a433fbd5
VZ
3073
3074 // unless the window was created initially hidden (i.e. Hide() had been
3075 // called before Create()), we should show it at GTK+ level as well
3076 if ( IsShown() )
3077 gtk_widget_show( m_widget );
b4071e91
RR
3078}
3079
1e6feb95 3080void wxWindowGTK::ConnectWidget( GtkWidget *widget )
b4071e91 3081{
43a18898
RR
3082 gtk_signal_connect( GTK_OBJECT(widget), "key_press_event",
3083 GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this );
c801d85f 3084
b666df2c
RR
3085 gtk_signal_connect( GTK_OBJECT(widget), "key_release_event",
3086 GTK_SIGNAL_FUNC(gtk_window_key_release_callback), (gpointer)this );
3087
43a18898
RR
3088 gtk_signal_connect( GTK_OBJECT(widget), "button_press_event",
3089 GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
47d67540 3090
43a18898
RR
3091 gtk_signal_connect( GTK_OBJECT(widget), "button_release_event",
3092 GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
47d67540 3093
43a18898
RR
3094 gtk_signal_connect( GTK_OBJECT(widget), "motion_notify_event",
3095 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
47d67540 3096
557c9f5b
JS
3097#ifdef __WXGTK20__
3098 gtk_signal_connect( GTK_OBJECT(widget), "scroll_event",
3099 GTK_SIGNAL_FUNC(gtk_window_wheel_callback), (gpointer)this );
ac103441
RR
3100 g_signal_connect(widget, "popup_menu",
3101 G_CALLBACK(wxgtk_window_popup_menu_callback), this);
557c9f5b
JS
3102#endif
3103
43a18898
RR
3104 gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event",
3105 GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
47d67540 3106
43a18898
RR
3107 gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
3108 GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
362c6693 3109}
c801d85f 3110
1e6feb95 3111bool wxWindowGTK::Destroy()
c801d85f 3112{
82b978d7 3113 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
47d67540 3114
0a164d4c 3115 m_hasVMT = false;
c801d85f 3116
f03fc89f 3117 return wxWindowBase::Destroy();
362c6693 3118}
c801d85f 3119
1e6feb95 3120void wxWindowGTK::DoMoveWindow(int x, int y, int width, int height)
23efdd02
RR
3121{
3122 gtk_pizza_set_size( GTK_PIZZA(m_parent->m_wxwindow), m_widget, x, y, width, height );
3123}
2daa0ce9 3124
1e6feb95 3125void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
c801d85f 3126{
82b978d7 3127 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
1e6feb95 3128 wxASSERT_MSG( (m_parent != NULL), wxT("wxWindowGTK::SetSize requires parent.\n") );
8bbe427f 3129
33611ebb 3130/*
f94fca1b 3131 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
33611ebb
RR
3132*/
3133
e27ce4e9 3134 if (m_resizing) return; /* I don't like recursions */
0a164d4c 3135 m_resizing = true;
1e6feb95 3136
b9f29261
VS
3137 int currentX, currentY;
3138 GetPosition(&currentX, &currentY);
443c834d 3139 if (x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
b9f29261 3140 x = currentX;
443c834d 3141 if (y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
b9f29261 3142 y = currentY;
a200c35e
VS
3143 AdjustForParentClientOrigin(x, y, sizeFlags);
3144
a2053b27 3145 if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
fb1585ae 3146 {
e27ce4e9 3147 /* don't set the size for children of wxNotebook, just take the values. */
fb1585ae
RR
3148 m_x = x;
3149 m_y = y;
3150 m_width = width;
ba4e3652 3151 m_height = height;
fb1585ae 3152 }
ba4e3652 3153 else
fb1585ae 3154 {
da048e3d 3155 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
85ad5eb5 3156 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
ba4e3652 3157 {
da048e3d
RR
3158 if (x != -1) m_x = x + pizza->xoffset;
3159 if (y != -1) m_y = y + pizza->yoffset;
ba4e3652
RR
3160 }
3161 else
3162 {
da048e3d
RR
3163 m_x = x + pizza->xoffset;
3164 m_y = y + pizza->yoffset;
ba4e3652 3165 }
47d67540 3166
a63d48fa 3167 // calculate the best size if we should auto size the window
c7e111cd
VZ
3168 if ( ((sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1) ||
3169 ((sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1) )
ba4e3652 3170 {
a63d48fa 3171 const wxSize sizeBest = GetBestSize();
c7e111cd 3172 if ( (sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1 )
a63d48fa 3173 width = sizeBest.x;
c7e111cd 3174 if ( (sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1 )
a63d48fa 3175 height = sizeBest.y;
ba4e3652
RR
3176 }
3177
a63d48fa
VZ
3178 if (width != -1)
3179 m_width = width;
3180 if (height != -1)
3181 m_height = height;
8bbe427f 3182
e7dda1ff
VS
3183 int minWidth = GetMinWidth(),
3184 minHeight = GetMinHeight(),
3185 maxWidth = GetMaxWidth(),
3186 maxHeight = GetMaxHeight();
3187
3188 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
3189 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
3190 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
3191 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
47d67540 3192
863e0817
RR
3193 int left_border = 0;
3194 int right_border = 0;
3195 int top_border = 0;
c50f1fb9 3196 int bottom_border = 0;
f03fc89f 3197
863e0817 3198 /* the default button has a border around it */
29f538ce 3199 if (GTK_WIDGET_CAN_DEFAULT(m_widget))
c50f1fb9 3200 {
863e0817 3201#ifdef __WXGTK20__
f893066b
RR
3202 GtkBorder *default_border = NULL;
3203 gtk_widget_style_get( m_widget, "default_border", &default_border, NULL );
3204 if (default_border)
863e0817 3205 {
f893066b
RR
3206 left_border += default_border->left;
3207 right_border += default_border->right;
3208 top_border += default_border->top;
3209 bottom_border += default_border->bottom;
3210 g_free( default_border );
863e0817
RR
3211 }
3212#else
3213 left_border = 6;
3214 right_border = 6;
3215 top_border = 6;
c50f1fb9 3216 bottom_border = 5;
67d78217 3217#endif
863e0817 3218 }
c50f1fb9 3219
863e0817
RR
3220 DoMoveWindow( m_x-top_border,
3221 m_y-left_border,
3222 m_width+left_border+right_border,
3223 m_height+top_border+bottom_border );
54517652 3224 }
148cd9b6 3225
5b8a521e
RR
3226 if (m_hasScrolling)
3227 {
1e6feb95 3228 /* Sometimes the client area changes size without the
b6fa52db
RR
3229 whole windows's size changing, but if the whole
3230 windows's size doesn't change, no wxSizeEvent will
3231 normally be sent. Here we add an extra test if
3232 the client test has been changed and this will
3233 be used then. */
5b8a521e
RR
3234 GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
3235 }
3236
54517652 3237/*
6d693bb4
RR
3238 wxPrintf( "OnSize sent from " );
3239 if (GetClassInfo() && GetClassInfo()->GetClassName())
3240 wxPrintf( GetClassInfo()->GetClassName() );
3241 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3242*/
3243
30760ce7
RR
3244 if (!m_nativeSizeEvent)
3245 {
3246 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
3247 event.SetEventObject( this );
3248 GetEventHandler()->ProcessEvent( event );
3249 }
6d693bb4 3250
0a164d4c 3251 m_resizing = false;
362c6693 3252}
c801d85f 3253
1e6feb95 3254void wxWindowGTK::OnInternalIdle()
9390a202 3255{
a589495e
VS
3256#ifdef __WXGTK20__
3257 if ( m_dirtyTabOrder )
3258 RealizeTabOrder();
3259#endif
c7382f91
JS
3260 // Update style if the window was not yet realized
3261 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
3262 if (m_needsStyleChange)
3263 {
3264 SetBackgroundStyle(GetBackgroundStyle());
3265 m_needsStyleChange = false;
3266 }
a589495e 3267
beab25bd 3268 // Update invalidated regions.
010afced 3269 GtkUpdate();
0fc5dbf5 3270
9146082c
RR
3271 wxCursor cursor = m_cursor;
3272 if (g_globalCursor.Ok()) cursor = g_globalCursor;
c50f1fb9 3273
f7a11f8c 3274 if (cursor.Ok())
9146082c 3275 {
3017f78d 3276 /* I now set the cursor anew in every OnInternalIdle call
b02da6b1
VZ
3277 as setting the cursor in a parent window also effects the
3278 windows above so that checking for the current cursor is
3279 not possible. */
148cd9b6 3280
9146082c 3281 if (m_wxwindow)
6a008b33 3282 {
da048e3d 3283 GdkWindow *window = GTK_PIZZA(m_wxwindow)->bin_window;
6a008b33 3284 if (window)
c50f1fb9 3285 gdk_window_set_cursor( window, cursor.GetCursor() );
6a008b33
VZ
3286
3287 if (!g_globalCursor.Ok())
3288 cursor = *wxSTANDARD_CURSOR;
3289
3290 window = m_widget->window;
5e014a0c 3291 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
9146082c 3292 gdk_window_set_cursor( window, cursor.GetCursor() );
5e014a0c 3293
6a008b33
VZ
3294 }
3295 else
3296 {
5e014a0c 3297
9146082c 3298 GdkWindow *window = m_widget->window;
5e014a0c 3299 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
9146082c 3300 gdk_window_set_cursor( window, cursor.GetCursor() );
5e014a0c 3301
6a008b33 3302 }
9146082c 3303 }
6a008b33 3304
e39af974
JS
3305 if (wxUpdateUIEvent::CanUpdate(this))
3306 UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
9390a202
RR
3307}
3308
1e6feb95 3309void wxWindowGTK::DoGetSize( int *width, int *height ) const
c801d85f 3310{
82b978d7 3311 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3312
fb1585ae
RR
3313 if (width) (*width) = m_width;
3314 if (height) (*height) = m_height;
362c6693 3315}
c801d85f 3316
1e6feb95 3317void wxWindowGTK::DoSetClientSize( int width, int height )
c801d85f 3318{
82b978d7
RD
3319 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3320
1ecc4d80 3321 if (!m_wxwindow)
c801d85f 3322 {
1ecc4d80 3323 SetSize( width, height );
c801d85f
KB
3324 }
3325 else
3326 {
1ecc4d80
RR
3327 int dw = 0;
3328 int dh = 0;
3329
1e6feb95 3330#ifndef __WXUNIVERSAL__
98d3fdbe
RR
3331 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
3332 {
5e014a0c 3333 /* when using GTK 1.2 we set the shadow border size to 2 */
6a008b33 3334 dw += 2 * 2;
98d3fdbe
RR
3335 dh += 2 * 2;
3336 }
5e014a0c
RR
3337 if (HasFlag(wxSIMPLE_BORDER))
3338 {
3339 /* when using GTK 1.2 we set the simple border size to 1 */
3340 dw += 1 * 2;
3341 dh += 1 * 2;
3342 }
1e6feb95 3343#endif // __WXUNIVERSAL__
034be888 3344
5b8a521e 3345 if (m_hasScrolling)
98d3fdbe 3346 {
324dbfec 3347 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2daa0ce9 3348
9000c624
RR
3349 GtkRequisition vscroll_req;
3350 vscroll_req.width = 2;
3351 vscroll_req.height = 2;
dd00f3f6 3352 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
9000c624 3353 (scroll_window->vscrollbar, &vscroll_req );
2daa0ce9 3354
9000c624
RR
3355 GtkRequisition hscroll_req;
3356 hscroll_req.width = 2;
3357 hscroll_req.height = 2;
dd00f3f6 3358 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
9000c624
RR
3359 (scroll_window->hscrollbar, &hscroll_req );
3360
dd00f3f6 3361 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
324dbfec 3362
1ecc4d80
RR
3363 if (scroll_window->vscrollbar_visible)
3364 {
9000c624 3365 dw += vscroll_req.width;
1ecc4d80
RR
3366 dw += scroll_class->scrollbar_spacing;
3367 }
3368
3369 if (scroll_window->hscrollbar_visible)
3370 {
9000c624 3371 dh += hscroll_req.height;
63cc5d9d 3372 dh += scroll_class->scrollbar_spacing;
1ecc4d80 3373 }
9000c624 3374 }
1ecc4d80 3375
034be888 3376 SetSize( width+dw, height+dh );
1ecc4d80 3377 }
362c6693 3378}
c801d85f 3379
1e6feb95 3380void wxWindowGTK::DoGetClientSize( int *width, int *height ) const
c801d85f 3381{
82b978d7 3382 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3383
1ecc4d80
RR
3384 if (!m_wxwindow)
3385 {
3386 if (width) (*width) = m_width;
3387 if (height) (*height) = m_height;
c801d85f
KB
3388 }
3389 else
3390 {
1ecc4d80
RR
3391 int dw = 0;
3392 int dh = 0;
3393
1e6feb95 3394#ifndef __WXUNIVERSAL__
98d3fdbe
RR
3395 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
3396 {
5e014a0c 3397 /* when using GTK 1.2 we set the shadow border size to 2 */
6a008b33 3398 dw += 2 * 2;
98d3fdbe
RR
3399 dh += 2 * 2;
3400 }
5e014a0c
RR
3401 if (HasFlag(wxSIMPLE_BORDER))
3402 {
3403 /* when using GTK 1.2 we set the simple border size to 1 */
3404 dw += 1 * 2;
3405 dh += 1 * 2;
3406 }
1e6feb95 3407#endif // __WXUNIVERSAL__
9000c624 3408
5b8a521e 3409 if (m_hasScrolling)
98d3fdbe 3410 {
6a008b33 3411 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2daa0ce9 3412
9000c624
RR
3413 GtkRequisition vscroll_req;
3414 vscroll_req.width = 2;
3415 vscroll_req.height = 2;
dd00f3f6 3416 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
9000c624 3417 (scroll_window->vscrollbar, &vscroll_req );
2daa0ce9 3418
9000c624
RR
3419 GtkRequisition hscroll_req;
3420 hscroll_req.width = 2;
3421 hscroll_req.height = 2;
dd00f3f6 3422 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
9000c624
RR
3423 (scroll_window->hscrollbar, &hscroll_req );
3424
dd00f3f6 3425 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
6a008b33 3426
1ecc4d80
RR
3427 if (scroll_window->vscrollbar_visible)
3428 {
9000c624 3429 dw += vscroll_req.width;
1ecc4d80
RR
3430 dw += scroll_class->scrollbar_spacing;
3431 }
3432
3433 if (scroll_window->hscrollbar_visible)
3434 {
9000c624 3435 dh += hscroll_req.height;
1ecc4d80
RR
3436 dh += scroll_class->scrollbar_spacing;
3437 }
6a008b33 3438 }
47d67540 3439
1ecc4d80
RR
3440 if (width) (*width) = m_width - dw;
3441 if (height) (*height) = m_height - dh;
3442 }
1e6feb95 3443
f94fca1b
RR
3444/*
3445 printf( "GetClientSize, name %s ", GetName().c_str() );
3446 if (width) printf( " width = %d", (*width) );
3447 if (height) printf( " height = %d", (*height) );
3448 printf( "\n" );
3449*/
362c6693 3450}
c801d85f 3451
1e6feb95 3452void wxWindowGTK::DoGetPosition( int *x, int *y ) const
c801d85f 3453{
82b978d7 3454 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3455
bf0c00c6
RR
3456 int dx = 0;
3457 int dy = 0;
3458 if (m_parent && m_parent->m_wxwindow)
3459 {
da048e3d 3460 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
b02da6b1
VZ
3461 dx = pizza->xoffset;
3462 dy = pizza->yoffset;
bf0c00c6 3463 }
94633ad9 3464
496beb3f
VS
3465 if (x) (*x) = m_x - dx;
3466 if (y) (*y) = m_y - dy;
362c6693 3467}
c801d85f 3468
1e6feb95 3469void wxWindowGTK::DoClientToScreen( int *x, int *y ) const
c801d85f 3470{
82b978d7 3471 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3472
a2053b27
RR
3473 if (!m_widget->window) return;
3474
43a18898
RR
3475 GdkWindow *source = (GdkWindow *) NULL;
3476 if (m_wxwindow)
da048e3d 3477 source = GTK_PIZZA(m_wxwindow)->bin_window;
43a18898
RR
3478 else
3479 source = m_widget->window;
47d67540 3480
43a18898
RR
3481 int org_x = 0;
3482 int org_y = 0;
3483 gdk_window_get_origin( source, &org_x, &org_y );
c801d85f 3484
43a18898 3485 if (!m_wxwindow)
c801d85f 3486 {
43a18898
RR
3487 if (GTK_WIDGET_NO_WINDOW (m_widget))
3488 {
3489 org_x += m_widget->allocation.x;
3490 org_y += m_widget->allocation.y;
3491 }
362c6693 3492 }
47d67540 3493
43a18898
RR
3494 if (x) *x += org_x;
3495 if (y) *y += org_y;
362c6693 3496}
c801d85f 3497
1e6feb95 3498void wxWindowGTK::DoScreenToClient( int *x, int *y ) const
c801d85f 3499{
82b978d7 3500 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3501
a2053b27
RR
3502 if (!m_widget->window) return;
3503
1ecc4d80
RR
3504 GdkWindow *source = (GdkWindow *) NULL;
3505 if (m_wxwindow)
da048e3d 3506 source = GTK_PIZZA(m_wxwindow)->bin_window;
1ecc4d80
RR
3507 else
3508 source = m_widget->window;
47d67540 3509
1ecc4d80
RR
3510 int org_x = 0;
3511 int org_y = 0;
3512 gdk_window_get_origin( source, &org_x, &org_y );
c801d85f 3513
1ecc4d80 3514 if (!m_wxwindow)
c801d85f 3515 {
1ecc4d80
RR
3516 if (GTK_WIDGET_NO_WINDOW (m_widget))
3517 {
3518 org_x += m_widget->allocation.x;
3519 org_y += m_widget->allocation.y;
3520 }
362c6693 3521 }
47d67540 3522
1ecc4d80
RR
3523 if (x) *x -= org_x;
3524 if (y) *y -= org_y;
362c6693 3525}
c801d85f 3526
1e6feb95 3527bool wxWindowGTK::Show( bool show )
c801d85f 3528{
0a164d4c 3529 wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
47d67540 3530
739730ca
RR
3531 if (!wxWindowBase::Show(show))
3532 {
3533 // nothing to do
0a164d4c 3534 return false;
739730ca 3535 }
8bbe427f 3536
f03fc89f
VZ
3537 if (show)
3538 gtk_widget_show( m_widget );
1ecc4d80 3539 else
f03fc89f 3540 gtk_widget_hide( m_widget );
8bbe427f 3541
2b5f62a0 3542 wxShowEvent eventShow(GetId(), show);
687706f5 3543 eventShow.SetEventObject(this);
2b5f62a0
VZ
3544
3545 GetEventHandler()->ProcessEvent(eventShow);
3546
0a164d4c 3547 return true;
362c6693 3548}
c801d85f 3549
3379ed37 3550static void wxWindowNotifyEnable(wxWindowGTK* win, bool enable)
fdca68a6
JS
3551{
3552 win->OnParentEnable(enable);
3553
3554 // Recurse, so that children have the opportunity to Do The Right Thing
3555 // and reset colours that have been messed up by a parent's (really ancestor's)
3556 // Enable call
222ed1d6 3557 for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
fdca68a6
JS
3558 node;
3559 node = node->GetNext() )
3560 {
3561 wxWindow *child = node->GetData();
3562 if (!child->IsKindOf(CLASSINFO(wxDialog)) && !child->IsKindOf(CLASSINFO(wxFrame)))
3563 wxWindowNotifyEnable(child, enable);
3564 }
3565}
3566
3379ed37 3567bool wxWindowGTK::Enable( bool enable )
c801d85f 3568{
0a164d4c 3569 wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
82b978d7 3570
739730ca
RR
3571 if (!wxWindowBase::Enable(enable))
3572 {
3573 // nothing to do
0a164d4c 3574 return false;
739730ca 3575 }
1ecc4d80 3576
f03fc89f
VZ
3577 gtk_widget_set_sensitive( m_widget, enable );
3578 if ( m_wxwindow )
3579 gtk_widget_set_sensitive( m_wxwindow, enable );
ff8bfdbb 3580
fdca68a6 3581 wxWindowNotifyEnable(this, enable);
513903c4 3582
0a164d4c 3583 return true;
362c6693 3584}
c801d85f 3585
1e6feb95 3586int wxWindowGTK::GetCharHeight() const
2f2aa628 3587{
82b978d7 3588 wxCHECK_MSG( (m_widget != NULL), 12, wxT("invalid window") );
47d67540 3589
cc402e64
VZ
3590 wxFont font = GetFont();
3591 wxCHECK_MSG( font.Ok(), 12, wxT("invalid font") );
2f2aa628 3592
bbd006c0
RR
3593#ifdef __WXGTK20__
3594 PangoContext *context = NULL;
3595 if (m_widget)
3596 context = gtk_widget_get_pango_context( m_widget );
3597
3598 if (!context)
3599 return 0;
3600
cc402e64 3601 PangoFontDescription *desc = font.GetNativeFontInfo()->description;
bbd006c0
RR
3602 PangoLayout *layout = pango_layout_new(context);
3603 pango_layout_set_font_description(layout, desc);
3604 pango_layout_set_text(layout, "H", 1);
3605 PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
3606
3607 PangoRectangle rect;
3608 pango_layout_line_get_extents(line, NULL, &rect);
3609
3610 g_object_unref( G_OBJECT( layout ) );
7de59551 3611
f69e2009 3612 return (int) PANGO_PIXELS(rect.height);
bbd006c0 3613#else
cc402e64 3614 GdkFont *gfont = font.GetInternalFont( 1.0 );
f03fc89f 3615
cc402e64 3616 return gfont->ascent + gfont->descent;
bbd006c0 3617#endif
362c6693 3618}
c801d85f 3619
1e6feb95 3620int wxWindowGTK::GetCharWidth() const
c33c4050 3621{
82b978d7 3622 wxCHECK_MSG( (m_widget != NULL), 8, wxT("invalid window") );
47d67540 3623
cc402e64
VZ
3624 wxFont font = GetFont();
3625 wxCHECK_MSG( font.Ok(), 8, wxT("invalid font") );
47d67540 3626
bbd006c0
RR
3627#ifdef __WXGTK20__
3628 PangoContext *context = NULL;
3629 if (m_widget)
3630 context = gtk_widget_get_pango_context( m_widget );
3631
3632 if (!context)
3633 return 0;
3634
cc402e64 3635 PangoFontDescription *desc = font.GetNativeFontInfo()->description;
bbd006c0
RR
3636 PangoLayout *layout = pango_layout_new(context);
3637 pango_layout_set_font_description(layout, desc);
95c430aa 3638 pango_layout_set_text(layout, "g", 1);
bbd006c0
RR
3639 PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
3640
3641 PangoRectangle rect;
3642 pango_layout_line_get_extents(line, NULL, &rect);
3643
3644 g_object_unref( G_OBJECT( layout ) );
7de59551 3645
f69e2009 3646 return (int) PANGO_PIXELS(rect.width);
bbd006c0 3647#else
cc402e64 3648 GdkFont *gfont = font.GetInternalFont( 1.0 );
ff8bfdbb 3649
cc402e64 3650 return gdk_string_width( gfont, "g" );
bbd006c0 3651#endif
c33c4050
RR
3652}
3653
1e6feb95 3654void wxWindowGTK::GetTextExtent( const wxString& string,
0a164d4c
WS
3655 int *x,
3656 int *y,
3657 int *descent,
3658 int *externalLeading,
3659 const wxFont *theFont ) const
c33c4050 3660{
cc402e64 3661 wxFont fontToUse = theFont ? *theFont : GetFont();
47d67540 3662
223d09f6 3663 wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
2b5f62a0 3664
0a164d4c 3665 if (string.empty())
48d011c8 3666 {
b15ed747
RR
3667 if (x) (*x) = 0;
3668 if (y) (*y) = 0;
48d011c8
RR
3669 return;
3670 }
47d67540 3671
2b5f62a0 3672#ifdef __WXGTK20__
48d011c8
RR
3673 PangoContext *context = NULL;
3674 if (m_widget)
2b5f62a0
VZ
3675 context = gtk_widget_get_pango_context( m_widget );
3676
48d011c8
RR
3677 if (!context)
3678 {
b15ed747
RR
3679 if (x) (*x) = 0;
3680 if (y) (*y) = 0;
48d011c8
RR
3681 return;
3682 }
2b5f62a0 3683
48d011c8
RR
3684 PangoFontDescription *desc = fontToUse.GetNativeFontInfo()->description;
3685 PangoLayout *layout = pango_layout_new(context);
3686 pango_layout_set_font_description(layout, desc);
3687 {
fb3ed106 3688#if wxUSE_UNICODE
48d011c8
RR
3689 const wxCharBuffer data = wxConvUTF8.cWC2MB( string );
3690 pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data ));
fb3ed106
RR
3691#else
3692 const wxWCharBuffer wdata = wxConvLocal.cMB2WC( string );
3693 const wxCharBuffer data = wxConvUTF8.cWC2MB( wdata );
3694 pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data ));
3695#endif
48d011c8 3696 }
2b5f62a0 3697
48d011c8 3698 PangoRectangle rect;
fd43b1b3 3699 pango_layout_get_extents(layout, NULL, &rect);
2b5f62a0 3700
f69e2009
VS
3701 if (x) (*x) = (wxCoord) PANGO_PIXELS(rect.width);
3702 if (y) (*y) = (wxCoord) PANGO_PIXELS(rect.height);
48d011c8
RR
3703 if (descent)
3704 {
f69e2009
VS
3705 PangoLayoutIter *iter = pango_layout_get_iter(layout);
3706 int baseline = pango_layout_iter_get_baseline(iter);
3707 pango_layout_iter_free(iter);
3708 *descent = *y - PANGO_PIXELS(baseline);
48d011c8
RR
3709 }
3710 if (externalLeading) (*externalLeading) = 0; // ??
2b5f62a0 3711
48d011c8
RR
3712 g_object_unref( G_OBJECT( layout ) );
3713#else
463c1fa1 3714 GdkFont *font = fontToUse.GetInternalFont( 1.0 );
fab591c5 3715 if (x) (*x) = gdk_string_width( font, wxGTK_CONV( string ) );
463c1fa1
RR
3716 if (y) (*y) = font->ascent + font->descent;
3717 if (descent) (*descent) = font->descent;
3718 if (externalLeading) (*externalLeading) = 0; // ??
48d011c8 3719#endif
c33c4050
RR
3720}
3721
1e6feb95 3722void wxWindowGTK::SetFocus()
c801d85f 3723{
82b978d7 3724 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
6cad4f1b
VZ
3725 if ( m_hasFocus )
3726 {
3727 // don't do anything if we already have focus
3728 return;
3729 }
2daa0ce9 3730
354aa1e3
RR
3731 if (m_wxwindow)
3732 {
173348db 3733 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
b231914f 3734 {
173348db 3735 gtk_widget_grab_focus (m_wxwindow);
b231914f 3736 }
354aa1e3 3737 }
b231914f 3738 else if (m_widget)
c801d85f 3739 {
eccd5602
RR
3740#ifdef __WXGTK20__
3741 if (GTK_IS_CONTAINER(m_widget))
3742 {
3743 gtk_widget_child_focus( m_widget, GTK_DIR_TAB_FORWARD );
3744 }
3745 else
3746#endif
173348db 3747 if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
463c1fa1 3748 {
0a164d4c 3749
d7fa7eaa 3750 if (!GTK_WIDGET_REALIZED(m_widget))
6aeb6f2a 3751 {
6cad4f1b
VZ
3752 // we can't set the focus to the widget now so we remember that
3753 // it should be focused and will do it later, during the idle
3754 // time, as soon as we can
3755 wxLogTrace(TRACE_FOCUS,
3756 _T("Delaying setting focus to %s(%s)"),
6aeb6f2a
VZ
3757 GetClassInfo()->GetClassName(), GetLabel().c_str());
3758
d7fa7eaa 3759 g_delayedFocus = this;
6aeb6f2a 3760 }
d7fa7eaa 3761 else
6aeb6f2a 3762 {
6cad4f1b
VZ
3763 wxLogTrace(TRACE_FOCUS,
3764 _T("Setting focus to %s(%s)"),
6aeb6f2a
VZ
3765 GetClassInfo()->GetClassName(), GetLabel().c_str());
3766
d7fa7eaa 3767 gtk_widget_grab_focus (m_widget);
6aeb6f2a 3768 }
463c1fa1 3769 }
0a164d4c 3770 else
eccd5602
RR
3771#ifndef __WXGTK20__
3772 if (GTK_IS_CONTAINER(m_widget))
ff8bfdbb 3773 {
59060b8c 3774 gtk_container_focus( GTK_CONTAINER(m_widget), GTK_DIR_TAB_FORWARD );
ff8bfdbb
VZ
3775 }
3776 else
eccd5602 3777#endif
ff8bfdbb 3778 {
6cad4f1b
VZ
3779 wxLogTrace(TRACE_FOCUS,
3780 _T("Can't set focus to %s(%s)"),
3781 GetClassInfo()->GetClassName(), GetLabel().c_str());
ff8bfdbb 3782 }
362c6693 3783 }
362c6693 3784}
c801d85f 3785
1e6feb95 3786bool wxWindowGTK::AcceptsFocus() const
b292e2f5 3787{
f03fc89f 3788 return m_acceptsFocus && wxWindowBase::AcceptsFocus();
b292e2f5
RR
3789}
3790
1e6feb95 3791bool wxWindowGTK::Reparent( wxWindowBase *newParentBase )
463c1fa1 3792{
0a164d4c 3793 wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
c50f1fb9 3794
1e6feb95
VZ
3795 wxWindowGTK *oldParent = m_parent,
3796 *newParent = (wxWindowGTK *)newParentBase;
a2053b27 3797
5fd11f09
RR
3798 wxASSERT( GTK_IS_WIDGET(m_widget) );
3799
f03fc89f 3800 if ( !wxWindowBase::Reparent(newParent) )
0a164d4c 3801 return false;
8bbe427f 3802
5fd11f09
RR
3803 wxASSERT( GTK_IS_WIDGET(m_widget) );
3804
3805 /* prevent GTK from deleting the widget arbitrarily */
3806 gtk_widget_ref( m_widget );
3807
8ce63e9d
RR
3808 if (oldParent)
3809 {
3017f78d 3810 gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget );
8ce63e9d 3811 }
c50f1fb9 3812
5fd11f09
RR
3813 wxASSERT( GTK_IS_WIDGET(m_widget) );
3814
8ce63e9d
RR
3815 if (newParent)
3816 {
3817 /* insert GTK representation */
3818 (*(newParent->m_insertCallback))(newParent, this);
3819 }
c50f1fb9 3820
5fd11f09
RR
3821 /* reverse: prevent GTK from deleting the widget arbitrarily */
3822 gtk_widget_unref( m_widget );
148cd9b6 3823
0a164d4c 3824 return true;
362c6693 3825}
c801d85f 3826
1e6feb95 3827void wxWindowGTK::DoAddChild(wxWindowGTK *child)
ddb6bc71 3828{
223d09f6 3829 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
ddb6bc71 3830
223d09f6 3831 wxASSERT_MSG( (child != NULL), wxT("invalid child window") );
ddb6bc71 3832
223d09f6 3833 wxASSERT_MSG( (m_insertCallback != NULL), wxT("invalid child insertion function") );
c50f1fb9 3834
ddb6bc71
RR
3835 /* add to list */
3836 AddChild( child );
c50f1fb9 3837
ddb6bc71
RR
3838 /* insert GTK representation */
3839 (*m_insertCallback)(this, child);
3840}
3841
a589495e
VS
3842#ifdef __WXGTK20__
3843
3844void wxWindowGTK::AddChild(wxWindowBase *child)
3845{
3846 wxWindowBase::AddChild(child);
3847 m_dirtyTabOrder = true;
3848 if (g_isIdle)
3849 wxapp_install_idle_handler();
3850}
3851
3852void wxWindowGTK::RemoveChild(wxWindowBase *child)
3853{
3854 wxWindowBase::RemoveChild(child);
3855 m_dirtyTabOrder = true;
3856 if (g_isIdle)
3857 wxapp_install_idle_handler();
3858}
0a164d4c 3859
a589495e
VS
3860void wxWindowGTK::DoMoveInTabOrder(wxWindow *win, MoveKind move)
3861{
3862 wxWindowBase::DoMoveInTabOrder(win, move);
3863 m_dirtyTabOrder = true;
3864 if (g_isIdle)
3865 wxapp_install_idle_handler();
3866}
3867
3868void wxWindowGTK::RealizeTabOrder()
3869{
3870 if (m_wxwindow)
3871 {
3872 if (m_children.size() > 0)
3873 {
3874 GList *chain = NULL;
0a164d4c 3875
a589495e
VS
3876 for (wxWindowList::const_iterator i = m_children.begin();
3877 i != m_children.end(); ++i)
3878 {
3879 chain = g_list_prepend(chain, (*i)->m_widget);
3880 }
0a164d4c 3881
a589495e 3882 chain = g_list_reverse(chain);
0a164d4c 3883
a589495e
VS
3884 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow), chain);
3885 g_list_free(chain);
3886 }
3887 else
3888 {
3889 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow));
3890 }
3891 }
0a164d4c 3892
a589495e
VS
3893 m_dirtyTabOrder = false;
3894}
3895
3896#endif // __WXGTK20__
3897
1e6feb95 3898void wxWindowGTK::Raise()
362c6693 3899{
82b978d7
RD
3900 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3901
fdfb8475
RR
3902 if (m_wxwindow && m_wxwindow->window)
3903 {
3904 gdk_window_raise( m_wxwindow->window );
3905 }
0a164d4c 3906 else if (m_widget->window)
fdfb8475
RR
3907 {
3908 gdk_window_raise( m_widget->window );
3909 }
362c6693
RR
3910}
3911
1e6feb95 3912void wxWindowGTK::Lower()
362c6693 3913{
82b978d7
RD
3914 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3915
fdfb8475
RR
3916 if (m_wxwindow && m_wxwindow->window)
3917 {
3918 gdk_window_lower( m_wxwindow->window );
3919 }
0a164d4c 3920 else if (m_widget->window)
fdfb8475
RR
3921 {
3922 gdk_window_lower( m_widget->window );
3923 }
362c6693 3924}
c801d85f 3925
1e6feb95 3926bool wxWindowGTK::SetCursor( const wxCursor &cursor )
86b29a61 3927{
0a164d4c 3928 wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
86b29a61 3929
f6bcfd97 3930 if (cursor == m_cursor)
0a164d4c 3931 return false;
f6bcfd97
BP
3932
3933 if (g_isIdle)
3934 wxapp_install_idle_handler();
1e6feb95 3935
f6bcfd97
BP
3936 if (cursor == wxNullCursor)
3937 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR );
3938 else
3939 return wxWindowBase::SetCursor( cursor );
362c6693 3940}
c801d85f 3941
1e6feb95 3942void wxWindowGTK::WarpPointer( int x, int y )
4f22cf8d 3943{
82b978d7
RD
3944 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3945
3bcc8d15
RR
3946 // We provide this function ourselves as it is
3947 // missing in GDK (top of this file).
148cd9b6 3948
ed673c6a
RR
3949 GdkWindow *window = (GdkWindow*) NULL;
3950 if (m_wxwindow)
da048e3d 3951 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a
RR
3952 else
3953 window = GetConnectWidget()->window;
148cd9b6 3954
ed673c6a
RR
3955 if (window)
3956 gdk_window_warp_pointer( window, x, y );
4f22cf8d
RR
3957}
3958
3013a903 3959
1e6feb95 3960void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
c801d85f 3961{
a67f1484
VZ
3962 if (!m_widget)
3963 return;
3964 if (!m_widget->window)
3965 return;
2b5f62a0 3966
4e5a4c69 3967#ifndef __WXGTK20__
ea323db3
RR
3968 if (g_isIdle)
3969 wxapp_install_idle_handler();
2b5f62a0 3970
a67f1484 3971 wxRect myRect;
75625d79
SN
3972 if (m_wxwindow && rect)
3973 {
3974 myRect.SetSize(wxSize( m_wxwindow->allocation.width,
3975 m_wxwindow->allocation.height));
a67f1484
VZ
3976 if ( myRect.Intersect(*rect).IsEmpty() )
3977 {
75625d79
SN
3978 // nothing to do, rectangle is empty
3979 return;
a67f1484
VZ
3980 }
3981
75625d79
SN
3982 rect = &myRect;
3983 }
3984
a67f1484 3985 // schedule the area for later updating in GtkUpdate()
139adb6a 3986 if (eraseBackground && m_wxwindow && m_wxwindow->window)
c801d85f 3987 {
139adb6a
RR
3988 if (rect)
3989 {
3bcc8d15 3990 m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height );
139adb6a
RR
3991 }
3992 else
3993 {
3bcc8d15
RR
3994 m_clearRegion.Clear();
3995 m_clearRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
139adb6a
RR
3996 }
3997 }
ff8bfdbb 3998
3bcc8d15 3999 if (rect)
139adb6a
RR
4000 {
4001 if (m_wxwindow)
b02da6b1 4002 {
3bcc8d15 4003 m_updateRegion.Union( rect->x, rect->y, rect->width, rect->height );
b02da6b1 4004 }
ff8bfdbb 4005 else
b6fa52db 4006 {
3bcc8d15
RR
4007 GdkRectangle gdk_rect;
4008 gdk_rect.x = rect->x;
4009 gdk_rect.y = rect->y;
4010 gdk_rect.width = rect->width;
4011 gdk_rect.height = rect->height;
4012 gtk_widget_draw( m_widget, &gdk_rect );
b6fa52db 4013 }
362c6693 4014 }
c801d85f 4015 else
139adb6a 4016 {
139adb6a 4017 if (m_wxwindow)
b02da6b1 4018 {
3bcc8d15
RR
4019 m_updateRegion.Clear();
4020 m_updateRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
b02da6b1 4021 }
139adb6a 4022 else
b6fa52db 4023 {
3bcc8d15 4024 gtk_widget_draw( m_widget, (GdkRectangle*) NULL );
b6fa52db 4025 }
139adb6a 4026 }
a67f1484 4027#else // GTK+ 2
4e5a4c69
RR
4028 if (m_wxwindow)
4029 {
a67f1484
VZ
4030 GdkRectangle gdk_rect,
4031 *p;
4e5a4c69
RR
4032 if (rect)
4033 {
4e5a4c69
RR
4034 gdk_rect.x = rect->x;
4035 gdk_rect.y = rect->y;
4036 gdk_rect.width = rect->width;
4037 gdk_rect.height = rect->height;
a67f1484 4038 p = &gdk_rect;
4e5a4c69 4039 }
a67f1484 4040 else // invalidate everything
4e5a4c69 4041 {
a67f1484 4042 p = NULL;
4e5a4c69 4043 }
a67f1484
VZ
4044
4045 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow)->bin_window, p, TRUE );
4e5a4c69 4046 }
a67f1484 4047#endif // GTK+ 1/2
362c6693 4048}
c801d85f 4049
beab25bd 4050void wxWindowGTK::Update()
010afced
RR
4051{
4052 GtkUpdate();
1b965a9c
VZ
4053
4054 // when we call Update() we really want to update the window immediately on
90e572f1 4055 // screen, even if it means flushing the entire queue and hence slowing down
1b965a9c
VZ
4056 // everything -- but it should still be done, it's just that Update() should
4057 // be called very rarely
4058 gdk_flush();
010afced
RR
4059}
4060
4061void wxWindowGTK::GtkUpdate()
beab25bd 4062{
4e5a4c69
RR
4063#ifdef __WXGTK20__
4064 if (m_wxwindow && GTK_PIZZA(m_wxwindow)->bin_window)
4065 gdk_window_process_updates( GTK_PIZZA(m_wxwindow)->bin_window, FALSE );
b15ed747 4066#else
beab25bd 4067 if (!m_updateRegion.IsEmpty())
23716407 4068 GtkSendPaintEvents();
b15ed747 4069#endif
a67f1484
VZ
4070
4071 // for consistency with other platforms (and also because it's convenient
4072 // to be able to update an entire TLW by calling Update() only once), we
4073 // should also update all our children here
4074 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
4075 node;
4076 node = node->GetNext() )
4077 {
4078 node->GetData()->GtkUpdate();
4079 }
beab25bd
RR
4080}
4081
4082void wxWindowGTK::GtkSendPaintEvents()
4083{
3bcc8d15
RR
4084 if (!m_wxwindow)
4085 {
2b5f62a0 4086#ifndef __WXGTK20__
3bcc8d15 4087 m_clearRegion.Clear();
b15ed747 4088#endif
3bcc8d15
RR
4089 m_updateRegion.Clear();
4090 return;
4091 }
beab25bd 4092
f90566f5 4093 // Clip to paint region in wxClientDC
0a164d4c 4094 m_clipPaintRegion = true;
fab591c5 4095
b15ed747
RR
4096 // widget to draw on
4097 GtkPizza *pizza = GTK_PIZZA (m_wxwindow);
2b5f62a0 4098
aac97549 4099 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM))
f90566f5
RR
4100 {
4101 // find ancestor from which to steal background
cd5e74ba 4102 wxWindow *parent = wxGetTopLevelParent((wxWindow *)this);
f90566f5 4103 if (!parent)
cc06fe74 4104 parent = (wxWindow*)this;
2b5f62a0 4105
822cf31c 4106 if (GTK_WIDGET_MAPPED(parent->m_widget))
f90566f5 4107 {
822cf31c
KH
4108 wxRegionIterator upd( m_updateRegion );
4109 while (upd)
4110 {
4111 GdkRectangle rect;
4112 rect.x = upd.GetX();
4113 rect.y = upd.GetY();
4114 rect.width = upd.GetWidth();
4115 rect.height = upd.GetHeight();
4116
4117 gtk_paint_flat_box( parent->m_widget->style,
4118 pizza->bin_window,
4119 (GtkStateType)GTK_WIDGET_STATE(m_wxwindow),
4120 GTK_SHADOW_NONE,
4121 &rect,
4122 parent->m_widget,
4123 (char *)"base",
4124 0, 0, -1, -1 );
4125
60d8e886 4126 ++upd;
822cf31c 4127 }
f90566f5
RR
4128 }
4129 }
4130 else
b15ed747
RR
4131
4132#ifdef __WXGTK20__
4133 {
4134 wxWindowDC dc( (wxWindow*)this );
4135 dc.SetClippingRegion( m_updateRegion );
4136
4137 wxEraseEvent erase_event( GetId(), &dc );
4138 erase_event.SetEventObject( this );
4139
4140 GetEventHandler()->ProcessEvent(erase_event);
4141 }
4142#else
4143 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
beab25bd 4144 {
3bcc8d15 4145 wxWindowDC dc( (wxWindow*)this );
62cb3cd8
RR
4146 if (m_clearRegion.IsEmpty())
4147 dc.SetClippingRegion( m_updateRegion );
4148 else
4149 dc.SetClippingRegion( m_clearRegion );
0fc5dbf5 4150
3bcc8d15
RR
4151 wxEraseEvent erase_event( GetId(), &dc );
4152 erase_event.SetEventObject( this );
0fc5dbf5 4153
c7382f91 4154 if (!GetEventHandler()->ProcessEvent(erase_event) && GetBackgroundStyle() != wxBG_STYLE_CUSTOM)
beab25bd 4155 {
994bc575
RR
4156 if (!g_eraseGC)
4157 {
f90566f5 4158 g_eraseGC = gdk_gc_new( pizza->bin_window );
994bc575
RR
4159 gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4160 }
1cd3409d 4161 gdk_gc_set_foreground( g_eraseGC, GetBackgroundColour().GetColor() );
0fc5dbf5 4162
3bcc8d15 4163 wxRegionIterator upd( m_clearRegion );
beab25bd
RR
4164 while (upd)
4165 {
f90566f5
RR
4166 gdk_draw_rectangle( pizza->bin_window, g_eraseGC, 1,
4167 upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
beab25bd
RR
4168 upd ++;
4169 }
4170 }
3bcc8d15 4171 m_clearRegion.Clear();
beab25bd 4172 }
b15ed747 4173#endif
beab25bd
RR
4174
4175 wxNcPaintEvent nc_paint_event( GetId() );
4176 nc_paint_event.SetEventObject( this );
4177 GetEventHandler()->ProcessEvent( nc_paint_event );
4178
4179 wxPaintEvent paint_event( GetId() );
4180 paint_event.SetEventObject( this );
4181 GetEventHandler()->ProcessEvent( paint_event );
4182
0a164d4c 4183 m_clipPaintRegion = false;
c89f5c02 4184
4106cebb 4185#if !defined(__WXUNIVERSAL__) && !defined(__WXGTK20__)
8f3e7ecc 4186 // The following code will result in all window-less widgets
77ffb593 4187 // being redrawn because the wxWidgets class is allowed to
8f3e7ecc 4188 // paint over the window-less widgets.
0fc5dbf5 4189
8f3e7ecc
RR
4190 GList *children = pizza->children;
4191 while (children)
c89f5c02 4192 {
8f3e7ecc
RR
4193 GtkPizzaChild *child = (GtkPizzaChild*) children->data;
4194 children = children->next;
2b5f62a0 4195
8f3e7ecc
RR
4196 if (GTK_WIDGET_NO_WINDOW (child->widget) &&
4197 GTK_WIDGET_DRAWABLE (child->widget))
4198 {
4199 // Get intersection of widget area and update region
4200 wxRegion region( m_updateRegion );
0fc5dbf5 4201
8f3e7ecc
RR
4202 GdkEventExpose gdk_event;
4203 gdk_event.type = GDK_EXPOSE;
4204 gdk_event.window = pizza->bin_window;
4205 gdk_event.count = 0;
4106cebb 4206 gdk_event.send_event = TRUE;
0fc5dbf5 4207
8f3e7ecc
RR
4208 wxRegionIterator upd( m_updateRegion );
4209 while (upd)
c89f5c02 4210 {
8f3e7ecc
RR
4211 GdkRectangle rect;
4212 rect.x = upd.GetX();
4213 rect.y = upd.GetY();
4214 rect.width = upd.GetWidth();
4215 rect.height = upd.GetHeight();
0fc5dbf5 4216
8f3e7ecc
RR
4217 if (gtk_widget_intersect (child->widget, &rect, &gdk_event.area))
4218 {
4219 gtk_widget_event (child->widget, (GdkEvent*) &gdk_event);
4220 }
0fc5dbf5 4221
8f3e7ecc 4222 upd ++;
c89f5c02
RR
4223 }
4224 }
4225 }
4106cebb 4226#endif // native GTK 1
c89f5c02
RR
4227
4228 m_updateRegion.Clear();
beab25bd
RR
4229}
4230
596f1d11 4231void wxWindowGTK::ClearBackground()
c801d85f 4232{
82b978d7
RD
4233 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4234
b15ed747 4235#ifndef __WXGTK20__
f234c60c
RR
4236 if (m_wxwindow && m_wxwindow->window)
4237 {
d7fa7eaa
RR
4238 m_clearRegion.Clear();
4239 wxSize size( GetClientSize() );
4240 m_clearRegion.Union( 0,0,size.x,size.y );
2b5f62a0 4241
d7fa7eaa 4242 // Better do this in idle?
010afced 4243 GtkUpdate();
f234c60c 4244 }
b15ed747 4245#endif
362c6693 4246}
c801d85f 4247
ff8bfdbb 4248#if wxUSE_TOOLTIPS
1e6feb95 4249void wxWindowGTK::DoSetToolTip( wxToolTip *tip )
b1170810 4250{
f03fc89f 4251 wxWindowBase::DoSetToolTip(tip);
ff8bfdbb 4252
f03fc89f 4253 if (m_tooltip)
3379ed37 4254 m_tooltip->Apply( (wxWindow *)this );
b1170810
RR
4255}
4256
1e6feb95 4257void wxWindowGTK::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
b1170810 4258{
aa154cb1
RR
4259 wxString tmp( tip );
4260 gtk_tooltips_set_tip( tips, GetConnectWidget(), wxGTK_CONV(tmp), (gchar*) NULL );
301cd871 4261}
ff8bfdbb 4262#endif // wxUSE_TOOLTIPS
b1170810 4263
1e6feb95 4264bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
c801d85f 4265{
0a164d4c 4266 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
8bbe427f 4267
739730ca 4268 if (!wxWindowBase::SetBackgroundColour(colour))
44dfb5ce 4269 return false;
c50f1fb9 4270
5edef14e 4271 if (colour.Ok())
994bc575 4272 {
5edef14e
VS
4273 // We need the pixel value e.g. for background clearing.
4274 m_backgroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
994bc575 4275 }
ca298c88 4276
5edef14e 4277 // apply style change (forceStyle=true so that new style is applied
c7382f91
JS
4278 // even if the bg colour changed from valid to wxNullColour)
4279 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM)
4280 ApplyWidgetStyle(true);
ea323db3 4281
5edef14e 4282 return true;
6de97a3b
RR
4283}
4284
1e6feb95 4285bool wxWindowGTK::SetForegroundColour( const wxColour &colour )
6de97a3b 4286{
0a164d4c 4287 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
8bbe427f 4288
739730ca
RR
4289 if (!wxWindowBase::SetForegroundColour(colour))
4290 {
5edef14e 4291 return false;
739730ca 4292 }
0a164d4c 4293
5edef14e 4294 if (colour.Ok())
ea323db3 4295 {
5edef14e
VS
4296 // We need the pixel value e.g. for background clearing.
4297 m_foregroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
ea323db3 4298 }
f03fc89f 4299
5edef14e
VS
4300 // apply style change (forceStyle=true so that new style is applied
4301 // even if the bg colour changed from valid to wxNullColour):
4302 ApplyWidgetStyle(true);
4303
44dfb5ce 4304 return true;
58614078
RR
4305}
4306
2b5f62a0
VZ
4307#ifdef __WXGTK20__
4308PangoContext *wxWindowGTK::GtkGetPangoDefaultContext()
4309{
4310 return gtk_widget_get_pango_context( m_widget );
4311}
2b5f62a0 4312#endif
0a164d4c 4313
5edef14e 4314GtkRcStyle *wxWindowGTK::CreateWidgetStyle(bool forceStyle)
58614078 4315{
f40fdaa3 4316 // do we need to apply any changes at all?
5edef14e 4317 if ( !forceStyle &&
984e8d0b
VS
4318 !m_font.Ok() &&
4319 !m_foregroundColour.Ok() && !m_backgroundColour.Ok() )
fb65642c 4320 {
f40fdaa3 4321 return NULL;
fb65642c
RR
4322 }
4323
f40fdaa3 4324 GtkRcStyle *style = gtk_rc_style_new();
1ecc4d80 4325
984e8d0b 4326 if ( m_font.Ok() )
db434467 4327 {
288059b2 4328#ifdef __WXGTK20__
0a164d4c 4329 style->font_desc =
f40fdaa3 4330 pango_font_description_copy( m_font.GetNativeFontInfo()->description );
288059b2 4331#else
f40fdaa3
VS
4332 wxString xfontname = m_font.GetNativeFontInfo()->GetXFontName();
4333 style->fontset_name = g_strdup(xfontname.c_str());
cfcc3932 4334#endif
288059b2 4335 }
1ecc4d80 4336
fe161a26 4337 if ( m_foregroundColour.Ok() )
1ecc4d80 4338 {
5edef14e 4339 GdkColor *fg = m_foregroundColour.GetColor();
0a164d4c 4340
5edef14e 4341 style->fg[GTK_STATE_NORMAL] = *fg;
f40fdaa3 4342 style->color_flags[GTK_STATE_NORMAL] = GTK_RC_FG;
0a164d4c 4343
5edef14e 4344 style->fg[GTK_STATE_PRELIGHT] = *fg;
f40fdaa3 4345 style->color_flags[GTK_STATE_PRELIGHT] = GTK_RC_FG;
0a164d4c 4346
5edef14e 4347 style->fg[GTK_STATE_ACTIVE] = *fg;
f40fdaa3 4348 style->color_flags[GTK_STATE_ACTIVE] = GTK_RC_FG;
1ecc4d80
RR
4349 }
4350
fe161a26 4351 if ( m_backgroundColour.Ok() )
1ecc4d80 4352 {
5edef14e
VS
4353 GdkColor *bg = m_backgroundColour.GetColor();
4354
4355 style->bg[GTK_STATE_NORMAL] = *bg;
4356 style->base[GTK_STATE_NORMAL] = *bg;
f40fdaa3
VS
4357 style->color_flags[GTK_STATE_NORMAL] = (GtkRcFlags)
4358 (style->color_flags[GTK_STATE_NORMAL] | GTK_RC_BG | GTK_RC_BASE);
0a164d4c 4359
5edef14e
VS
4360 style->bg[GTK_STATE_PRELIGHT] = *bg;
4361 style->base[GTK_STATE_PRELIGHT] = *bg;
f40fdaa3
VS
4362 style->color_flags[GTK_STATE_PRELIGHT] = (GtkRcFlags)
4363 (style->color_flags[GTK_STATE_PRELIGHT] | GTK_RC_BG | GTK_RC_BASE);
0a164d4c 4364
5edef14e
VS
4365 style->bg[GTK_STATE_ACTIVE] = *bg;
4366 style->base[GTK_STATE_ACTIVE] = *bg;
f40fdaa3
VS
4367 style->color_flags[GTK_STATE_ACTIVE] = (GtkRcFlags)
4368 (style->color_flags[GTK_STATE_ACTIVE] | GTK_RC_BG | GTK_RC_BASE);
0a164d4c 4369
5edef14e
VS
4370 style->bg[GTK_STATE_INSENSITIVE] = *bg;
4371 style->base[GTK_STATE_INSENSITIVE] = *bg;
f40fdaa3
VS
4372 style->color_flags[GTK_STATE_INSENSITIVE] = (GtkRcFlags)
4373 (style->color_flags[GTK_STATE_INSENSITIVE] | GTK_RC_BG | GTK_RC_BASE);
1ecc4d80 4374 }
0a164d4c 4375
f40fdaa3 4376 return style;
a81258be
RR
4377}
4378
f8e045e2 4379void wxWindowGTK::ApplyWidgetStyle(bool forceStyle)
a81258be 4380{
f8e045e2
RD
4381 GtkRcStyle *style = CreateWidgetStyle(forceStyle);
4382 if ( style )
4383 {
7074ce35 4384 DoApplyWidgetStyle(style);
f8e045e2
RD
4385 gtk_rc_style_unref(style);
4386 }
6dd18972
VS
4387
4388 // Style change may affect GTK+'s size calculation:
4389 InvalidateBestSize();
6de97a3b
RR
4390}
4391
7074ce35
VS
4392void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle *style)
4393{
4394 if (m_wxwindow)
7074ce35 4395 gtk_widget_modify_style(m_wxwindow, style);
7cb93e45
RR
4396 else
4397 gtk_widget_modify_style(m_widget, style);
7074ce35
VS
4398}
4399
c7382f91
JS
4400bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style)
4401{
4402 wxWindowBase::SetBackgroundStyle(style);
0a164d4c 4403
c7382f91
JS
4404 if (style == wxBG_STYLE_CUSTOM)
4405 {
4406 GdkWindow *window = (GdkWindow*) NULL;
4407 if (m_wxwindow)
4408 window = GTK_PIZZA(m_wxwindow)->bin_window;
4409 else
4410 window = GetConnectWidget()->window;
4411
4412 if (window)
4413 {
4414 // Make sure GDK/X11 doesn't refresh the window
4415 // automatically.
4416 gdk_window_set_back_pixmap( window, None, False );
4417#ifdef __X__
4418 Display* display = GDK_WINDOW_DISPLAY(window);
4419 XFlush(display);
4420#endif
4421 m_needsStyleChange = false;
4422 }
4423 else
4424 // Do in OnIdle, because the window is not yet available
4425 m_needsStyleChange = true;
0a164d4c 4426
c7382f91
JS
4427 // Don't apply widget style, or we get a grey background
4428 }
4429 else
4430 {
4431 // apply style change (forceStyle=true so that new style is applied
4432 // even if the bg colour changed from valid to wxNullColour):
4433 ApplyWidgetStyle(true);
4434 }
4435 return true;
4436}
7074ce35 4437
06cfab17 4438#if wxUSE_DRAG_AND_DROP
ac57418f 4439
1e6feb95 4440void wxWindowGTK::SetDropTarget( wxDropTarget *dropTarget )
c801d85f 4441{
82b978d7
RD
4442 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4443
1ecc4d80 4444 GtkWidget *dnd_widget = GetConnectWidget();
47d67540 4445
1ecc4d80 4446 if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
47d67540 4447
1ecc4d80
RR
4448 if (m_dropTarget) delete m_dropTarget;
4449 m_dropTarget = dropTarget;
47d67540 4450
1ecc4d80 4451 if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
362c6693 4452}
c801d85f 4453
f03fc89f 4454#endif // wxUSE_DRAG_AND_DROP
ac57418f 4455
1e6feb95 4456GtkWidget* wxWindowGTK::GetConnectWidget()
e3e65dac 4457{
1ecc4d80
RR
4458 GtkWidget *connect_widget = m_widget;
4459 if (m_wxwindow) connect_widget = m_wxwindow;
47d67540 4460
1ecc4d80 4461 return connect_widget;
e3e65dac 4462}
47d67540 4463
1e6feb95 4464bool wxWindowGTK::IsOwnGtkWindow( GdkWindow *window )
903f689b 4465{
148cd9b6 4466 if (m_wxwindow)
da048e3d 4467 return (window == GTK_PIZZA(m_wxwindow)->bin_window);
148cd9b6 4468
1ecc4d80 4469 return (window == m_widget->window);
903f689b
RR
4470}
4471
1e6feb95 4472bool wxWindowGTK::SetFont( const wxFont &font )
c801d85f 4473{
0a164d4c 4474 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
9c288e4d 4475
5edef14e
VS
4476 if (!wxWindowBase::SetFont(font))
4477 return false;
c801d85f 4478
5edef14e
VS
4479 // apply style change (forceStyle=true so that new style is applied
4480 // even if the font changed from valid to wxNullFont):
0a164d4c 4481 ApplyWidgetStyle(true);
5edef14e
VS
4482
4483 return true;
362c6693 4484}
c801d85f 4485
94633ad9 4486void wxWindowGTK::DoCaptureMouse()
c801d85f 4487{
82b978d7
RD
4488 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4489
ed673c6a 4490 GdkWindow *window = (GdkWindow*) NULL;
b231914f
VZ
4491 if (m_wxwindow)
4492 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a 4493 else
b231914f 4494 window = GetConnectWidget()->window;
148cd9b6 4495
e4606ed9 4496 wxCHECK_RET( window, _T("CaptureMouse() failed") );
c50f1fb9 4497
b231914f 4498 wxCursor* cursor = & m_cursor;
cca602ac
JS
4499 if (!cursor->Ok())
4500 cursor = wxSTANDARD_CURSOR;
4501
ed673c6a 4502 gdk_pointer_grab( window, FALSE,
1ecc4d80
RR
4503 (GdkEventMask)
4504 (GDK_BUTTON_PRESS_MASK |
4505 GDK_BUTTON_RELEASE_MASK |
148cd9b6 4506 GDK_POINTER_MOTION_HINT_MASK |
1ecc4d80 4507 GDK_POINTER_MOTION_MASK),
ff8bfdbb 4508 (GdkWindow *) NULL,
cca602ac 4509 cursor->GetCursor(),
b02da6b1 4510 (guint32)GDK_CURRENT_TIME );
b231914f 4511 g_captureWindow = this;
0a164d4c 4512 g_captureWindowHasMouse = true;
362c6693 4513}
c801d85f 4514
94633ad9 4515void wxWindowGTK::DoReleaseMouse()
c801d85f 4516{
82b978d7
RD
4517 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4518
e4606ed9 4519 wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") );
47d67540 4520
c43430bb
VS
4521 g_captureWindow = (wxWindowGTK*) NULL;
4522
ed673c6a 4523 GdkWindow *window = (GdkWindow*) NULL;
b231914f
VZ
4524 if (m_wxwindow)
4525 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a 4526 else
b231914f 4527 window = GetConnectWidget()->window;
148cd9b6 4528
b02da6b1
VZ
4529 if (!window)
4530 return;
c50f1fb9 4531
b02da6b1 4532 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
362c6693 4533}
c801d85f 4534
1e6feb95
VZ
4535/* static */
4536wxWindow *wxWindowBase::GetCapture()
4537{
4538 return (wxWindow *)g_captureWindow;
4539}
4540
4541bool wxWindowGTK::IsRetained() const
c801d85f 4542{
0a164d4c 4543 return false;
362c6693 4544}
c801d85f 4545
1e6feb95 4546void wxWindowGTK::SetScrollbar( int orient, int pos, int thumbVisible,
cb43b372 4547 int range, bool refresh )
c801d85f 4548{
82b978d7
RD
4549 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4550
223d09f6 4551 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
c801d85f 4552
0a164d4c 4553 m_hasScrolling = true;
47d67540 4554
1ecc4d80 4555 if (orient == wxHORIZONTAL)
cb43b372 4556 {
1ecc4d80
RR
4557 float fpos = (float)pos;
4558 float frange = (float)range;
4559 float fthumb = (float)thumbVisible;
4560 if (fpos > frange-fthumb) fpos = frange-fthumb;
4561 if (fpos < 0.0) fpos = 0.0;
4562
4563 if ((fabs(frange-m_hAdjust->upper) < 0.2) &&
4564 (fabs(fthumb-m_hAdjust->page_size) < 0.2))
4565 {
4566 SetScrollPos( orient, pos, refresh );
4567 return;
4568 }
47d67540 4569
1ecc4d80 4570 m_oldHorizontalPos = fpos;
47d67540 4571
1ecc4d80
RR
4572 m_hAdjust->lower = 0.0;
4573 m_hAdjust->upper = frange;
4574 m_hAdjust->value = fpos;
4575 m_hAdjust->step_increment = 1.0;
4576 m_hAdjust->page_increment = (float)(wxMax(fthumb,0));
4577 m_hAdjust->page_size = fthumb;
cb43b372 4578 }
1ecc4d80
RR
4579 else
4580 {
4581 float fpos = (float)pos;
4582 float frange = (float)range;
4583 float fthumb = (float)thumbVisible;
4584 if (fpos > frange-fthumb) fpos = frange-fthumb;
4585 if (fpos < 0.0) fpos = 0.0;
4586
4587 if ((fabs(frange-m_vAdjust->upper) < 0.2) &&
4588 (fabs(fthumb-m_vAdjust->page_size) < 0.2))
4589 {
4590 SetScrollPos( orient, pos, refresh );
4591 return;
4592 }
47d67540 4593
1ecc4d80 4594 m_oldVerticalPos = fpos;
47d67540 4595
1ecc4d80
RR
4596 m_vAdjust->lower = 0.0;
4597 m_vAdjust->upper = frange;
4598 m_vAdjust->value = fpos;
4599 m_vAdjust->step_increment = 1.0;
4600 m_vAdjust->page_increment = (float)(wxMax(fthumb,0));
4601 m_vAdjust->page_size = fthumb;
4602 }
47d67540 4603
eb082a08
RR
4604 if (orient == wxHORIZONTAL)
4605 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
4606 else
4607 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
362c6693 4608}
c801d85f 4609
87a3ebe9
VZ
4610void wxWindowGTK::GtkUpdateScrollbar(int orient)
4611{
4612 GtkAdjustment *adj = orient == wxHORIZONTAL ? m_hAdjust : m_vAdjust;
4613 GtkSignalFunc fn = orient == wxHORIZONTAL
4614 ? (GtkSignalFunc)gtk_window_hscroll_callback
4615 : (GtkSignalFunc)gtk_window_vscroll_callback;
4616
4617 gtk_signal_disconnect_by_func(GTK_OBJECT(adj), fn, (gpointer)this);
4618 gtk_signal_emit_by_name(GTK_OBJECT(adj), "value_changed");
4619 gtk_signal_connect(GTK_OBJECT(adj), "value_changed", fn, (gpointer)this);
4620}
4621
1e6feb95 4622void wxWindowGTK::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
c801d85f 4623{
82b978d7 4624 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
223d09f6 4625 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
1ecc4d80 4626
87a3ebe9 4627 GtkAdjustment *adj = orient == wxHORIZONTAL ? m_hAdjust : m_vAdjust;
1ecc4d80 4628
87a3ebe9
VZ
4629 float fpos = (float)pos;
4630 if (fpos > adj->upper - adj->page_size)
4631 fpos = adj->upper - adj->page_size;
4632 if (fpos < 0.0)
4633 fpos = 0.0;
4634 *(orient == wxHORIZONTAL ? &m_oldHorizontalPos : &m_oldVerticalPos) = fpos;
ff8bfdbb 4635
87a3ebe9
VZ
4636 if (fabs(fpos-adj->value) < 0.2)
4637 return;
4638 adj->value = fpos;
47d67540 4639
87a3ebe9 4640 if ( m_wxwindow->window )
47d67540 4641 {
cb43b372 4642 }
362c6693 4643}
c801d85f 4644
1e6feb95 4645int wxWindowGTK::GetScrollThumb( int orient ) const
c801d85f 4646{
82b978d7
RD
4647 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
4648
223d09f6 4649 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
47d67540 4650
1ecc4d80
RR
4651 if (orient == wxHORIZONTAL)
4652 return (int)(m_hAdjust->page_size+0.5);
4653 else
4654 return (int)(m_vAdjust->page_size+0.5);
362c6693 4655}
c801d85f 4656
1e6feb95 4657int wxWindowGTK::GetScrollPos( int orient ) const
c801d85f 4658{
82b978d7 4659 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
47d67540 4660
223d09f6 4661 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
c801d85f 4662
1ecc4d80
RR
4663 if (orient == wxHORIZONTAL)
4664 return (int)(m_hAdjust->value+0.5);
4665 else
4666 return (int)(m_vAdjust->value+0.5);
362c6693 4667}
c801d85f 4668
1e6feb95 4669int wxWindowGTK::GetScrollRange( int orient ) const
c801d85f 4670{
82b978d7 4671 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
47d67540 4672
223d09f6 4673 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
c801d85f 4674
1ecc4d80
RR
4675 if (orient == wxHORIZONTAL)
4676 return (int)(m_hAdjust->upper+0.5);
4677 else
4678 return (int)(m_vAdjust->upper+0.5);
362c6693 4679}
c801d85f 4680
1e6feb95 4681void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
c801d85f 4682{
82b978d7
RD
4683 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4684
223d09f6 4685 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
2b5f62a0 4686
f47ae6e7 4687 // No scrolling requested.
8e217128 4688 if ((dx == 0) && (dy == 0)) return;
0fc5dbf5 4689
4e5a4c69 4690#ifndef __WXGTK20__
35917d22
RR
4691 if (!m_updateRegion.IsEmpty())
4692 {
4693 m_updateRegion.Offset( dx, dy );
0fc5dbf5 4694
35917d22
RR
4695 int cw = 0;
4696 int ch = 0;
4697 GetClientSize( &cw, &ch );
4698 m_updateRegion.Intersect( 0, 0, cw, ch );
4699 }
0fc5dbf5 4700
3bcc8d15
RR
4701 if (!m_clearRegion.IsEmpty())
4702 {
4703 m_clearRegion.Offset( dx, dy );
0fc5dbf5 4704
3bcc8d15
RR
4705 int cw = 0;
4706 int ch = 0;
4707 GetClientSize( &cw, &ch );
4708 m_clearRegion.Intersect( 0, 0, cw, ch );
4709 }
3fc6e5fa
RR
4710#endif
4711
0a164d4c 4712 m_clipPaintRegion = true;
0fc5dbf5 4713
da048e3d 4714 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
0fc5dbf5 4715
0a164d4c 4716 m_clipPaintRegion = false;
c801d85f 4717}
3723b7b1 4718
015dca24
MR
4719void wxWindowGTK::SetWindowStyleFlag( long style )
4720{
4721 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4722 wxWindowBase::SetWindowStyleFlag(style);
4723}
4e5a4c69 4724
3723b7b1
JS
4725// Find the wxWindow at the current mouse position, also returning the mouse
4726// position.
4727wxWindow* wxFindWindowAtPointer(wxPoint& pt)
4728{
59a12e90
JS
4729 pt = wxGetMousePosition();
4730 wxWindow* found = wxFindWindowAtPoint(pt);
4731 return found;
3723b7b1
JS
4732}
4733
4734// Get the current mouse position.
4735wxPoint wxGetMousePosition()
4736{
59a12e90
JS
4737 /* This crashes when used within wxHelpContext,
4738 so we have to use the X-specific implementation below.
4739 gint x, y;
4740 GdkModifierType *mask;
4741 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4742
4743 return wxPoint(x, y);
4744 */
4745
3723b7b1
JS
4746 int x, y;
4747 GdkWindow* windowAtPtr = gdk_window_at_pointer(& x, & y);
59a12e90 4748
37d81cc2 4749 Display *display = windowAtPtr ? GDK_WINDOW_XDISPLAY(windowAtPtr) : GDK_DISPLAY();
59a12e90
JS
4750 Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
4751 Window rootReturn, childReturn;
4752 int rootX, rootY, winX, winY;
4753 unsigned int maskReturn;
4754
4755 XQueryPointer (display,
5cd09f0b
RR
4756 rootWindow,
4757 &rootReturn,
59a12e90
JS
4758 &childReturn,
4759 &rootX, &rootY, &winX, &winY, &maskReturn);
4760 return wxPoint(rootX, rootY);
4761
3723b7b1
JS
4762}
4763
224016a8
JS
4764// Needed for implementing e.g. combobox on wxGTK within a modal dialog.
4765void wxAddGrab(wxWindow* window)
4766{
4767 gtk_grab_add( (GtkWidget*) window->GetHandle() );
4768}
4769
4770void wxRemoveGrab(wxWindow* window)
4771{
4772 gtk_grab_remove( (GtkWidget*) window->GetHandle() );
4773}
4774
4e5a4c69 4775// ----------------------------------------------------------------------------
224016a8 4776// wxWinModule
4e5a4c69
RR
4777// ----------------------------------------------------------------------------
4778
4779class wxWinModule : public wxModule
4780{
4781public:
4782 bool OnInit();
4783 void OnExit();
4784
4785private:
4786 DECLARE_DYNAMIC_CLASS(wxWinModule)
4787};
4788
4789IMPLEMENT_DYNAMIC_CLASS(wxWinModule, wxModule)
4790
4791bool wxWinModule::OnInit()
4792{
994bc575
RR
4793 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4794 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
0fc5dbf5 4795
0a164d4c 4796 return true;
4e5a4c69
RR
4797}
4798
4799void wxWinModule::OnExit()
4800{
994bc575
RR
4801 if (g_eraseGC)
4802 gdk_gc_unref( g_eraseGC );
4e5a4c69
RR
4803}
4804