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