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