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