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