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