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