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