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