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