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