]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/window.cpp
fixes SetFirstItem, Thanks to David Wright
[wxWidgets.git] / src / gtk / window.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
faa94f3e 2// Name: src/gtk/window.cpp
9a33c3ef 3// Purpose: wxWindowGTK implementation
c801d85f 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"
cca410b3 22 #include "wx/toplevel.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"
18680f86 27 #include "wx/math.h"
88a7a4e1
WS
28#endif
29
bfeeb7f3
PC
30#include "wx/dnd.h"
31#include "wx/tooltip.h"
32#include "wx/caret.h"
48d011c8 33#include "wx/fontutil.h"
8ab7b4c5 34#include "wx/sysopt.h"
b4071e91 35
fab591c5 36#include <ctype.h>
c801d85f 37
9e691f46 38#include "wx/gtk/private.h"
bbd92d1d 39#include "wx/gtk/private/win_gtk.h"
4a99d597
VS
40#include "wx/gtk/private/event.h"
41using namespace wxGTKImpl;
14b44999 42
3b81515c 43#ifdef GDK_WINDOWING_X11
3ac8d3bc 44#include <gdk/gdkx.h>
25cc08c0 45#include "wx/x11/private/wrapxkb.h"
3b81515c
VZ
46#else
47typedef guint KeySym;
48#endif
6bc8a1c8 49
14b44999
VS
50#include <gdk/gdkkeysyms.h>
51#if GTK_CHECK_VERSION(3,0,0)
52#include <gdk/gdkkeysyms-compat.h>
53#endif
54
14421681
VZ
55// gdk_window_set_composited() is only supported since 2.12
56#define wxGTK_VERSION_REQUIRED_FOR_COMPOSITING 2,12,0
57#define wxGTK_HAS_COMPOSITING_SUPPORT GTK_CHECK_VERSION(2,12,0)
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
08f53168
PC
119 it has to handle the client area widget (of the type wxPizza, defined in
120 win_gtk.cpp), but there could be any number of widgets, handled by a class.
8bbe427f
VZ
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
08f53168 125 the type wxPizza.
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-
08f53168 131 Window and a m_wxwindow field that is pointer to a wxPizza 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()
08f53168 145 which actually moves the window and its sub-windows. Note that wxPizza
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
08f53168 148 in various places using the pizza->m_scroll_x and pizza->m_scroll_y 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
c2246a38
RR
179 for the parent. To prevent this from doing too much harm, SetCursor calls
180 GTKUpdateCursor, which will recursively re-set the cursors of all child windows.
30760ce7
RR
181 Also don't forget that cursors (like much else) are connected to GdkWindows,
182 not GtkWidgets and that the "window" field of a GtkWidget might very well
90e572f1 183 point to the GdkWindow of the parent widget (-> "window-less widget") and
30760ce7 184 that the two obviously have very different meanings.
868a2826
RR
185*/
186
f03fc89f
VZ
187//-----------------------------------------------------------------------------
188// data
189//-----------------------------------------------------------------------------
190
b541538f
PC
191// Don't allow event propagation during drag
192bool g_blockEventsOnDrag;
193// Don't allow mouse event propagation during scroll
194bool g_blockEventsOnScroll;
238d735d 195extern wxCursor g_globalCursor;
f68586e5 196
1e6feb95
VZ
197// mouse capture state: the window which has it and if the mouse is currently
198// inside it
d3b9f782 199static wxWindowGTK *g_captureWindow = NULL;
0a164d4c 200static bool g_captureWindowHasMouse = false;
1e6feb95 201
22f43cb5
VS
202// The window that currently has focus:
203static wxWindowGTK *gs_currentFocus = NULL;
204// The window that is scheduled to get focus in the next event loop iteration
205// or NULL if there's no pending focus change:
206static wxWindowGTK *gs_pendingFocus = NULL;
1e6feb95 207
bd2e08d0
VS
208// the window that has deferred focus-out event pending, if any (see
209// GTKAddDeferredFocusOut() for details)
210static wxWindowGTK *gs_deferredFocusOut = NULL;
d7fa7eaa 211
5e513780
RR
212// global variables because GTK+ DnD want to have the
213// mouse event that caused it
d3b9f782 214GdkEvent *g_lastMouseEvent = NULL;
5e513780 215int g_lastButtonNumber = 0;
8f9850dd 216
2e563988
RR
217//-----------------------------------------------------------------------------
218// debug
219//-----------------------------------------------------------------------------
220
6cad4f1b 221// the trace mask used for the focus debugging messages
9a83f860 222#define TRACE_FOCUS wxT("focus")
6cad4f1b 223
47c93b63
RR
224//-----------------------------------------------------------------------------
225// "size_request" of m_widget
226//-----------------------------------------------------------------------------
227
865bb325 228extern "C" {
9800347d
FM
229static void
230wxgtk_window_size_request_callback(GtkWidget * WXUNUSED(widget),
231 GtkRequisition *requisition,
232 wxWindow * win)
47c93b63 233{
e1f448ee 234 int w, h;
47c93b63 235 win->GetSize( &w, &h );
e1f448ee
VZ
236 if (w < 2)
237 w = 2;
238 if (h < 2)
239 h = 2;
1e6feb95 240
47c93b63
RR
241 requisition->height = h;
242 requisition->width = w;
243}
865bb325 244}
47c93b63 245
c801d85f 246//-----------------------------------------------------------------------------
034be888 247// "expose_event" of m_wxwindow
c801d85f
KB
248//-----------------------------------------------------------------------------
249
865bb325 250extern "C" {
7f7beb1d 251static gboolean
f089940f 252gtk_window_expose_callback( GtkWidget*,
7f7beb1d
MR
253 GdkEventExpose *gdk_event,
254 wxWindow *win )
47d67540 255{
f089940f 256 if (gdk_event->window == win->GTKGetDrawingWindow())
3d2d8da1 257 {
8d49fda6
PC
258 win->GetUpdateRegion() = wxRegion( gdk_event->region );
259 win->GtkSendPaintEvents();
3d2d8da1 260 }
90e572f1 261 // Let parent window draw window-less widgets
2109c024 262 return FALSE;
b6fa52db 263}
865bb325 264}
b6fa52db 265
75f661bb 266#ifndef __WXUNIVERSAL__
08f53168 267//-----------------------------------------------------------------------------
75f661bb 268// "expose_event" from m_wxwindow->parent, for drawing border
08f53168
PC
269//-----------------------------------------------------------------------------
270
08f53168
PC
271extern "C" {
272static gboolean
6de67633 273expose_event_border(GtkWidget* widget, GdkEventExpose* gdk_event, wxWindow* win)
08f53168 274{
f089940f 275 if (gdk_event->window != gtk_widget_get_parent_window(win->m_wxwindow))
75f661bb
PC
276 return false;
277
6e7cf3bd
PC
278 if (!win->IsShown())
279 return false;
280
989d151c
PC
281 GtkAllocation alloc;
282 gtk_widget_get_allocation(win->m_wxwindow, &alloc);
75f661bb
PC
283 const int x = alloc.x;
284 const int y = alloc.y;
285 const int w = alloc.width;
286 const int h = alloc.height;
287
288 if (w <= 0 || h <= 0)
08f53168
PC
289 return false;
290
08f53168
PC
291 if (win->HasFlag(wxBORDER_SIMPLE))
292 {
830910cc 293 gdk_draw_rectangle(gdk_event->window,
08f09504 294 gtk_widget_get_style(widget)->black_gc, false, x, y, w - 1, h - 1);
08f53168
PC
295 }
296 else
297 {
298 GtkShadowType shadow = GTK_SHADOW_IN;
299 if (win->HasFlag(wxBORDER_RAISED))
300 shadow = GTK_SHADOW_OUT;
03eaa52a
PC
301
302 // Style detail to use
303 const char* detail;
75f661bb 304 if (win->m_widget == win->m_wxwindow)
03eaa52a
PC
305 // for non-scrollable wxWindows
306 detail = "entry";
307 else
308 // for scrollable ones
309 detail = "viewport";
310
4f4f76de
PC
311 // clip rect is required to avoid painting background
312 // over upper left (w,h) of parent window
313 GdkRectangle clipRect = { x, y, w, h };
08f53168 314 gtk_paint_shadow(
08f09504 315 gtk_widget_get_style(win->m_wxwindow), gdk_event->window, GTK_STATE_NORMAL,
4f4f76de 316 shadow, &clipRect, wxGTKPrivate::GetEntryWidget(), detail, x, y, w, h);
08f53168 317 }
75f661bb
PC
318 return false;
319}
320}
321
322//-----------------------------------------------------------------------------
323// "parent_set" from m_wxwindow
324//-----------------------------------------------------------------------------
08f53168 325
75f661bb
PC
326extern "C" {
327static void
cb0c51ac 328parent_set(GtkWidget* widget, GtkWidget* old_parent, wxWindow* win)
75f661bb
PC
329{
330 if (old_parent)
331 {
332 g_signal_handlers_disconnect_by_func(
333 old_parent, (void*)expose_event_border, win);
334 }
08f09504
PC
335 GtkWidget* parent = gtk_widget_get_parent(widget);
336 if (parent)
75f661bb 337 {
08f09504 338 g_signal_connect_after(parent, "expose_event",
75f661bb
PC
339 G_CALLBACK(expose_event_border), win);
340 }
08f53168
PC
341}
342}
343#endif // !__WXUNIVERSAL__
344
c801d85f 345//-----------------------------------------------------------------------------
b292e2f5 346// "key_press_event" from any window
c801d85f 347//-----------------------------------------------------------------------------
c801d85f 348
74710601 349// set WXTRACE to this to see the key event codes on the console
9a83f860 350#define TRACE_KEYS wxT("keyevent")
f17393f1 351
1c6896d7
VZ
352// translates an X key symbol to WXK_XXX value
353//
354// if isChar is true it means that the value returned will be used for EVT_CHAR
355// event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
356// for example, while if it is false it means that the value is going to be
357// used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
358// WXK_NUMPAD_DIVIDE
359static long wxTranslateKeySymToWXKey(KeySym keysym, bool isChar)
360{
361 long key_code;
362
363 switch ( keysym )
364 {
365 // Shift, Control and Alt don't generate the CHAR events at all
366 case GDK_Shift_L:
367 case GDK_Shift_R:
368 key_code = isChar ? 0 : WXK_SHIFT;
369 break;
370 case GDK_Control_L:
371 case GDK_Control_R:
372 key_code = isChar ? 0 : WXK_CONTROL;
373 break;
374 case GDK_Meta_L:
375 case GDK_Meta_R:
376 case GDK_Alt_L:
377 case GDK_Alt_R:
378 case GDK_Super_L:
379 case GDK_Super_R:
380 key_code = isChar ? 0 : WXK_ALT;
381 break;
382
383 // neither do the toggle modifies
384 case GDK_Scroll_Lock:
385 key_code = isChar ? 0 : WXK_SCROLL;
386 break;
387
388 case GDK_Caps_Lock:
389 key_code = isChar ? 0 : WXK_CAPITAL;
390 break;
391
392 case GDK_Num_Lock:
393 key_code = isChar ? 0 : WXK_NUMLOCK;
394 break;
395
396
397 // various other special keys
398 case GDK_Menu:
399 key_code = WXK_MENU;
400 break;
401
402 case GDK_Help:
403 key_code = WXK_HELP;
404 break;
405
406 case GDK_BackSpace:
407 key_code = WXK_BACK;
408 break;
409
410 case GDK_ISO_Left_Tab:
411 case GDK_Tab:
412 key_code = WXK_TAB;
413 break;
414
415 case GDK_Linefeed:
416 case GDK_Return:
417 key_code = WXK_RETURN;
418 break;
419
420 case GDK_Clear:
421 key_code = WXK_CLEAR;
422 break;
423
424 case GDK_Pause:
425 key_code = WXK_PAUSE;
426 break;
427
428 case GDK_Select:
429 key_code = WXK_SELECT;
430 break;
431
432 case GDK_Print:
433 key_code = WXK_PRINT;
434 break;
435
436 case GDK_Execute:
437 key_code = WXK_EXECUTE;
438 break;
439
440 case GDK_Escape:
441 key_code = WXK_ESCAPE;
442 break;
443
444 // cursor and other extended keyboard keys
445 case GDK_Delete:
446 key_code = WXK_DELETE;
447 break;
448
449 case GDK_Home:
450 key_code = WXK_HOME;
451 break;
452
453 case GDK_Left:
454 key_code = WXK_LEFT;
455 break;
456
457 case GDK_Up:
458 key_code = WXK_UP;
459 break;
460
461 case GDK_Right:
462 key_code = WXK_RIGHT;
463 break;
464
465 case GDK_Down:
466 key_code = WXK_DOWN;
467 break;
468
469 case GDK_Prior: // == GDK_Page_Up
faa94f3e 470 key_code = WXK_PAGEUP;
1c6896d7
VZ
471 break;
472
473 case GDK_Next: // == GDK_Page_Down
faa94f3e 474 key_code = WXK_PAGEDOWN;
1c6896d7
VZ
475 break;
476
477 case GDK_End:
478 key_code = WXK_END;
479 break;
480
481 case GDK_Begin:
482 key_code = WXK_HOME;
483 break;
484
485 case GDK_Insert:
486 key_code = WXK_INSERT;
487 break;
488
489
490 // numpad keys
491 case GDK_KP_0:
492 case GDK_KP_1:
493 case GDK_KP_2:
494 case GDK_KP_3:
495 case GDK_KP_4:
496 case GDK_KP_5:
497 case GDK_KP_6:
498 case GDK_KP_7:
499 case GDK_KP_8:
500 case GDK_KP_9:
2a230426 501 key_code = (isChar ? '0' : int(WXK_NUMPAD0)) + keysym - GDK_KP_0;
1c6896d7
VZ
502 break;
503
504 case GDK_KP_Space:
2a230426 505 key_code = isChar ? ' ' : int(WXK_NUMPAD_SPACE);
1c6896d7
VZ
506 break;
507
508 case GDK_KP_Tab:
509 key_code = isChar ? WXK_TAB : WXK_NUMPAD_TAB;
510 break;
511
512 case GDK_KP_Enter:
513 key_code = isChar ? WXK_RETURN : WXK_NUMPAD_ENTER;
514 break;
515
516 case GDK_KP_F1:
517 key_code = isChar ? WXK_F1 : WXK_NUMPAD_F1;
518 break;
519
520 case GDK_KP_F2:
521 key_code = isChar ? WXK_F2 : WXK_NUMPAD_F2;
522 break;
523
524 case GDK_KP_F3:
525 key_code = isChar ? WXK_F3 : WXK_NUMPAD_F3;
526 break;
527
528 case GDK_KP_F4:
529 key_code = isChar ? WXK_F4 : WXK_NUMPAD_F4;
530 break;
531
532 case GDK_KP_Home:
533 key_code = isChar ? WXK_HOME : WXK_NUMPAD_HOME;
534 break;
535
536 case GDK_KP_Left:
537 key_code = isChar ? WXK_LEFT : WXK_NUMPAD_LEFT;
538 break;
539
540 case GDK_KP_Up:
541 key_code = isChar ? WXK_UP : WXK_NUMPAD_UP;
542 break;
543
544 case GDK_KP_Right:
545 key_code = isChar ? WXK_RIGHT : WXK_NUMPAD_RIGHT;
546 break;
547
548 case GDK_KP_Down:
549 key_code = isChar ? WXK_DOWN : WXK_NUMPAD_DOWN;
550 break;
551
552 case GDK_KP_Prior: // == GDK_KP_Page_Up
faa94f3e 553 key_code = isChar ? WXK_PAGEUP : WXK_NUMPAD_PAGEUP;
1c6896d7
VZ
554 break;
555
556 case GDK_KP_Next: // == GDK_KP_Page_Down
faa94f3e 557 key_code = isChar ? WXK_PAGEDOWN : WXK_NUMPAD_PAGEDOWN;
1c6896d7
VZ
558 break;
559
560 case GDK_KP_End:
561 key_code = isChar ? WXK_END : WXK_NUMPAD_END;
562 break;
563
564 case GDK_KP_Begin:
565 key_code = isChar ? WXK_HOME : WXK_NUMPAD_BEGIN;
566 break;
567
568 case GDK_KP_Insert:
569 key_code = isChar ? WXK_INSERT : WXK_NUMPAD_INSERT;
570 break;
571
572 case GDK_KP_Delete:
573 key_code = isChar ? WXK_DELETE : WXK_NUMPAD_DELETE;
574 break;
575
576 case GDK_KP_Equal:
2a230426 577 key_code = isChar ? '=' : int(WXK_NUMPAD_EQUAL);
1c6896d7
VZ
578 break;
579
580 case GDK_KP_Multiply:
2a230426 581 key_code = isChar ? '*' : int(WXK_NUMPAD_MULTIPLY);
1c6896d7
VZ
582 break;
583
584 case GDK_KP_Add:
2a230426 585 key_code = isChar ? '+' : int(WXK_NUMPAD_ADD);
1c6896d7
VZ
586 break;
587
588 case GDK_KP_Separator:
589 // FIXME: what is this?
2a230426 590 key_code = isChar ? '.' : int(WXK_NUMPAD_SEPARATOR);
1c6896d7
VZ
591 break;
592
593 case GDK_KP_Subtract:
2a230426 594 key_code = isChar ? '-' : int(WXK_NUMPAD_SUBTRACT);
1c6896d7
VZ
595 break;
596
597 case GDK_KP_Decimal:
2a230426 598 key_code = isChar ? '.' : int(WXK_NUMPAD_DECIMAL);
1c6896d7
VZ
599 break;
600
601 case GDK_KP_Divide:
2a230426 602 key_code = isChar ? '/' : int(WXK_NUMPAD_DIVIDE);
1c6896d7
VZ
603 break;
604
605
606 // function keys
607 case GDK_F1:
608 case GDK_F2:
609 case GDK_F3:
610 case GDK_F4:
611 case GDK_F5:
612 case GDK_F6:
613 case GDK_F7:
614 case GDK_F8:
615 case GDK_F9:
616 case GDK_F10:
617 case GDK_F11:
618 case GDK_F12:
619 key_code = WXK_F1 + keysym - GDK_F1;
620 break;
621
622 default:
623 key_code = 0;
624 }
625
626 return key_code;
627}
628
629static inline bool wxIsAsciiKeysym(KeySym ks)
630{
631 return ks < 256;
632}
633
a3c15d89
VS
634static void wxFillOtherKeyEventFields(wxKeyEvent& event,
635 wxWindowGTK *win,
636 GdkEventKey *gdk_event)
637{
a3c15d89 638 event.SetTimestamp( gdk_event->time );
cfa8c7d6 639 event.SetId(win->GetId());
d0fb62a6 640
a3c15d89
VS
641 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK) != 0;
642 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK) != 0;
643 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK) != 0;
87ec008f 644 event.m_metaDown = (gdk_event->state & GDK_META_MASK) != 0;
d0fb62a6
VZ
645
646 // Normally we take the state of modifiers directly from the low level GDK
647 // event but unfortunately GDK uses a different convention from MSW for the
648 // key events corresponding to the modifier keys themselves: in it, when
649 // e.g. Shift key is pressed, GDK_SHIFT_MASK is not set while it is set
650 // when Shift is released. Under MSW the situation is exactly reversed and
651 // the modifier corresponding to the key is set when it is pressed and
652 // unset when it is released. To ensure consistent behaviour between
653 // platforms (and because it seems to make slightly more sense, although
654 // arguably both behaviours are reasonable) we follow MSW here.
655 //
656 // Final notice: we set the flags to the desired value instead of just
657 // inverting them because they are not set correctly (i.e. in the same way
658 // as for the real events generated by the user) for wxUIActionSimulator-
659 // produced events and it seems better to keep that class code the same
660 // among all platforms and fix the discrepancy here instead of adding
661 // wxGTK-specific code to wxUIActionSimulator.
662 const bool isPress = gdk_event->type == GDK_KEY_PRESS;
663 switch ( gdk_event->keyval )
664 {
665 case GDK_Shift_L:
666 case GDK_Shift_R:
667 event.m_shiftDown = isPress;
668 break;
669
670 case GDK_Control_L:
671 case GDK_Control_R:
672 event.m_controlDown = isPress;
673 break;
674
675 case GDK_Alt_L:
676 case GDK_Alt_R:
677 event.m_altDown = isPress;
678 break;
679
680 case GDK_Meta_L:
681 case GDK_Meta_R:
682 case GDK_Super_L:
683 case GDK_Super_R:
684 event.m_metaDown = isPress;
685 break;
686 }
687
a3c15d89 688 event.m_rawCode = (wxUint32) gdk_event->keyval;
5995a84f 689 event.m_rawFlags = gdk_event->hardware_keycode;
d0fb62a6 690
f795e586
PC
691 wxGetMousePosition(&event.m_x, &event.m_y);
692 win->ScreenToClient(&event.m_x, &event.m_y);
a3c15d89
VS
693 event.SetEventObject( win );
694}
695
696
74710601
VZ
697static bool
698wxTranslateGTKKeyEventToWx(wxKeyEvent& event,
699 wxWindowGTK *win,
700 GdkEventKey *gdk_event)
47d67540 701{
1c6896d7
VZ
702 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
703 // but only event->keyval which is quite useless to us, so remember
704 // the last character from GDK_KEY_PRESS and reuse it as last resort
705 //
706 // NB: should be MT-safe as we're always called from the main thread only
707 static struct
708 {
709 KeySym keysym;
710 long keycode;
711 } s_lastKeyPress = { 0, 0 };
712
713 KeySym keysym = gdk_event->keyval;
0a62b197 714
9a83f860
VZ
715 wxLogTrace(TRACE_KEYS, wxT("Key %s event: keysym = %ld"),
716 event.GetEventType() == wxEVT_KEY_UP ? wxT("release")
717 : wxT("press"),
0a62b197
VZ
718 keysym);
719
0a164d4c 720 long key_code = wxTranslateKeySymToWXKey(keysym, false /* !isChar */);
1c6896d7
VZ
721
722 if ( !key_code )
723 {
724 // do we have the translation or is it a plain ASCII character?
725 if ( (gdk_event->length == 1) || wxIsAsciiKeysym(keysym) )
726 {
727 // we should use keysym if it is ASCII as X does some translations
728 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
729 // which we don't want here (but which we do use for OnChar())
730 if ( !wxIsAsciiKeysym(keysym) )
731 {
732 keysym = (KeySym)gdk_event->string[0];
733 }
a2053b27 734
3b81515c 735#ifdef GDK_WINDOWING_X11
1c6896d7 736 // we want to always get the same key code when the same key is
90e572f1 737 // pressed regardless of the state of the modifiers, i.e. on a
1c6896d7
VZ
738 // standard US keyboard pressing '5' or '%' ('5' key with
739 // Shift) should result in the same key code in OnKeyDown():
740 // '5' (although OnChar() will get either '5' or '%').
741 //
742 // to do it we first translate keysym to keycode (== scan code)
743 // and then back but always using the lower register
744 Display *dpy = (Display *)wxGetDisplay();
745 KeyCode keycode = XKeysymToKeycode(dpy, keysym);
0a62b197 746
9a83f860 747 wxLogTrace(TRACE_KEYS, wxT("\t-> keycode %d"), keycode);
0a62b197 748
25cc08c0
VZ
749#ifdef HAVE_X11_XKBLIB_H
750 KeySym keysymNormalized = XkbKeycodeToKeysym(dpy, keycode, 0, 0);
751#else
1c6896d7 752 KeySym keysymNormalized = XKeycodeToKeysym(dpy, keycode, 0);
25cc08c0 753#endif
1c6896d7
VZ
754
755 // use the normalized, i.e. lower register, keysym if we've
756 // got one
757 key_code = keysymNormalized ? keysymNormalized : keysym;
3b81515c
VZ
758#else
759 key_code = keysym;
760#endif
1c6896d7
VZ
761
762 // as explained above, we want to have lower register key codes
763 // normally but for the letter keys we want to have the upper ones
764 //
765 // NB: don't use XConvertCase() here, we want to do it for letters
766 // only
767 key_code = toupper(key_code);
768 }
769 else // non ASCII key, what to do?
770 {
771 // by default, ignore it
772 key_code = 0;
773
774 // but if we have cached information from the last KEY_PRESS
775 if ( gdk_event->type == GDK_KEY_RELEASE )
776 {
777 // then reuse it
778 if ( keysym == s_lastKeyPress.keysym )
779 {
780 key_code = s_lastKeyPress.keycode;
781 }
782 }
783 }
784
785 if ( gdk_event->type == GDK_KEY_PRESS )
786 {
787 // remember it to be reused for KEY_UP event later
788 s_lastKeyPress.keysym = keysym;
789 s_lastKeyPress.keycode = key_code;
790 }
791 }
792
9a83f860 793 wxLogTrace(TRACE_KEYS, wxT("\t-> wxKeyCode %ld"), key_code);
c801d85f 794
74710601 795 // sending unknown key events doesn't really make sense
1c6896d7 796 if ( !key_code )
0a164d4c 797 return false;
3d6f7261 798
276f883f
VZ
799 event.m_keyCode = key_code;
800
7333c0ef
VZ
801#if wxUSE_UNICODE
802 event.m_uniChar = gdk_keyval_to_unicode(key_code ? key_code : keysym);
803 if ( !event.m_uniChar && event.m_keyCode <= WXK_DELETE )
804 {
805 // Set Unicode key code to the ASCII equivalent for compatibility. E.g.
806 // let RETURN generate the key event with both key and Unicode key
807 // codes of 13.
808 event.m_uniChar = event.m_keyCode;
809 }
810#endif // wxUSE_UNICODE
811
1c6896d7 812 // now fill all the other fields
a3c15d89 813 wxFillOtherKeyEventFields(event, win, gdk_event);
0a164d4c 814
0a164d4c 815 return true;
74710601
VZ
816}
817
7c5e6fc6 818
a3c15d89
VS
819struct wxGtkIMData
820{
821 GtkIMContext *context;
822 GdkEventKey *lastKeyEvent;
823
824 wxGtkIMData()
825 {
826 context = gtk_im_multicontext_new();
827 lastKeyEvent = NULL;
828 }
829 ~wxGtkIMData()
830 {
3fe39b0c 831 g_object_unref (context);
a3c15d89
VS
832 }
833};
a3c15d89 834
2933f70a
VZ
835namespace
836{
837
f47a3591
VZ
838// Send wxEVT_CHAR_HOOK event to the parent of the window and return true only
839// if it was processed (and not skipped).
840bool SendCharHookEvent(const wxKeyEvent& event, wxWindow *win)
2933f70a 841{
3a95f73c
VZ
842 // wxEVT_CHAR_HOOK must be sent to allow the parent windows (e.g. a dialog
843 // which typically closes when Esc key is pressed in any of its controls)
5c16a699
VZ
844 // to handle key events in all of its children unless the mouse is captured
845 // in which case we consider that the keyboard should be "captured" too.
846 if ( !g_captureWindow )
2933f70a 847 {
3a95f73c 848 wxKeyEvent eventCharHook(wxEVT_CHAR_HOOK, event);
4cf1a9bf
VZ
849 if ( win->HandleWindowEvent(eventCharHook)
850 && !event.IsNextEventAllowed() )
3a95f73c 851 return true;
2933f70a
VZ
852 }
853
f47a3591 854 return false;
2933f70a
VZ
855}
856
64c502e8
VZ
857// Adjust wxEVT_CHAR event key code fields. This function takes care of two
858// conventions:
859// (a) Ctrl-letter key presses generate key codes in range 1..26
860// (b) Unicode key codes are same as key codes for the codes in 1..255 range
861void AdjustCharEventKeyCodes(wxKeyEvent& event)
862{
863 const int code = event.m_keyCode;
864
865 // Check for (a) above.
866 if ( event.ControlDown() )
867 {
868 // We intentionally don't use isupper/lower() here, we really need
869 // ASCII letters only as it doesn't make sense to translate any other
870 // ones into this range which has only 26 slots.
871 if ( code >= 'a' && code <= 'z' )
872 event.m_keyCode = code - 'a' + 1;
873 else if ( code >= 'A' && code <= 'Z' )
874 event.m_keyCode = code - 'A' + 1;
875
876#if wxUSE_UNICODE
877 // Adjust the Unicode equivalent in the same way too.
878 if ( event.m_keyCode != code )
879 event.m_uniChar = event.m_keyCode;
880#endif // wxUSE_UNICODE
881 }
882
883#if wxUSE_UNICODE
884 // Check for (b) from above.
885 //
886 // FIXME: Should we do it for key codes up to 255?
887 if ( !event.m_uniChar && code < WXK_DELETE )
888 event.m_uniChar = code;
889#endif // wxUSE_UNICODE
890}
891
2933f70a
VZ
892} // anonymous namespace
893
14037106
PC
894// If a widget does not handle a key or mouse event, GTK+ sends it up the
895// parent chain until it is handled. These events are not supposed to propagate
896// in wxWidgets, so this code avoids handling them in any parent wxWindow,
897// while still allowing the event to propagate so things like native keyboard
898// navigation will work.
899#define wxPROCESS_EVENT_ONCE(EventType, event) \
900 static EventType eventPrev; \
901 if (memcmp(&eventPrev, event, sizeof(EventType)) == 0) \
902 return false; \
903 eventPrev = *event
904
865bb325 905extern "C" {
7f7beb1d 906static gboolean
3591d10f 907gtk_window_key_press_callback( GtkWidget *WXUNUSED(widget),
7f7beb1d
MR
908 GdkEventKey *gdk_event,
909 wxWindow *win )
74710601 910{
1c6896d7
VZ
911 if (!win->m_hasVMT)
912 return FALSE;
913 if (g_blockEventsOnDrag)
914 return FALSE;
f1272160 915
14037106
PC
916 wxPROCESS_EVENT_ONCE(GdkEventKey, gdk_event);
917
f1272160
RR
918 wxKeyEvent event( wxEVT_KEY_DOWN );
919 bool ret = false;
920 bool return_after_IM = false;
921
84dc821c
JS
922 if( wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
923 {
f47a3591
VZ
924 // Send the CHAR_HOOK event first
925 if ( SendCharHookEvent(event, win) )
926 {
927 // Don't do anything at all with this event any more.
928 return TRUE;
929 }
930
84dc821c 931 // Emit KEY_DOWN event
937013e0 932 ret = win->HandleWindowEvent( event );
84dc821c
JS
933 }
934 else
f1272160
RR
935 {
936 // Return after IM processing as we cannot do
937 // anything with it anyhow.
938 return_after_IM = true;
939 }
940
9cbe96d0 941 if (!ret && win->m_imData)
f6fca1f8 942 {
9cbe96d0
VZ
943 win->m_imData->lastKeyEvent = gdk_event;
944
f1272160
RR
945 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
946 // docs, if IM filter returns true, no further processing should be done.
0a164d4c 947 // we should send the key_down event anyway.
f1272160 948 bool intercepted_by_IM = gtk_im_context_filter_keypress(win->m_imData->context, gdk_event);
f6fca1f8 949 win->m_imData->lastKeyEvent = NULL;
f1272160
RR
950 if (intercepted_by_IM)
951 {
9a83f860 952 wxLogTrace(TRACE_KEYS, wxT("Key event intercepted by IM"));
7f7beb1d 953 return TRUE;
f1272160 954 }
f6fca1f8 955 }
68567a96 956
f1272160 957 if (return_after_IM)
7f7beb1d 958 return FALSE;
68567a96 959
50b58dec
RD
960#if wxUSE_ACCEL
961 if (!ret)
962 {
963 wxWindowGTK *ancestor = win;
964 while (ancestor)
965 {
966 int command = ancestor->GetAcceleratorTable()->GetCommand( event );
967 if (command != -1)
968 {
b1bb04c5
VS
969 wxCommandEvent menu_event( wxEVT_COMMAND_MENU_SELECTED, command );
970 ret = ancestor->HandleWindowEvent( menu_event );
971
972 if ( !ret )
973 {
974 // if the accelerator wasn't handled as menu event, try
975 // it as button click (for compatibility with other
976 // platforms):
977 wxCommandEvent button_event( wxEVT_COMMAND_BUTTON_CLICKED, command );
978 ret = ancestor->HandleWindowEvent( button_event );
979 }
980
50b58dec
RD
981 break;
982 }
983 if (ancestor->IsTopLevel())
984 break;
985 ancestor = ancestor->GetParent();
986 }
987 }
988#endif // wxUSE_ACCEL
989
1ec3a984
RR
990 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
991 // will only be sent if it is not in an accelerator table.
2dde25b9 992 if (!ret)
d728dd40 993 {
7c5e6fc6 994 long key_code;
1c6896d7 995 KeySym keysym = gdk_event->keyval;
36025bcc 996 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
0a164d4c 997 key_code = wxTranslateKeySymToWXKey(keysym, true /* isChar */);
36025bcc 998 if ( !key_code )
1c6896d7 999 {
0b187670 1000 if ( wxIsAsciiKeysym(keysym) )
1ec3a984 1001 {
36025bcc
VS
1002 // ASCII key
1003 key_code = (unsigned char)keysym;
1004 }
0b187670
RR
1005 // gdk_event->string is actually deprecated
1006 else if ( gdk_event->length == 1 )
1007 {
1008 key_code = (unsigned char)gdk_event->string[0];
1009 }
36025bcc 1010 }
7c5e6fc6 1011
36025bcc
VS
1012 if ( key_code )
1013 {
f47a3591
VZ
1014 wxKeyEvent eventChar(wxEVT_CHAR, event);
1015
9a83f860 1016 wxLogTrace(TRACE_KEYS, wxT("Char event: %ld"), key_code);
7c5e6fc6 1017
f47a3591 1018 eventChar.m_keyCode = key_code;
7c5e6fc6 1019
64c502e8 1020 AdjustCharEventKeyCodes(eventChar);
1dabdced 1021
f47a3591 1022 ret = win->HandleWindowEvent(eventChar);
f17393f1 1023 }
d728dd40 1024 }
4d3ab2a0 1025
c7b2e494 1026 return ret;
2b5f62a0 1027}
865bb325 1028}
2b5f62a0 1029
865bb325 1030extern "C" {
7f7beb1d 1031static void
e4161a2a 1032gtk_wxwindow_commit_cb (GtkIMContext * WXUNUSED(context),
7f7beb1d
MR
1033 const gchar *str,
1034 wxWindow *window)
2b5f62a0 1035{
f47a3591 1036 wxKeyEvent event( wxEVT_CHAR );
2b5f62a0 1037
a3c15d89
VS
1038 // take modifiers, cursor position, timestamp etc. from the last
1039 // key_press_event that was fed into Input Method:
1040 if (window->m_imData->lastKeyEvent)
1041 {
1042 wxFillOtherKeyEventFields(event,
1043 window, window->m_imData->lastKeyEvent);
1044 }
28c513cb
RR
1045 else
1046 {
1047 event.SetEventObject( window );
1048 }
a3c15d89 1049
6256849f
VS
1050 const wxString data(wxGTK_CONV_BACK_SYS(str));
1051 if( data.empty() )
5bfaca1b 1052 return;
7c5e6fc6 1053
6256849f 1054 for( wxString::const_iterator pstr = data.begin(); pstr != data.end(); ++pstr )
7c5e6fc6 1055 {
5bfaca1b
VS
1056#if wxUSE_UNICODE
1057 event.m_uniChar = *pstr;
f6fca1f8 1058 // Backward compatible for ISO-8859-1
5bfaca1b 1059 event.m_keyCode = *pstr < 256 ? event.m_uniChar : 0;
9a83f860 1060 wxLogTrace(TRACE_KEYS, wxT("IM sent character '%c'"), event.m_uniChar);
5bfaca1b 1061#else
6256849f 1062 event.m_keyCode = (char)*pstr;
5bfaca1b 1063#endif // wxUSE_UNICODE
1dabdced 1064
64c502e8 1065 AdjustCharEventKeyCodes(event);
1dabdced 1066
f47a3591 1067 window->HandleWindowEvent(event);
2b5f62a0
VZ
1068 }
1069}
865bb325 1070}
2b5f62a0
VZ
1071
1072
b666df2c
RR
1073//-----------------------------------------------------------------------------
1074// "key_release_event" from any window
1075//-----------------------------------------------------------------------------
1076
865bb325 1077extern "C" {
7f7beb1d 1078static gboolean
e4161a2a 1079gtk_window_key_release_callback( GtkWidget * WXUNUSED(widget),
7f7beb1d
MR
1080 GdkEventKey *gdk_event,
1081 wxWindowGTK *win )
b666df2c 1082{
74710601
VZ
1083 if (!win->m_hasVMT)
1084 return FALSE;
b666df2c 1085
74710601
VZ
1086 if (g_blockEventsOnDrag)
1087 return FALSE;
b666df2c 1088
14037106
PC
1089 wxPROCESS_EVENT_ONCE(GdkEventKey, gdk_event);
1090
b666df2c 1091 wxKeyEvent event( wxEVT_KEY_UP );
74710601 1092 if ( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
b666df2c 1093 {
90e572f1 1094 // unknown key pressed, ignore (the event would be useless anyhow)
74710601 1095 return FALSE;
b666df2c
RR
1096 }
1097
97687291 1098 return win->GTKProcessEvent(event);
b666df2c 1099}
865bb325 1100}
b666df2c 1101
c5f9d156
VS
1102// ============================================================================
1103// the mouse events
1104// ============================================================================
1105
d1f2ac45
VZ
1106// ----------------------------------------------------------------------------
1107// mouse event processing helpers
1108// ----------------------------------------------------------------------------
1109
2daa0ce9
VZ
1110static void AdjustEventButtonState(wxMouseEvent& event)
1111{
1112 // GDK reports the old state of the button for a button press event, but
1113 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1114 // for a LEFT_DOWN event, not FALSE, so we will invert
1115 // left/right/middleDown for the corresponding click events
1e6feb95 1116
1a8caf94
RR
1117 if ((event.GetEventType() == wxEVT_LEFT_DOWN) ||
1118 (event.GetEventType() == wxEVT_LEFT_DCLICK) ||
1119 (event.GetEventType() == wxEVT_LEFT_UP))
1120 {
1121 event.m_leftDown = !event.m_leftDown;
1122 return;
1123 }
1124
1125 if ((event.GetEventType() == wxEVT_MIDDLE_DOWN) ||
1126 (event.GetEventType() == wxEVT_MIDDLE_DCLICK) ||
1127 (event.GetEventType() == wxEVT_MIDDLE_UP))
2daa0ce9 1128 {
1a8caf94
RR
1129 event.m_middleDown = !event.m_middleDown;
1130 return;
1131 }
1132
1133 if ((event.GetEventType() == wxEVT_RIGHT_DOWN) ||
1134 (event.GetEventType() == wxEVT_RIGHT_DCLICK) ||
1135 (event.GetEventType() == wxEVT_RIGHT_UP))
1136 {
1137 event.m_rightDown = !event.m_rightDown;
1138 return;
2daa0ce9 1139 }
e7cda1c3
VZ
1140
1141 if ((event.GetEventType() == wxEVT_AUX1_DOWN) ||
1142 (event.GetEventType() == wxEVT_AUX1_DCLICK))
1143 {
1144 event.m_aux1Down = true;
1145 return;
1146 }
1147
1148 if ((event.GetEventType() == wxEVT_AUX2_DOWN) ||
1149 (event.GetEventType() == wxEVT_AUX2_DCLICK))
1150 {
1151 event.m_aux2Down = true;
1152 return;
1153 }
2daa0ce9
VZ
1154}
1155
58072456 1156// find the window to send the mouse event to
d1f2ac45
VZ
1157static
1158wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y)
1159{
7d4909b2
RR
1160 wxCoord xx = x;
1161 wxCoord yy = y;
1162
d1f2ac45
VZ
1163 if (win->m_wxwindow)
1164 {
08f53168
PC
1165 wxPizza* pizza = WX_PIZZA(win->m_wxwindow);
1166 xx += pizza->m_scroll_x;
1167 yy += pizza->m_scroll_y;
d1f2ac45
VZ
1168 }
1169
222ed1d6 1170 wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
d1f2ac45
VZ
1171 while (node)
1172 {
34670bda 1173 wxWindow* child = static_cast<wxWindow*>(node->GetData());
d1f2ac45 1174
b1d4dd7a 1175 node = node->GetNext();
d1f2ac45
VZ
1176 if (!child->IsShown())
1177 continue;
1178
71ead4bf 1179 if (child->GTKIsTransparentForMouse())
d1f2ac45
VZ
1180 {
1181 // wxStaticBox is transparent in the box itself
1182 int xx1 = child->m_x;
1183 int yy1 = child->m_y;
1184 int xx2 = child->m_x + child->m_width;
7408cf7f 1185 int yy2 = child->m_y + child->m_height;
d1f2ac45
VZ
1186
1187 // left
7d4909b2 1188 if (((xx >= xx1) && (xx <= xx1+10) && (yy >= yy1) && (yy <= yy2)) ||
d1f2ac45 1189 // right
7d4909b2 1190 ((xx >= xx2-10) && (xx <= xx2) && (yy >= yy1) && (yy <= yy2)) ||
d1f2ac45 1191 // top
7d4909b2 1192 ((xx >= xx1) && (xx <= xx2) && (yy >= yy1) && (yy <= yy1+10)) ||
d1f2ac45 1193 // bottom
7d4909b2 1194 ((xx >= xx1) && (xx <= xx2) && (yy >= yy2-1) && (yy <= yy2)))
d1f2ac45
VZ
1195 {
1196 win = child;
1197 x -= child->m_x;
1198 y -= child->m_y;
1199 break;
1200 }
1201
1202 }
1203 else
1204 {
d3b9f782 1205 if ((child->m_wxwindow == NULL) &&
58072456 1206 win->IsClientAreaChild(child) &&
7d4909b2
RR
1207 (child->m_x <= xx) &&
1208 (child->m_y <= yy) &&
af3653dd
RR
1209 (child->m_x+child->m_width >= xx) &&
1210 (child->m_y+child->m_height >= yy))
d1f2ac45
VZ
1211 {
1212 win = child;
1213 x -= child->m_x;
1214 y -= child->m_y;
1215 break;
1216 }
1217 }
1218 }
1219
1220 return win;
1221}
1222
ef5c70f9
VZ
1223// ----------------------------------------------------------------------------
1224// common event handlers helpers
1225// ----------------------------------------------------------------------------
1226
97687291
VZ
1227bool wxWindowGTK::GTKProcessEvent(wxEvent& event) const
1228{
1229 // nothing special at this level
937013e0 1230 return HandleWindowEvent(event);
97687291
VZ
1231}
1232
02bad830
VZ
1233bool wxWindowGTK::GTKShouldIgnoreEvent() const
1234{
1235 return !m_hasVMT || g_blockEventsOnDrag;
1236}
1237
5478f221 1238int wxWindowGTK::GTKCallbackCommonPrologue(GdkEventAny *event) const
ef5c70f9 1239{
ef5c70f9 1240 if (!m_hasVMT)
5478f221 1241 return FALSE;
ef5c70f9 1242 if (g_blockEventsOnDrag)
5478f221 1243 return TRUE;
ef5c70f9 1244 if (g_blockEventsOnScroll)
5478f221 1245 return TRUE;
ef5c70f9
VZ
1246
1247 if (!GTKIsOwnWindow(event->window))
5478f221 1248 return FALSE;
ef5c70f9 1249
5478f221 1250 return -1;
ef5c70f9
VZ
1251}
1252
1253// overloads for all GDK event types we use here: we need to have this as
1254// GdkEventXXX can't be implicitly cast to GdkEventAny even if it, in fact,
1255// derives from it in the sense that the structs have the same layout
1256#define wxDEFINE_COMMON_PROLOGUE_OVERLOAD(T) \
5478f221 1257 static int wxGtkCallbackCommonPrologue(T *event, wxWindowGTK *win) \
ef5c70f9
VZ
1258 { \
1259 return win->GTKCallbackCommonPrologue((GdkEventAny *)event); \
1260 }
1261
1262wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventButton)
1263wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventMotion)
1264wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventCrossing)
1265
1266#undef wxDEFINE_COMMON_PROLOGUE_OVERLOAD
1267
5478f221
VZ
1268#define wxCOMMON_CALLBACK_PROLOGUE(event, win) \
1269 const int rc = wxGtkCallbackCommonPrologue(event, win); \
1270 if ( rc != -1 ) \
1271 return rc
1272
ef5c70f9
VZ
1273// all event handlers must have C linkage as they're called from GTK+ C code
1274extern "C"
1275{
1276
c801d85f 1277//-----------------------------------------------------------------------------
2f2aa628
RR
1278// "button_press_event"
1279//-----------------------------------------------------------------------------
c801d85f 1280
7f7beb1d
MR
1281static gboolean
1282gtk_window_button_press_callback( GtkWidget *widget,
1283 GdkEventButton *gdk_event,
1284 wxWindowGTK *win )
903f689b 1285{
14037106
PC
1286 wxPROCESS_EVENT_ONCE(GdkEventButton, gdk_event);
1287
5478f221 1288 wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
034be888 1289
8f9850dd
RR
1290 g_lastButtonNumber = gdk_event->button;
1291
90e572f1 1292 // GDK sends surplus button down events
2b5f62a0
VZ
1293 // before a double click event. We
1294 // need to filter these out.
1e89eecd 1295 if ((gdk_event->type == GDK_BUTTON_PRESS) && (win->m_wxwindow))
2b5f62a0
VZ
1296 {
1297 GdkEvent *peek_event = gdk_event_peek();
1298 if (peek_event)
1299 {
8b8a8e0e
RR
1300 if ((peek_event->type == GDK_2BUTTON_PRESS) ||
1301 (peek_event->type == GDK_3BUTTON_PRESS))
2b5f62a0
VZ
1302 {
1303 gdk_event_free( peek_event );
1304 return TRUE;
1305 }
1306 else
1307 {
1308 gdk_event_free( peek_event );
1309 }
1310 }
1311 }
1312
2daa0ce9 1313 wxEventType event_type = wxEVT_NULL;
47d67540 1314
15475ced
VZ
1315 if ( gdk_event->type == GDK_2BUTTON_PRESS &&
1316 gdk_event->button >= 1 && gdk_event->button <= 3 )
1317 {
1318 // Reset GDK internal timestamp variables in order to disable GDK
1319 // triple click events. GDK will then next time believe no button has
1320 // been clicked just before, and send a normal button click event.
1321 GdkDisplay* display = gtk_widget_get_display (widget);
1322 display->button_click_time[1] = 0;
1323 display->button_click_time[0] = 0;
1324 }
15475ced 1325
f5e27805 1326 if (gdk_event->button == 1)
c801d85f 1327 {
f3f0d961 1328 // note that GDK generates triple click events which are not supported
77ffb593 1329 // by wxWidgets but still have to be passed to the app as otherwise
f3f0d961 1330 // clicks would simply go missing
f5e27805
RR
1331 switch (gdk_event->type)
1332 {
15475ced
VZ
1333 // we shouldn't get triple clicks at all for GTK2 because we
1334 // suppress them artificially using the code above but we still
1335 // should map them to something for GTK1 and not just ignore them
1336 // as this would lose clicks
f3f0d961
VZ
1337 case GDK_3BUTTON_PRESS: // we could also map this to DCLICK...
1338 case GDK_BUTTON_PRESS:
1339 event_type = wxEVT_LEFT_DOWN;
1340 break;
1341
1342 case GDK_2BUTTON_PRESS:
1343 event_type = wxEVT_LEFT_DCLICK;
1344 break;
b1f50e65
VZ
1345
1346 default:
1347 // just to silence gcc warnings
1348 ;
f5e27805 1349 }
362c6693 1350 }
f5e27805 1351 else if (gdk_event->button == 2)
c801d85f 1352 {
f5e27805
RR
1353 switch (gdk_event->type)
1354 {
15475ced 1355 case GDK_3BUTTON_PRESS:
f3f0d961
VZ
1356 case GDK_BUTTON_PRESS:
1357 event_type = wxEVT_MIDDLE_DOWN;
1358 break;
1359
1360 case GDK_2BUTTON_PRESS:
1361 event_type = wxEVT_MIDDLE_DCLICK;
1362 break;
b1f50e65
VZ
1363
1364 default:
1365 ;
f5e27805 1366 }
362c6693 1367 }
f5e27805 1368 else if (gdk_event->button == 3)
c801d85f 1369 {
f5e27805
RR
1370 switch (gdk_event->type)
1371 {
15475ced 1372 case GDK_3BUTTON_PRESS:
f3f0d961
VZ
1373 case GDK_BUTTON_PRESS:
1374 event_type = wxEVT_RIGHT_DOWN;
1375 break;
1376
1377 case GDK_2BUTTON_PRESS:
1378 event_type = wxEVT_RIGHT_DCLICK;
1379 break;
b1f50e65
VZ
1380
1381 default:
1382 ;
2b5f62a0
VZ
1383 }
1384 }
47d67540 1385
e7cda1c3
VZ
1386 else if (gdk_event->button == 8)
1387 {
1388 switch (gdk_event->type)
1389 {
1390 case GDK_3BUTTON_PRESS:
1391 case GDK_BUTTON_PRESS:
1392 event_type = wxEVT_AUX1_DOWN;
1393 break;
1394
1395 case GDK_2BUTTON_PRESS:
1396 event_type = wxEVT_AUX1_DCLICK;
1397 break;
1398
1399 default:
1400 ;
1401 }
1402 }
1403
1404 else if (gdk_event->button == 9)
1405 {
1406 switch (gdk_event->type)
1407 {
1408 case GDK_3BUTTON_PRESS:
1409 case GDK_BUTTON_PRESS:
1410 event_type = wxEVT_AUX2_DOWN;
1411 break;
1412
1413 case GDK_2BUTTON_PRESS:
1414 event_type = wxEVT_AUX2_DCLICK;
1415 break;
1416
1417 default:
1418 ;
1419 }
1420 }
1421
2daa0ce9
VZ
1422 if ( event_type == wxEVT_NULL )
1423 {
1424 // unknown mouse button or click type
1425 return FALSE;
1426 }
1427
8f9850dd 1428 g_lastMouseEvent = (GdkEvent*) gdk_event;
fcb29b23 1429
f5e27805 1430 wxMouseEvent event( event_type );
c5f9d156 1431 InitMouseEvent( win, event, gdk_event );
47d67540 1432
2daa0ce9 1433 AdjustEventButtonState(event);
94633ad9 1434
90e572f1
MR
1435 // find the correct window to send the event to: it may be a different one
1436 // from the one which got it at GTK+ level because some controls don't have
d1f2ac45
VZ
1437 // their own X window and thus cannot get any events.
1438 if ( !g_captureWindow )
1439 win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
ff8bfdbb 1440
ccb9fa0d
RD
1441 // reset the event object and id in case win changed.
1442 event.SetEventObject( win );
1443 event.SetId( win->GetId() );
670f9935 1444
fcb29b23 1445 bool ret = win->GTKProcessEvent( event );
5e513780 1446 g_lastMouseEvent = NULL;
fcb29b23
VZ
1447 if ( ret )
1448 return TRUE;
47d67540 1449
78cd9c69 1450 if ((event_type == wxEVT_LEFT_DOWN) && !win->IsOfStandardClass() &&
22f43cb5 1451 (gs_currentFocus != win) /* && win->IsFocusable() */)
8622e8cd 1452 {
c7bfb76a 1453 win->SetFocus();
8622e8cd
RR
1454 }
1455
ac103441
RR
1456 if (event_type == wxEVT_RIGHT_DOWN)
1457 {
1458 // generate a "context menu" event: this is similar to right mouse
1459 // click under many GUIs except that it is generated differently
1460 // (right up under MSW, ctrl-click under Mac, right down here) and
1461 //
1462 // (a) it's a command event and so is propagated to the parent
1463 // (b) under some ports it can be generated from kbd too
1464 // (c) it uses screen coords (because of (a))
1465 wxContextMenuEvent evtCtx(
1466 wxEVT_CONTEXT_MENU,
1467 win->GetId(),
1468 win->ClientToScreen(event.GetPosition()));
1469 evtCtx.SetEventObject(win);
97687291 1470 return win->GTKProcessEvent(evtCtx);
ac103441
RR
1471 }
1472
034be888 1473 return FALSE;
362c6693 1474}
c801d85f
KB
1475
1476//-----------------------------------------------------------------------------
97b3455a 1477// "button_release_event"
2f2aa628 1478//-----------------------------------------------------------------------------
c801d85f 1479
7f7beb1d 1480static gboolean
71ead4bf 1481gtk_window_button_release_callback( GtkWidget *WXUNUSED(widget),
7f7beb1d
MR
1482 GdkEventButton *gdk_event,
1483 wxWindowGTK *win )
47d67540 1484{
14037106
PC
1485 wxPROCESS_EVENT_ONCE(GdkEventButton, gdk_event);
1486
5478f221 1487 wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
47d67540 1488
8f9850dd
RR
1489 g_lastButtonNumber = 0;
1490
f5e27805 1491 wxEventType event_type = wxEVT_NULL;
47d67540 1492
f5e27805
RR
1493 switch (gdk_event->button)
1494 {
2b5f62a0
VZ
1495 case 1:
1496 event_type = wxEVT_LEFT_UP;
1497 break;
1498
1499 case 2:
1500 event_type = wxEVT_MIDDLE_UP;
1501 break;
1502
1503 case 3:
1504 event_type = wxEVT_RIGHT_UP;
1505 break;
1506
e7cda1c3
VZ
1507 case 8:
1508 event_type = wxEVT_AUX1_UP;
1509 break;
1510
1511 case 9:
1512 event_type = wxEVT_AUX2_UP;
1513 break;
1514
2b5f62a0 1515 default:
6a17b868 1516 // unknown button, don't process
2b5f62a0 1517 return FALSE;
f5e27805 1518 }
47d67540 1519
8f9850dd 1520 g_lastMouseEvent = (GdkEvent*) gdk_event;
fcb29b23 1521
f5e27805 1522 wxMouseEvent event( event_type );
c5f9d156 1523 InitMouseEvent( win, event, gdk_event );
f5e27805 1524
2daa0ce9
VZ
1525 AdjustEventButtonState(event);
1526
d1f2ac45
VZ
1527 if ( !g_captureWindow )
1528 win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
47d67540 1529
ccb9fa0d
RD
1530 // reset the event object and id in case win changed.
1531 event.SetEventObject( win );
1532 event.SetId( win->GetId() );
1533
e6cac2df 1534 bool ret = win->GTKProcessEvent(event);
f4322df6 1535
e6cac2df 1536 g_lastMouseEvent = NULL;
f4322df6 1537
e6cac2df 1538 return ret;
362c6693 1539}
c801d85f
KB
1540
1541//-----------------------------------------------------------------------------
2f2aa628
RR
1542// "motion_notify_event"
1543//-----------------------------------------------------------------------------
c801d85f 1544
7f7beb1d 1545static gboolean
e4161a2a 1546gtk_window_motion_notify_callback( GtkWidget * WXUNUSED(widget),
7f7beb1d
MR
1547 GdkEventMotion *gdk_event,
1548 wxWindowGTK *win )
47d67540 1549{
14037106
PC
1550 wxPROCESS_EVENT_ONCE(GdkEventMotion, gdk_event);
1551
5478f221 1552 wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
034be888 1553
ff8bfdbb 1554 if (gdk_event->is_hint)
aae24d21 1555 {
f7a11f8c
RR
1556 int x = 0;
1557 int y = 0;
1558 GdkModifierType state;
1559 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
1560 gdk_event->x = x;
1561 gdk_event->y = y;
aae24d21 1562 }
ff8bfdbb 1563
8f9850dd
RR
1564 g_lastMouseEvent = (GdkEvent*) gdk_event;
1565
e380f72b 1566 wxMouseEvent event( wxEVT_MOTION );
c5f9d156 1567 InitMouseEvent(win, event, gdk_event);
e380f72b 1568
50382578 1569 if ( g_captureWindow )
2f2aa628 1570 {
6a17b868 1571 // synthesise a mouse enter or leave event if needed
1e6feb95 1572 GdkWindow *winUnderMouse = gdk_window_at_pointer(NULL, NULL);
7c5e6fc6 1573 // This seems to be necessary and actually been added to
50382578
RR
1574 // GDK itself in version 2.0.X
1575 gdk_flush();
7c5e6fc6 1576
1e6feb95
VZ
1577 bool hasMouse = winUnderMouse == gdk_event->window;
1578 if ( hasMouse != g_captureWindowHasMouse )
1579 {
1580 // the mouse changed window
1581 g_captureWindowHasMouse = hasMouse;
1582
17a1ebd1
VZ
1583 wxMouseEvent eventM(g_captureWindowHasMouse ? wxEVT_ENTER_WINDOW
1584 : wxEVT_LEAVE_WINDOW);
1585 InitMouseEvent(win, eventM, gdk_event);
1586 eventM.SetEventObject(win);
97687291 1587 win->GTKProcessEvent(eventM);
1e6feb95
VZ
1588 }
1589 }
1590 else // no capture
1591 {
d1f2ac45 1592 win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
ccb9fa0d
RD
1593
1594 // reset the event object and id in case win changed.
1595 event.SetEventObject( win );
1596 event.SetId( win->GetId() );
2f2aa628 1597 }
47d67540 1598
38f69be1
RR
1599 if ( !g_captureWindow )
1600 {
1601 wxSetCursorEvent cevent( event.m_x, event.m_y );
97687291 1602 if (win->GTKProcessEvent( cevent ))
38f69be1 1603 {
ec1e0c66 1604 win->SetCursor( cevent.GetCursor() );
38f69be1
RR
1605 }
1606 }
2e1f5012 1607
5e513780 1608 bool ret = win->GTKProcessEvent(event);
fcb29b23 1609
5e513780
RR
1610 g_lastMouseEvent = NULL;
1611
1612 return ret;
362c6693 1613}
c801d85f 1614
557c9f5b 1615//-----------------------------------------------------------------------------
40e5ebbf 1616// "scroll_event" (mouse wheel event)
557c9f5b
JS
1617//-----------------------------------------------------------------------------
1618
7f251559
RR
1619static gboolean
1620window_scroll_event_hscrollbar(GtkWidget*, GdkEventScroll* gdk_event, wxWindow* win)
1621{
1622 if (gdk_event->direction != GDK_SCROLL_LEFT &&
1623 gdk_event->direction != GDK_SCROLL_RIGHT)
1624 {
1625 return false;
1626 }
1627
7f251559 1628 GtkRange *range = win->m_scrollBar[wxWindow::ScrollDir_Horz];
7f251559 1629
fc9ab22a 1630 if (range && gtk_widget_get_visible(GTK_WIDGET(range)))
7f251559 1631 {
08f09504 1632 GtkAdjustment* adj = gtk_range_get_adjustment(range);
989d151c 1633 double delta = gtk_adjustment_get_step_increment(adj) * 3;
7f251559
RR
1634 if (gdk_event->direction == GDK_SCROLL_LEFT)
1635 delta = -delta;
1636
989d151c 1637 gtk_range_set_value(range, gtk_adjustment_get_value(adj) + delta);
7f251559
RR
1638
1639 return TRUE;
1640 }
1641
1642 return FALSE;
1643}
1644
7f7beb1d 1645static gboolean
76e4be8e 1646window_scroll_event(GtkWidget*, GdkEventScroll* gdk_event, wxWindow* win)
557c9f5b 1647{
76e4be8e 1648 wxMouseEvent event(wxEVT_MOUSEWHEEL);
b4e43132 1649 InitMouseEvent(win, event, gdk_event);
c53c7fad
RD
1650
1651 // FIXME: Get these values from GTK or GDK
58d185f7 1652 event.m_linesPerAction = 3;
60773911 1653 event.m_wheelDelta = 120;
4eeceb15
VZ
1654
1655 // Determine the scroll direction.
1656 switch (gdk_event->direction)
1657 {
1658 case GDK_SCROLL_UP:
1659 case GDK_SCROLL_RIGHT:
1660 event.m_wheelRotation = 120;
1661 break;
1662
1663 case GDK_SCROLL_DOWN:
1664 case GDK_SCROLL_LEFT:
1665 event.m_wheelRotation = -120;
1666 break;
1667
1668 default:
1669 return false; // Unknown/unhandled direction
1670 }
1671
1672 // And the scroll axis.
1673 switch (gdk_event->direction)
1674 {
1675 case GDK_SCROLL_UP:
1676 case GDK_SCROLL_DOWN:
1677 event.m_wheelAxis = wxMOUSE_WHEEL_VERTICAL;
1678 break;
1679
1680 case GDK_SCROLL_LEFT:
1681 case GDK_SCROLL_RIGHT:
1682 event.m_wheelAxis = wxMOUSE_WHEEL_HORIZONTAL;
1683 break;
1684 }
557c9f5b 1685
7f251559
RR
1686 if (win->GTKProcessEvent(event))
1687 return TRUE;
35510e48 1688
7f251559 1689 GtkRange *range = win->m_scrollBar[wxWindow::ScrollDir_Vert];
7f251559 1690
fc9ab22a 1691 if (range && gtk_widget_get_visible(GTK_WIDGET(range)))
7f251559 1692 {
08f09504 1693 GtkAdjustment* adj = gtk_range_get_adjustment(range);
989d151c 1694 double delta = gtk_adjustment_get_step_increment(adj) * 3;
7f251559 1695 if (gdk_event->direction == GDK_SCROLL_UP)
08f09504 1696 delta = -delta;
7f251559 1697
989d151c 1698 gtk_range_set_value(range, gtk_adjustment_get_value(adj) + delta);
7f251559
RR
1699
1700 return TRUE;
1701 }
1702
1703 return FALSE;
557c9f5b 1704}
ac103441
RR
1705
1706//-----------------------------------------------------------------------------
1707// "popup-menu"
1708//-----------------------------------------------------------------------------
ef5c70f9 1709
ac103441
RR
1710static gboolean wxgtk_window_popup_menu_callback(GtkWidget*, wxWindowGTK* win)
1711{
ac9d38d8 1712 wxContextMenuEvent event(wxEVT_CONTEXT_MENU, win->GetId(), wxPoint(-1, -1));
ac103441 1713 event.SetEventObject(win);
97687291 1714 return win->GTKProcessEvent(event);
ac103441 1715}
557c9f5b 1716
c801d85f 1717//-----------------------------------------------------------------------------
2f2aa628
RR
1718// "focus_in_event"
1719//-----------------------------------------------------------------------------
c801d85f 1720
7f7beb1d 1721static gboolean
e4161a2a 1722gtk_window_focus_in_callback( GtkWidget * WXUNUSED(widget),
7f7beb1d 1723 GdkEventFocus *WXUNUSED(event),
bd2e08d0 1724 wxWindowGTK *win )
c801d85f 1725{
bd2e08d0 1726 return win->GTKHandleFocusIn();
362c6693 1727}
c801d85f
KB
1728
1729//-----------------------------------------------------------------------------
2f2aa628
RR
1730// "focus_out_event"
1731//-----------------------------------------------------------------------------
c801d85f 1732
7f7beb1d 1733static gboolean
e4161a2a
VZ
1734gtk_window_focus_out_callback( GtkWidget * WXUNUSED(widget),
1735 GdkEventFocus * WXUNUSED(gdk_event),
7f7beb1d 1736 wxWindowGTK *win )
c801d85f 1737{
bd2e08d0 1738 return win->GTKHandleFocusOut();
362c6693 1739}
c801d85f 1740
bd2e08d0
VS
1741//-----------------------------------------------------------------------------
1742// "focus"
1743//-----------------------------------------------------------------------------
1744
28e88942
VZ
1745static gboolean
1746wx_window_focus_callback(GtkWidget *widget,
e4161a2a 1747 GtkDirectionType WXUNUSED(direction),
28e88942
VZ
1748 wxWindowGTK *win)
1749{
08f53168 1750 // the default handler for focus signal in GtkScrolledWindow sets
28e88942
VZ
1751 // focus to the window itself even if it doesn't accept focus, i.e. has no
1752 // GTK_CAN_FOCUS in its style -- work around this by forcibly preventing
1753 // the signal from reaching gtk_scrolled_window_focus() if we don't have
1754 // any children which might accept focus (we know we don't accept the focus
1755 // ourselves as this signal is only connected in this case)
1756 if ( win->GetChildren().empty() )
1757 g_signal_stop_emission_by_name(widget, "focus");
1758
1759 // we didn't change the focus
1760 return FALSE;
1761}
1762
b4071e91
RR
1763//-----------------------------------------------------------------------------
1764// "enter_notify_event"
1765//-----------------------------------------------------------------------------
1766
f3a5f83a
MR
1767static gboolean
1768gtk_window_enter_callback( GtkWidget *widget,
1769 GdkEventCrossing *gdk_event,
1770 wxWindowGTK *win )
b4071e91 1771{
5478f221 1772 wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
47d67540 1773
7f5f144a
RR
1774 // Event was emitted after a grab
1775 if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
7c5e6fc6 1776
4a33eba6
RR
1777 int x = 0;
1778 int y = 0;
1779 GdkModifierType state = (GdkModifierType)0;
ff8bfdbb 1780
989d151c 1781 gdk_window_get_pointer(gtk_widget_get_window(widget), &x, &y, &state);
ff8bfdbb 1782
edc1d330 1783 wxMouseEvent event( wxEVT_ENTER_WINDOW );
c5f9d156
VS
1784 InitMouseEvent(win, event, gdk_event);
1785 wxPoint pt = win->GetClientAreaOrigin();
1786 event.m_x = x + pt.x;
1787 event.m_y = y + pt.y;
ff8bfdbb 1788
38f69be1
RR
1789 if ( !g_captureWindow )
1790 {
1791 wxSetCursorEvent cevent( event.m_x, event.m_y );
97687291 1792 if (win->GTKProcessEvent( cevent ))
38f69be1 1793 {
ec1e0c66 1794 win->SetCursor( cevent.GetCursor() );
38f69be1
RR
1795 }
1796 }
2e1f5012 1797
97687291 1798 return win->GTKProcessEvent(event);
b4071e91 1799}
47d67540 1800
b4071e91
RR
1801//-----------------------------------------------------------------------------
1802// "leave_notify_event"
1803//-----------------------------------------------------------------------------
1804
f3a5f83a
MR
1805static gboolean
1806gtk_window_leave_callback( GtkWidget *widget,
1807 GdkEventCrossing *gdk_event,
1808 wxWindowGTK *win )
b4071e91 1809{
5478f221 1810 wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
b292e2f5 1811
7f5f144a
RR
1812 // Event was emitted after an ungrab
1813 if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
7c5e6fc6 1814
e380f72b 1815 wxMouseEvent event( wxEVT_LEAVE_WINDOW );
47d67540 1816
4a33eba6
RR
1817 int x = 0;
1818 int y = 0;
1819 GdkModifierType state = (GdkModifierType)0;
ff8bfdbb 1820
989d151c 1821 gdk_window_get_pointer(gtk_widget_get_window(widget), &x, &y, &state);
ff8bfdbb 1822
b4e43132 1823 InitMouseEvent(win, event, gdk_event);
ff8bfdbb 1824
97687291 1825 return win->GTKProcessEvent(event);
b4071e91 1826}
47d67540 1827
c801d85f 1828//-----------------------------------------------------------------------------
add7cadd 1829// "value_changed" from scrollbar
2f2aa628 1830//-----------------------------------------------------------------------------
c801d85f 1831
add7cadd
PC
1832static void
1833gtk_scrollbar_value_changed(GtkRange* range, wxWindow* win)
47d67540 1834{
71ead4bf 1835 wxEventType eventType = win->GTKGetScrollEventType(range);
add7cadd
PC
1836 if (eventType != wxEVT_NULL)
1837 {
1838 // Convert scroll event type to scrollwin event type
1839 eventType += wxEVT_SCROLLWIN_TOP - wxEVT_SCROLL_TOP;
22c9b211
VZ
1840
1841 // find the scrollbar which generated the event
1842 wxWindowGTK::ScrollDir dir = win->ScrollDirFromRange(range);
35510e48 1843
22c9b211 1844 // generate the corresponding wx event
bfeeb7f3 1845 const int orient = wxWindow::OrientFromScrollDir(dir);
add7cadd
PC
1846 wxScrollWinEvent event(eventType, win->GetScrollPos(orient), orient);
1847 event.SetEventObject(win);
22c9b211 1848
97687291 1849 win->GTKProcessEvent(event);
add7cadd 1850 }
362c6693 1851}
c801d85f 1852
cb43b372
RR
1853//-----------------------------------------------------------------------------
1854// "button_press_event" from scrollbar
1855//-----------------------------------------------------------------------------
1856
7f7beb1d 1857static gboolean
add7cadd 1858gtk_scrollbar_button_press_event(GtkRange*, GdkEventButton*, wxWindow* win)
cb43b372 1859{
0a164d4c 1860 g_blockEventsOnScroll = true;
add7cadd 1861 win->m_mouseButtonDown = true;
9e691f46 1862
add7cadd 1863 return false;
cb43b372
RR
1864}
1865
c918b2cd
PC
1866//-----------------------------------------------------------------------------
1867// "event_after" from scrollbar
1868//-----------------------------------------------------------------------------
1869
c918b2cd
PC
1870static void
1871gtk_scrollbar_event_after(GtkRange* range, GdkEvent* event, wxWindow* win)
1872{
1873 if (event->type == GDK_BUTTON_RELEASE)
1874 {
1875 g_signal_handlers_block_by_func(range, (void*)gtk_scrollbar_event_after, win);
1876
bfeeb7f3 1877 const int orient = wxWindow::OrientFromScrollDir(
22c9b211 1878 win->ScrollDirFromRange(range));
74ab5f5b
VZ
1879 wxScrollWinEvent evt(wxEVT_SCROLLWIN_THUMBRELEASE,
1880 win->GetScrollPos(orient), orient);
1881 evt.SetEventObject(win);
1882 win->GTKProcessEvent(evt);
c918b2cd
PC
1883 }
1884}
c918b2cd 1885
cb43b372
RR
1886//-----------------------------------------------------------------------------
1887// "button_release_event" from scrollbar
1888//-----------------------------------------------------------------------------
1889
7f7beb1d 1890static gboolean
add7cadd 1891gtk_scrollbar_button_release_event(GtkRange* range, GdkEventButton*, wxWindow* win)
cb43b372 1892{
0a164d4c 1893 g_blockEventsOnScroll = false;
add7cadd
PC
1894 win->m_mouseButtonDown = false;
1895 // If thumb tracking
2a23d363 1896 if (win->m_isScrolling)
88413fec 1897 {
add7cadd 1898 win->m_isScrolling = false;
c918b2cd 1899 // Hook up handler to send thumb release event after this emission is finished.
8ea30e36
PC
1900 // To allow setting scroll position from event handler, sending event must
1901 // be deferred until after the GtkRange handler for this signal has run
c918b2cd 1902 g_signal_handlers_unblock_by_func(range, (void*)gtk_scrollbar_event_after, win);
88413fec
RR
1903 }
1904
add7cadd 1905 return false;
cb43b372 1906}
ca298c88 1907
a2053b27
RR
1908//-----------------------------------------------------------------------------
1909// "realize" from m_widget
1910//-----------------------------------------------------------------------------
1911
7f7beb1d 1912static void
514b0e13 1913gtk_window_realized_callback(GtkWidget* WXUNUSED(widget), wxWindowGTK* win)
a2053b27 1914{
612515af
VZ
1915 win->GTKHandleRealized();
1916}
1917
1a0d3739
PC
1918//-----------------------------------------------------------------------------
1919// "unrealize" from m_wxwindow
1920//-----------------------------------------------------------------------------
1921
1922static void unrealize(GtkWidget*, wxWindowGTK* win)
1923{
1924 if (win->m_imData)
1925 gtk_im_context_set_client_window(win->m_imData->context, NULL);
1926}
1927
b79395c5 1928//-----------------------------------------------------------------------------
cca410b3 1929// "size_allocate" from m_wxwindow or m_widget
b79395c5
RR
1930//-----------------------------------------------------------------------------
1931
cca410b3
PC
1932static void
1933size_allocate(GtkWidget*, GtkAllocation* alloc, wxWindow* win)
8f75cb6c 1934{
cca410b3
PC
1935 int w = alloc->width;
1936 int h = alloc->height;
1937 if (win->m_wxwindow)
5b8a521e 1938 {
08f53168
PC
1939 int border_x, border_y;
1940 WX_PIZZA(win->m_wxwindow)->get_border_widths(border_x, border_y);
1941 w -= 2 * border_x;
1942 h -= 2 * border_y;
cca410b3
PC
1943 if (w < 0) w = 0;
1944 if (h < 0) h = 0;
1945 }
1946 if (win->m_oldClientWidth != w || win->m_oldClientHeight != h)
1947 {
1948 win->m_oldClientWidth = w;
1949 win->m_oldClientHeight = h;
1950 // this callback can be connected to m_wxwindow,
1951 // so always get size from m_widget->allocation
989d151c
PC
1952 GtkAllocation a;
1953 gtk_widget_get_allocation(win->m_widget, &a);
1954 win->m_width = a.width;
1955 win->m_height = a.height;
cca410b3
PC
1956 if (!win->m_nativeSizeEvent)
1957 {
1958 wxSizeEvent event(win->GetSize(), win->GetId());
1959 event.SetEventObject(win);
1960 win->GTKProcessEvent(event);
1961 }
5b8a521e 1962 }
8f75cb6c
RR
1963}
1964
7738af59 1965//-----------------------------------------------------------------------------
78cd9c69 1966// "grab_broken"
7738af59
VZ
1967//-----------------------------------------------------------------------------
1968
db885f2a
PC
1969#if GTK_CHECK_VERSION(2, 8, 0)
1970static gboolean
1971gtk_window_grab_broken( GtkWidget*,
7738af59
VZ
1972 GdkEventGrabBroken *event,
1973 wxWindow *win )
1974{
1975 // Mouse capture has been lost involuntarily, notify the application
db885f2a 1976 if(!event->keyboard && wxWindow::GetCapture() == win)
7738af59
VZ
1977 {
1978 wxMouseCaptureLostEvent evt( win->GetId() );
1979 evt.SetEventObject( win );
937013e0 1980 win->HandleWindowEvent( evt );
7738af59 1981 }
db885f2a 1982 return false;
7738af59 1983}
4b859ff4 1984#endif
7738af59 1985
013151c7
JS
1986//-----------------------------------------------------------------------------
1987// "style_set"
1988//-----------------------------------------------------------------------------
1989
1990static
1991void gtk_window_style_set_callback( GtkWidget *WXUNUSED(widget),
1992 GtkStyle *previous_style,
1993 wxWindow* win )
1994{
013151c7
JS
1995 if (win && previous_style)
1996 {
030f4112
PC
1997 if (win->IsTopLevel())
1998 {
1999 wxSysColourChangedEvent event;
2000 event.SetEventObject(win);
2001 win->GTKProcessEvent(event);
2002 }
2003 else
2004 {
2005 // Border width could change, which will change client size.
2006 // Make sure size event occurs for this
2007 win->m_oldClientWidth = 0;
2008 }
013151c7
JS
2009 }
2010}
2011
ef5c70f9
VZ
2012} // extern "C"
2013
f0b87ef9
PC
2014void wxWindowGTK::GTKHandleRealized()
2015{
2016 if (m_imData)
2017 {
2018 gtk_im_context_set_client_window
2019 (
2020 m_imData->context,
2021 m_wxwindow ? GTKGetDrawingWindow()
2022 : gtk_widget_get_window(m_widget)
2023 );
2024 }
2025
14421681
VZ
2026 // Use composited window if background is transparent, if supported.
2027 if (m_backgroundStyle == wxBG_STYLE_TRANSPARENT)
2028 {
2029#if wxGTK_HAS_COMPOSITING_SUPPORT
2030 if (IsTransparentBackgroundSupported())
2031 {
2032 GdkWindow* const window = GTKGetDrawingWindow();
2033 if (window)
2034 gdk_window_set_composited(window, true);
2035 }
2036 else
2037#endif // wxGTK_HAS_COMPOSITING_SUPPORT
2038 {
2039 // We revert to erase mode if transparency is not supported
2040 m_backgroundStyle = wxBG_STYLE_ERASE;
2041 }
2042 }
2043
2044
f0b87ef9
PC
2045 // We cannot set colours and fonts before the widget
2046 // been realized, so we do this directly after realization
2047 // or otherwise in idle time
2048
2049 if (m_needsStyleChange)
2050 {
2051 SetBackgroundStyle(GetBackgroundStyle());
2052 m_needsStyleChange = false;
2053 }
2054
514b0e13 2055 wxWindowCreateEvent event(static_cast<wxWindow*>(this));
f0b87ef9
PC
2056 event.SetEventObject( this );
2057 GTKProcessEvent( event );
2058
2059 GTKUpdateCursor(true, false);
2060}
2061
ef5c70f9
VZ
2062// ----------------------------------------------------------------------------
2063// this wxWindowBase function is implemented here (in platform-specific file)
2064// because it is static and so couldn't be made virtual
2065// ----------------------------------------------------------------------------
2066
2067wxWindow *wxWindowBase::DoFindFocus()
2068{
39258ad7
VZ
2069 // For compatibility with wxMSW, pretend that showing a popup menu doesn't
2070 // change the focus and that it remains on the window showing it, even
2071 // though the real focus does change in GTK.
2072 extern wxMenu *wxCurrentPopupMenu;
2073 if ( wxCurrentPopupMenu )
2074 return wxCurrentPopupMenu->GetInvokingWindow();
2075
22f43cb5 2076 wxWindowGTK *focus = gs_pendingFocus ? gs_pendingFocus : gs_currentFocus;
ef5c70f9 2077 // the cast is necessary when we compile in wxUniversal mode
5c33522f 2078 return static_cast<wxWindow*>(focus);
865bb325 2079}
63081513 2080
48200154 2081void wxWindowGTK::AddChildGTK(wxWindowGTK* child)
6ca41e57 2082{
9a33c3ef 2083 wxASSERT_MSG(m_wxwindow, "Cannot add a child to a window without a client area");
03647350 2084
9a33c3ef
FM
2085 // the window might have been scrolled already, we
2086 // have to adapt the position
48200154 2087 wxPizza* pizza = WX_PIZZA(m_wxwindow);
08f53168
PC
2088 child->m_x += pizza->m_scroll_x;
2089 child->m_y += pizza->m_scroll_y;
148cd9b6 2090
08f53168
PC
2091 gtk_widget_set_size_request(
2092 child->m_widget, child->m_width, child->m_height);
f089940f 2093 pizza->put(child->m_widget, child->m_x, child->m_y);
6ca41e57
RR
2094}
2095
bbe0af5b
RR
2096//-----------------------------------------------------------------------------
2097// global functions
2098//-----------------------------------------------------------------------------
2099
1e6feb95 2100wxWindow *wxGetActiveWindow()
bbe0af5b 2101{
6cad4f1b 2102 return wxWindow::FindFocus();
bbe0af5b
RR
2103}
2104
7dd40b6f
RD
2105
2106wxMouseState wxGetMouseState()
2107{
2108 wxMouseState ms;
2109
2110 gint x;
2111 gint y;
2112 GdkModifierType mask;
2113
2114 gdk_window_get_pointer(NULL, &x, &y, &mask);
2115
2116 ms.SetX(x);
2117 ms.SetY(y);
c4021a79
PC
2118 ms.SetLeftDown((mask & GDK_BUTTON1_MASK) != 0);
2119 ms.SetMiddleDown((mask & GDK_BUTTON2_MASK) != 0);
2120 ms.SetRightDown((mask & GDK_BUTTON3_MASK) != 0);
e7cda1c3 2121 // see the comment in InitMouseEvent()
c4021a79
PC
2122 ms.SetAux1Down((mask & GDK_BUTTON4_MASK) != 0);
2123 ms.SetAux2Down((mask & GDK_BUTTON5_MASK) != 0);
2124
2125 ms.SetControlDown((mask & GDK_CONTROL_MASK) != 0);
2126 ms.SetShiftDown((mask & GDK_SHIFT_MASK) != 0);
2127 ms.SetAltDown((mask & GDK_MOD1_MASK) != 0);
2128 ms.SetMetaDown((mask & GDK_META_MASK) != 0);
3d257b8d 2129
7dd40b6f
RD
2130 return ms;
2131}
3d257b8d 2132
c801d85f 2133//-----------------------------------------------------------------------------
1e6feb95 2134// wxWindowGTK
c801d85f
KB
2135//-----------------------------------------------------------------------------
2136
6522713c
VZ
2137// in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2138// method
1e6feb95 2139#ifdef __WXUNIVERSAL__
6522713c 2140 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK, wxWindowBase)
28953245 2141#endif // __WXUNIVERSAL__
c801d85f 2142
1e6feb95 2143void wxWindowGTK::Init()
c801d85f 2144{
f03fc89f 2145 // GTK specific
d3b9f782
VZ
2146 m_widget = NULL;
2147 m_wxwindow = NULL;
2148 m_focusWidget = NULL;
8bbe427f 2149
f03fc89f 2150 // position/size
a2053b27
RR
2151 m_x = 0;
2152 m_y = 0;
2153 m_width = 0;
e380f72b 2154 m_height = 0;
8bbe427f 2155
0a164d4c 2156 m_hasVMT = false;
02761f6c 2157
c6212a0c 2158 m_showOnIdle = false;
148cd9b6 2159
0a164d4c
WS
2160 m_noExpose = false;
2161 m_nativeSizeEvent = false;
94633ad9 2162
0a164d4c 2163 m_isScrolling = false;
add7cadd 2164 m_mouseButtonDown = false;
add7cadd 2165
22c9b211
VZ
2166 // initialize scrolling stuff
2167 for ( int dir = 0; dir < ScrollDir_Max; dir++ )
2168 {
2169 m_scrollBar[dir] = NULL;
2170 m_scrollPos[dir] = 0;
22c9b211 2171 }
f03fc89f 2172
815ac4a7
VZ
2173 m_oldClientWidth =
2174 m_oldClientHeight = 0;
8bbe427f 2175
0a164d4c 2176 m_clipPaintRegion = false;
b6fa52db 2177
c7382f91
JS
2178 m_needsStyleChange = false;
2179
5e014a0c 2180 m_cursor = *wxSTANDARD_CURSOR;
2daa0ce9 2181
a3c15d89 2182 m_imData = NULL;
a589495e 2183 m_dirtyTabOrder = false;
362c6693 2184}
c801d85f 2185
1e6feb95 2186wxWindowGTK::wxWindowGTK()
68995f26
VZ
2187{
2188 Init();
2189}
2190
1e6feb95
VZ
2191wxWindowGTK::wxWindowGTK( wxWindow *parent,
2192 wxWindowID id,
2193 const wxPoint &pos,
2194 const wxSize &size,
2195 long style,
2196 const wxString &name )
6ca41e57 2197{
68995f26
VZ
2198 Init();
2199
e380f72b 2200 Create( parent, id, pos, size, style, name );
6ca41e57 2201}
8bbe427f 2202
1e6feb95
VZ
2203bool wxWindowGTK::Create( wxWindow *parent,
2204 wxWindowID id,
2205 const wxPoint &pos,
2206 const wxSize &size,
2207 long style,
2208 const wxString &name )
c801d85f 2209{
e5048854
JS
2210 // Get default border
2211 wxBorder border = GetBorder(style);
9800347d 2212
e5048854
JS
2213 style &= ~wxBORDER_MASK;
2214 style |= border;
ac9d38d8 2215
4dcaf11a
RR
2216 if (!PreCreation( parent, pos, size ) ||
2217 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
2218 {
1e6feb95 2219 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
0a164d4c 2220 return false;
4dcaf11a 2221 }
47d67540 2222
7da4a9cf
RR
2223 // We should accept the native look
2224#if 0
2225 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
2226 scroll_class->scrollbar_spacing = 0;
2227#endif
2228
e5048854 2229
0f52f610 2230 m_wxwindow = wxPizza::New(m_windowStyle);
75f661bb
PC
2231#ifndef __WXUNIVERSAL__
2232 if (HasFlag(wxPizza::BORDER_STYLES))
2233 {
2234 g_signal_connect(m_wxwindow, "parent_set",
2235 G_CALLBACK(parent_set), this);
2236 }
2237#endif
3e09bcfd 2238 if (!HasFlag(wxHSCROLL) && !HasFlag(wxVSCROLL))
c9192212 2239 m_widget = m_wxwindow;
6552c7af
RR
2240 else
2241 {
d3b9f782 2242 m_widget = gtk_scrolled_window_new( NULL, NULL );
ff8bfdbb 2243
6552c7af 2244 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
47d67540 2245
6552c7af
RR
2246 // There is a conflict with default bindings at GTK+
2247 // level between scrolled windows and notebooks both of which want to use
2248 // Ctrl-PageUp/Down: scrolled windows for scrolling in the horizontal
2249 // direction and notebooks for changing pages -- we decide that if we don't
2250 // have wxHSCROLL style we can safely sacrifice horizontal scrolling if it
2251 // means we can get working keyboard navigation in notebooks
2252 if ( !HasFlag(wxHSCROLL) )
fd4081aa 2253 {
6552c7af
RR
2254 GtkBindingSet *
2255 bindings = gtk_binding_set_by_class(G_OBJECT_GET_CLASS(m_widget));
2256 if ( bindings )
2257 {
2258 gtk_binding_entry_remove(bindings, GDK_Page_Up, GDK_CONTROL_MASK);
2259 gtk_binding_entry_remove(bindings, GDK_Page_Down, GDK_CONTROL_MASK);
2260 }
fd4081aa 2261 }
fd4081aa 2262
6552c7af
RR
2263 if (HasFlag(wxALWAYS_SHOW_SB))
2264 {
2265 gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_ALWAYS, GTK_POLICY_ALWAYS );
6552c7af
RR
2266 }
2267 else
2268 {
2269 gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
2270 }
47d67540 2271
989d151c
PC
2272 m_scrollBar[ScrollDir_Horz] = GTK_RANGE(gtk_scrolled_window_get_hscrollbar(scrolledWindow));
2273 m_scrollBar[ScrollDir_Vert] = GTK_RANGE(gtk_scrolled_window_get_vscrollbar(scrolledWindow));
6552c7af
RR
2274 if (GetLayoutDirection() == wxLayout_RightToLeft)
2275 gtk_range_set_inverted( m_scrollBar[ScrollDir_Horz], TRUE );
47d67540 2276
6552c7af 2277 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
4e5a4c69 2278
6552c7af
RR
2279 // connect various scroll-related events
2280 for ( int dir = 0; dir < ScrollDir_Max; dir++ )
2281 {
2282 // these handlers block mouse events to any window during scrolling
2283 // such as motion events and prevent GTK and wxWidgets from fighting
2284 // over where the slider should be
2285 g_signal_connect(m_scrollBar[dir], "button_press_event",
22c9b211 2286 G_CALLBACK(gtk_scrollbar_button_press_event), this);
6552c7af 2287 g_signal_connect(m_scrollBar[dir], "button_release_event",
22c9b211
VZ
2288 G_CALLBACK(gtk_scrollbar_button_release_event), this);
2289
6552c7af 2290 gulong handler_id = g_signal_connect(m_scrollBar[dir], "event_after",
22c9b211 2291 G_CALLBACK(gtk_scrollbar_event_after), this);
6552c7af 2292 g_signal_handler_block(m_scrollBar[dir], handler_id);
22c9b211 2293
6552c7af 2294 // these handlers get notified when scrollbar slider moves
40e5ebbf 2295 g_signal_connect_after(m_scrollBar[dir], "value_changed",
22c9b211 2296 G_CALLBACK(gtk_scrollbar_value_changed), this);
6552c7af 2297 }
76ed8f8d 2298
6552c7af
RR
2299 gtk_widget_show( m_wxwindow );
2300 }
9ff9d30c 2301 g_object_ref(m_widget);
47d67540 2302
f03fc89f
VZ
2303 if (m_parent)
2304 m_parent->DoAddChild( this );
94633ad9 2305
76fcf0f2 2306 m_focusWidget = m_wxwindow;
8bbe427f 2307
29901843
VS
2308 SetCanFocus(AcceptsFocus());
2309
e380f72b 2310 PostCreation();
8bbe427f 2311
0a164d4c 2312 return true;
362c6693 2313}
c801d85f 2314
1e6feb95 2315wxWindowGTK::~wxWindowGTK()
c801d85f 2316{
7de59551
RD
2317 SendDestroyEvent();
2318
22f43cb5
VS
2319 if (gs_currentFocus == this)
2320 gs_currentFocus = NULL;
2321 if (gs_pendingFocus == this)
2322 gs_pendingFocus = NULL;
44cd54c2 2323
bd2e08d0
VS
2324 if ( gs_deferredFocusOut == this )
2325 gs_deferredFocusOut = NULL;
3e679f01 2326
0a164d4c 2327 m_hasVMT = false;
47d67540 2328
02c3e53b
JS
2329 // destroy children before destroying this window itself
2330 DestroyChildren();
2331
2332 // unhook focus handlers to prevent stray events being
2333 // propagated to this (soon to be) dead object
2334 if (m_focusWidget != NULL)
2335 {
9fa72bd2
MR
2336 g_signal_handlers_disconnect_by_func (m_focusWidget,
2337 (gpointer) gtk_window_focus_in_callback,
2338 this);
2339 g_signal_handlers_disconnect_by_func (m_focusWidget,
2340 (gpointer) gtk_window_focus_out_callback,
2341 this);
02c3e53b
JS
2342 }
2343
f03fc89f 2344 if (m_widget)
0a164d4c 2345 Show( false );
8bbe427f 2346
f6551618
MW
2347 // delete before the widgets to avoid a crash on solaris
2348 delete m_imData;
1a0d3739 2349 m_imData = NULL;
f6551618 2350
2f55b88c
PC
2351 // avoid problem with GTK+ 2.18 where a frozen window causes the whole
2352 // TLW to be frozen, and if the window is then destroyed, nothing ever
2353 // gets painted again
2354 if (IsFrozen())
2355 DoThaw();
2356
f03fc89f 2357 if (m_widget)
a2053b27 2358 {
9ff9d30c
PC
2359 // Note that gtk_widget_destroy() does not destroy the widget, it just
2360 // emits the "destroy" signal. The widget is not actually destroyed
2361 // until its reference count drops to zero.
2362 gtk_widget_destroy(m_widget);
2363 // Release our reference, should be the last one
2364 g_object_unref(m_widget);
2365 m_widget = NULL;
a2053b27 2366 }
9ff9d30c 2367 m_wxwindow = NULL;
362c6693 2368}
c801d85f 2369
1e6feb95 2370bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos, const wxSize &size )
c801d85f 2371{
e8375af8
VZ
2372 if ( GTKNeedsParent() )
2373 {
2374 wxCHECK_MSG( parent, false, wxT("Must have non-NULL parent") );
2375 }
8bbe427f 2376
a7c26d10
RD
2377 // Use either the given size, or the default if -1 is given.
2378 // See wxWindowBase for these functions.
3013a903 2379 m_width = WidthDefault(size.x) ;
f03fc89f 2380 m_height = HeightDefault(size.y);
8bbe427f 2381
b4261b20
PC
2382 if (pos != wxDefaultPosition)
2383 {
2384 m_x = pos.x;
2385 m_y = pos.y;
2386 }
8bbe427f 2387
0a164d4c 2388 return true;
c801d85f
KB
2389}
2390
1e6feb95 2391void wxWindowGTK::PostCreation()
c801d85f 2392{
82b978d7
RD
2393 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2394
14421681
VZ
2395#if wxGTK_HAS_COMPOSITING_SUPPORT
2396 // Set RGBA visual as soon as possible to minimize the possibility that
2397 // somebody uses the wrong one.
2398 if ( m_backgroundStyle == wxBG_STYLE_TRANSPARENT &&
2399 IsTransparentBackgroundSupported() )
2400 {
2401 GdkScreen *screen = gtk_widget_get_screen (m_widget);
2402
2403 GdkColormap *rgba_colormap = gdk_screen_get_rgba_colormap (screen);
2404
2405 if (rgba_colormap)
2406 gtk_widget_set_colormap(m_widget, rgba_colormap);
2407 }
2408#endif // wxGTK_HAS_COMPOSITING_SUPPORT
2409
43a18898
RR
2410 if (m_wxwindow)
2411 {
147bc491 2412 if (!m_noExpose)
b02da6b1 2413 {
77ffb593 2414 // these get reported to wxWidgets -> wxPaintEvent
1e6feb95 2415
9fa72bd2
MR
2416 g_signal_connect (m_wxwindow, "expose_event",
2417 G_CALLBACK (gtk_window_expose_callback), this);
147bc491 2418
847dfdb4 2419 if (GetLayoutDirection() == wxLayout_LeftToRight)
08f53168 2420 gtk_widget_set_redraw_on_allocate(m_wxwindow, HasFlag(wxFULL_REPAINT_ON_RESIZE));
93d23d8f 2421 }
2b5f62a0 2422
ed56a258
JS
2423 // Create input method handler
2424 m_imData = new wxGtkIMData;
2425
2b5f62a0 2426 // Cannot handle drawing preedited text yet
a3c15d89 2427 gtk_im_context_set_use_preedit( m_imData->context, FALSE );
2b5f62a0 2428
9fa72bd2 2429 g_signal_connect (m_imData->context, "commit",
da210120 2430 G_CALLBACK (gtk_wxwindow_commit_cb), this);
1a0d3739 2431 g_signal_connect(m_wxwindow, "unrealize", G_CALLBACK(unrealize), this);
43a18898 2432 }
47d67540 2433
76fcf0f2 2434 // focus handling
63081513 2435
06fda9e8
RR
2436 if (!GTK_IS_WINDOW(m_widget))
2437 {
2438 if (m_focusWidget == NULL)
2439 m_focusWidget = m_widget;
0a164d4c 2440
4c20ee63
RR
2441 if (m_wxwindow)
2442 {
2443 g_signal_connect (m_focusWidget, "focus_in_event",
9fa72bd2 2444 G_CALLBACK (gtk_window_focus_in_callback), this);
4c20ee63 2445 g_signal_connect (m_focusWidget, "focus_out_event",
f1e57cb9 2446 G_CALLBACK (gtk_window_focus_out_callback), this);
4c20ee63
RR
2447 }
2448 else
2449 {
2450 g_signal_connect_after (m_focusWidget, "focus_in_event",
2451 G_CALLBACK (gtk_window_focus_in_callback), this);
2452 g_signal_connect_after (m_focusWidget, "focus_out_event",
2453 G_CALLBACK (gtk_window_focus_out_callback), this);
2454 }
06fda9e8 2455 }
76fcf0f2 2456
28e88942
VZ
2457 if ( !AcceptsFocusFromKeyboard() )
2458 {
80332672 2459 SetCanFocus(false);
28e88942
VZ
2460
2461 g_signal_connect(m_widget, "focus",
2462 G_CALLBACK(wx_window_focus_callback), this);
2463 }
2464
76fcf0f2 2465 // connect to the various key and mouse handlers
63081513 2466
a2053b27 2467 GtkWidget *connect_widget = GetConnectWidget();
f03fc89f 2468
a2053b27 2469 ConnectWidget( connect_widget );
47d67540 2470
843101f7
VS
2471 // We cannot set colours, fonts and cursors before the widget has been
2472 // realized, so we do this directly after realization -- unless the widget
2473 // was in fact realized already.
2474 if ( gtk_widget_get_realized(connect_widget) )
2475 {
2476 gtk_window_realized_callback(connect_widget, this);
2477 }
2478 else
2479 {
2480 g_signal_connect (connect_widget, "realize",
2481 G_CALLBACK (gtk_window_realized_callback), this);
2482 }
2daa0ce9 2483
cca410b3
PC
2484 if (!IsTopLevel())
2485 {
2486 g_signal_connect(m_wxwindow ? m_wxwindow : m_widget, "size_allocate",
2487 G_CALLBACK(size_allocate), this);
2488 }
2489
db885f2a 2490#if GTK_CHECK_VERSION(2, 8, 0)
bb8afd65
VZ
2491 if ( gtk_check_version(2,8,0) == NULL )
2492 {
2493 // Make sure we can notify the app when mouse capture is lost
2494 if ( m_wxwindow )
4b859ff4 2495 {
4b859ff4 2496 g_signal_connect (m_wxwindow, "grab_broken_event",
7738af59 2497 G_CALLBACK (gtk_window_grab_broken), this);
4b859ff4 2498 }
7738af59 2499
bb8afd65 2500 if ( connect_widget != m_wxwindow )
4b859ff4 2501 {
4b859ff4 2502 g_signal_connect (connect_widget, "grab_broken_event",
7738af59 2503 G_CALLBACK (gtk_window_grab_broken), this);
4b859ff4 2504 }
63081513 2505 }
bb8afd65 2506#endif // GTK+ >= 2.8
2daa0ce9 2507
92153555 2508 if ( GTKShouldConnectSizeRequest() )
47c93b63
RR
2509 {
2510 // This is needed if we want to add our windows into native
024e9a4c 2511 // GTK controls, such as the toolbar. With this callback, the
47c93b63 2512 // toolbar gets to know the correct size (the one set by the
024e9a4c 2513 // programmer). Sadly, it misbehaves for wxComboBox.
9fa72bd2
MR
2514 g_signal_connect (m_widget, "size_request",
2515 G_CALLBACK (wxgtk_window_size_request_callback),
2516 this);
47c93b63 2517 }
1e6feb95 2518
40bab631
VS
2519 InheritAttributes();
2520
0a164d4c 2521 m_hasVMT = true;
e892f2fd 2522
978af864 2523 SetLayoutDirection(wxLayout_Default);
a433fbd5
VZ
2524
2525 // unless the window was created initially hidden (i.e. Hide() had been
2526 // called before Create()), we should show it at GTK+ level as well
2527 if ( IsShown() )
2528 gtk_widget_show( m_widget );
b4071e91
RR
2529}
2530
1da8e6e4
VZ
2531unsigned long
2532wxWindowGTK::GTKConnectWidget(const char *signal, wxGTKCallback callback)
a0c8bb73
VZ
2533{
2534 return g_signal_connect(m_widget, signal, callback, this);
2535}
2536
1e6feb95 2537void wxWindowGTK::ConnectWidget( GtkWidget *widget )
b4071e91 2538{
9fa72bd2
MR
2539 g_signal_connect (widget, "key_press_event",
2540 G_CALLBACK (gtk_window_key_press_callback), this);
2541 g_signal_connect (widget, "key_release_event",
2542 G_CALLBACK (gtk_window_key_release_callback), this);
2543 g_signal_connect (widget, "button_press_event",
2544 G_CALLBACK (gtk_window_button_press_callback), this);
2545 g_signal_connect (widget, "button_release_event",
2546 G_CALLBACK (gtk_window_button_release_callback), this);
2547 g_signal_connect (widget, "motion_notify_event",
2548 G_CALLBACK (gtk_window_motion_notify_callback), this);
35510e48 2549
9fa72bd2 2550 g_signal_connect (widget, "scroll_event",
76e4be8e 2551 G_CALLBACK (window_scroll_event), this);
7f251559
RR
2552 if (m_scrollBar[ScrollDir_Horz])
2553 g_signal_connect (m_scrollBar[ScrollDir_Horz], "scroll_event",
2554 G_CALLBACK (window_scroll_event_hscrollbar), this);
2555 if (m_scrollBar[ScrollDir_Vert])
2556 g_signal_connect (m_scrollBar[ScrollDir_Vert], "scroll_event",
2557 G_CALLBACK (window_scroll_event), this);
35510e48 2558
9fa72bd2
MR
2559 g_signal_connect (widget, "popup_menu",
2560 G_CALLBACK (wxgtk_window_popup_menu_callback), this);
2561 g_signal_connect (widget, "enter_notify_event",
2562 G_CALLBACK (gtk_window_enter_callback), this);
2563 g_signal_connect (widget, "leave_notify_event",
2564 G_CALLBACK (gtk_window_leave_callback), this);
013151c7 2565
030f4112 2566 if (m_wxwindow && (IsTopLevel() || HasFlag(wxBORDER_RAISED | wxBORDER_SUNKEN | wxBORDER_THEME)))
013151c7
JS
2567 g_signal_connect (m_wxwindow, "style_set",
2568 G_CALLBACK (gtk_window_style_set_callback), this);
362c6693 2569}
c801d85f 2570
1e6feb95 2571bool wxWindowGTK::Destroy()
c801d85f 2572{
0a164d4c 2573 m_hasVMT = false;
c801d85f 2574
f03fc89f 2575 return wxWindowBase::Destroy();
362c6693 2576}
c801d85f 2577
3cc04de7
PC
2578static GSList* gs_queueResizeList;
2579
2580extern "C" {
2581static gboolean queue_resize(void*)
2582{
2583 gdk_threads_enter();
2584 for (GSList* p = gs_queueResizeList; p; p = p->next)
2585 {
2586 if (p->data)
2587 {
2588 gtk_widget_queue_resize(GTK_WIDGET(p->data));
2589 g_object_remove_weak_pointer(G_OBJECT(p->data), &p->data);
2590 }
2591 }
2592 g_slist_free(gs_queueResizeList);
2593 gs_queueResizeList = NULL;
2594 gdk_threads_leave();
2595 return false;
2596}
2597}
2598
1e6feb95 2599void wxWindowGTK::DoMoveWindow(int x, int y, int width, int height)
23efdd02 2600{
01a49fd4
PC
2601 GtkWidget* parent = gtk_widget_get_parent(m_widget);
2602 if (WX_IS_PIZZA(parent))
2603 {
2604 WX_PIZZA(parent)->move(m_widget, x, y);
2605 gtk_widget_set_size_request(m_widget, width, height);
2606 }
3cc04de7
PC
2607
2608 // With GTK3, gtk_widget_queue_resize() is ignored while a size-allocate
2609 // is in progress. This situation is common in wxWidgets, since
2610 // size-allocate can generate wxSizeEvent and size event handlers often
2611 // call SetSize(), directly or indirectly. Work around this by deferring
2612 // the queue-resize until after size-allocate processing is finished.
2613 if (g_slist_find(gs_queueResizeList, m_widget) == NULL)
2614 {
2615 if (gs_queueResizeList == NULL)
2616 g_idle_add_full(GTK_PRIORITY_RESIZE, queue_resize, NULL, NULL);
2617 gs_queueResizeList = g_slist_prepend(gs_queueResizeList, m_widget);
2618 g_object_add_weak_pointer(G_OBJECT(m_widget), &gs_queueResizeList->data);
2619 }
23efdd02 2620}
2daa0ce9 2621
82008f15
PC
2622void wxWindowGTK::ConstrainSize()
2623{
2624#ifdef __WXGPE__
2625 // GPE's window manager doesn't like size hints at all, esp. when the user
2626 // has to use the virtual keyboard, so don't constrain size there
2627 if (!IsTopLevel())
2628#endif
2629 {
2630 const wxSize minSize = GetMinSize();
2631 const wxSize maxSize = GetMaxSize();
2632 if (minSize.x > 0 && m_width < minSize.x) m_width = minSize.x;
2633 if (minSize.y > 0 && m_height < minSize.y) m_height = minSize.y;
2634 if (maxSize.x > 0 && m_width > maxSize.x) m_width = maxSize.x;
2635 if (maxSize.y > 0 && m_height > maxSize.y) m_height = maxSize.y;
2636 }
2637}
2638
1e6feb95 2639void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
c801d85f 2640{
01a49fd4 2641 wxCHECK_RET(m_widget, "invalid window");
8bbe427f 2642
90dcb0d9
PC
2643 int scrollX = 0, scrollY = 0;
2644 GtkWidget* parent = gtk_widget_get_parent(m_widget);
2645 if (WX_IS_PIZZA(parent))
6d50fada 2646 {
90dcb0d9
PC
2647 wxPizza* pizza = WX_PIZZA(parent);
2648 scrollX = pizza->m_scroll_x;
2649 scrollY = pizza->m_scroll_y;
6d50fada 2650 }
90dcb0d9
PC
2651 if (x != -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
2652 x += scrollX;
2653 else
2654 x = m_x;
2655 if (y != -1 || (sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
2656 y += scrollY;
2657 else
2658 y = m_y;
a200c35e 2659
fe39b16a
RR
2660 // calculate the best size if we should auto size the window
2661 if ( ((sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1) ||
2662 ((sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1) )
2663 {
2664 const wxSize sizeBest = GetBestSize();
2665 if ( (sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1 )
2666 width = sizeBest.x;
2667 if ( (sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1 )
2668 height = sizeBest.y;
2669 }
2670
4d711190
PC
2671 if (width == -1)
2672 width = m_width;
2673 if (height == -1)
2674 height = m_height;
fe39b16a 2675
4d711190
PC
2676 const bool sizeChange = m_width != width || m_height != height;
2677 if (sizeChange || m_x != x || m_y != y)
fb1585ae 2678 {
90dcb0d9
PC
2679 m_x = x;
2680 m_y = y;
4d711190
PC
2681 m_width = width;
2682 m_height = height;
47d67540 2683
863e0817 2684 /* the default button has a border around it */
fc9ab22a 2685 if (gtk_widget_get_can_default(m_widget))
c50f1fb9 2686 {
f893066b
RR
2687 GtkBorder *default_border = NULL;
2688 gtk_widget_style_get( m_widget, "default_border", &default_border, NULL );
2689 if (default_border)
863e0817 2690 {
0604cfd7
PC
2691 x -= default_border->left;
2692 y -= default_border->top;
2693 width += default_border->left + default_border->right;
2694 height += default_border->top + default_border->bottom;
6cfdfed8 2695 gtk_border_free( default_border );
863e0817 2696 }
863e0817 2697 }
c50f1fb9 2698
0604cfd7 2699 DoMoveWindow(x, y, width, height);
54517652 2700 }
148cd9b6 2701
01a49fd4 2702 if ((sizeChange && !m_nativeSizeEvent) || (sizeFlags & wxSIZE_FORCE_EVENT))
5b8a521e 2703 {
cca410b3
PC
2704 // update these variables to keep size_allocate handler
2705 // from sending another size event for this change
5b8a521e 2706 GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
6d693bb4 2707
e47e063a
RR
2708 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
2709 event.SetEventObject( this );
2710 HandleWindowEvent( event );
30760ce7 2711 }
362c6693 2712}
c801d85f 2713
71ead4bf 2714bool wxWindowGTK::GTKShowFromOnIdle()
9390a202 2715{
fc9ab22a 2716 if (IsShown() && m_showOnIdle && !gtk_widget_get_visible (m_widget))
f46ad98f
RR
2717 {
2718 GtkAllocation alloc;
2719 alloc.x = m_x;
2720 alloc.y = m_y;
2721 alloc.width = m_width;
2722 alloc.height = m_height;
2723 gtk_widget_size_allocate( m_widget, &alloc );
2724 gtk_widget_show( m_widget );
2725 wxShowEvent eventShow(GetId(), true);
2726 eventShow.SetEventObject(this);
937013e0 2727 HandleWindowEvent(eventShow);
f46ad98f 2728 m_showOnIdle = false;
7317857d 2729 return true;
f46ad98f 2730 }
02761f6c 2731
7317857d
RR
2732 return false;
2733}
2734
2735void wxWindowGTK::OnInternalIdle()
2736{
bd2e08d0
VS
2737 if ( gs_deferredFocusOut )
2738 GTKHandleDeferredFocusOut();
2739
7317857d 2740 // Check if we have to show window now
71ead4bf 2741 if (GTKShowFromOnIdle()) return;
7317857d
RR
2742
2743 if ( m_dirtyTabOrder )
2744 {
2745 m_dirtyTabOrder = false;
2746 RealizeTabOrder();
2747 }
2748
6a50a2c4 2749 wxWindowBase::OnInternalIdle();
9390a202
RR
2750}
2751
1e6feb95 2752void wxWindowGTK::DoGetSize( int *width, int *height ) const
c801d85f 2753{
fb1585ae
RR
2754 if (width) (*width) = m_width;
2755 if (height) (*height) = m_height;
362c6693 2756}
c801d85f 2757
1e6feb95 2758void wxWindowGTK::DoSetClientSize( int width, int height )
c801d85f 2759{
82b978d7
RD
2760 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2761
949ff63e
PC
2762 const wxSize size = GetSize();
2763 const wxSize clientSize = GetClientSize();
2764 SetSize(width + (size.x - clientSize.x), height + (size.y - clientSize.y));
362c6693 2765}
c801d85f 2766
1e6feb95 2767void wxWindowGTK::DoGetClientSize( int *width, int *height ) const
c801d85f 2768{
82b978d7 2769 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 2770
09bf8378
PC
2771 int w = m_width;
2772 int h = m_height;
2773
fcdd5335 2774 if ( m_wxwindow )
c801d85f 2775 {
8466fc74 2776 // if window is scrollable, account for scrollbars
fcdd5335 2777 if ( GTK_IS_SCROLLED_WINDOW(m_widget) )
8466fc74 2778 {
fcdd5335
VZ
2779 GtkPolicyType policy[ScrollDir_Max];
2780 gtk_scrolled_window_get_policy(GTK_SCROLLED_WINDOW(m_widget),
2781 &policy[ScrollDir_Horz],
2782 &policy[ScrollDir_Vert]);
2783
2784 for ( int i = 0; i < ScrollDir_Max; i++ )
8466fc74 2785 {
fcdd5335
VZ
2786 // don't account for the scrollbars we don't have
2787 GtkRange * const range = m_scrollBar[i];
2788 if ( !range )
2789 continue;
2790
2791 // nor for the ones we have but don't current show
2792 switch ( policy[i] )
2793 {
2794 case GTK_POLICY_NEVER:
2795 // never shown so doesn't take any place
2796 continue;
2797
2798 case GTK_POLICY_ALWAYS:
2799 // no checks necessary
2800 break;
2801
2802 case GTK_POLICY_AUTOMATIC:
2803 // may be shown or not, check
2804 GtkAdjustment *adj = gtk_range_get_adjustment(range);
989d151c 2805 if (gtk_adjustment_get_upper(adj) <= gtk_adjustment_get_page_size(adj))
fcdd5335
VZ
2806 continue;
2807 }
2808
9800347d 2809 GtkScrolledWindowClass *scroll_class =
7da4a9cf
RR
2810 GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
2811
fcdd5335
VZ
2812 GtkRequisition req;
2813 gtk_widget_size_request(GTK_WIDGET(range), &req);
8466fc74 2814 if (i == ScrollDir_Horz)
7da4a9cf 2815 h -= req.height + scroll_class->scrollbar_spacing;
8466fc74 2816 else
7da4a9cf 2817 w -= req.width + scroll_class->scrollbar_spacing;
8466fc74
PC
2818 }
2819 }
09bf8378 2820
b3554952
VZ
2821 const wxSize sizeBorders = DoGetBorderSize();
2822 w -= sizeBorders.x;
2823 h -= sizeBorders.y;
9000c624 2824
69346023
PC
2825 if (w < 0)
2826 w = 0;
2827 if (h < 0)
2828 h = 0;
1ecc4d80 2829 }
1e6feb95 2830
09bf8378
PC
2831 if (width) *width = w;
2832 if (height) *height = h;
362c6693 2833}
c801d85f 2834
b3554952
VZ
2835wxSize wxWindowGTK::DoGetBorderSize() const
2836{
2837 if ( !m_wxwindow )
2838 return wxWindowBase::DoGetBorderSize();
2839
2840 int x, y;
2841 WX_PIZZA(m_wxwindow)->get_border_widths(x, y);
2842
2843 return 2*wxSize(x, y);
2844}
2845
1e6feb95 2846void wxWindowGTK::DoGetPosition( int *x, int *y ) const
c801d85f 2847{
bf0c00c6
RR
2848 int dx = 0;
2849 int dy = 0;
b4261b20
PC
2850 GtkWidget* parent = NULL;
2851 if (m_widget)
2852 parent = gtk_widget_get_parent(m_widget);
2853 if (WX_IS_PIZZA(parent))
bf0c00c6 2854 {
b4261b20 2855 wxPizza* pizza = WX_PIZZA(parent);
08f53168
PC
2856 dx = pizza->m_scroll_x;
2857 dy = pizza->m_scroll_y;
bf0c00c6 2858 }
496beb3f
VS
2859 if (x) (*x) = m_x - dx;
2860 if (y) (*y) = m_y - dy;
362c6693 2861}
c801d85f 2862
1e6feb95 2863void wxWindowGTK::DoClientToScreen( int *x, int *y ) const
c801d85f 2864{
82b978d7 2865 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 2866
989d151c 2867 if (gtk_widget_get_window(m_widget) == NULL) return;
a2053b27 2868
d3b9f782 2869 GdkWindow *source = NULL;
43a18898 2870 if (m_wxwindow)
989d151c 2871 source = gtk_widget_get_window(m_wxwindow);
43a18898 2872 else
989d151c 2873 source = gtk_widget_get_window(m_widget);
47d67540 2874
43a18898
RR
2875 int org_x = 0;
2876 int org_y = 0;
2877 gdk_window_get_origin( source, &org_x, &org_y );
c801d85f 2878
43a18898 2879 if (!m_wxwindow)
c801d85f 2880 {
fc9ab22a 2881 if (!gtk_widget_get_has_window(m_widget))
43a18898 2882 {
989d151c
PC
2883 GtkAllocation a;
2884 gtk_widget_get_allocation(m_widget, &a);
2885 org_x += a.x;
2886 org_y += a.y;
43a18898 2887 }
362c6693 2888 }
47d67540 2889
49e74855
RR
2890
2891 if (x)
2892 {
2893 if (GetLayoutDirection() == wxLayout_RightToLeft)
2894 *x = (GetClientSize().x - *x) + org_x;
fcb29b23 2895 else
49e74855
RR
2896 *x += org_x;
2897 }
fcb29b23 2898
43a18898 2899 if (y) *y += org_y;
362c6693 2900}
c801d85f 2901
1e6feb95 2902void wxWindowGTK::DoScreenToClient( int *x, int *y ) const
c801d85f 2903{
82b978d7 2904 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 2905
989d151c 2906 if (!gtk_widget_get_realized(m_widget)) return;
a2053b27 2907
d3b9f782 2908 GdkWindow *source = NULL;
1ecc4d80 2909 if (m_wxwindow)
989d151c 2910 source = gtk_widget_get_window(m_wxwindow);
1ecc4d80 2911 else
989d151c 2912 source = gtk_widget_get_window(m_widget);
47d67540 2913
1ecc4d80
RR
2914 int org_x = 0;
2915 int org_y = 0;
2916 gdk_window_get_origin( source, &org_x, &org_y );
c801d85f 2917
1ecc4d80 2918 if (!m_wxwindow)
c801d85f 2919 {
fc9ab22a 2920 if (!gtk_widget_get_has_window(m_widget))
1ecc4d80 2921 {
989d151c
PC
2922 GtkAllocation a;
2923 gtk_widget_get_allocation(m_widget, &a);
2924 org_x += a.x;
2925 org_y += a.y;
1ecc4d80 2926 }
362c6693 2927 }
47d67540 2928
49e74855
RR
2929 if (x)
2930 {
2931 if (GetLayoutDirection() == wxLayout_RightToLeft)
2932 *x = (GetClientSize().x - *x) - org_x;
fcb29b23 2933 else
49e74855
RR
2934 *x -= org_x;
2935 }
1ecc4d80 2936 if (y) *y -= org_y;
362c6693 2937}
c801d85f 2938
1e6feb95 2939bool wxWindowGTK::Show( bool show )
c801d85f 2940{
3cc57044 2941 if ( !wxWindowBase::Show(show) )
739730ca
RR
2942 {
2943 // nothing to do
0a164d4c 2944 return false;
739730ca 2945 }
8bbe427f 2946
3cc57044
VZ
2947 // notice that we may call Hide() before the window is created and this is
2948 // actually useful to create it hidden initially -- but we can't call
2949 // Show() before it is created
2950 if ( !m_widget )
f46ad98f 2951 {
3cc57044
VZ
2952 wxASSERT_MSG( !show, "can't show invalid window" );
2953 return true;
f46ad98f 2954 }
3cc57044
VZ
2955
2956 if ( show )
f46ad98f 2957 {
3cc57044
VZ
2958 if ( m_showOnIdle )
2959 {
2960 // defer until later
2961 return true;
2962 }
2963
2964 gtk_widget_show(m_widget);
f46ad98f 2965 }
3cc57044
VZ
2966 else // hide
2967 {
2968 gtk_widget_hide(m_widget);
2969 }
2970
2971 wxShowEvent eventShow(GetId(), show);
2972 eventShow.SetEventObject(this);
2973 HandleWindowEvent(eventShow);
2b5f62a0 2974
0a164d4c 2975 return true;
362c6693 2976}
c801d85f 2977
47a8a4d5 2978void wxWindowGTK::DoEnable( bool enable )
fdca68a6 2979{
47a8a4d5 2980 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
1ecc4d80 2981
f03fc89f 2982 gtk_widget_set_sensitive( m_widget, enable );
6552c7af 2983 if (m_wxwindow && (m_wxwindow != m_widget))
f03fc89f 2984 gtk_widget_set_sensitive( m_wxwindow, enable );
362c6693 2985}
c801d85f 2986
1e6feb95 2987int wxWindowGTK::GetCharHeight() const
2f2aa628 2988{
82b978d7 2989 wxCHECK_MSG( (m_widget != NULL), 12, wxT("invalid window") );
47d67540 2990
cc402e64 2991 wxFont font = GetFont();
a1b806b9 2992 wxCHECK_MSG( font.IsOk(), 12, wxT("invalid font") );
2f2aa628 2993
db885f2a 2994 PangoContext* context = gtk_widget_get_pango_context(m_widget);
bbd006c0
RR
2995
2996 if (!context)
2997 return 0;
2998
cc402e64 2999 PangoFontDescription *desc = font.GetNativeFontInfo()->description;
bbd006c0
RR
3000 PangoLayout *layout = pango_layout_new(context);
3001 pango_layout_set_font_description(layout, desc);
3002 pango_layout_set_text(layout, "H", 1);
3003 PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
3004
3005 PangoRectangle rect;
3006 pango_layout_line_get_extents(line, NULL, &rect);
3007
3fe39b0c 3008 g_object_unref (layout);
7de59551 3009
f69e2009 3010 return (int) PANGO_PIXELS(rect.height);
362c6693 3011}
c801d85f 3012
1e6feb95 3013int wxWindowGTK::GetCharWidth() const
c33c4050 3014{
82b978d7 3015 wxCHECK_MSG( (m_widget != NULL), 8, wxT("invalid window") );
47d67540 3016
cc402e64 3017 wxFont font = GetFont();
a1b806b9 3018 wxCHECK_MSG( font.IsOk(), 8, wxT("invalid font") );
47d67540 3019
db885f2a 3020 PangoContext* context = gtk_widget_get_pango_context(m_widget);
bbd006c0
RR
3021
3022 if (!context)
3023 return 0;
3024
cc402e64 3025 PangoFontDescription *desc = font.GetNativeFontInfo()->description;
bbd006c0
RR
3026 PangoLayout *layout = pango_layout_new(context);
3027 pango_layout_set_font_description(layout, desc);
95c430aa 3028 pango_layout_set_text(layout, "g", 1);
bbd006c0
RR
3029 PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
3030
3031 PangoRectangle rect;
3032 pango_layout_line_get_extents(line, NULL, &rect);
3033
3fe39b0c 3034 g_object_unref (layout);
7de59551 3035
f69e2009 3036 return (int) PANGO_PIXELS(rect.width);
c33c4050
RR
3037}
3038
6de70470
VZ
3039void wxWindowGTK::DoGetTextExtent( const wxString& string,
3040 int *x,
3041 int *y,
3042 int *descent,
3043 int *externalLeading,
3044 const wxFont *theFont ) const
c33c4050 3045{
cc402e64 3046 wxFont fontToUse = theFont ? *theFont : GetFont();
47d67540 3047
a1b806b9 3048 wxCHECK_RET( fontToUse.IsOk(), wxT("invalid font") );
2b5f62a0 3049
0a164d4c 3050 if (string.empty())
48d011c8 3051 {
b15ed747
RR
3052 if (x) (*x) = 0;
3053 if (y) (*y) = 0;
48d011c8
RR
3054 return;
3055 }
47d67540 3056
48d011c8
RR
3057 PangoContext *context = NULL;
3058 if (m_widget)
2b5f62a0
VZ
3059 context = gtk_widget_get_pango_context( m_widget );
3060
48d011c8
RR
3061 if (!context)
3062 {
b15ed747
RR
3063 if (x) (*x) = 0;
3064 if (y) (*y) = 0;
48d011c8
RR
3065 return;
3066 }
2b5f62a0 3067
48d011c8
RR
3068 PangoFontDescription *desc = fontToUse.GetNativeFontInfo()->description;
3069 PangoLayout *layout = pango_layout_new(context);
3070 pango_layout_set_font_description(layout, desc);
3071 {
a3669332
VZ
3072 const wxCharBuffer data = wxGTK_CONV( string );
3073 if ( data )
3074 pango_layout_set_text(layout, data, strlen(data));
48d011c8 3075 }
2b5f62a0 3076
48d011c8 3077 PangoRectangle rect;
fd43b1b3 3078 pango_layout_get_extents(layout, NULL, &rect);
2b5f62a0 3079
f69e2009
VS
3080 if (x) (*x) = (wxCoord) PANGO_PIXELS(rect.width);
3081 if (y) (*y) = (wxCoord) PANGO_PIXELS(rect.height);
48d011c8
RR
3082 if (descent)
3083 {
f69e2009
VS
3084 PangoLayoutIter *iter = pango_layout_get_iter(layout);
3085 int baseline = pango_layout_iter_get_baseline(iter);
3086 pango_layout_iter_free(iter);
3087 *descent = *y - PANGO_PIXELS(baseline);
48d011c8
RR
3088 }
3089 if (externalLeading) (*externalLeading) = 0; // ??
2b5f62a0 3090
3fe39b0c 3091 g_object_unref (layout);
c33c4050
RR
3092}
3093
36a845fe
RR
3094void wxWindowGTK::GTKDisableFocusOutEvent()
3095{
3096 g_signal_handlers_block_by_func( m_focusWidget,
3097 (gpointer) gtk_window_focus_out_callback, this);
3098}
3099
3100void wxWindowGTK::GTKEnableFocusOutEvent()
3101{
3102 g_signal_handlers_unblock_by_func( m_focusWidget,
3103 (gpointer) gtk_window_focus_out_callback, this);
3104}
bd2e08d0
VS
3105
3106bool wxWindowGTK::GTKHandleFocusIn()
ef5c70f9 3107{
bd2e08d0
VS
3108 // Disable default focus handling for custom windows since the default GTK+
3109 // handler issues a repaint
3110 const bool retval = m_wxwindow ? true : false;
3111
3112
3113 // NB: if there's still unprocessed deferred focus-out event (see
3114 // GTKHandleFocusOut() for explanation), we need to process it first so
3115 // that the order of focus events -- focus-out first, then focus-in
3116 // elsewhere -- is preserved
3117 if ( gs_deferredFocusOut )
ef5c70f9 3118 {
bd2e08d0
VS
3119 if ( GTKNeedsToFilterSameWindowFocus() &&
3120 gs_deferredFocusOut == this )
ef5c70f9 3121 {
bd2e08d0
VS
3122 // GTK+ focus changed from this wxWindow back to itself, so don't
3123 // emit any events at all
3124 wxLogTrace(TRACE_FOCUS,
3125 "filtered out spurious focus change within %s(%p, %s)",
3126 GetClassInfo()->GetClassName(), this, GetLabel());
3127 gs_deferredFocusOut = NULL;
3128 return retval;
ef5c70f9 3129 }
bd2e08d0
VS
3130
3131 // otherwise we need to send focus-out first
3132 wxASSERT_MSG ( gs_deferredFocusOut != this,
3133 "GTKHandleFocusIn(GTKFocus_Normal) called even though focus changed back to itself - derived class should handle this" );
3134 GTKHandleDeferredFocusOut();
ef5c70f9
VZ
3135 }
3136
bd2e08d0
VS
3137
3138 wxLogTrace(TRACE_FOCUS,
3139 "handling focus_in event for %s(%p, %s)",
3140 GetClassInfo()->GetClassName(), this, GetLabel());
3141
3142 if (m_imData)
3143 gtk_im_context_focus_in(m_imData->context);
3144
22f43cb5
VS
3145 gs_currentFocus = this;
3146 gs_pendingFocus = NULL;
bd2e08d0
VS
3147
3148#if wxUSE_CARET
3149 // caret needs to be informed about focus change
3150 wxCaret *caret = GetCaret();
3151 if ( caret )
3152 {
3153 caret->OnSetFocus();
3154 }
3155#endif // wxUSE_CARET
3156
3157 // Notify the parent keeping track of focus for the kbd navigation
3158 // purposes that we got it.
b22bb1a0 3159 wxChildFocusEvent eventChildFocus(static_cast<wxWindow*>(this));
bd2e08d0
VS
3160 GTKProcessEvent(eventChildFocus);
3161
3162 wxFocusEvent eventFocus(wxEVT_SET_FOCUS, GetId());
3163 eventFocus.SetEventObject(this);
3164 GTKProcessEvent(eventFocus);
3165
3166 return retval;
ef5c70f9
VZ
3167}
3168
bd2e08d0 3169bool wxWindowGTK::GTKHandleFocusOut()
7cec1c9e 3170{
bd2e08d0
VS
3171 // Disable default focus handling for custom windows since the default GTK+
3172 // handler issues a repaint
3173 const bool retval = m_wxwindow ? true : false;
3174
3175
3176 // NB: If a control is composed of several GtkWidgets and when focus
3177 // changes from one of them to another within the same wxWindow, we get
3178 // a focus-out event followed by focus-in for another GtkWidget owned
3179 // by the same wx control. We don't want to generate two spurious
3180 // wxEVT_SET_FOCUS events in this case, so we defer sending wx events
3181 // from GTKHandleFocusOut() until we know for sure it's not coming back
3182 // (i.e. in GTKHandleFocusIn() or at idle time).
3183 if ( GTKNeedsToFilterSameWindowFocus() )
7cec1c9e 3184 {
bd2e08d0
VS
3185 wxASSERT_MSG( gs_deferredFocusOut == NULL,
3186 "deferred focus out event already pending" );
3187 wxLogTrace(TRACE_FOCUS,
3188 "deferring focus_out event for %s(%p, %s)",
3189 GetClassInfo()->GetClassName(), this, GetLabel());
3190 gs_deferredFocusOut = this;
3191 return retval;
7cec1c9e
RR
3192 }
3193
bd2e08d0
VS
3194 GTKHandleFocusOutNoDeferring();
3195
3196 return retval;
3197}
3198
3199void wxWindowGTK::GTKHandleFocusOutNoDeferring()
3200{
3201 wxLogTrace(TRACE_FOCUS,
3202 "handling focus_out event for %s(%p, %s)",
3203 GetClassInfo()->GetClassName(), this, GetLabel());
3204
3205 if (m_imData)
3206 gtk_im_context_focus_out(m_imData->context);
3207
22f43cb5 3208 if ( gs_currentFocus != this )
7cec1c9e 3209 {
22f43cb5 3210 // Something is terribly wrong, gs_currentFocus is out of sync with the
bd2e08d0
VS
3211 // real focus. We will reset it to NULL anyway, because after this
3212 // focus-out event is handled, one of the following with happen:
3213 //
3214 // * either focus will go out of the app altogether, in which case
22f43cb5 3215 // gs_currentFocus _should_ be NULL
bd2e08d0
VS
3216 //
3217 // * or it goes to another control, in which case focus-in event will
22f43cb5 3218 // follow immediately and it will set gs_currentFocus to the right
bd2e08d0
VS
3219 // value
3220 wxLogDebug("window %s(%p, %s) lost focus even though it didn't have it",
3221 GetClassInfo()->GetClassName(), this, GetLabel());
3222 }
22f43cb5 3223 gs_currentFocus = NULL;
db885f2a 3224
bd2e08d0
VS
3225#if wxUSE_CARET
3226 // caret needs to be informed about focus change
3227 wxCaret *caret = GetCaret();
3228 if ( caret )
3229 {
3230 caret->OnKillFocus();
354aa1e3 3231 }
bd2e08d0
VS
3232#endif // wxUSE_CARET
3233
3234 wxFocusEvent event( wxEVT_KILL_FOCUS, GetId() );
3235 event.SetEventObject( this );
9a237e2f 3236 event.SetWindow( FindFocus() );
bd2e08d0
VS
3237 GTKProcessEvent( event );
3238}
3239
3240/*static*/
3241void wxWindowGTK::GTKHandleDeferredFocusOut()
3242{
3243 // NB: See GTKHandleFocusOut() for explanation. This function is called
3244 // from either GTKHandleFocusIn() or OnInternalIdle() to process
3245 // deferred event.
3246 if ( gs_deferredFocusOut )
c801d85f 3247 {
bd2e08d0
VS
3248 wxWindowGTK *win = gs_deferredFocusOut;
3249 gs_deferredFocusOut = NULL;
db885f2a 3250
bd2e08d0
VS
3251 wxLogTrace(TRACE_FOCUS,
3252 "processing deferred focus_out event for %s(%p, %s)",
3253 win->GetClassInfo()->GetClassName(), win, win->GetLabel());
fcb29b23 3254
bd2e08d0
VS
3255 win->GTKHandleFocusOutNoDeferring();
3256 }
3257}
0a164d4c 3258
bd2e08d0
VS
3259void wxWindowGTK::SetFocus()
3260{
3261 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
6aeb6f2a 3262
bd2e08d0
VS
3263 // Setting "physical" focus is not immediate in GTK+ and while
3264 // gtk_widget_is_focus ("determines if the widget is the focus widget
3265 // within its toplevel", i.e. returns true for one widget per TLW, not
3266 // globally) returns true immediately after grabbing focus,
3267 // GTK_WIDGET_HAS_FOCUS (which returns true only for the one widget that
4c51a665 3268 // has focus at the moment) takes effect only after the window is shown
bd2e08d0
VS
3269 // (if it was hidden at the moment of the call) or at the next event loop
3270 // iteration.
3271 //
3272 // Because we want to FindFocus() call immediately following
3273 // foo->SetFocus() to return foo, we have to keep track of "pending" focus
3274 // ourselves.
22f43cb5 3275 gs_pendingFocus = this;
bd2e08d0
VS
3276
3277 GtkWidget *widget = m_wxwindow ? m_wxwindow : m_focusWidget;
3278
3279 if ( GTK_IS_CONTAINER(widget) &&
fc9ab22a 3280 !gtk_widget_get_can_focus(widget) )
bd2e08d0
VS
3281 {
3282 wxLogTrace(TRACE_FOCUS,
9a83f860 3283 wxT("Setting focus to a child of %s(%p, %s)"),
bd2e08d0
VS
3284 GetClassInfo()->GetClassName(), this, GetLabel().c_str());
3285 gtk_widget_child_focus(widget, GTK_DIR_TAB_FORWARD);
3286 }
3287 else
3288 {
3289 wxLogTrace(TRACE_FOCUS,
9a83f860 3290 wxT("Setting focus to %s(%p, %s)"),
bd2e08d0
VS
3291 GetClassInfo()->GetClassName(), this, GetLabel().c_str());
3292 gtk_widget_grab_focus(widget);
362c6693 3293 }
362c6693 3294}
c801d85f 3295
80332672
VZ
3296void wxWindowGTK::SetCanFocus(bool canFocus)
3297{
fc9ab22a 3298 gtk_widget_set_can_focus(m_widget, canFocus);
80332672
VZ
3299
3300 if ( m_wxwindow && (m_widget != m_wxwindow) )
3301 {
fc9ab22a 3302 gtk_widget_set_can_focus(m_wxwindow, canFocus);
80332672
VZ
3303 }
3304}
3305
1e6feb95 3306bool wxWindowGTK::Reparent( wxWindowBase *newParentBase )
463c1fa1 3307{
0a164d4c 3308 wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
c50f1fb9 3309
0edbdf6a 3310 wxWindowGTK * const newParent = (wxWindowGTK *)newParentBase;
a2053b27 3311
5fd11f09
RR
3312 wxASSERT( GTK_IS_WIDGET(m_widget) );
3313
f03fc89f 3314 if ( !wxWindowBase::Reparent(newParent) )
0a164d4c 3315 return false;
8bbe427f 3316
5fd11f09
RR
3317 wxASSERT( GTK_IS_WIDGET(m_widget) );
3318
0edbdf6a
VZ
3319 // Notice that old m_parent pointer might be non-NULL here but the widget
3320 // still not have any parent at GTK level if it's a notebook page that had
3321 // been removed from the notebook so test this at GTK level and not wx one.
3322 if ( GtkWidget *parentGTK = gtk_widget_get_parent(m_widget) )
3323 gtk_container_remove(GTK_CONTAINER(parentGTK), m_widget);
c50f1fb9 3324
5fd11f09
RR
3325 wxASSERT( GTK_IS_WIDGET(m_widget) );
3326
8ce63e9d
RR
3327 if (newParent)
3328 {
fc9ab22a 3329 if (gtk_widget_get_visible (newParent->m_widget))
f46ad98f
RR
3330 {
3331 m_showOnIdle = true;
3332 gtk_widget_hide( m_widget );
3333 }
8ce63e9d 3334 /* insert GTK representation */
48200154 3335 newParent->AddChildGTK(this);
8ce63e9d 3336 }
c50f1fb9 3337
978af864 3338 SetLayoutDirection(wxLayout_Default);
148cd9b6 3339
0a164d4c 3340 return true;
362c6693 3341}
c801d85f 3342
1e6feb95 3343void wxWindowGTK::DoAddChild(wxWindowGTK *child)
ddb6bc71 3344{
223d09f6 3345 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
223d09f6 3346 wxASSERT_MSG( (child != NULL), wxT("invalid child window") );
ddb6bc71 3347
ddb6bc71
RR
3348 /* add to list */
3349 AddChild( child );
c50f1fb9 3350
ddb6bc71 3351 /* insert GTK representation */
48200154 3352 AddChildGTK(child);
ddb6bc71
RR
3353}
3354
a589495e
VS
3355void wxWindowGTK::AddChild(wxWindowBase *child)
3356{
3357 wxWindowBase::AddChild(child);
3358 m_dirtyTabOrder = true;
a1abca32 3359 wxTheApp->WakeUpIdle();
a589495e
VS
3360}
3361
3362void wxWindowGTK::RemoveChild(wxWindowBase *child)
3363{
3364 wxWindowBase::RemoveChild(child);
3365 m_dirtyTabOrder = true;
a1abca32 3366 wxTheApp->WakeUpIdle();
a589495e 3367}
0a164d4c 3368
978af864
VZ
3369/* static */
3370wxLayoutDirection wxWindowGTK::GTKGetLayout(GtkWidget *widget)
3371{
10bd1f7d 3372 return gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL
978af864
VZ
3373 ? wxLayout_RightToLeft
3374 : wxLayout_LeftToRight;
3375}
3376
3377/* static */
3378void wxWindowGTK::GTKSetLayout(GtkWidget *widget, wxLayoutDirection dir)
3379{
9a83f860 3380 wxASSERT_MSG( dir != wxLayout_Default, wxT("invalid layout direction") );
978af864 3381
10bd1f7d 3382 gtk_widget_set_direction(widget,
978af864
VZ
3383 dir == wxLayout_RightToLeft ? GTK_TEXT_DIR_RTL
3384 : GTK_TEXT_DIR_LTR);
3385}
3386
3387wxLayoutDirection wxWindowGTK::GetLayoutDirection() const
3388{
3389 return GTKGetLayout(m_widget);
3390}
3391
3392void wxWindowGTK::SetLayoutDirection(wxLayoutDirection dir)
3393{
3394 if ( dir == wxLayout_Default )
3395 {
3396 const wxWindow *const parent = GetParent();
3397 if ( parent )
3398 {
3399 // inherit layout from parent.
3400 dir = parent->GetLayoutDirection();
3401 }
3402 else // no parent, use global default layout
3403 {
3404 dir = wxTheApp->GetLayoutDirection();
3405 }
3406 }
3407
3408 if ( dir == wxLayout_Default )
3409 return;
3410
3411 GTKSetLayout(m_widget, dir);
fcb29b23 3412
6552c7af 3413 if (m_wxwindow && (m_wxwindow != m_widget))
69597639
RR
3414 GTKSetLayout(m_wxwindow, dir);
3415}
3416
3417wxCoord
3418wxWindowGTK::AdjustForLayoutDirection(wxCoord x,
3419 wxCoord WXUNUSED(width),
3420 wxCoord WXUNUSED(widthTotal)) const
3421{
08f53168 3422 // We now mirror the coordinates of RTL windows in wxPizza
69597639 3423 return x;
978af864
VZ
3424}
3425
915bd4e4 3426void wxWindowGTK::DoMoveInTabOrder(wxWindow *win, WindowOrder move)
a589495e
VS
3427{
3428 wxWindowBase::DoMoveInTabOrder(win, move);
3429 m_dirtyTabOrder = true;
a1abca32 3430 wxTheApp->WakeUpIdle();
a589495e
VS
3431}
3432
5644933f
VZ
3433bool wxWindowGTK::DoNavigateIn(int flags)
3434{
3435 if ( flags & wxNavigationKeyEvent::WinChange )
3436 {
9a83f860 3437 wxFAIL_MSG( wxT("not implemented") );
5644933f
VZ
3438
3439 return false;
3440 }
3441 else // navigate inside the container
3442 {
7a3ba5af 3443 wxWindow *parent = wxGetTopLevelParent((wxWindow *)this);
9a83f860 3444 wxCHECK_MSG( parent, false, wxT("every window must have a TLW parent") );
5644933f
VZ
3445
3446 GtkDirectionType dir;
3447 dir = flags & wxNavigationKeyEvent::IsForward ? GTK_DIR_TAB_FORWARD
3448 : GTK_DIR_TAB_BACKWARD;
3449
3450 gboolean rc;
3451 g_signal_emit_by_name(parent->m_widget, "focus", dir, &rc);
3452
3453 return rc == TRUE;
3454 }
3455}
3456
2e1f5012
VZ
3457bool wxWindowGTK::GTKWidgetNeedsMnemonic() const
3458{
3459 // none needed by default
3460 return false;
3461}
3462
3463void wxWindowGTK::GTKWidgetDoSetMnemonic(GtkWidget* WXUNUSED(w))
3464{
3465 // nothing to do by default since none is needed
3466}
3467
a589495e
VS
3468void wxWindowGTK::RealizeTabOrder()
3469{
3470 if (m_wxwindow)
3471 {
12848fda 3472 if ( !m_children.empty() )
a589495e 3473 {
259858fc 3474 // we don't only construct the correct focus chain but also use
2e1f5012
VZ
3475 // this opportunity to update the mnemonic widgets for the widgets
3476 // that need them
259858fc 3477
a589495e 3478 GList *chain = NULL;
2e1f5012 3479 wxWindowGTK* mnemonicWindow = NULL;
0a164d4c 3480
12848fda
VZ
3481 for ( wxWindowList::const_iterator i = m_children.begin();
3482 i != m_children.end();
3483 ++i )
a589495e 3484 {
259858fc 3485 wxWindowGTK *win = *i;
2e1f5012 3486
a3edb930
VZ
3487 bool focusableFromKeyboard = win->AcceptsFocusFromKeyboard();
3488
2e1f5012 3489 if ( mnemonicWindow )
259858fc 3490 {
a3edb930 3491 if ( focusableFromKeyboard )
259858fc 3492 {
2e1f5012
VZ
3493 // wxComboBox et al. needs to focus on on a different
3494 // widget than m_widget, so if the main widget isn't
3495 // focusable try the connect widget
3496 GtkWidget* w = win->m_widget;
fc9ab22a 3497 if ( !gtk_widget_get_can_focus(w) )
2e1f5012
VZ
3498 {
3499 w = win->GetConnectWidget();
fc9ab22a 3500 if ( !gtk_widget_get_can_focus(w) )
2e1f5012
VZ
3501 w = NULL;
3502 }
3503
3504 if ( w )
3505 {
3506 mnemonicWindow->GTKWidgetDoSetMnemonic(w);
3507 mnemonicWindow = NULL;
3508 }
259858fc
VZ
3509 }
3510 }
2e1f5012 3511 else if ( win->GTKWidgetNeedsMnemonic() )
259858fc 3512 {
2e1f5012 3513 mnemonicWindow = win;
259858fc 3514 }
259858fc 3515
a3edb930
VZ
3516 if ( focusableFromKeyboard )
3517 chain = g_list_prepend(chain, win->m_widget);
a589495e 3518 }
0a164d4c 3519
a589495e 3520 chain = g_list_reverse(chain);
0a164d4c 3521
a589495e
VS
3522 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow), chain);
3523 g_list_free(chain);
3524 }
12848fda 3525 else // no children
a589495e
VS
3526 {
3527 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow));
3528 }
3529 }
a589495e
VS
3530}
3531
1e6feb95 3532void wxWindowGTK::Raise()
362c6693 3533{
82b978d7
RD
3534 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3535
989d151c 3536 if (m_wxwindow && gtk_widget_get_window(m_wxwindow))
fdfb8475 3537 {
989d151c 3538 gdk_window_raise(gtk_widget_get_window(m_wxwindow));
fdfb8475 3539 }
989d151c 3540 else if (gtk_widget_get_window(m_widget))
fdfb8475 3541 {
989d151c 3542 gdk_window_raise(gtk_widget_get_window(m_widget));
fdfb8475 3543 }
362c6693
RR
3544}
3545
1e6feb95 3546void wxWindowGTK::Lower()
362c6693 3547{
82b978d7
RD
3548 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3549
989d151c 3550 if (m_wxwindow && gtk_widget_get_window(m_wxwindow))
fdfb8475 3551 {
989d151c 3552 gdk_window_lower(gtk_widget_get_window(m_wxwindow));
fdfb8475 3553 }
989d151c 3554 else if (gtk_widget_get_window(m_widget))
fdfb8475 3555 {
989d151c 3556 gdk_window_lower(gtk_widget_get_window(m_widget));
fdfb8475 3557 }
362c6693 3558}
c801d85f 3559
1e6feb95 3560bool wxWindowGTK::SetCursor( const wxCursor &cursor )
86b29a61 3561{
a1b806b9 3562 if ( !wxWindowBase::SetCursor(cursor.IsOk() ? cursor : *wxSTANDARD_CURSOR) )
2f262021 3563 return false;
f6bcfd97 3564
2f262021 3565 GTKUpdateCursor();
1e6feb95 3566
2f262021 3567 return true;
ef5c70f9
VZ
3568}
3569
c2246a38 3570void wxWindowGTK::GTKUpdateCursor(bool update_self /*=true*/, bool recurse /*=true*/)
ef5c70f9 3571{
c2246a38 3572 if (update_self)
ef5c70f9 3573 {
a1b806b9
DS
3574 wxCursor cursor(g_globalCursor.IsOk() ? g_globalCursor : GetCursor());
3575 if ( cursor.IsOk() )
ef5c70f9 3576 {
9c76b9af
RR
3577 wxArrayGdkWindows windowsThis;
3578 GdkWindow* window = GTKGetWindow(windowsThis);
3579 if (window)
3580 gdk_window_set_cursor( window, cursor.GetCursor() );
3581 else
ef5c70f9 3582 {
9c76b9af
RR
3583 const size_t count = windowsThis.size();
3584 for ( size_t n = 0; n < count; n++ )
5dd7eef7 3585 {
9c76b9af
RR
3586 GdkWindow *win = windowsThis[n];
3587 // It can be zero if the window has not been realized yet.
3588 if ( win )
c2246a38 3589 {
c2246a38
RR
3590 gdk_window_set_cursor(win, cursor.GetCursor());
3591 }
5dd7eef7 3592 }
c2246a38
RR
3593 }
3594 }
3595 }
3596
3597 if (recurse)
3598 {
3599 for (wxWindowList::iterator it = GetChildren().begin(); it != GetChildren().end(); ++it)
3600 {
3601 (*it)->GTKUpdateCursor( true );
ef5c70f9
VZ
3602 }
3603 }
362c6693 3604}
c801d85f 3605
1e6feb95 3606void wxWindowGTK::WarpPointer( int x, int y )
4f22cf8d 3607{
82b978d7
RD
3608 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3609
1ddb3b55
PC
3610 ClientToScreen(&x, &y);
3611 GdkDisplay* display = gtk_widget_get_display(m_widget);
3612 GdkScreen* screen = gtk_widget_get_screen(m_widget);
3613#ifdef __WXGTK30__
3614 GdkDeviceManager* manager = gdk_display_get_device_manager(display);
3615 gdk_device_warp(gdk_device_manager_get_client_pointer(manager), screen, x, y);
3616#else
3b81515c 3617#ifdef GDK_WINDOWING_X11
1ddb3b55
PC
3618 XWarpPointer(GDK_DISPLAY_XDISPLAY(display),
3619 None,
3620 GDK_WINDOW_XID(gdk_screen_get_root_window(screen)),
3621 0, 0, 0, 0, x, y);
3622#endif
3b81515c 3623#endif
4f22cf8d
RR
3624}
3625
22c9b211 3626wxWindowGTK::ScrollDir wxWindowGTK::ScrollDirFromRange(GtkRange *range) const
0c131a5a 3627{
22c9b211
VZ
3628 // find the scrollbar which generated the event
3629 for ( int dir = 0; dir < ScrollDir_Max; dir++ )
0c131a5a 3630 {
22c9b211
VZ
3631 if ( range == m_scrollBar[dir] )
3632 return (ScrollDir)dir;
0c131a5a 3633 }
22c9b211 3634
9a83f860 3635 wxFAIL_MSG( wxT("event from unknown scrollbar received") );
22c9b211
VZ
3636
3637 return ScrollDir_Max;
0c131a5a
VZ
3638}
3639
22c9b211 3640bool wxWindowGTK::DoScrollByUnits(ScrollDir dir, ScrollUnit unit, int units)
0c131a5a 3641{
add7cadd 3642 bool changed = false;
22c9b211
VZ
3643 GtkRange* range = m_scrollBar[dir];
3644 if ( range && units )
add7cadd 3645 {
08f09504 3646 GtkAdjustment* adj = gtk_range_get_adjustment(range);
989d151c
PC
3647 double inc = unit == ScrollUnit_Line ? gtk_adjustment_get_step_increment(adj)
3648 : gtk_adjustment_get_page_increment(adj);
22c9b211 3649
989d151c 3650 const int posOld = wxRound(gtk_adjustment_get_value(adj));
22c9b211
VZ
3651 gtk_range_set_value(range, posOld + units*inc);
3652
989d151c 3653 changed = wxRound(gtk_adjustment_get_value(adj)) != posOld;
add7cadd 3654 }
22c9b211 3655
add7cadd 3656 return changed;
0c131a5a 3657}
3013a903 3658
22c9b211
VZ
3659bool wxWindowGTK::ScrollLines(int lines)
3660{
3661 return DoScrollByUnits(ScrollDir_Vert, ScrollUnit_Line, lines);
3662}
3663
3664bool wxWindowGTK::ScrollPages(int pages)
3665{
3666 return DoScrollByUnits(ScrollDir_Vert, ScrollUnit_Page, pages);
3667}
3668
e4161a2a
VZ
3669void wxWindowGTK::Refresh(bool WXUNUSED(eraseBackground),
3670 const wxRect *rect)
c801d85f 3671{
c968ba80 3672 if (m_wxwindow)
4e5a4c69 3673 {
ffaaf107 3674 if (gtk_widget_get_mapped(m_wxwindow))
d0285203 3675 {
ffaaf107
PC
3676 GdkWindow* window = gtk_widget_get_window(m_wxwindow);
3677 if (rect)
3678 {
3679 GdkRectangle r = { rect->x, rect->y, rect->width, rect->height };
3680 if (GetLayoutDirection() == wxLayout_RightToLeft)
3681 r.x = gdk_window_get_width(window) - r.x - rect->width;
3682 gdk_window_invalidate_rect(window, &r, true);
3683 }
3684 else
3685 gdk_window_invalidate_rect(window, NULL, true);
d0285203 3686 }
4e5a4c69 3687 }
ffaaf107 3688 else if (m_widget)
c968ba80 3689 {
ffaaf107
PC
3690 if (gtk_widget_get_mapped(m_widget))
3691 {
3692 if (rect)
3693 gtk_widget_queue_draw_area(m_widget, rect->x, rect->y, rect->width, rect->height);
3694 else
3695 gtk_widget_queue_draw(m_widget);
3696 }
c968ba80 3697 }
362c6693 3698}
c801d85f 3699
beab25bd 3700void wxWindowGTK::Update()
010afced 3701{
fc9ab22a 3702 if (m_widget && gtk_widget_get_mapped(m_widget))
ab0c1a3c
PC
3703 {
3704 GdkDisplay* display = gtk_widget_get_display(m_widget);
3705 // Flush everything out to the server, and wait for it to finish.
3706 // This ensures nothing will overwrite the drawing we are about to do.
3707 gdk_display_sync(display);
010afced 3708
f089940f
PC
3709 GdkWindow* window = GTKGetDrawingWindow();
3710 if (window == NULL)
989d151c 3711 window = gtk_widget_get_window(m_widget);
f089940f 3712 gdk_window_process_updates(window, true);
03647350 3713
6cab4fca
PC
3714 // Flush again, but no need to wait for it to finish
3715 gdk_display_flush(display);
a67f1484 3716 }
beab25bd
RR
3717}
3718
657b4fd4 3719bool wxWindowGTK::DoIsExposed( int x, int y ) const
847dfdb4
RR
3720{
3721 return m_updateRegion.Contains(x, y) != wxOutRegion;
3722}
3723
657b4fd4 3724bool wxWindowGTK::DoIsExposed( int x, int y, int w, int h ) const
847dfdb4
RR
3725{
3726 if (GetLayoutDirection() == wxLayout_RightToLeft)
3727 return m_updateRegion.Contains(x-w, y, w, h) != wxOutRegion;
3728 else
3729 return m_updateRegion.Contains(x, y, w, h) != wxOutRegion;
3730}
3731
beab25bd
RR
3732void wxWindowGTK::GtkSendPaintEvents()
3733{
3bcc8d15
RR
3734 if (!m_wxwindow)
3735 {
3bcc8d15
RR
3736 m_updateRegion.Clear();
3737 return;
3738 }
ac900e6b
PC
3739#if wxGTK_HAS_COMPOSITING_SUPPORT
3740 cairo_t* cr = NULL;
3741#endif
f90566f5 3742 // Clip to paint region in wxClientDC
0a164d4c 3743 m_clipPaintRegion = true;
fab591c5 3744
bcb614b3
RR
3745 m_nativeUpdateRegion = m_updateRegion;
3746
847dfdb4
RR
3747 if (GetLayoutDirection() == wxLayout_RightToLeft)
3748 {
bcb614b3
RR
3749 // Transform m_updateRegion under RTL
3750 m_updateRegion.Clear();
fcb29b23 3751
847dfdb4 3752 gint width;
989d151c 3753 gdk_drawable_get_size(gtk_widget_get_window(m_wxwindow), &width, NULL);
fcb29b23 3754
bcb614b3 3755 wxRegionIterator upd( m_nativeUpdateRegion );
847dfdb4
RR
3756 while (upd)
3757 {
3758 wxRect rect;
3759 rect.x = upd.GetX();
3760 rect.y = upd.GetY();
3761 rect.width = upd.GetWidth();
3762 rect.height = upd.GetHeight();
fcb29b23 3763
847dfdb4 3764 rect.x = width - rect.x - rect.width;
bcb614b3 3765 m_updateRegion.Union( rect );
fcb29b23 3766
847dfdb4
RR
3767 ++upd;
3768 }
3769 }
fcb29b23 3770
9c61c5b0 3771 switch ( GetBackgroundStyle() )
f90566f5 3772 {
14421681 3773 case wxBG_STYLE_TRANSPARENT:
ac900e6b
PC
3774#if wxGTK_HAS_COMPOSITING_SUPPORT
3775 if (IsTransparentBackgroundSupported())
14421681
VZ
3776 {
3777 // Set a transparent background, so that overlaying in parent
3778 // might indeed let see through where this child did not
3779 // explicitly paint.
3780 // NB: it works also for top level windows (but this is the
3781 // windows manager which then does the compositing job)
ac900e6b
PC
3782 cr = gdk_cairo_create(m_wxwindow->window);
3783 gdk_cairo_region(cr, m_nativeUpdateRegion.GetRegion());
3784 cairo_clip(cr);
3785
3786 cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
3787 cairo_paint(cr);
3788 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
3789 cairo_surface_flush(cairo_get_target(cr));
14421681 3790 }
ac900e6b
PC
3791#endif // wxGTK_HAS_COMPOSITING_SUPPORT
3792 break;
14421681 3793
9c61c5b0 3794 case wxBG_STYLE_ERASE:
822cf31c 3795 {
9c61c5b0
VZ
3796 wxWindowDC dc( (wxWindow*)this );
3797 dc.SetDeviceClippingRegion( m_updateRegion );
3798
3799 // Work around gtk-qt <= 0.60 bug whereby the window colour
3800 // remains grey
3801 if ( UseBgCol() &&
3802 wxSystemOptions::
3803 GetOptionInt("gtk.window.force-background-colour") )
3804 {
3805 dc.SetBackground(GetBackgroundColour());
3806 dc.Clear();
3807 }
3808
3809 wxEraseEvent erase_event( GetId(), &dc );
3810 erase_event.SetEventObject( this );
3811
3812 if ( HandleWindowEvent(erase_event) )
3813 {
3814 // background erased, don't do it again
3815 break;
3816 }
822cf31c 3817 }
9c61c5b0 3818 // fall through
b15ed747 3819
9c61c5b0
VZ
3820 case wxBG_STYLE_SYSTEM:
3821 if ( GetThemeEnabled() )
3822 {
3823 // find ancestor from which to steal background
3824 wxWindow *parent = wxGetTopLevelParent((wxWindow *)this);
3825 if (!parent)
3826 parent = (wxWindow*)this;
3827
fc9ab22a 3828 if (gtk_widget_get_mapped(parent->m_widget))
9c61c5b0
VZ
3829 {
3830 wxRegionIterator upd( m_nativeUpdateRegion );
3831 while (upd)
3832 {
3833 GdkRectangle rect;
3834 rect.x = upd.GetX();
3835 rect.y = upd.GetY();
3836 rect.width = upd.GetWidth();
3837 rect.height = upd.GetHeight();
3838
08f09504 3839 gtk_paint_flat_box(gtk_widget_get_style(parent->m_widget),
f089940f 3840 GTKGetDrawingWindow(),
989d151c 3841 gtk_widget_get_state(m_wxwindow),
9c61c5b0
VZ
3842 GTK_SHADOW_NONE,
3843 &rect,
3844 parent->m_widget,
3845 (char *)"base",
3846 0, 0, -1, -1 );
3847
3848 ++upd;
3849 }
3850 }
3851 }
3852 break;
8ab7b4c5 3853
9c61c5b0
VZ
3854 case wxBG_STYLE_PAINT:
3855 // nothing to do: window will be painted over in EVT_PAINT
3856 break;
b15ed747 3857
9c61c5b0
VZ
3858 default:
3859 wxFAIL_MSG( "unsupported background style" );
b15ed747 3860 }
03eaa52a 3861
beab25bd
RR
3862 wxNcPaintEvent nc_paint_event( GetId() );
3863 nc_paint_event.SetEventObject( this );
937013e0 3864 HandleWindowEvent( nc_paint_event );
03eaa52a 3865
beab25bd
RR
3866 wxPaintEvent paint_event( GetId() );
3867 paint_event.SetEventObject( this );
937013e0 3868 HandleWindowEvent( paint_event );
beab25bd 3869
ac900e6b
PC
3870#if wxGTK_HAS_COMPOSITING_SUPPORT
3871 if (IsTransparentBackgroundSupported())
14421681 3872 { // now composite children which need it
14421681
VZ
3873 // Overlay all our composite children on top of the painted area
3874 wxWindowList::compatibility_iterator node;
3875 for ( node = m_children.GetFirst(); node ; node = node->GetNext() )
3876 {
3877 wxWindow *compositeChild = node->GetData();
3878 if (compositeChild->GetBackgroundStyle() == wxBG_STYLE_TRANSPARENT)
3879 {
ac900e6b
PC
3880 if (cr == NULL)
3881 {
3882 cr = gdk_cairo_create(m_wxwindow->window);
3883 gdk_cairo_region(cr, m_nativeUpdateRegion.GetRegion());
3884 cairo_clip(cr);
3885 }
3886
14421681 3887 GtkWidget *child = compositeChild->m_wxwindow;
ac900e6b
PC
3888 GtkAllocation alloc;
3889 gtk_widget_get_allocation(child, &alloc);
14421681
VZ
3890
3891 // The source data is the (composited) child
ac900e6b
PC
3892 gdk_cairo_set_source_window(
3893 cr, gtk_widget_get_window(child), alloc.x, alloc.y);
14421681 3894
ac900e6b 3895 cairo_paint(cr);
14421681
VZ
3896 }
3897 }
ac900e6b
PC
3898 if (cr)
3899 cairo_destroy(cr);
14421681 3900 }
ac900e6b 3901#endif // wxGTK_HAS_COMPOSITING_SUPPORT
14421681 3902
0a164d4c 3903 m_clipPaintRegion = false;
c89f5c02 3904
c89f5c02 3905 m_updateRegion.Clear();
bcb614b3 3906 m_nativeUpdateRegion.Clear();
beab25bd
RR
3907}
3908
8e1a5bf9
VZ
3909void wxWindowGTK::SetDoubleBuffered( bool on )
3910{
3911 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3912
3913 if ( m_wxwindow )
3914 gtk_widget_set_double_buffered( m_wxwindow, on );
3915}
3916
2e992e06
VZ
3917bool wxWindowGTK::IsDoubleBuffered() const
3918{
fc9ab22a 3919 return gtk_widget_get_double_buffered( m_wxwindow );
2e992e06
VZ
3920}
3921
596f1d11 3922void wxWindowGTK::ClearBackground()
c801d85f 3923{
82b978d7 3924 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
362c6693 3925}
c801d85f 3926
ff8bfdbb 3927#if wxUSE_TOOLTIPS
1e6feb95 3928void wxWindowGTK::DoSetToolTip( wxToolTip *tip )
b1170810 3929{
558a94bd 3930 if (m_tooltip != tip)
fb4b0165 3931 {
558a94bd
PC
3932 wxWindowBase::DoSetToolTip(tip);
3933
3934 if (m_tooltip)
3935 m_tooltip->GTKSetWindow(static_cast<wxWindow*>(this));
3936 else
3937 GTKApplyToolTip(NULL);
fb4b0165 3938 }
b1170810
RR
3939}
3940
558a94bd 3941void wxWindowGTK::GTKApplyToolTip(const char* tip)
b1170810 3942{
558a94bd 3943 wxToolTip::GTKApply(GetConnectWidget(), tip);
301cd871 3944}
ff8bfdbb 3945#endif // wxUSE_TOOLTIPS
b1170810 3946
1e6feb95 3947bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
c801d85f 3948{
0a164d4c 3949 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
8bbe427f 3950
739730ca 3951 if (!wxWindowBase::SetBackgroundColour(colour))
44dfb5ce 3952 return false;
c50f1fb9 3953
a1b806b9 3954 if (colour.IsOk())
994bc575 3955 {
5edef14e
VS
3956 // We need the pixel value e.g. for background clearing.
3957 m_backgroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
994bc575 3958 }
ca298c88 3959
5edef14e 3960 // apply style change (forceStyle=true so that new style is applied
c7382f91 3961 // even if the bg colour changed from valid to wxNullColour)
9c61c5b0 3962 GTKApplyWidgetStyle(true);
ea323db3 3963
5edef14e 3964 return true;
6de97a3b
RR
3965}
3966
1e6feb95 3967bool wxWindowGTK::SetForegroundColour( const wxColour &colour )
6de97a3b 3968{
0a164d4c 3969 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
8bbe427f 3970
739730ca
RR
3971 if (!wxWindowBase::SetForegroundColour(colour))
3972 {
5edef14e 3973 return false;
739730ca 3974 }
0a164d4c 3975
a1b806b9 3976 if (colour.IsOk())
ea323db3 3977 {
5edef14e
VS
3978 // We need the pixel value e.g. for background clearing.
3979 m_foregroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
ea323db3 3980 }
f03fc89f 3981
5edef14e
VS
3982 // apply style change (forceStyle=true so that new style is applied
3983 // even if the bg colour changed from valid to wxNullColour):
496e7ec6 3984 GTKApplyWidgetStyle(true);
5edef14e 3985
44dfb5ce 3986 return true;
58614078
RR
3987}
3988
496e7ec6 3989PangoContext *wxWindowGTK::GTKGetPangoDefaultContext()
2b5f62a0
VZ
3990{
3991 return gtk_widget_get_pango_context( m_widget );
3992}
0a164d4c 3993
496e7ec6 3994GtkRcStyle *wxWindowGTK::GTKCreateWidgetStyle(bool forceStyle)
58614078 3995{
f40fdaa3 3996 // do we need to apply any changes at all?
5edef14e 3997 if ( !forceStyle &&
a1b806b9
DS
3998 !m_font.IsOk() &&
3999 !m_foregroundColour.IsOk() && !m_backgroundColour.IsOk() )
fb65642c 4000 {
f40fdaa3 4001 return NULL;
fb65642c
RR
4002 }
4003
f40fdaa3 4004 GtkRcStyle *style = gtk_rc_style_new();
1ecc4d80 4005
a1b806b9 4006 if ( m_font.IsOk() )
db434467 4007 {
0a164d4c 4008 style->font_desc =
f40fdaa3 4009 pango_font_description_copy( m_font.GetNativeFontInfo()->description );
288059b2 4010 }
1ecc4d80 4011
532ae0f6
VZ
4012 int flagsNormal = 0,
4013 flagsPrelight = 0,
4014 flagsActive = 0,
4015 flagsInsensitive = 0;
4016
a1b806b9 4017 if ( m_foregroundColour.IsOk() )
1ecc4d80 4018 {
c6685317 4019 const GdkColor *fg = m_foregroundColour.GetColor();
0a164d4c 4020
532ae0f6
VZ
4021 style->fg[GTK_STATE_NORMAL] =
4022 style->text[GTK_STATE_NORMAL] = *fg;
4023 flagsNormal |= GTK_RC_FG | GTK_RC_TEXT;
0a164d4c 4024
532ae0f6
VZ
4025 style->fg[GTK_STATE_PRELIGHT] =
4026 style->text[GTK_STATE_PRELIGHT] = *fg;
4027 flagsPrelight |= GTK_RC_FG | GTK_RC_TEXT;
0a164d4c 4028
532ae0f6
VZ
4029 style->fg[GTK_STATE_ACTIVE] =
4030 style->text[GTK_STATE_ACTIVE] = *fg;
4031 flagsActive |= GTK_RC_FG | GTK_RC_TEXT;
1ecc4d80
RR
4032 }
4033
a1b806b9 4034 if ( m_backgroundColour.IsOk() )
1ecc4d80 4035 {
c6685317 4036 const GdkColor *bg = m_backgroundColour.GetColor();
5edef14e 4037
532ae0f6 4038 style->bg[GTK_STATE_NORMAL] =
5edef14e 4039 style->base[GTK_STATE_NORMAL] = *bg;
532ae0f6 4040 flagsNormal |= GTK_RC_BG | GTK_RC_BASE;
0a164d4c 4041
532ae0f6 4042 style->bg[GTK_STATE_PRELIGHT] =
5edef14e 4043 style->base[GTK_STATE_PRELIGHT] = *bg;
532ae0f6 4044 flagsPrelight |= GTK_RC_BG | GTK_RC_BASE;
0a164d4c 4045
532ae0f6 4046 style->bg[GTK_STATE_ACTIVE] =
5edef14e 4047 style->base[GTK_STATE_ACTIVE] = *bg;
532ae0f6 4048 flagsActive |= GTK_RC_BG | GTK_RC_BASE;
0a164d4c 4049
532ae0f6 4050 style->bg[GTK_STATE_INSENSITIVE] =
5edef14e 4051 style->base[GTK_STATE_INSENSITIVE] = *bg;
532ae0f6 4052 flagsInsensitive |= GTK_RC_BG | GTK_RC_BASE;
1ecc4d80 4053 }
0a164d4c 4054
532ae0f6
VZ
4055 style->color_flags[GTK_STATE_NORMAL] = (GtkRcFlags)flagsNormal;
4056 style->color_flags[GTK_STATE_PRELIGHT] = (GtkRcFlags)flagsPrelight;
4057 style->color_flags[GTK_STATE_ACTIVE] = (GtkRcFlags)flagsActive;
4058 style->color_flags[GTK_STATE_INSENSITIVE] = (GtkRcFlags)flagsInsensitive;
4059
f40fdaa3 4060 return style;
a81258be
RR
4061}
4062
496e7ec6 4063void wxWindowGTK::GTKApplyWidgetStyle(bool forceStyle)
a81258be 4064{
496e7ec6 4065 GtkRcStyle *style = GTKCreateWidgetStyle(forceStyle);
f8e045e2
RD
4066 if ( style )
4067 {
7074ce35 4068 DoApplyWidgetStyle(style);
08f09504 4069 g_object_unref(style);
f8e045e2 4070 }
6dd18972
VS
4071
4072 // Style change may affect GTK+'s size calculation:
4073 InvalidateBestSize();
6de97a3b
RR
4074}
4075
7074ce35
VS
4076void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle *style)
4077{
0d013e46
VZ
4078 if ( m_wxwindow )
4079 {
4080 // block the signal temporarily to avoid sending
4081 // wxSysColourChangedEvents when we change the colours ourselves
4082 bool unblock = false;
4083 if ( IsTopLevel() )
4084 {
4085 unblock = true;
4086 g_signal_handlers_block_by_func(
4087 m_wxwindow, (void *)gtk_window_style_set_callback, this);
4088 }
013151c7 4089
7074ce35 4090 gtk_widget_modify_style(m_wxwindow, style);
0d013e46
VZ
4091
4092 if ( unblock )
4093 {
4094 g_signal_handlers_unblock_by_func(
4095 m_wxwindow, (void *)gtk_window_style_set_callback, this);
4096 }
4097 }
7cb93e45 4098 else
0d013e46 4099 {
7cb93e45 4100 gtk_widget_modify_style(m_widget, style);
0d013e46 4101 }
7074ce35
VS
4102}
4103
c7382f91
JS
4104bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style)
4105{
14421681
VZ
4106 if (!wxWindowBase::SetBackgroundStyle(style))
4107 return false;
0a164d4c 4108
14421681
VZ
4109 GdkWindow *window;
4110 if ( m_wxwindow )
c7382f91 4111 {
14421681
VZ
4112 window = GTKGetDrawingWindow();
4113 }
4114 else
4115 {
4116 GtkWidget * const w = GetConnectWidget();
4117 window = w ? gtk_widget_get_window(w) : NULL;
4118 }
4119
4120 bool wantNoBackPixmap = style == wxBG_STYLE_PAINT || style == wxBG_STYLE_TRANSPARENT;
c7382f91 4121
14421681
VZ
4122 if ( wantNoBackPixmap )
4123 {
c7382f91
JS
4124 if (window)
4125 {
4126 // Make sure GDK/X11 doesn't refresh the window
4127 // automatically.
3b81515c 4128 gdk_window_set_back_pixmap( window, NULL, FALSE );
c7382f91
JS
4129 m_needsStyleChange = false;
4130 }
788f9633
VZ
4131 else // window not realized yet
4132 {
6041f69c 4133 // Do when window is realized
c7382f91 4134 m_needsStyleChange = true;
788f9633 4135 }
0a164d4c 4136
c7382f91
JS
4137 // Don't apply widget style, or we get a grey background
4138 }
4139 else
4140 {
4141 // apply style change (forceStyle=true so that new style is applied
4142 // even if the bg colour changed from valid to wxNullColour):
496e7ec6 4143 GTKApplyWidgetStyle(true);
c7382f91 4144 }
9c61c5b0 4145
c7382f91
JS
4146 return true;
4147}
7074ce35 4148
14421681
VZ
4149bool wxWindowGTK::IsTransparentBackgroundSupported(wxString* reason) const
4150{
ac900e6b 4151#if wxGTK_HAS_COMPOSITING_SUPPORT
14421681
VZ
4152 if (gtk_check_version(wxGTK_VERSION_REQUIRED_FOR_COMPOSITING) != NULL)
4153 {
4154 if (reason)
4155 {
4156 *reason = _("GTK+ installed on this machine is too old to "
4157 "support screen compositing, please install "
4158 "GTK+ 2.12 or later.");
4159 }
4160
4161 return false;
4162 }
4163
4164 // NB: We don't check here if the particular kind of widget supports
4165 // transparency, we check only if it would be possible for a generic window
4166
4167 wxCHECK_MSG ( m_widget, false, "Window must be created first" );
4168
4169 if (!gdk_screen_is_composited(gtk_widget_get_screen(m_widget)))
4170 {
4171 if (reason)
4172 {
4173 *reason = _("Compositing not supported by this system, "
4174 "please enable it in your Window Manager.");
4175 }
4176
4177 return false;
4178 }
4179
4180 return true;
ac900e6b 4181#else
14421681
VZ
4182 if (reason)
4183 {
4184 *reason = _("This program was compiled with a too old version of GTK+, "
4185 "please rebuild with GTK+ 2.12 or newer.");
4186 }
14421681
VZ
4187#endif // wxGTK_HAS_COMPOSITING_SUPPORT/!wxGTK_HAS_COMPOSITING_SUPPORT
4188
4189 return false;
4190}
4191
bcf7614c
PC
4192// ----------------------------------------------------------------------------
4193// Pop-up menu stuff
4194// ----------------------------------------------------------------------------
4195
4196#if wxUSE_MENUS_NATIVE
4197
edd6813c
PC
4198extern "C" {
4199static
bcf7614c
PC
4200void wxPopupMenuPositionCallback( GtkMenu *menu,
4201 gint *x, gint *y,
4202 gboolean * WXUNUSED(whatever),
4203 gpointer user_data )
4204{
4205 // ensure that the menu appears entirely on screen
4206 GtkRequisition req;
4207 gtk_widget_get_child_requisition(GTK_WIDGET(menu), &req);
4208
4209 wxSize sizeScreen = wxGetDisplaySize();
4210 wxPoint *pos = (wxPoint*)user_data;
4211
4212 gint xmax = sizeScreen.x - req.width,
4213 ymax = sizeScreen.y - req.height;
4214
4215 *x = pos->x < xmax ? pos->x : xmax;
4216 *y = pos->y < ymax ? pos->y : ymax;
4217}
edd6813c
PC
4218}
4219
bcf7614c
PC
4220bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
4221{
4222 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
4223
a1c6f069 4224 menu->UpdateUI();
bcf7614c
PC
4225
4226 wxPoint pos;
4227 gpointer userdata;
4228 GtkMenuPositionFunc posfunc;
4229 if ( x == -1 && y == -1 )
4230 {
4231 // use GTK's default positioning algorithm
4232 userdata = NULL;
4233 posfunc = NULL;
4234 }
4235 else
4236 {
4237 pos = ClientToScreen(wxPoint(x, y));
4238 userdata = &pos;
4239 posfunc = wxPopupMenuPositionCallback;
4240 }
4241
4242 menu->m_popupShown = true;
4243 gtk_menu_popup(
4244 GTK_MENU(menu->m_menu),
d3b9f782
VZ
4245 NULL, // parent menu shell
4246 NULL, // parent menu item
bcf7614c
PC
4247 posfunc, // function to position it
4248 userdata, // client data
4249 0, // button used to activate it
4250 gtk_get_current_event_time()
4251 );
4252
4253 while (menu->m_popupShown)
4254 {
4255 gtk_main_iteration();
4256 }
4257
4258 return true;
4259}
4260
4261#endif // wxUSE_MENUS_NATIVE
4262
06cfab17 4263#if wxUSE_DRAG_AND_DROP
ac57418f 4264
1e6feb95 4265void wxWindowGTK::SetDropTarget( wxDropTarget *dropTarget )
c801d85f 4266{
82b978d7
RD
4267 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4268
1ecc4d80 4269 GtkWidget *dnd_widget = GetConnectWidget();
47d67540 4270
1fe91d70 4271 if (m_dropTarget) m_dropTarget->GtkUnregisterWidget( dnd_widget );
47d67540 4272
1ecc4d80
RR
4273 if (m_dropTarget) delete m_dropTarget;
4274 m_dropTarget = dropTarget;
47d67540 4275
1fe91d70 4276 if (m_dropTarget) m_dropTarget->GtkRegisterWidget( dnd_widget );
362c6693 4277}
c801d85f 4278
f03fc89f 4279#endif // wxUSE_DRAG_AND_DROP
ac57418f 4280
1e6feb95 4281GtkWidget* wxWindowGTK::GetConnectWidget()
e3e65dac 4282{
1ecc4d80
RR
4283 GtkWidget *connect_widget = m_widget;
4284 if (m_wxwindow) connect_widget = m_wxwindow;
47d67540 4285
1ecc4d80 4286 return connect_widget;
e3e65dac 4287}
47d67540 4288
ef5c70f9 4289bool wxWindowGTK::GTKIsOwnWindow(GdkWindow *window) const
903f689b 4290{
ef5c70f9
VZ
4291 wxArrayGdkWindows windowsThis;
4292 GdkWindow * const winThis = GTKGetWindow(windowsThis);
148cd9b6 4293
ef5c70f9
VZ
4294 return winThis ? window == winThis
4295 : windowsThis.Index(window) != wxNOT_FOUND;
4296}
4297
4298GdkWindow *wxWindowGTK::GTKGetWindow(wxArrayGdkWindows& WXUNUSED(windows)) const
4299{
989d151c 4300 return m_wxwindow ? GTKGetDrawingWindow() : gtk_widget_get_window(m_widget);
903f689b
RR
4301}
4302
1e6feb95 4303bool wxWindowGTK::SetFont( const wxFont &font )
c801d85f 4304{
0a164d4c 4305 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
9c288e4d 4306
5edef14e
VS
4307 if (!wxWindowBase::SetFont(font))
4308 return false;
c801d85f 4309
5edef14e
VS
4310 // apply style change (forceStyle=true so that new style is applied
4311 // even if the font changed from valid to wxNullFont):
496e7ec6 4312 GTKApplyWidgetStyle(true);
5edef14e
VS
4313
4314 return true;
362c6693 4315}
c801d85f 4316
94633ad9 4317void wxWindowGTK::DoCaptureMouse()
c801d85f 4318{
82b978d7
RD
4319 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4320
d3b9f782 4321 GdkWindow *window = NULL;
b231914f 4322 if (m_wxwindow)
f089940f 4323 window = GTKGetDrawingWindow();
ed673c6a 4324 else
989d151c 4325 window = gtk_widget_get_window(GetConnectWidget());
148cd9b6 4326
9a83f860 4327 wxCHECK_RET( window, wxT("CaptureMouse() failed") );
c50f1fb9 4328
f516d986 4329 const wxCursor* cursor = &m_cursor;
a1b806b9 4330 if (!cursor->IsOk())
cca602ac
JS
4331 cursor = wxSTANDARD_CURSOR;
4332
ed673c6a 4333 gdk_pointer_grab( window, FALSE,
1ecc4d80
RR
4334 (GdkEventMask)
4335 (GDK_BUTTON_PRESS_MASK |
4336 GDK_BUTTON_RELEASE_MASK |
148cd9b6 4337 GDK_POINTER_MOTION_HINT_MASK |
1ecc4d80 4338 GDK_POINTER_MOTION_MASK),
d3b9f782 4339 NULL,
cca602ac 4340 cursor->GetCursor(),
b02da6b1 4341 (guint32)GDK_CURRENT_TIME );
b231914f 4342 g_captureWindow = this;
0a164d4c 4343 g_captureWindowHasMouse = true;
362c6693 4344}
c801d85f 4345
94633ad9 4346void wxWindowGTK::DoReleaseMouse()
c801d85f 4347{
82b978d7
RD
4348 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4349
e4606ed9 4350 wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") );
47d67540 4351
d3b9f782 4352 g_captureWindow = NULL;
c43430bb 4353
d3b9f782 4354 GdkWindow *window = NULL;
b231914f 4355 if (m_wxwindow)
f089940f 4356 window = GTKGetDrawingWindow();
ed673c6a 4357 else
989d151c 4358 window = gtk_widget_get_window(GetConnectWidget());
148cd9b6 4359
b02da6b1
VZ
4360 if (!window)
4361 return;
c50f1fb9 4362
b02da6b1 4363 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
362c6693 4364}
c801d85f 4365
7738af59
VZ
4366void wxWindowGTK::GTKReleaseMouseAndNotify()
4367{
4368 DoReleaseMouse();
4369 wxMouseCaptureLostEvent evt(GetId());
4370 evt.SetEventObject( this );
937013e0 4371 HandleWindowEvent( evt );
7738af59
VZ
4372}
4373
1e6feb95
VZ
4374/* static */
4375wxWindow *wxWindowBase::GetCapture()
4376{
4377 return (wxWindow *)g_captureWindow;
4378}
4379
4380bool wxWindowGTK::IsRetained() const
c801d85f 4381{
0a164d4c 4382 return false;
362c6693 4383}
c801d85f 4384
22c9b211
VZ
4385void wxWindowGTK::SetScrollbar(int orient,
4386 int pos,
4387 int thumbVisible,
4388 int range,
4389 bool WXUNUSED(update))
c801d85f 4390{
63c95f27
PC
4391 const int dir = ScrollDirFromOrient(orient);
4392 GtkRange* const sb = m_scrollBar[dir];
9a83f860 4393 wxCHECK_RET( sb, wxT("this window is not scrollable") );
c801d85f 4394
8466fc74 4395 if (range <= 0)
de7bb802
PC
4396 {
4397 // GtkRange requires upper > lower
4398 range =
4399 thumbVisible = 1;
4400 }
47d67540 4401
63c95f27
PC
4402 g_signal_handlers_block_by_func(
4403 sb, (void*)gtk_scrollbar_value_changed, this);
4404
2bca0d20 4405 gtk_range_set_increments(sb, 1, thumbVisible);
989d151c 4406 gtk_adjustment_set_page_size(gtk_range_get_adjustment(sb), thumbVisible);
63c95f27 4407 gtk_range_set_range(sb, 0, range);
2bca0d20
PC
4408 gtk_range_set_value(sb, pos);
4409 m_scrollPos[dir] = gtk_range_get_value(sb);
63c95f27
PC
4410
4411 g_signal_handlers_unblock_by_func(
4412 sb, (void*)gtk_scrollbar_value_changed, this);
87a3ebe9
VZ
4413}
4414
22c9b211 4415void wxWindowGTK::SetScrollPos(int orient, int pos, bool WXUNUSED(refresh))
c801d85f 4416{
b9e7f011
VZ
4417 const int dir = ScrollDirFromOrient(orient);
4418 GtkRange * const sb = m_scrollBar[dir];
9a83f860 4419 wxCHECK_RET( sb, wxT("this window is not scrollable") );
1ecc4d80 4420
add7cadd
PC
4421 // This check is more than an optimization. Without it, the slider
4422 // will not move smoothly while tracking when using wxScrollHelper.
4423 if (GetScrollPos(orient) != pos)
47d67540 4424 {
63c95f27
PC
4425 g_signal_handlers_block_by_func(
4426 sb, (void*)gtk_scrollbar_value_changed, this);
40e5ebbf 4427
63c95f27 4428 gtk_range_set_value(sb, pos);
2bca0d20 4429 m_scrollPos[dir] = gtk_range_get_value(sb);
98264520 4430
63c95f27
PC
4431 g_signal_handlers_unblock_by_func(
4432 sb, (void*)gtk_scrollbar_value_changed, this);
cb43b372 4433 }
362c6693 4434}
c801d85f 4435
22c9b211 4436int wxWindowGTK::GetScrollThumb(int orient) const
c801d85f 4437{
b9e7f011 4438 GtkRange * const sb = m_scrollBar[ScrollDirFromOrient(orient)];
9a83f860 4439 wxCHECK_MSG( sb, 0, wxT("this window is not scrollable") );
47d67540 4440
989d151c 4441 return wxRound(gtk_adjustment_get_page_size(gtk_range_get_adjustment(sb)));
362c6693 4442}
c801d85f 4443
1e6feb95 4444int wxWindowGTK::GetScrollPos( int orient ) const
c801d85f 4445{
b9e7f011 4446 GtkRange * const sb = m_scrollBar[ScrollDirFromOrient(orient)];
9a83f860 4447 wxCHECK_MSG( sb, 0, wxT("this window is not scrollable") );
c801d85f 4448
2bca0d20 4449 return wxRound(gtk_range_get_value(sb));
362c6693 4450}
c801d85f 4451
1e6feb95 4452int wxWindowGTK::GetScrollRange( int orient ) const
c801d85f 4453{
b9e7f011 4454 GtkRange * const sb = m_scrollBar[ScrollDirFromOrient(orient)];
9a83f860 4455 wxCHECK_MSG( sb, 0, wxT("this window is not scrollable") );
c801d85f 4456
989d151c 4457 return wxRound(gtk_adjustment_get_upper(gtk_range_get_adjustment(sb)));
add7cadd
PC
4458}
4459
4460// Determine if increment is the same as +/-x, allowing for some small
4461// difference due to possible inexactness in floating point arithmetic
4462static inline bool IsScrollIncrement(double increment, double x)
4463{
4464 wxASSERT(increment > 0);
4465 const double tolerance = 1.0 / 1024;
4466 return fabs(increment - fabs(x)) < tolerance;
4467}
4468
71ead4bf 4469wxEventType wxWindowGTK::GTKGetScrollEventType(GtkRange* range)
add7cadd 4470{
add7cadd
PC
4471 wxASSERT(range == m_scrollBar[0] || range == m_scrollBar[1]);
4472
4473 const int barIndex = range == m_scrollBar[1];
fcb29b23 4474
2bca0d20 4475 const double value = gtk_range_get_value(range);
fcb29b23 4476
add7cadd
PC
4477 // save previous position
4478 const double oldPos = m_scrollPos[barIndex];
4479 // update current position
2bca0d20 4480 m_scrollPos[barIndex] = value;
add7cadd 4481 // If event should be ignored, or integral position has not changed
2bca0d20 4482 if (!m_hasVMT || g_blockEventsOnDrag || wxRound(value) == wxRound(oldPos))
add7cadd
PC
4483 {
4484 return wxEVT_NULL;
4485 }
4486
4487 wxEventType eventType = wxEVT_SCROLL_THUMBTRACK;
4488 if (!m_isScrolling)
4489 {
4490 // Difference from last change event
2bca0d20 4491 const double diff = value - oldPos;
add7cadd
PC
4492 const bool isDown = diff > 0;
4493
2bca0d20 4494 GtkAdjustment* adj = gtk_range_get_adjustment(range);
989d151c 4495 if (IsScrollIncrement(gtk_adjustment_get_step_increment(adj), diff))
add7cadd
PC
4496 {
4497 eventType = isDown ? wxEVT_SCROLL_LINEDOWN : wxEVT_SCROLL_LINEUP;
4498 }
989d151c 4499 else if (IsScrollIncrement(gtk_adjustment_get_page_increment(adj), diff))
add7cadd
PC
4500 {
4501 eventType = isDown ? wxEVT_SCROLL_PAGEDOWN : wxEVT_SCROLL_PAGEUP;
4502 }
4503 else if (m_mouseButtonDown)
4504 {
4505 // Assume track event
4506 m_isScrolling = true;
4507 }
4508 }
4509 return eventType;
362c6693 4510}
c801d85f 4511
1e6feb95 4512void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
c801d85f 4513{
82b978d7
RD
4514 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4515
223d09f6 4516 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
2b5f62a0 4517
f47ae6e7 4518 // No scrolling requested.
8e217128 4519 if ((dx == 0) && (dy == 0)) return;
35510e48 4520
0a164d4c 4521 m_clipPaintRegion = true;
0fc5dbf5 4522
08f53168 4523 WX_PIZZA(m_wxwindow)->scroll(dx, dy);
0fc5dbf5 4524
0a164d4c 4525 m_clipPaintRegion = false;
113faca1 4526
231018bd 4527#if wxUSE_CARET
113faca1
JS
4528 bool restoreCaret = (GetCaret() != NULL && GetCaret()->IsVisible());
4529 if (restoreCaret)
4530 {
4531 wxRect caretRect(GetCaret()->GetPosition(), GetCaret()->GetSize());
4532 if (dx > 0)
4533 caretRect.width += dx;
4534 else
fcb29b23 4535 {
113faca1 4536 caretRect.x += dx; caretRect.width -= dx;
fcb29b23 4537 }
113faca1
JS
4538 if (dy > 0)
4539 caretRect.height += dy;
4540 else
fcb29b23 4541 {
113faca1 4542 caretRect.y += dy; caretRect.height -= dy;
fcb29b23
VZ
4543 }
4544
113faca1
JS
4545 RefreshRect(caretRect);
4546 }
fcb29b23 4547#endif // wxUSE_CARET
c801d85f 4548}
3723b7b1 4549
496e7ec6 4550void wxWindowGTK::GTKScrolledWindowSetBorder(GtkWidget* w, int wxstyle)
6493aaca
VZ
4551{
4552 //RN: Note that static controls usually have no border on gtk, so maybe
88a7a4e1 4553 //it makes sense to treat that as simply no border at the wx level
6493aaca
VZ
4554 //as well...
4555 if (!(wxstyle & wxNO_BORDER) && !(wxstyle & wxBORDER_STATIC))
4556 {
4557 GtkShadowType gtkstyle;
88a7a4e1 4558
6493aaca
VZ
4559 if(wxstyle & wxBORDER_RAISED)
4560 gtkstyle = GTK_SHADOW_OUT;
ec2d6790 4561 else if ((wxstyle & wxBORDER_SUNKEN) || (wxstyle & wxBORDER_THEME))
6493aaca 4562 gtkstyle = GTK_SHADOW_IN;
78cd9c69
JS
4563#if 0
4564 // Now obsolete
6493aaca
VZ
4565 else if (wxstyle & wxBORDER_DOUBLE)
4566 gtkstyle = GTK_SHADOW_ETCHED_IN;
78cd9c69 4567#endif
6493aaca
VZ
4568 else //default
4569 gtkstyle = GTK_SHADOW_IN;
4570
88a7a4e1 4571 gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(w),
6493aaca
VZ
4572 gtkstyle );
4573 }
4574}
4575
3723b7b1
JS
4576// Find the wxWindow at the current mouse position, also returning the mouse
4577// position.
4578wxWindow* wxFindWindowAtPointer(wxPoint& pt)
4579{
59a12e90
JS
4580 pt = wxGetMousePosition();
4581 wxWindow* found = wxFindWindowAtPoint(pt);
4582 return found;
3723b7b1
JS
4583}
4584
4585// Get the current mouse position.
4586wxPoint wxGetMousePosition()
4587{
5105db37
PC
4588 wxWindow* tlw = NULL;
4589 if (!wxTopLevelWindows.empty())
4590 tlw = wxTopLevelWindows.front();
4591 GdkDisplay* display;
4592 if (tlw && tlw->m_widget)
4593 display = gtk_widget_get_display(tlw->m_widget);
4594 else
4595 display = gdk_display_get_default();
59a12e90 4596
3723b7b1 4597 int x, y;
5105db37
PC
4598 gdk_display_get_pointer(display, NULL, &x, &y, NULL);
4599 return wxPoint(x, y);
3723b7b1
JS
4600}
4601
08f53168
PC
4602GdkWindow* wxWindowGTK::GTKGetDrawingWindow() const
4603{
4604 GdkWindow* window = NULL;
4605 if (m_wxwindow)
989d151c 4606 window = gtk_widget_get_window(m_wxwindow);
08f53168
PC
4607 return window;
4608}
5f346ddc
VS
4609
4610// ----------------------------------------------------------------------------
4611// freeze/thaw
4612// ----------------------------------------------------------------------------
4613
89267fe5
VS
4614extern "C"
4615{
4616
4617// this is called if we attempted to freeze unrealized widget when it finally
4618// is realized (and so can be frozen):
f089940f 4619static void wx_frozen_widget_realize(GtkWidget* w, wxWindowGTK* win)
89267fe5 4620{
fc9ab22a
VS
4621 wxASSERT( w && gtk_widget_get_has_window(w) );
4622 wxASSERT( gtk_widget_get_realized(w) );
89267fe5
VS
4623
4624 g_signal_handlers_disconnect_by_func
4625 (
4626 w,
4627 (void*)wx_frozen_widget_realize,
f089940f 4628 win
89267fe5
VS
4629 );
4630
989d151c 4631 GdkWindow* window;
9914bfbb
PC
4632 if (w == win->m_wxwindow)
4633 window = win->GTKGetDrawingWindow();
989d151c
PC
4634 else
4635 window = gtk_widget_get_window(w);
f089940f 4636 gdk_window_freeze_updates(window);
89267fe5
VS
4637}
4638
4639} // extern "C"
4640
5f346ddc
VS
4641void wxWindowGTK::GTKFreezeWidget(GtkWidget *w)
4642{
fc9ab22a 4643 if ( !w || !gtk_widget_get_has_window(w) )
89267fe5
VS
4644 return; // window-less widget, cannot be frozen
4645
989d151c
PC
4646 GdkWindow* window = gtk_widget_get_window(w);
4647 if (window == NULL)
89267fe5
VS
4648 {
4649 // we can't thaw unrealized widgets because they don't have GdkWindow,
4650 // so set it up to be done immediately after realization:
4651 g_signal_connect_after
4652 (
4653 w,
4654 "realize",
4655 G_CALLBACK(wx_frozen_widget_realize),
f089940f 4656 this
89267fe5
VS
4657 );
4658 return;
4659 }
4660
9914bfbb
PC
4661 if (w == m_wxwindow)
4662 window = GTKGetDrawingWindow();
f089940f 4663 gdk_window_freeze_updates(window);
5f346ddc
VS
4664}
4665
4666void wxWindowGTK::GTKThawWidget(GtkWidget *w)
4667{
fc9ab22a 4668 if ( !w || !gtk_widget_get_has_window(w) )
89267fe5
VS
4669 return; // window-less widget, cannot be frozen
4670
989d151c
PC
4671 GdkWindow* window = gtk_widget_get_window(w);
4672 if (window == NULL)
89267fe5
VS
4673 {
4674 // the widget wasn't realized yet, no need to thaw
4675 g_signal_handlers_disconnect_by_func
4676 (
4677 w,
4678 (void*)wx_frozen_widget_realize,
f089940f 4679 this
89267fe5
VS
4680 );
4681 return;
4682 }
4683
9914bfbb
PC
4684 if (w == m_wxwindow)
4685 window = GTKGetDrawingWindow();
f089940f 4686 gdk_window_thaw_updates(window);
5f346ddc
VS
4687}
4688
4689void wxWindowGTK::DoFreeze()
4690{
4691 GTKFreezeWidget(m_widget);
4692 if ( m_wxwindow && m_widget != m_wxwindow )
4693 GTKFreezeWidget(m_wxwindow);
4694}
4695
4696void wxWindowGTK::DoThaw()
4697{
4698 GTKThawWidget(m_widget);
4699 if ( m_wxwindow && m_widget != m_wxwindow )
4700 GTKThawWidget(m_wxwindow);
4701}