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