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