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