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