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