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