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