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