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