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