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