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