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