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