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