]> git.saurik.com Git - wxWidgets.git/blame - src/gtk/window.cpp
Commented out call that breaks metal style setting before Create
[wxWidgets.git] / src / gtk / window.cpp
CommitLineData
c801d85f 1/////////////////////////////////////////////////////////////////////////////
f6bcfd97 2// Name: gtk/window.cpp
c801d85f
KB
3// Purpose:
4// Author: Robert Roebling
c67d8618 5// Id: $Id$
01111366 6// Copyright: (c) 1998 Robert Roebling, Julian Smart
65571936 7// Licence: wxWindows licence
c801d85f
KB
8/////////////////////////////////////////////////////////////////////////////
9
14f355c2
VS
10// For compilers that support precompilation, includes "wx.h".
11#include "wx/wxprec.h"
12
d02af7bb
JJ
13#ifdef __VMS
14#define XWarpPointer XWARPPOINTER
15#endif
16
c801d85f 17#include "wx/window.h"
33611ebb 18#include "wx/dcclient.h"
c801d85f
KB
19#include "wx/frame.h"
20#include "wx/app.h"
21#include "wx/layout.h"
22#include "wx/utils.h"
23#include "wx/dialog.h"
24#include "wx/msgdlg.h"
0fc5dbf5 25#include "wx/module.h"
024e9a4c 26#include "wx/combobox.h"
fe39b16a
RR
27#if wxUSE_TOOLBAR_NATIVE
28#include "wx/toolbar.h"
29#endif
bfc6fde4 30
06cfab17 31#if wxUSE_DRAG_AND_DROP
bfc6fde4 32 #include "wx/dnd.h"
ac57418f 33#endif
bfc6fde4 34
cad880f5 35#if wxUSE_TOOLTIPS
bfc6fde4 36 #include "wx/tooltip.h"
cad880f5 37#endif
bfc6fde4 38
f6bcfd97
BP
39#if wxUSE_CARET
40 #include "wx/caret.h"
41#endif // wxUSE_CARET
42
ab93a576 43#if wxUSE_TEXTCTRL
0fc5dbf5 44 #include "wx/textctrl.h"
ab93a576
RD
45#endif
46
30dea054 47#include "wx/menu.h"
d4c99d6f 48#include "wx/statusbr.h"
b4071e91 49#include "wx/intl.h"
3bc755fc 50#include "wx/settings.h"
3069ac4e 51#include "wx/log.h"
48d011c8 52#include "wx/fontutil.h"
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)
27df579a 272 window = GDK_ROOT_PARENT();
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 );
ed673c6a
RR
393 gdk_gc_unref( gc );
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
654 key_code = WXK_PRIOR;
655 break;
656
657 case GDK_Next: // == GDK_Page_Down
658 key_code = WXK_NEXT;
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
737 key_code = isChar ? WXK_PRIOR : WXK_NUMPAD_PRIOR;
738 break;
739
740 case GDK_KP_Next: // == GDK_KP_Page_Down
741 key_code = isChar ? WXK_NEXT : WXK_NUMPAD_NEXT;
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
2b5f62a0 1201#if wxUSE_UNICODE
5bfaca1b 1202 const wxWCharBuffer data = wxConvUTF8.cMB2WC( (char*)str );
2b5f62a0 1203#else
5bfaca1b
VS
1204 const wxWCharBuffer wdata = wxConvUTF8.cMB2WC( (char*)str );
1205 const wxCharBuffer data = wxConvLocal.cWC2MB( wdata );
a3c15d89 1206#endif // wxUSE_UNICODE
5bfaca1b
VS
1207 if( !(const wxChar*)data )
1208 return;
7c5e6fc6 1209
a3c15d89 1210 bool ret = false;
7c5e6fc6
RD
1211
1212 // Implement OnCharHook by checking ancestor top level windows
1213 wxWindow *parent = window;
1214 while (parent && !parent->IsTopLevel())
2b5f62a0 1215 parent = parent->GetParent();
2b5f62a0 1216
5bfaca1b 1217 for( const wxChar* pstr = data; *pstr; pstr++ )
7c5e6fc6 1218 {
5bfaca1b
VS
1219#if wxUSE_UNICODE
1220 event.m_uniChar = *pstr;
f6fca1f8 1221 // Backward compatible for ISO-8859-1
5bfaca1b
VS
1222 event.m_keyCode = *pstr < 256 ? event.m_uniChar : 0;
1223 wxLogTrace(TRACE_KEYS, _T("IM sent character '%c'"), event.m_uniChar);
1224#else
1225 event.m_keyCode = *pstr;
1226#endif // wxUSE_UNICODE
1dabdced
RD
1227
1228 // To conform to the docs we need to translate Ctrl-alpha
1229 // characters to values in the range 1-26.
1230 if (event.ControlDown() && *pstr >= 'a' && *pstr <= 'z' )
1231 {
1232 event.m_keyCode = *pstr - 'a' + 1;
1233#if wxUSE_UNICODE
1234 event.m_uniChar = event.m_keyCode;
7f7beb1d
MR
1235#endif
1236 }
1dabdced 1237
5bfaca1b
VS
1238 if (parent)
1239 {
1240 event.SetEventType( wxEVT_CHAR_HOOK );
1241 ret = parent->GetEventHandler()->ProcessEvent( event );
1242 }
1243
1244 if (!ret)
1245 {
1246 event.SetEventType(wxEVT_CHAR);
1247 ret = window->GetEventHandler()->ProcessEvent( event );
1248 }
2b5f62a0
VZ
1249 }
1250}
865bb325 1251}
2b5f62a0
VZ
1252
1253
b666df2c
RR
1254//-----------------------------------------------------------------------------
1255// "key_release_event" from any window
1256//-----------------------------------------------------------------------------
1257
865bb325 1258extern "C" {
7f7beb1d
MR
1259static gboolean
1260gtk_window_key_release_callback( GtkWidget *widget,
1261 GdkEventKey *gdk_event,
1262 wxWindowGTK *win )
b666df2c 1263{
3ac8d3bc
RR
1264 DEBUG_MAIN_THREAD
1265
c50f1fb9 1266 if (g_isIdle)
a2053b27
RR
1267 wxapp_install_idle_handler();
1268
74710601
VZ
1269 if (!win->m_hasVMT)
1270 return FALSE;
b666df2c 1271
74710601
VZ
1272 if (g_blockEventsOnDrag)
1273 return FALSE;
b666df2c
RR
1274
1275 wxKeyEvent event( wxEVT_KEY_UP );
74710601 1276 if ( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
b666df2c 1277 {
90e572f1 1278 // unknown key pressed, ignore (the event would be useless anyhow)
74710601 1279 return FALSE;
b666df2c
RR
1280 }
1281
74710601
VZ
1282 if ( !win->GetEventHandler()->ProcessEvent( event ) )
1283 return FALSE;
1284
9fa72bd2 1285 g_signal_stop_emission_by_name (widget, "key_release_event");
74710601 1286 return TRUE;
b666df2c 1287}
865bb325 1288}
b666df2c 1289
c5f9d156
VS
1290// ============================================================================
1291// the mouse events
1292// ============================================================================
1293
d1f2ac45
VZ
1294// ----------------------------------------------------------------------------
1295// mouse event processing helpers
1296// ----------------------------------------------------------------------------
1297
50f00d0c
VS
1298// init wxMouseEvent with the info from GdkEventXXX struct
1299template<typename T> void InitMouseEvent(wxWindowGTK *win,
1300 wxMouseEvent& event,
1301 T *gdk_event)
1302{
1303 event.SetTimestamp( gdk_event->time );
1304 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1305 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1306 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1307 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1308 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1309 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1310 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1311 if (event.GetEventType() == wxEVT_MOUSEWHEEL)
1312 {
1313 event.m_linesPerAction = 3;
60773911 1314 event.m_wheelDelta = 120;
50f00d0c
VS
1315 if (((GdkEventButton*)gdk_event)->button == 4)
1316 event.m_wheelRotation = 120;
1317 else if (((GdkEventButton*)gdk_event)->button == 5)
1318 event.m_wheelRotation = -120;
1319 }
1320
1321 wxPoint pt = win->GetClientAreaOrigin();
1322 event.m_x = (wxCoord)gdk_event->x - pt.x;
1323 event.m_y = (wxCoord)gdk_event->y - pt.y;
1324
1325 event.SetEventObject( win );
1326 event.SetId( win->GetId() );
1327 event.SetTimestamp( gdk_event->time );
1328}
c5f9d156 1329
2daa0ce9
VZ
1330static void AdjustEventButtonState(wxMouseEvent& event)
1331{
1332 // GDK reports the old state of the button for a button press event, but
1333 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1334 // for a LEFT_DOWN event, not FALSE, so we will invert
1335 // left/right/middleDown for the corresponding click events
1e6feb95 1336
1a8caf94
RR
1337 if ((event.GetEventType() == wxEVT_LEFT_DOWN) ||
1338 (event.GetEventType() == wxEVT_LEFT_DCLICK) ||
1339 (event.GetEventType() == wxEVT_LEFT_UP))
1340 {
1341 event.m_leftDown = !event.m_leftDown;
1342 return;
1343 }
1344
1345 if ((event.GetEventType() == wxEVT_MIDDLE_DOWN) ||
1346 (event.GetEventType() == wxEVT_MIDDLE_DCLICK) ||
1347 (event.GetEventType() == wxEVT_MIDDLE_UP))
2daa0ce9 1348 {
1a8caf94
RR
1349 event.m_middleDown = !event.m_middleDown;
1350 return;
1351 }
1352
1353 if ((event.GetEventType() == wxEVT_RIGHT_DOWN) ||
1354 (event.GetEventType() == wxEVT_RIGHT_DCLICK) ||
1355 (event.GetEventType() == wxEVT_RIGHT_UP))
1356 {
1357 event.m_rightDown = !event.m_rightDown;
1358 return;
2daa0ce9
VZ
1359 }
1360}
1361
d1f2ac45
VZ
1362// find the window to send the mouse event too
1363static
1364wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y)
1365{
7d4909b2
RR
1366 wxCoord xx = x;
1367 wxCoord yy = y;
1368
d1f2ac45
VZ
1369 if (win->m_wxwindow)
1370 {
1371 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
7d4909b2
RR
1372 xx += pizza->xoffset;
1373 yy += pizza->yoffset;
d1f2ac45
VZ
1374 }
1375
222ed1d6 1376 wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
d1f2ac45
VZ
1377 while (node)
1378 {
b1d4dd7a 1379 wxWindowGTK *child = node->GetData();
d1f2ac45 1380
b1d4dd7a 1381 node = node->GetNext();
d1f2ac45
VZ
1382 if (!child->IsShown())
1383 continue;
1384
1385 if (child->IsTransparentForMouse())
1386 {
1387 // wxStaticBox is transparent in the box itself
1388 int xx1 = child->m_x;
1389 int yy1 = child->m_y;
1390 int xx2 = child->m_x + child->m_width;
7408cf7f 1391 int yy2 = child->m_y + child->m_height;
d1f2ac45
VZ
1392
1393 // left
7d4909b2 1394 if (((xx >= xx1) && (xx <= xx1+10) && (yy >= yy1) && (yy <= yy2)) ||
d1f2ac45 1395 // right
7d4909b2 1396 ((xx >= xx2-10) && (xx <= xx2) && (yy >= yy1) && (yy <= yy2)) ||
d1f2ac45 1397 // top
7d4909b2 1398 ((xx >= xx1) && (xx <= xx2) && (yy >= yy1) && (yy <= yy1+10)) ||
d1f2ac45 1399 // bottom
7d4909b2 1400 ((xx >= xx1) && (xx <= xx2) && (yy >= yy2-1) && (yy <= yy2)))
d1f2ac45
VZ
1401 {
1402 win = child;
1403 x -= child->m_x;
1404 y -= child->m_y;
1405 break;
1406 }
1407
1408 }
1409 else
1410 {
1411 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
7d4909b2
RR
1412 (child->m_x <= xx) &&
1413 (child->m_y <= yy) &&
af3653dd
RR
1414 (child->m_x+child->m_width >= xx) &&
1415 (child->m_y+child->m_height >= yy))
d1f2ac45
VZ
1416 {
1417 win = child;
1418 x -= child->m_x;
1419 y -= child->m_y;
1420 break;
1421 }
1422 }
1423 }
1424
1425 return win;
1426}
1427
c801d85f 1428//-----------------------------------------------------------------------------
2f2aa628
RR
1429// "button_press_event"
1430//-----------------------------------------------------------------------------
c801d85f 1431
865bb325 1432extern "C" {
7f7beb1d
MR
1433static gboolean
1434gtk_window_button_press_callback( GtkWidget *widget,
1435 GdkEventButton *gdk_event,
1436 wxWindowGTK *win )
903f689b 1437{
3ac8d3bc
RR
1438 DEBUG_MAIN_THREAD
1439
c50f1fb9 1440 if (g_isIdle)
a2053b27
RR
1441 wxapp_install_idle_handler();
1442
1443/*
223d09f6 1444 wxPrintf( wxT("1) OnButtonPress from ") );
a2053b27
RR
1445 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1446 wxPrintf( win->GetClassInfo()->GetClassName() );
223d09f6 1447 wxPrintf( wxT(".\n") );
a2053b27 1448*/
a2053b27 1449 if (!win->m_hasVMT) return FALSE;
f5e27805 1450 if (g_blockEventsOnDrag) return TRUE;
76ed8f8d 1451 if (g_blockEventsOnScroll) return TRUE;
c801d85f 1452
034be888
RR
1453 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1454
afbe906a 1455 if (win->m_wxwindow && (g_focusWindow != win) && win->AcceptsFocus())
c801d85f 1456 {
afbe906a 1457 gtk_widget_grab_focus( win->m_wxwindow );
c801d85f 1458/*
afbe906a
RR
1459 wxPrintf( wxT("GrabFocus from ") );
1460 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1461 wxPrintf( win->GetClassInfo()->GetClassName() );
1462 wxPrintf( wxT(".\n") );
c801d85f 1463*/
362c6693 1464 }
47d67540 1465
90e572f1 1466 // GDK sends surplus button down events
2b5f62a0
VZ
1467 // before a double click event. We
1468 // need to filter these out.
1469 if (gdk_event->type == GDK_BUTTON_PRESS)
1470 {
1471 GdkEvent *peek_event = gdk_event_peek();
1472 if (peek_event)
1473 {
8b8a8e0e
RR
1474 if ((peek_event->type == GDK_2BUTTON_PRESS) ||
1475 (peek_event->type == GDK_3BUTTON_PRESS))
2b5f62a0
VZ
1476 {
1477 gdk_event_free( peek_event );
1478 return TRUE;
1479 }
1480 else
1481 {
1482 gdk_event_free( peek_event );
1483 }
1484 }
1485 }
1486
2daa0ce9 1487 wxEventType event_type = wxEVT_NULL;
47d67540 1488
127304e9
VS
1489 // GdkDisplay is a GTK+ 2.2.0 thing
1490#if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
15475ced 1491 if ( gdk_event->type == GDK_2BUTTON_PRESS &&
cc35003a 1492 !gtk_check_version(2,2,0) &&
15475ced
VZ
1493 gdk_event->button >= 1 && gdk_event->button <= 3 )
1494 {
1495 // Reset GDK internal timestamp variables in order to disable GDK
1496 // triple click events. GDK will then next time believe no button has
1497 // been clicked just before, and send a normal button click event.
1498 GdkDisplay* display = gtk_widget_get_display (widget);
1499 display->button_click_time[1] = 0;
1500 display->button_click_time[0] = 0;
1501 }
1502#endif // GTK 2+
1503
f5e27805 1504 if (gdk_event->button == 1)
c801d85f 1505 {
f3f0d961 1506 // note that GDK generates triple click events which are not supported
77ffb593 1507 // by wxWidgets but still have to be passed to the app as otherwise
f3f0d961 1508 // clicks would simply go missing
f5e27805
RR
1509 switch (gdk_event->type)
1510 {
15475ced
VZ
1511 // we shouldn't get triple clicks at all for GTK2 because we
1512 // suppress them artificially using the code above but we still
1513 // should map them to something for GTK1 and not just ignore them
1514 // as this would lose clicks
f3f0d961
VZ
1515 case GDK_3BUTTON_PRESS: // we could also map this to DCLICK...
1516 case GDK_BUTTON_PRESS:
1517 event_type = wxEVT_LEFT_DOWN;
1518 break;
1519
1520 case GDK_2BUTTON_PRESS:
1521 event_type = wxEVT_LEFT_DCLICK;
1522 break;
b1f50e65
VZ
1523
1524 default:
1525 // just to silence gcc warnings
1526 ;
f5e27805 1527 }
362c6693 1528 }
f5e27805 1529 else if (gdk_event->button == 2)
c801d85f 1530 {
f5e27805
RR
1531 switch (gdk_event->type)
1532 {
15475ced 1533 case GDK_3BUTTON_PRESS:
f3f0d961
VZ
1534 case GDK_BUTTON_PRESS:
1535 event_type = wxEVT_MIDDLE_DOWN;
1536 break;
1537
1538 case GDK_2BUTTON_PRESS:
1539 event_type = wxEVT_MIDDLE_DCLICK;
1540 break;
b1f50e65
VZ
1541
1542 default:
1543 ;
f5e27805 1544 }
362c6693 1545 }
f5e27805 1546 else if (gdk_event->button == 3)
c801d85f 1547 {
f5e27805
RR
1548 switch (gdk_event->type)
1549 {
15475ced 1550 case GDK_3BUTTON_PRESS:
f3f0d961
VZ
1551 case GDK_BUTTON_PRESS:
1552 event_type = wxEVT_RIGHT_DOWN;
1553 break;
1554
1555 case GDK_2BUTTON_PRESS:
1556 event_type = wxEVT_RIGHT_DCLICK;
1557 break;
b1f50e65
VZ
1558
1559 default:
1560 ;
2b5f62a0
VZ
1561 }
1562 }
f3f0d961 1563 else if (gdk_event->button == 4 || gdk_event->button == 5)
2b5f62a0 1564 {
f3f0d961 1565 if (gdk_event->type == GDK_BUTTON_PRESS )
2b5f62a0 1566 {
f3f0d961 1567 event_type = wxEVT_MOUSEWHEEL;
2b5f62a0
VZ
1568 }
1569 }
47d67540 1570
2daa0ce9
VZ
1571 if ( event_type == wxEVT_NULL )
1572 {
1573 // unknown mouse button or click type
1574 return FALSE;
1575 }
1576
f5e27805 1577 wxMouseEvent event( event_type );
c5f9d156 1578 InitMouseEvent( win, event, gdk_event );
47d67540 1579
2daa0ce9 1580 AdjustEventButtonState(event);
94633ad9 1581
90e572f1 1582 // wxListBox actually gets mouse events from the item, so we need to give it
3ae4c570
VZ
1583 // a chance to correct this
1584 win->FixUpMouseEvent(widget, event.m_x, event.m_y);
2daa0ce9 1585
90e572f1
MR
1586 // find the correct window to send the event to: it may be a different one
1587 // from the one which got it at GTK+ level because some controls don't have
d1f2ac45
VZ
1588 // their own X window and thus cannot get any events.
1589 if ( !g_captureWindow )
1590 win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
ff8bfdbb 1591
f5e27805 1592 if (win->GetEventHandler()->ProcessEvent( event ))
034be888 1593 {
9fa72bd2 1594 g_signal_stop_emission_by_name (widget, "button_press_event");
f03fc89f 1595 return TRUE;
034be888 1596 }
47d67540 1597
ac103441
RR
1598 if (event_type == wxEVT_RIGHT_DOWN)
1599 {
1600 // generate a "context menu" event: this is similar to right mouse
1601 // click under many GUIs except that it is generated differently
1602 // (right up under MSW, ctrl-click under Mac, right down here) and
1603 //
1604 // (a) it's a command event and so is propagated to the parent
1605 // (b) under some ports it can be generated from kbd too
1606 // (c) it uses screen coords (because of (a))
1607 wxContextMenuEvent evtCtx(
1608 wxEVT_CONTEXT_MENU,
1609 win->GetId(),
1610 win->ClientToScreen(event.GetPosition()));
1611 evtCtx.SetEventObject(win);
1612 return win->GetEventHandler()->ProcessEvent(evtCtx);
1613 }
1614
034be888 1615 return FALSE;
362c6693 1616}
865bb325 1617}
c801d85f
KB
1618
1619//-----------------------------------------------------------------------------
97b3455a 1620// "button_release_event"
2f2aa628 1621//-----------------------------------------------------------------------------
c801d85f 1622
865bb325 1623extern "C" {
7f7beb1d
MR
1624static gboolean
1625gtk_window_button_release_callback( GtkWidget *widget,
1626 GdkEventButton *gdk_event,
1627 wxWindowGTK *win )
47d67540 1628{
3ac8d3bc
RR
1629 DEBUG_MAIN_THREAD
1630
c50f1fb9 1631 if (g_isIdle)
a2053b27
RR
1632 wxapp_install_idle_handler();
1633
1634 if (!win->m_hasVMT) return FALSE;
034be888
RR
1635 if (g_blockEventsOnDrag) return FALSE;
1636 if (g_blockEventsOnScroll) return FALSE;
c801d85f 1637
034be888 1638 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
47d67540 1639
f5e27805 1640 wxEventType event_type = wxEVT_NULL;
47d67540 1641
f5e27805
RR
1642 switch (gdk_event->button)
1643 {
2b5f62a0
VZ
1644 case 1:
1645 event_type = wxEVT_LEFT_UP;
1646 break;
1647
1648 case 2:
1649 event_type = wxEVT_MIDDLE_UP;
1650 break;
1651
1652 case 3:
1653 event_type = wxEVT_RIGHT_UP;
1654 break;
1655
1656 default:
1657 // unknwon button, don't process
1658 return FALSE;
f5e27805 1659 }
47d67540 1660
f5e27805 1661 wxMouseEvent event( event_type );
c5f9d156 1662 InitMouseEvent( win, event, gdk_event );
f5e27805 1663
2daa0ce9
VZ
1664 AdjustEventButtonState(event);
1665
3ae4c570
VZ
1666 // same wxListBox hack as above
1667 win->FixUpMouseEvent(widget, event.m_x, event.m_y);
e2762ff0 1668
d1f2ac45
VZ
1669 if ( !g_captureWindow )
1670 win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
47d67540 1671
f5e27805 1672 if (win->GetEventHandler()->ProcessEvent( event ))
034be888 1673 {
9fa72bd2 1674 g_signal_stop_emission_by_name (widget, "button_release_event");
f03fc89f 1675 return TRUE;
034be888 1676 }
47d67540 1677
034be888 1678 return FALSE;
362c6693 1679}
865bb325 1680}
c801d85f
KB
1681
1682//-----------------------------------------------------------------------------
2f2aa628
RR
1683// "motion_notify_event"
1684//-----------------------------------------------------------------------------
c801d85f 1685
865bb325 1686extern "C" {
7f7beb1d
MR
1687static gboolean
1688gtk_window_motion_notify_callback( GtkWidget *widget,
1689 GdkEventMotion *gdk_event,
1690 wxWindowGTK *win )
47d67540 1691{
3ac8d3bc
RR
1692 DEBUG_MAIN_THREAD
1693
c50f1fb9 1694 if (g_isIdle)
a2053b27
RR
1695 wxapp_install_idle_handler();
1696
1697 if (!win->m_hasVMT) return FALSE;
034be888
RR
1698 if (g_blockEventsOnDrag) return FALSE;
1699 if (g_blockEventsOnScroll) return FALSE;
148cd9b6 1700
034be888
RR
1701 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1702
ff8bfdbb 1703 if (gdk_event->is_hint)
aae24d21 1704 {
f7a11f8c
RR
1705 int x = 0;
1706 int y = 0;
1707 GdkModifierType state;
1708 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
1709 gdk_event->x = x;
1710 gdk_event->y = y;
aae24d21 1711 }
ff8bfdbb 1712
c801d85f 1713/*
e380f72b
RR
1714 printf( "OnMotion from " );
1715 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1716 printf( win->GetClassInfo()->GetClassName() );
1717 printf( ".\n" );
aae24d21 1718*/
47d67540 1719
e380f72b 1720 wxMouseEvent event( wxEVT_MOTION );
c5f9d156 1721 InitMouseEvent(win, event, gdk_event);
e380f72b 1722
50382578 1723 if ( g_captureWindow )
2f2aa628 1724 {
1e6feb95
VZ
1725 // synthetize a mouse enter or leave event if needed
1726 GdkWindow *winUnderMouse = gdk_window_at_pointer(NULL, NULL);
7c5e6fc6 1727 // This seems to be necessary and actually been added to
50382578
RR
1728 // GDK itself in version 2.0.X
1729 gdk_flush();
7c5e6fc6 1730
1e6feb95
VZ
1731 bool hasMouse = winUnderMouse == gdk_event->window;
1732 if ( hasMouse != g_captureWindowHasMouse )
1733 {
1734 // the mouse changed window
1735 g_captureWindowHasMouse = hasMouse;
1736
17a1ebd1
VZ
1737 wxMouseEvent eventM(g_captureWindowHasMouse ? wxEVT_ENTER_WINDOW
1738 : wxEVT_LEAVE_WINDOW);
1739 InitMouseEvent(win, eventM, gdk_event);
1740 eventM.SetEventObject(win);
1741 win->GetEventHandler()->ProcessEvent(eventM);
1e6feb95
VZ
1742 }
1743 }
1744 else // no capture
1745 {
d1f2ac45 1746 win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
2f2aa628 1747 }
47d67540 1748
38f69be1
RR
1749 if ( !g_captureWindow )
1750 {
1751 wxSetCursorEvent cevent( event.m_x, event.m_y );
1752 if (win->GetEventHandler()->ProcessEvent( cevent ))
1753 {
1754 // Rewrite cursor handling here (away from idle).
1755 }
1756 }
2e1f5012 1757
e380f72b 1758 if (win->GetEventHandler()->ProcessEvent( event ))
034be888 1759 {
9fa72bd2 1760 g_signal_stop_emission_by_name (widget, "motion_notify_event");
f03fc89f 1761 return TRUE;
034be888 1762 }
47d67540 1763
034be888 1764 return FALSE;
362c6693 1765}
865bb325 1766}
c801d85f 1767
557c9f5b
JS
1768//-----------------------------------------------------------------------------
1769// "mouse_wheel_event"
1770//-----------------------------------------------------------------------------
1771
865bb325 1772extern "C" {
7f7beb1d
MR
1773static gboolean
1774gtk_window_wheel_callback (GtkWidget * widget,
1775 GdkEventScroll * gdk_event,
1776 wxWindowGTK * win)
557c9f5b
JS
1777{
1778 DEBUG_MAIN_THREAD
1779
1780 if (g_isIdle)
1781 wxapp_install_idle_handler();
1782
1783 wxEventType event_type = wxEVT_NULL;
1784 if (gdk_event->direction == GDK_SCROLL_UP)
1785 event_type = wxEVT_MOUSEWHEEL;
1786 else if (gdk_event->direction == GDK_SCROLL_DOWN)
1787 event_type = wxEVT_MOUSEWHEEL;
1788 else
1789 return FALSE;
0a164d4c 1790
557c9f5b
JS
1791 wxMouseEvent event( event_type );
1792 // Can't use InitMouse macro because scroll events don't have button
1793 event.SetTimestamp( gdk_event->time );
1794 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1795 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1796 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1797 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1798 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1799 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1800 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
58d185f7 1801 event.m_linesPerAction = 3;
60773911 1802 event.m_wheelDelta = 120;
557c9f5b
JS
1803 if (gdk_event->direction == GDK_SCROLL_UP)
1804 event.m_wheelRotation = 120;
1805 else
1806 event.m_wheelRotation = -120;
1807
1808 wxPoint pt = win->GetClientAreaOrigin();
1809 event.m_x = (wxCoord)gdk_event->x - pt.x;
1810 event.m_y = (wxCoord)gdk_event->y - pt.y;
1811
1812 event.SetEventObject( win );
1813 event.SetId( win->GetId() );
1814 event.SetTimestamp( gdk_event->time );
0a164d4c 1815
557c9f5b
JS
1816 if (win->GetEventHandler()->ProcessEvent( event ))
1817 {
9fa72bd2 1818 g_signal_stop_emission_by_name (widget, "scroll_event");
557c9f5b
JS
1819 return TRUE;
1820 }
1821
1822 return FALSE;
1823}
865bb325 1824}
ac103441
RR
1825
1826//-----------------------------------------------------------------------------
1827// "popup-menu"
1828//-----------------------------------------------------------------------------
865bb325 1829extern "C" {
ac103441
RR
1830static gboolean wxgtk_window_popup_menu_callback(GtkWidget*, wxWindowGTK* win)
1831{
1832 wxContextMenuEvent event(
1833 wxEVT_CONTEXT_MENU,
1834 win->GetId(),
1835 wxPoint(-1, -1));
1836 event.SetEventObject(win);
1837 return win->GetEventHandler()->ProcessEvent(event);
1838}
865bb325 1839}
557c9f5b 1840
c801d85f 1841//-----------------------------------------------------------------------------
2f2aa628
RR
1842// "focus_in_event"
1843//-----------------------------------------------------------------------------
c801d85f 1844
6aeb6f2a
VZ
1845// send the wxChildFocusEvent and wxFocusEvent, common code of
1846// gtk_window_focus_in_callback() and SetFocus()
1847static bool DoSendFocusEvents(wxWindow *win)
1848{
1849 // Notify the parent keeping track of focus for the kbd navigation
1850 // purposes that we got it.
1851 wxChildFocusEvent eventChildFocus(win);
1852 (void)win->GetEventHandler()->ProcessEvent(eventChildFocus);
1853
1854 wxFocusEvent eventFocus(wxEVT_SET_FOCUS, win->GetId());
1855 eventFocus.SetEventObject(win);
1856
1857 return win->GetEventHandler()->ProcessEvent(eventFocus);
1858}
1859
865bb325 1860extern "C" {
7f7beb1d
MR
1861static gboolean
1862gtk_window_focus_in_callback( GtkWidget *widget,
1863 GdkEventFocus *WXUNUSED(event),
1864 wxWindow *win )
c801d85f 1865{
3ac8d3bc 1866 DEBUG_MAIN_THREAD
0a164d4c 1867
c50f1fb9 1868 if (g_isIdle)
a2053b27
RR
1869 wxapp_install_idle_handler();
1870
a3c15d89
VS
1871 if (win->m_imData)
1872 gtk_im_context_focus_in(win->m_imData->context);
4b1ae153 1873
1e6feb95 1874 g_focusWindowLast =
b292e2f5 1875 g_focusWindow = win;
ff8bfdbb 1876
6cad4f1b
VZ
1877 wxLogTrace(TRACE_FOCUS,
1878 _T("%s: focus in"), win->GetName().c_str());
7de59551 1879
b79395c5
RR
1880#ifdef HAVE_XIM
1881 if (win->m_ic)
1882 gdk_im_begin(win->m_ic, win->m_wxwindow->window);
1883#endif
1884
1e6feb95 1885#if wxUSE_CARET
f6bcfd97
BP
1886 // caret needs to be informed about focus change
1887 wxCaret *caret = win->GetCaret();
1888 if ( caret )
1889 {
1890 caret->OnSetFocus();
1891 }
1892#endif // wxUSE_CARET
1893
f7108f16 1894 gboolean ret = FALSE;
628bad75 1895
6cad4f1b
VZ
1896 // does the window itself think that it has the focus?
1897 if ( !win->m_hasFocus )
5cd09f0b 1898 {
6cad4f1b 1899 // not yet, notify it
0a164d4c
WS
1900 win->m_hasFocus = true;
1901
628bad75 1902 (void)DoSendFocusEvents(win);
7f7beb1d
MR
1903
1904 ret = TRUE;
034be888 1905 }
ca298c88 1906
628bad75
RR
1907 // Disable default focus handling for custom windows
1908 // since the default GTK+ handler issues a repaint
1909 if (win->m_wxwindow)
4c20ee63 1910 return ret;
7f7beb1d
MR
1911
1912 return FALSE;
362c6693 1913}
865bb325 1914}
c801d85f
KB
1915
1916//-----------------------------------------------------------------------------
2f2aa628
RR
1917// "focus_out_event"
1918//-----------------------------------------------------------------------------
c801d85f 1919
865bb325 1920extern "C" {
7f7beb1d
MR
1921static gboolean
1922gtk_window_focus_out_callback( GtkWidget *widget,
1923 GdkEventFocus *gdk_event,
1924 wxWindowGTK *win )
c801d85f 1925{
3ac8d3bc
RR
1926 DEBUG_MAIN_THREAD
1927
c50f1fb9 1928 if (g_isIdle)
a2053b27
RR
1929 wxapp_install_idle_handler();
1930
a3c15d89
VS
1931 if (win->m_imData)
1932 gtk_im_context_focus_out(win->m_imData->context);
4b1ae153 1933
6cad4f1b
VZ
1934 wxLogTrace( TRACE_FOCUS,
1935 _T("%s: focus out"), win->GetName().c_str() );
b231914f 1936
148cd9b6 1937
3379ed37 1938 wxWindowGTK *winFocus = wxFindFocusedChild(win);
f6bcfd97
BP
1939 if ( winFocus )
1940 win = winFocus;
1941
1e6feb95 1942 g_focusWindow = (wxWindowGTK *)NULL;
148cd9b6 1943
b79395c5
RR
1944#ifdef HAVE_XIM
1945 if (win->m_ic)
1946 gdk_im_end();
1947#endif
1948
1e6feb95 1949#if wxUSE_CARET
f6bcfd97
BP
1950 // caret needs to be informed about focus change
1951 wxCaret *caret = win->GetCaret();
1952 if ( caret )
1953 {
1954 caret->OnKillFocus();
1955 }
1956#endif // wxUSE_CARET
1957
f7108f16 1958 gboolean ret = FALSE;
628bad75 1959
6cad4f1b
VZ
1960 // don't send the window a kill focus event if it thinks that it doesn't
1961 // have focus already
1962 if ( win->m_hasFocus )
5cd09f0b 1963 {
0a164d4c 1964 win->m_hasFocus = false;
6cad4f1b
VZ
1965
1966 wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
1967 event.SetEventObject( win );
1968
a752b8c4 1969 (void)win->GetEventHandler()->ProcessEvent( event );
7f7beb1d
MR
1970
1971 ret = TRUE;
034be888 1972 }
7f7beb1d 1973
628bad75
RR
1974 // Disable default focus handling for custom windows
1975 // since the default GTK+ handler issues a repaint
1976 if (win->m_wxwindow)
4c20ee63 1977 return ret;
7f7beb1d
MR
1978
1979 return FALSE;
362c6693 1980}
865bb325 1981}
c801d85f 1982
b4071e91
RR
1983//-----------------------------------------------------------------------------
1984// "enter_notify_event"
1985//-----------------------------------------------------------------------------
1986
865bb325 1987extern "C" {
f3a5f83a
MR
1988static gboolean
1989gtk_window_enter_callback( GtkWidget *widget,
1990 GdkEventCrossing *gdk_event,
1991 wxWindowGTK *win )
b4071e91 1992{
3ac8d3bc
RR
1993 DEBUG_MAIN_THREAD
1994
c50f1fb9 1995 if (g_isIdle)
a2053b27 1996 wxapp_install_idle_handler();
ca298c88 1997
a2053b27
RR
1998 if (!win->m_hasVMT) return FALSE;
1999 if (g_blockEventsOnDrag) return FALSE;
47d67540 2000
7f5f144a
RR
2001 // Event was emitted after a grab
2002 if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
7c5e6fc6 2003
a2053b27 2004 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
b292e2f5 2005
4a33eba6
RR
2006 int x = 0;
2007 int y = 0;
2008 GdkModifierType state = (GdkModifierType)0;
ff8bfdbb 2009
a2053b27 2010 gdk_window_get_pointer( widget->window, &x, &y, &state );
ff8bfdbb 2011
edc1d330 2012 wxMouseEvent event( wxEVT_ENTER_WINDOW );
c5f9d156
VS
2013 InitMouseEvent(win, event, gdk_event);
2014 wxPoint pt = win->GetClientAreaOrigin();
2015 event.m_x = x + pt.x;
2016 event.m_y = y + pt.y;
ff8bfdbb 2017
38f69be1
RR
2018 if ( !g_captureWindow )
2019 {
2020 wxSetCursorEvent cevent( event.m_x, event.m_y );
2021 if (win->GetEventHandler()->ProcessEvent( cevent ))
2022 {
2023 // Rewrite cursor handling here (away from idle).
2024 }
2025 }
2e1f5012 2026
e380f72b 2027 if (win->GetEventHandler()->ProcessEvent( event ))
034be888 2028 {
9fa72bd2 2029 g_signal_stop_emission_by_name (widget, "enter_notify_event");
034be888
RR
2030 return TRUE;
2031 }
ca298c88 2032
034be888 2033 return FALSE;
b4071e91 2034}
865bb325 2035}
47d67540 2036
b4071e91
RR
2037//-----------------------------------------------------------------------------
2038// "leave_notify_event"
2039//-----------------------------------------------------------------------------
2040
865bb325 2041extern "C" {
f3a5f83a
MR
2042static gboolean
2043gtk_window_leave_callback( GtkWidget *widget,
2044 GdkEventCrossing *gdk_event,
2045 wxWindowGTK *win )
b4071e91 2046{
3ac8d3bc
RR
2047 DEBUG_MAIN_THREAD
2048
c50f1fb9 2049 if (g_isIdle)
a2053b27 2050 wxapp_install_idle_handler();
acfd422a 2051
a2053b27
RR
2052 if (!win->m_hasVMT) return FALSE;
2053 if (g_blockEventsOnDrag) return FALSE;
b292e2f5 2054
7f5f144a
RR
2055 // Event was emitted after an ungrab
2056 if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
7c5e6fc6 2057
a2053b27 2058 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
c50f1fb9 2059
e380f72b 2060 wxMouseEvent event( wxEVT_LEAVE_WINDOW );
d1367c3d 2061 event.SetTimestamp( gdk_event->time );
e380f72b 2062 event.SetEventObject( win );
47d67540 2063
4a33eba6
RR
2064 int x = 0;
2065 int y = 0;
2066 GdkModifierType state = (GdkModifierType)0;
ff8bfdbb 2067
4a33eba6 2068 gdk_window_get_pointer( widget->window, &x, &y, &state );
ff8bfdbb 2069
74710601
VZ
2070 event.m_shiftDown = (state & GDK_SHIFT_MASK) != 0;
2071 event.m_controlDown = (state & GDK_CONTROL_MASK) != 0;
2072 event.m_altDown = (state & GDK_MOD1_MASK) != 0;
2073 event.m_metaDown = (state & GDK_MOD2_MASK) != 0;
2074 event.m_leftDown = (state & GDK_BUTTON1_MASK) != 0;
2075 event.m_middleDown = (state & GDK_BUTTON2_MASK) != 0;
2076 event.m_rightDown = (state & GDK_BUTTON3_MASK) != 0;
4a33eba6 2077
c5f9d156
VS
2078 wxPoint pt = win->GetClientAreaOrigin();
2079 event.m_x = x + pt.x;
2080 event.m_y = y + pt.y;
ff8bfdbb 2081
e380f72b 2082 if (win->GetEventHandler()->ProcessEvent( event ))
034be888 2083 {
9fa72bd2 2084 g_signal_stop_emission_by_name (widget, "leave_notify_event");
034be888
RR
2085 return TRUE;
2086 }
ca298c88 2087
034be888 2088 return FALSE;
b4071e91 2089}
865bb325 2090}
47d67540 2091
c801d85f 2092//-----------------------------------------------------------------------------
2f2aa628
RR
2093// "value_changed" from m_vAdjust
2094//-----------------------------------------------------------------------------
c801d85f 2095
865bb325 2096extern "C" {
9e691f46 2097static void gtk_window_vscroll_callback( GtkAdjustment *adjust,
9e691f46 2098 wxWindowGTK *win )
c801d85f 2099{
3ac8d3bc
RR
2100 DEBUG_MAIN_THREAD
2101
c50f1fb9 2102 if (g_isIdle)
a2053b27 2103 wxapp_install_idle_handler();
c801d85f 2104
a2053b27 2105 if (g_blockEventsOnDrag) return;
47d67540 2106
a2053b27 2107 if (!win->m_hasVMT) return;
148cd9b6 2108
5e014a0c 2109 float diff = adjust->value - win->m_oldVerticalPos;
e380f72b 2110 if (fabs(diff) < 0.2) return;
148cd9b6 2111
5e014a0c 2112 win->m_oldVerticalPos = adjust->value;
47d67540 2113
afa7bd1e 2114 wxEventType command = GtkScrollWinTypeToWx(GTK_SCROLL_JUMP);
148cd9b6 2115
5e014a0c 2116 int value = (int)(adjust->value+0.5);
c801d85f 2117
c5b42c87 2118 wxScrollWinEvent event( command, value, wxVERTICAL );
e380f72b
RR
2119 event.SetEventObject( win );
2120 win->GetEventHandler()->ProcessEvent( event );
362c6693 2121}
865bb325 2122}
c801d85f
KB
2123
2124//-----------------------------------------------------------------------------
2f2aa628
RR
2125// "value_changed" from m_hAdjust
2126//-----------------------------------------------------------------------------
c801d85f 2127
865bb325 2128extern "C" {
9e691f46 2129static void gtk_window_hscroll_callback( GtkAdjustment *adjust,
9e691f46 2130 wxWindowGTK *win )
47d67540 2131{
3ac8d3bc
RR
2132 DEBUG_MAIN_THREAD
2133
c50f1fb9 2134 if (g_isIdle)
a2053b27 2135 wxapp_install_idle_handler();
47d67540 2136
a2053b27
RR
2137 if (g_blockEventsOnDrag) return;
2138 if (!win->m_hasVMT) return;
47d67540 2139
5e014a0c 2140 float diff = adjust->value - win->m_oldHorizontalPos;
e380f72b 2141 if (fabs(diff) < 0.2) return;
148cd9b6 2142
afa7bd1e 2143 wxEventType command = GtkScrollWinTypeToWx(GTK_SCROLL_JUMP);
148cd9b6 2144
9e691f46 2145 win->m_oldHorizontalPos = adjust->value;
148cd9b6 2146
5e014a0c 2147 int value = (int)(adjust->value+0.5);
47d67540 2148
c5b42c87 2149 wxScrollWinEvent event( command, value, wxHORIZONTAL );
e380f72b
RR
2150 event.SetEventObject( win );
2151 win->GetEventHandler()->ProcessEvent( event );
362c6693 2152}
865bb325 2153}
c801d85f 2154
cb43b372
RR
2155//-----------------------------------------------------------------------------
2156// "button_press_event" from scrollbar
2157//-----------------------------------------------------------------------------
2158
865bb325 2159extern "C" {
7f7beb1d
MR
2160static gboolean
2161gtk_scrollbar_button_press_callback( GtkWidget *widget,
2162 GdkEventButton *gdk_event,
2163 wxWindowGTK *win)
cb43b372 2164{
3ac8d3bc
RR
2165 DEBUG_MAIN_THREAD
2166
c50f1fb9 2167 if (g_isIdle)
a2053b27
RR
2168 wxapp_install_idle_handler();
2169
d6d26e04 2170
0a164d4c 2171 g_blockEventsOnScroll = true;
9e691f46 2172
68567a96
MR
2173// FIXME: there is no 'slider' field in GTK+ 2.0 any more
2174#if 0
2a23d363 2175 win->m_isScrolling = (gdk_event->window == widget->slider);
9e691f46 2176#endif
47d67540 2177
e380f72b 2178 return FALSE;
cb43b372 2179}
865bb325 2180}
cb43b372
RR
2181
2182//-----------------------------------------------------------------------------
2183// "button_release_event" from scrollbar
2184//-----------------------------------------------------------------------------
2185
865bb325 2186extern "C" {
7f7beb1d
MR
2187static gboolean
2188gtk_scrollbar_button_release_callback( GtkRange *widget,
2189 GdkEventButton *WXUNUSED(gdk_event),
2190 wxWindowGTK *win)
cb43b372 2191{
3ac8d3bc
RR
2192 DEBUG_MAIN_THREAD
2193
1ecc4d80 2194// don't test here as we can release the mouse while being over
5e014a0c 2195// a different window than the slider
76ed8f8d
RR
2196//
2197// if (gdk_event->window != widget->slider) return FALSE;
cb43b372 2198
0a164d4c 2199 g_blockEventsOnScroll = false;
47d67540 2200
2a23d363 2201 if (win->m_isScrolling)
88413fec 2202 {
d6d26e04 2203 wxEventType command = wxEVT_SCROLLWIN_THUMBRELEASE;
2a23d363
RR
2204 int value = -1;
2205 int dir = -1;
2daa0ce9 2206
2a23d363
RR
2207 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
2208 if (widget == GTK_RANGE(scrolledWindow->hscrollbar))
2209 {
2210 value = (int)(win->m_hAdjust->value+0.5);
2211 dir = wxHORIZONTAL;
2212 }
2213 if (widget == GTK_RANGE(scrolledWindow->vscrollbar))
2214 {
2215 value = (int)(win->m_vAdjust->value+0.5);
2216 dir = wxVERTICAL;
2217 }
2daa0ce9 2218
2a23d363 2219 wxScrollWinEvent event( command, value, dir );
2a23d363
RR
2220 event.SetEventObject( win );
2221 win->GetEventHandler()->ProcessEvent( event );
88413fec
RR
2222 }
2223
0a164d4c 2224 win->m_isScrolling = false;
2daa0ce9 2225
e380f72b 2226 return FALSE;
cb43b372 2227}
865bb325 2228}
cb43b372 2229
f03fc89f
VZ
2230// ----------------------------------------------------------------------------
2231// this wxWindowBase function is implemented here (in platform-specific file)
2232// because it is static and so couldn't be made virtual
2233// ----------------------------------------------------------------------------
2b07d713 2234
0fe02759 2235wxWindow *wxWindowBase::DoFindFocus()
2b07d713 2236{
1e6feb95
VZ
2237 // the cast is necessary when we compile in wxUniversal mode
2238 return (wxWindow *)g_focusWindow;
2b07d713 2239}
ca298c88 2240
a2053b27
RR
2241//-----------------------------------------------------------------------------
2242// "realize" from m_widget
2243//-----------------------------------------------------------------------------
2244
b79395c5
RR
2245/* We cannot set colours and fonts before the widget has
2246 been realized, so we do this directly after realization. */
a2053b27 2247
865bb325 2248extern "C" {
7f7beb1d 2249static void
2b5f62a0 2250gtk_window_realized_callback( GtkWidget *m_widget, wxWindow *win )
a2053b27 2251{
3ac8d3bc
RR
2252 DEBUG_MAIN_THREAD
2253
c50f1fb9 2254 if (g_isIdle)
a2053b27 2255 wxapp_install_idle_handler();
0a164d4c 2256
a3c15d89 2257 if (win->m_imData)
2b5f62a0
VZ
2258 {
2259 GtkPizza *pizza = GTK_PIZZA( m_widget );
a3c15d89
VS
2260 gtk_im_context_set_client_window( win->m_imData->context,
2261 pizza->bin_window );
2b5f62a0 2262 }
2b5f62a0 2263
3c679789
RR
2264 wxWindowCreateEvent event( win );
2265 event.SetEventObject( win );
2266 win->GetEventHandler()->ProcessEvent( event );
a2053b27 2267}
865bb325 2268}
a2053b27 2269
b79395c5
RR
2270//-----------------------------------------------------------------------------
2271// "size_allocate"
2272//-----------------------------------------------------------------------------
2273
865bb325 2274extern "C" {
8f75cb6c 2275static
adc1999b
RR
2276void gtk_window_size_callback( GtkWidget *WXUNUSED(widget),
2277 GtkAllocation *WXUNUSED(alloc),
8f75cb6c
RR
2278 wxWindow *win )
2279{
2280 if (g_isIdle)
2281 wxapp_install_idle_handler();
2daa0ce9 2282
5b8a521e 2283 if (!win->m_hasScrolling) return;
2daa0ce9 2284
5b8a521e
RR
2285 int client_width = 0;
2286 int client_height = 0;
2287 win->GetClientSize( &client_width, &client_height );
2288 if ((client_width == win->m_oldClientWidth) && (client_height == win->m_oldClientHeight))
2289 return;
2daa0ce9 2290
5b8a521e
RR
2291 win->m_oldClientWidth = client_width;
2292 win->m_oldClientHeight = client_height;
2daa0ce9 2293
5b8a521e
RR
2294 if (!win->m_nativeSizeEvent)
2295 {
2296 wxSizeEvent event( win->GetSize(), win->GetId() );
2297 event.SetEventObject( win );
2298 win->GetEventHandler()->ProcessEvent( event );
2299 }
8f75cb6c 2300}
865bb325 2301}
8f75cb6c
RR
2302
2303
3ed2e7ce
VZ
2304#ifdef HAVE_XIM
2305 #define WXUNUSED_UNLESS_XIM(param) param
2306#else
2307 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2308#endif
2309
b79395c5
RR
2310/* Resize XIM window */
2311
865bb325 2312extern "C" {
3ed2e7ce 2313static
8f75cb6c
RR
2314void gtk_wxwindow_size_callback( GtkWidget* WXUNUSED_UNLESS_XIM(widget),
2315 GtkAllocation* WXUNUSED_UNLESS_XIM(alloc),
1e6feb95 2316 wxWindowGTK* WXUNUSED_UNLESS_XIM(win) )
b79395c5
RR
2317{
2318 if (g_isIdle)
2319 wxapp_install_idle_handler();
2daa0ce9 2320
9a8c7620 2321#ifdef HAVE_XIM
b79395c5
RR
2322 if (!win->m_ic)
2323 return;
2324
b79395c5
RR
2325 if (gdk_ic_get_style (win->m_ic) & GDK_IM_PREEDIT_POSITION)
2326 {
2327 gint width, height;
2328
3ed2e7ce 2329 gdk_window_get_size (widget->window, &width, &height);
b79395c5
RR
2330 win->m_icattr->preedit_area.width = width;
2331 win->m_icattr->preedit_area.height = height;
2332 gdk_ic_set_attr (win->m_ic, win->m_icattr, GDK_IC_PREEDIT_AREA);
2333 }
9a8c7620 2334#endif // HAVE_XIM
b79395c5 2335}
865bb325 2336}
b79395c5 2337
63081513
RR
2338//-----------------------------------------------------------------------------
2339// "realize" from m_wxwindow
2340//-----------------------------------------------------------------------------
2341
2342/* Initialize XIM support */
2343
865bb325 2344extern "C" {
7f7beb1d 2345static void
3ed2e7ce 2346gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget),
1e6feb95 2347 wxWindowGTK * WXUNUSED_UNLESS_XIM(win) )
63081513
RR
2348{
2349 if (g_isIdle)
2350 wxapp_install_idle_handler();
2351
d06800f1 2352#ifdef HAVE_XIM
7f7beb1d
MR
2353 if (win->m_ic) return;
2354 if (!widget) return;
2355 if (!gdk_im_ready()) return;
63081513
RR
2356
2357 win->m_icattr = gdk_ic_attr_new();
7f7beb1d 2358 if (!win->m_icattr) return;
2daa0ce9 2359
63081513
RR
2360 gint width, height;
2361 GdkEventMask mask;
2362 GdkColormap *colormap;
2363 GdkICAttr *attr = win->m_icattr;
b58b1dfc 2364 unsigned attrmask = GDK_IC_ALL_REQ;
63081513 2365 GdkIMStyle style;
b79395c5
RR
2366 GdkIMStyle supported_style = (GdkIMStyle)
2367 (GDK_IM_PREEDIT_NONE |
1e6feb95
VZ
2368 GDK_IM_PREEDIT_NOTHING |
2369 GDK_IM_PREEDIT_POSITION |
2370 GDK_IM_STATUS_NONE |
2371 GDK_IM_STATUS_NOTHING);
63081513
RR
2372
2373 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
1e6feb95 2374 supported_style = (GdkIMStyle)(supported_style & ~GDK_IM_PREEDIT_POSITION);
63081513
RR
2375
2376 attr->style = style = gdk_im_decide_style (supported_style);
2377 attr->client_window = widget->window;
2378
2379 if ((colormap = gtk_widget_get_colormap (widget)) !=
1e6feb95 2380 gtk_widget_get_default_colormap ())
63081513 2381 {
5cd09f0b
RR
2382 attrmask |= GDK_IC_PREEDIT_COLORMAP;
2383 attr->preedit_colormap = colormap;
63081513 2384 }
2daa0ce9 2385
63081513
RR
2386 attrmask |= GDK_IC_PREEDIT_FOREGROUND;
2387 attrmask |= GDK_IC_PREEDIT_BACKGROUND;
2388 attr->preedit_foreground = widget->style->fg[GTK_STATE_NORMAL];
2389 attr->preedit_background = widget->style->base[GTK_STATE_NORMAL];
2390
2391 switch (style & GDK_IM_PREEDIT_MASK)
2392 {
1e6feb95
VZ
2393 case GDK_IM_PREEDIT_POSITION:
2394 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
2395 {
2396 g_warning ("over-the-spot style requires fontset");
2397 break;
2398 }
63081513 2399
1e6feb95 2400 gdk_window_get_size (widget->window, &width, &height);
63081513 2401
1e6feb95
VZ
2402 attrmask |= GDK_IC_PREEDIT_POSITION_REQ;
2403 attr->spot_location.x = 0;
2404 attr->spot_location.y = height;
2405 attr->preedit_area.x = 0;
2406 attr->preedit_area.y = 0;
2407 attr->preedit_area.width = width;
2408 attr->preedit_area.height = height;
2409 attr->preedit_fontset = widget->style->font;
63081513 2410
1e6feb95 2411 break;
b79395c5 2412 }
2daa0ce9 2413
b58b1dfc 2414 win->m_ic = gdk_ic_new (attr, (GdkICAttributesType)attrmask);
2daa0ce9 2415
63081513 2416 if (win->m_ic == NULL)
1e6feb95 2417 g_warning ("Can't create input context.");
63081513 2418 else
1e6feb95
VZ
2419 {
2420 mask = gdk_window_get_events (widget->window);
2421 mask = (GdkEventMask)(mask | gdk_ic_get_events (win->m_ic));
2422 gdk_window_set_events (widget->window, mask);
2423
2424 if (GTK_WIDGET_HAS_FOCUS(widget))
2425 gdk_im_begin (win->m_ic, widget->window);
2426 }
2427#endif // HAVE_XIM
63081513 2428}
865bb325 2429}
63081513 2430
6ca41e57 2431//-----------------------------------------------------------------------------
1e6feb95 2432// InsertChild for wxWindowGTK.
6ca41e57
RR
2433//-----------------------------------------------------------------------------
2434
1e6feb95 2435/* Callback for wxWindowGTK. This very strange beast has to be used because
b1170810
RR
2436 * C++ has no virtual methods in a constructor. We have to emulate a
2437 * virtual function here as wxNotebook requires a different way to insert
2438 * a child in it. I had opted for creating a wxNotebookPage window class
2439 * which would have made this superfluous (such in the MDI window system),
2440 * but no-one was listening to me... */
6ca41e57 2441
1e6feb95 2442static void wxInsertChildInWindow( wxWindowGTK* parent, wxWindowGTK* child )
6ca41e57 2443{
bf0c00c6
RR
2444 /* the window might have been scrolled already, do we
2445 have to adapt the position */
da048e3d
RR
2446 GtkPizza *pizza = GTK_PIZZA(parent->m_wxwindow);
2447 child->m_x += pizza->xoffset;
2448 child->m_y += pizza->yoffset;
148cd9b6 2449
da048e3d 2450 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
a2053b27
RR
2451 GTK_WIDGET(child->m_widget),
2452 child->m_x,
2453 child->m_y,
2454 child->m_width,
2455 child->m_height );
6ca41e57
RR
2456}
2457
bbe0af5b
RR
2458//-----------------------------------------------------------------------------
2459// global functions
2460//-----------------------------------------------------------------------------
2461
1e6feb95 2462wxWindow *wxGetActiveWindow()
bbe0af5b 2463{
6cad4f1b 2464 return wxWindow::FindFocus();
bbe0af5b
RR
2465}
2466
7dd40b6f
RD
2467
2468wxMouseState wxGetMouseState()
2469{
2470 wxMouseState ms;
2471
2472 gint x;
2473 gint y;
2474 GdkModifierType mask;
2475
2476 gdk_window_get_pointer(NULL, &x, &y, &mask);
2477
2478 ms.SetX(x);
2479 ms.SetY(y);
2480 ms.SetLeftDown(mask & GDK_BUTTON1_MASK);
2481 ms.SetMiddleDown(mask & GDK_BUTTON2_MASK);
2482 ms.SetRightDown(mask & GDK_BUTTON3_MASK);
2483
2484 ms.SetControlDown(mask & GDK_CONTROL_MASK);
2485 ms.SetShiftDown(mask & GDK_SHIFT_MASK);
2486 ms.SetAltDown(mask & GDK_MOD1_MASK);
2487 ms.SetMetaDown(mask & GDK_MOD2_MASK);
3d257b8d 2488
7dd40b6f
RD
2489 return ms;
2490}
3d257b8d 2491
c801d85f 2492//-----------------------------------------------------------------------------
1e6feb95 2493// wxWindowGTK
c801d85f
KB
2494//-----------------------------------------------------------------------------
2495
6522713c
VZ
2496// in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2497// method
1e6feb95 2498#ifdef __WXUNIVERSAL__
6522713c
VZ
2499 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK, wxWindowBase)
2500#else // __WXGTK__
1e6feb95 2501 IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
6522713c 2502#endif // __WXUNIVERSAL__/__WXGTK__
c801d85f 2503
1e6feb95 2504void wxWindowGTK::Init()
c801d85f 2505{
f03fc89f 2506 // GTK specific
a2053b27 2507 m_widget = (GtkWidget *) NULL;
e380f72b 2508 m_wxwindow = (GtkWidget *) NULL;
76fcf0f2 2509 m_focusWidget = (GtkWidget *) NULL;
8bbe427f 2510
f03fc89f 2511 // position/size
a2053b27
RR
2512 m_x = 0;
2513 m_y = 0;
2514 m_width = 0;
e380f72b 2515 m_height = 0;
8bbe427f 2516
0a164d4c
WS
2517 m_sizeSet = false;
2518 m_hasVMT = false;
2519 m_needParent = true;
2520 m_isBeingDeleted = false;
148cd9b6 2521
0a164d4c
WS
2522 m_noExpose = false;
2523 m_nativeSizeEvent = false;
94633ad9 2524
0a164d4c
WS
2525 m_hasScrolling = false;
2526 m_isScrolling = false;
f03fc89f 2527
a2053b27 2528 m_hAdjust = (GtkAdjustment*) NULL;
e380f72b 2529 m_vAdjust = (GtkAdjustment*) NULL;
815ac4a7 2530 m_oldHorizontalPos =
e380f72b 2531 m_oldVerticalPos = 0.0;
815ac4a7
VZ
2532 m_oldClientWidth =
2533 m_oldClientHeight = 0;
8bbe427f 2534
0a164d4c 2535 m_resizing = false;
8bbe427f 2536
ddb6bc71 2537 m_insertCallback = (wxInsertChildFunction) NULL;
8bbe427f 2538
0a164d4c
WS
2539 m_acceptsFocus = false;
2540 m_hasFocus = false;
148cd9b6 2541
0a164d4c 2542 m_clipPaintRegion = false;
b6fa52db 2543
c7382f91
JS
2544 m_needsStyleChange = false;
2545
5e014a0c 2546 m_cursor = *wxSTANDARD_CURSOR;
2daa0ce9 2547
a3c15d89 2548 m_imData = NULL;
a589495e 2549 m_dirtyTabOrder = false;
362c6693 2550}
c801d85f 2551
1e6feb95 2552wxWindowGTK::wxWindowGTK()
68995f26
VZ
2553{
2554 Init();
2555}
2556
1e6feb95
VZ
2557wxWindowGTK::wxWindowGTK( wxWindow *parent,
2558 wxWindowID id,
2559 const wxPoint &pos,
2560 const wxSize &size,
2561 long style,
2562 const wxString &name )
6ca41e57 2563{
68995f26
VZ
2564 Init();
2565
e380f72b 2566 Create( parent, id, pos, size, style, name );
6ca41e57 2567}
8bbe427f 2568
1e6feb95
VZ
2569bool wxWindowGTK::Create( wxWindow *parent,
2570 wxWindowID id,
2571 const wxPoint &pos,
2572 const wxSize &size,
2573 long style,
2574 const wxString &name )
c801d85f 2575{
4dcaf11a
RR
2576 if (!PreCreation( parent, pos, size ) ||
2577 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
2578 {
1e6feb95 2579 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
0a164d4c 2580 return false;
4dcaf11a 2581 }
47d67540 2582
ddb6bc71 2583 m_insertCallback = wxInsertChildInWindow;
2b5f62a0 2584
e380f72b 2585 m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
38c7b3d3 2586 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
ff8bfdbb 2587
f03fc89f 2588 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
47d67540 2589
dd00f3f6 2590 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
e380f72b 2591 scroll_class->scrollbar_spacing = 0;
47d67540 2592
f03fc89f 2593 gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
47d67540 2594
f03fc89f
VZ
2595 m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->hscrollbar) );
2596 m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->vscrollbar) );
47d67540 2597
da048e3d 2598 m_wxwindow = gtk_pizza_new();
0fc5dbf5 2599
1e6feb95 2600#ifndef __WXUNIVERSAL__
da048e3d 2601 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
b292e2f5 2602
f03fc89f 2603 if (HasFlag(wxRAISED_BORDER))
034be888 2604 {
da048e3d 2605 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_OUT );
034be888 2606 }
f03fc89f 2607 else if (HasFlag(wxSUNKEN_BORDER))
034be888 2608 {
da048e3d 2609 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_IN );
5e014a0c
RR
2610 }
2611 else if (HasFlag(wxSIMPLE_BORDER))
2612 {
da048e3d 2613 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_THIN );
034be888
RR
2614 }
2615 else
2616 {
da048e3d 2617 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_NONE );
034be888 2618 }
1e6feb95 2619#endif // __WXUNIVERSAL__
47d67540 2620
4e5a4c69
RR
2621 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
2622
3da17724 2623 GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
0a164d4c 2624 m_acceptsFocus = true;
ca298c88 2625
e380f72b 2626 // I _really_ don't want scrollbars in the beginning
a2053b27
RR
2627 m_vAdjust->lower = 0.0;
2628 m_vAdjust->upper = 1.0;
2629 m_vAdjust->value = 0.0;
2630 m_vAdjust->step_increment = 1.0;
2631 m_vAdjust->page_increment = 1.0;
2632 m_vAdjust->page_size = 5.0;
9fa72bd2 2633 g_signal_emit_by_name (m_vAdjust, "changed");
a2053b27
RR
2634 m_hAdjust->lower = 0.0;
2635 m_hAdjust->upper = 1.0;
2636 m_hAdjust->value = 0.0;
2637 m_hAdjust->step_increment = 1.0;
2638 m_hAdjust->page_increment = 1.0;
2639 m_hAdjust->page_size = 5.0;
9fa72bd2 2640 g_signal_emit_by_name (m_hAdjust, "changed");
f03fc89f
VZ
2641
2642 // these handlers block mouse events to any window during scrolling such as
77ffb593 2643 // motion events and prevent GTK and wxWidgets from fighting over where the
f03fc89f 2644 // slider should be
9fa72bd2
MR
2645 g_signal_connect (scrolledWindow->vscrollbar, "button_press_event",
2646 G_CALLBACK (gtk_scrollbar_button_press_callback), this);
2647 g_signal_connect (scrolledWindow->hscrollbar, "button_press_event",
2648 G_CALLBACK (gtk_scrollbar_button_press_callback), this);
2649 g_signal_connect (scrolledWindow->vscrollbar, "button_release_event",
2650 G_CALLBACK (gtk_scrollbar_button_release_callback), this);
2651 g_signal_connect (scrolledWindow->hscrollbar, "button_release_event",
2652 G_CALLBACK (gtk_scrollbar_button_release_callback), this);
8bbe427f 2653
034be888 2654 // these handlers get notified when screen updates are required either when
76ed8f8d
RR
2655 // scrolling or when the window size (and therefore scrollbar configuration)
2656 // has changed
2657
9fa72bd2
MR
2658 g_signal_connect (m_hAdjust, "value_changed",
2659 G_CALLBACK (gtk_window_hscroll_callback), this);
2660 g_signal_connect (m_vAdjust, "value_changed",
2661 G_CALLBACK (gtk_window_vscroll_callback), this);
76ed8f8d 2662
f03fc89f 2663 gtk_widget_show( m_wxwindow );
47d67540 2664
f03fc89f
VZ
2665 if (m_parent)
2666 m_parent->DoAddChild( this );
94633ad9 2667
76fcf0f2 2668 m_focusWidget = m_wxwindow;
8bbe427f 2669
e380f72b 2670 PostCreation();
8bbe427f 2671
0a164d4c 2672 return true;
362c6693 2673}
c801d85f 2674
1e6feb95 2675wxWindowGTK::~wxWindowGTK()
c801d85f 2676{
7de59551
RD
2677 SendDestroyEvent();
2678
44cd54c2
JS
2679 if (g_focusWindow == this)
2680 g_focusWindow = NULL;
2681
3e679f01
VZ
2682 if ( g_delayedFocus == this )
2683 g_delayedFocus = NULL;
2684
0a164d4c
WS
2685 m_isBeingDeleted = true;
2686 m_hasVMT = false;
47d67540 2687
02c3e53b
JS
2688 // destroy children before destroying this window itself
2689 DestroyChildren();
2690
2691 // unhook focus handlers to prevent stray events being
2692 // propagated to this (soon to be) dead object
2693 if (m_focusWidget != NULL)
2694 {
9fa72bd2
MR
2695 g_signal_handlers_disconnect_by_func (m_focusWidget,
2696 (gpointer) gtk_window_focus_in_callback,
2697 this);
2698 g_signal_handlers_disconnect_by_func (m_focusWidget,
2699 (gpointer) gtk_window_focus_out_callback,
2700 this);
02c3e53b
JS
2701 }
2702
f03fc89f 2703 if (m_widget)
0a164d4c 2704 Show( false );
8bbe427f 2705
63081513
RR
2706#ifdef HAVE_XIM
2707 if (m_ic)
2708 gdk_ic_destroy (m_ic);
2709 if (m_icattr)
2710 gdk_ic_attr_destroy (m_icattr);
2711#endif
2712
f6551618
MW
2713 // delete before the widgets to avoid a crash on solaris
2714 delete m_imData;
f6551618 2715
f03fc89f 2716 if (m_wxwindow)
a2053b27 2717 {
f03fc89f 2718 gtk_widget_destroy( m_wxwindow );
c50f1fb9 2719 m_wxwindow = (GtkWidget*) NULL;
a2053b27 2720 }
8bbe427f 2721
f03fc89f 2722 if (m_widget)
a2053b27 2723 {
f03fc89f 2724 gtk_widget_destroy( m_widget );
c50f1fb9 2725 m_widget = (GtkWidget*) NULL;
a2053b27 2726 }
362c6693 2727}
c801d85f 2728
1e6feb95 2729bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos, const wxSize &size )
c801d85f 2730{
0a164d4c 2731 wxCHECK_MSG( !m_needParent || parent, false, wxT("Need complete parent.") );
8bbe427f 2732
a7c26d10
RD
2733 // Use either the given size, or the default if -1 is given.
2734 // See wxWindowBase for these functions.
3013a903 2735 m_width = WidthDefault(size.x) ;
f03fc89f 2736 m_height = HeightDefault(size.y);
8bbe427f 2737
43a18898
RR
2738 m_x = (int)pos.x;
2739 m_y = (int)pos.y;
8bbe427f 2740
0a164d4c 2741 return true;
c801d85f
KB
2742}
2743
1e6feb95 2744void wxWindowGTK::PostCreation()
c801d85f 2745{
82b978d7
RD
2746 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2747
43a18898
RR
2748 if (m_wxwindow)
2749 {
147bc491 2750 if (!m_noExpose)
b02da6b1 2751 {
77ffb593 2752 // these get reported to wxWidgets -> wxPaintEvent
1e6feb95 2753
b420fb6a
RR
2754 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow), TRUE );
2755
9fa72bd2
MR
2756 g_signal_connect (m_wxwindow, "expose_event",
2757 G_CALLBACK (gtk_window_expose_callback), this);
147bc491 2758
cbab6fe5 2759 gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
93d23d8f 2760 }
2b5f62a0 2761
ed56a258
JS
2762 // Create input method handler
2763 m_imData = new wxGtkIMData;
2764
2b5f62a0 2765 // Cannot handle drawing preedited text yet
a3c15d89 2766 gtk_im_context_set_use_preedit( m_imData->context, FALSE );
2b5f62a0 2767
9fa72bd2 2768 g_signal_connect (m_imData->context, "commit",
da210120 2769 G_CALLBACK (gtk_wxwindow_commit_cb), this);
148cd9b6 2770
67d78217 2771 // these are called when the "sunken" or "raised" borders are drawn
9fa72bd2
MR
2772 g_signal_connect (m_widget, "expose_event",
2773 G_CALLBACK (gtk_window_own_expose_callback), this);
43a18898 2774 }
47d67540 2775
76fcf0f2 2776 // focus handling
63081513 2777
06fda9e8
RR
2778 if (!GTK_IS_WINDOW(m_widget))
2779 {
2780 if (m_focusWidget == NULL)
2781 m_focusWidget = m_widget;
0a164d4c 2782
4c20ee63
RR
2783 if (m_wxwindow)
2784 {
2785 g_signal_connect (m_focusWidget, "focus_in_event",
9fa72bd2 2786 G_CALLBACK (gtk_window_focus_in_callback), this);
4c20ee63 2787 g_signal_connect (m_focusWidget, "focus_out_event",
f1e57cb9 2788 G_CALLBACK (gtk_window_focus_out_callback), this);
4c20ee63
RR
2789 }
2790 else
2791 {
2792 g_signal_connect_after (m_focusWidget, "focus_in_event",
2793 G_CALLBACK (gtk_window_focus_in_callback), this);
2794 g_signal_connect_after (m_focusWidget, "focus_out_event",
2795 G_CALLBACK (gtk_window_focus_out_callback), this);
2796 }
06fda9e8 2797 }
76fcf0f2
RR
2798
2799 // connect to the various key and mouse handlers
63081513 2800
a2053b27 2801 GtkWidget *connect_widget = GetConnectWidget();
f03fc89f 2802
a2053b27 2803 ConnectWidget( connect_widget );
47d67540 2804
63081513 2805 /* We cannot set colours, fonts and cursors before the widget has
a2053b27 2806 been realized, so we do this directly after realization */
9fa72bd2
MR
2807 g_signal_connect (connect_widget, "realize",
2808 G_CALLBACK (gtk_window_realized_callback), this);
2daa0ce9 2809
63081513
RR
2810 if (m_wxwindow)
2811 {
47c93b63 2812 // Catch native resize events
9fa72bd2
MR
2813 g_signal_connect (m_wxwindow, "size_allocate",
2814 G_CALLBACK (gtk_window_size_callback), this);
2daa0ce9 2815
47c93b63 2816 // Initialize XIM support
9fa72bd2
MR
2817 g_signal_connect (m_wxwindow, "realize",
2818 G_CALLBACK (gtk_wxwindow_realized_callback), this);
8f75cb6c 2819
47c93b63 2820 // And resize XIM window
9fa72bd2
MR
2821 g_signal_connect (m_wxwindow, "size_allocate",
2822 G_CALLBACK (gtk_wxwindow_size_callback), this);
63081513 2823 }
2daa0ce9 2824
024e9a4c
RR
2825 if (GTK_IS_COMBO(m_widget))
2826 {
2827 GtkCombo *gcombo = GTK_COMBO(m_widget);
0a164d4c 2828
9fa72bd2
MR
2829 g_signal_connect (gcombo->entry, "size_request",
2830 G_CALLBACK (wxgtk_combo_size_request_callback),
2831 this);
024e9a4c
RR
2832 }
2833 else
47c93b63
RR
2834 {
2835 // This is needed if we want to add our windows into native
024e9a4c 2836 // GTK controls, such as the toolbar. With this callback, the
47c93b63 2837 // toolbar gets to know the correct size (the one set by the
024e9a4c 2838 // programmer). Sadly, it misbehaves for wxComboBox.
9fa72bd2
MR
2839 g_signal_connect (m_widget, "size_request",
2840 G_CALLBACK (wxgtk_window_size_request_callback),
2841 this);
47c93b63 2842 }
1e6feb95 2843
40bab631
VS
2844 InheritAttributes();
2845
0a164d4c 2846 m_hasVMT = true;
a433fbd5
VZ
2847
2848 // unless the window was created initially hidden (i.e. Hide() had been
2849 // called before Create()), we should show it at GTK+ level as well
2850 if ( IsShown() )
2851 gtk_widget_show( m_widget );
b4071e91
RR
2852}
2853
1e6feb95 2854void wxWindowGTK::ConnectWidget( GtkWidget *widget )
b4071e91 2855{
9fa72bd2
MR
2856 g_signal_connect (widget, "key_press_event",
2857 G_CALLBACK (gtk_window_key_press_callback), this);
2858 g_signal_connect (widget, "key_release_event",
2859 G_CALLBACK (gtk_window_key_release_callback), this);
2860 g_signal_connect (widget, "button_press_event",
2861 G_CALLBACK (gtk_window_button_press_callback), this);
2862 g_signal_connect (widget, "button_release_event",
2863 G_CALLBACK (gtk_window_button_release_callback), this);
2864 g_signal_connect (widget, "motion_notify_event",
2865 G_CALLBACK (gtk_window_motion_notify_callback), this);
2866 g_signal_connect (widget, "scroll_event",
2867 G_CALLBACK (gtk_window_wheel_callback), this);
2868 g_signal_connect (widget, "popup_menu",
2869 G_CALLBACK (wxgtk_window_popup_menu_callback), this);
2870 g_signal_connect (widget, "enter_notify_event",
2871 G_CALLBACK (gtk_window_enter_callback), this);
2872 g_signal_connect (widget, "leave_notify_event",
2873 G_CALLBACK (gtk_window_leave_callback), this);
362c6693 2874}
c801d85f 2875
1e6feb95 2876bool wxWindowGTK::Destroy()
c801d85f 2877{
82b978d7 2878 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
47d67540 2879
0a164d4c 2880 m_hasVMT = false;
c801d85f 2881
f03fc89f 2882 return wxWindowBase::Destroy();
362c6693 2883}
c801d85f 2884
1e6feb95 2885void wxWindowGTK::DoMoveWindow(int x, int y, int width, int height)
23efdd02
RR
2886{
2887 gtk_pizza_set_size( GTK_PIZZA(m_parent->m_wxwindow), m_widget, x, y, width, height );
2888}
2daa0ce9 2889
1e6feb95 2890void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
c801d85f 2891{
82b978d7 2892 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
1e6feb95 2893 wxASSERT_MSG( (m_parent != NULL), wxT("wxWindowGTK::SetSize requires parent.\n") );
8bbe427f 2894
33611ebb 2895/*
f94fca1b 2896 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
33611ebb
RR
2897*/
2898
e27ce4e9 2899 if (m_resizing) return; /* I don't like recursions */
0a164d4c 2900 m_resizing = true;
1e6feb95 2901
b9f29261
VS
2902 int currentX, currentY;
2903 GetPosition(&currentX, &currentY);
443c834d 2904 if (x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
b9f29261 2905 x = currentX;
443c834d 2906 if (y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
b9f29261 2907 y = currentY;
a200c35e
VS
2908 AdjustForParentClientOrigin(x, y, sizeFlags);
2909
fe39b16a
RR
2910 // calculate the best size if we should auto size the window
2911 if ( ((sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1) ||
2912 ((sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1) )
2913 {
2914 const wxSize sizeBest = GetBestSize();
2915 if ( (sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1 )
2916 width = sizeBest.x;
2917 if ( (sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1 )
2918 height = sizeBest.y;
2919 }
2920
2921 if (width != -1)
2922 m_width = width;
2923 if (height != -1)
2924 m_height = height;
2925
2926 int minWidth = GetMinWidth(),
2927 minHeight = GetMinHeight(),
2928 maxWidth = GetMaxWidth(),
2929 maxHeight = GetMaxHeight();
2930
2931 if ((minWidth != -1) && (m_width < minWidth )) m_width = minWidth;
2932 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
2933 if ((maxWidth != -1) && (m_width > maxWidth )) m_width = maxWidth;
2934 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
2935
2936#if wxUSE_TOOLBAR_NATIVE
2937 if (wxDynamicCast(GetParent(), wxToolBar))
fb1585ae 2938 {
fe39b16a
RR
2939 // don't take the x,y values, they're wrong because toolbar sets them
2940 GtkWidget *widget = GTK_WIDGET(m_widget);
2941 gtk_widget_set_size_request (widget, m_width, m_height);
2942 if (GTK_WIDGET_VISIBLE (widget))
2943 gtk_widget_queue_resize (widget);
2944 }
2e1f5012 2945 else
fe39b16a
RR
2946#endif
2947 if (m_parent->m_wxwindow == NULL) // i.e. wxNotebook
2948 {
2949 // don't set the size for children of wxNotebook, just take the values.
fb1585ae
RR
2950 m_x = x;
2951 m_y = y;
2952 m_width = width;
ba4e3652 2953 m_height = height;
fb1585ae 2954 }
ba4e3652 2955 else
fb1585ae 2956 {
da048e3d 2957 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
85ad5eb5 2958 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
ba4e3652 2959 {
da048e3d
RR
2960 if (x != -1) m_x = x + pizza->xoffset;
2961 if (y != -1) m_y = y + pizza->yoffset;
ba4e3652
RR
2962 }
2963 else
2964 {
da048e3d
RR
2965 m_x = x + pizza->xoffset;
2966 m_y = y + pizza->yoffset;
ba4e3652 2967 }
47d67540 2968
863e0817
RR
2969 int left_border = 0;
2970 int right_border = 0;
2971 int top_border = 0;
c50f1fb9 2972 int bottom_border = 0;
f03fc89f 2973
863e0817 2974 /* the default button has a border around it */
29f538ce 2975 if (GTK_WIDGET_CAN_DEFAULT(m_widget))
c50f1fb9 2976 {
f893066b
RR
2977 GtkBorder *default_border = NULL;
2978 gtk_widget_style_get( m_widget, "default_border", &default_border, NULL );
2979 if (default_border)
863e0817 2980 {
f893066b
RR
2981 left_border += default_border->left;
2982 right_border += default_border->right;
2983 top_border += default_border->top;
2984 bottom_border += default_border->bottom;
2985 g_free( default_border );
863e0817 2986 }
863e0817 2987 }
c50f1fb9 2988
863e0817
RR
2989 DoMoveWindow( m_x-top_border,
2990 m_y-left_border,
2991 m_width+left_border+right_border,
2992 m_height+top_border+bottom_border );
54517652 2993 }
148cd9b6 2994
5b8a521e
RR
2995 if (m_hasScrolling)
2996 {
1e6feb95 2997 /* Sometimes the client area changes size without the
b6fa52db
RR
2998 whole windows's size changing, but if the whole
2999 windows's size doesn't change, no wxSizeEvent will
3000 normally be sent. Here we add an extra test if
3001 the client test has been changed and this will
3002 be used then. */
5b8a521e
RR
3003 GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
3004 }
3005
54517652 3006/*
6d693bb4
RR
3007 wxPrintf( "OnSize sent from " );
3008 if (GetClassInfo() && GetClassInfo()->GetClassName())
3009 wxPrintf( GetClassInfo()->GetClassName() );
3010 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3011*/
3012
30760ce7
RR
3013 if (!m_nativeSizeEvent)
3014 {
3015 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
3016 event.SetEventObject( this );
3017 GetEventHandler()->ProcessEvent( event );
3018 }
6d693bb4 3019
0a164d4c 3020 m_resizing = false;
362c6693 3021}
c801d85f 3022
1e6feb95 3023void wxWindowGTK::OnInternalIdle()
9390a202 3024{
a589495e 3025 if ( m_dirtyTabOrder )
12848fda
VZ
3026 {
3027 m_dirtyTabOrder = false;
a589495e 3028 RealizeTabOrder();
12848fda 3029 }
68567a96 3030
c7382f91
JS
3031 // Update style if the window was not yet realized
3032 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
3033 if (m_needsStyleChange)
3034 {
3035 SetBackgroundStyle(GetBackgroundStyle());
3036 m_needsStyleChange = false;
3037 }
a589495e 3038
beab25bd 3039 // Update invalidated regions.
010afced 3040 GtkUpdate();
0fc5dbf5 3041
9146082c
RR
3042 wxCursor cursor = m_cursor;
3043 if (g_globalCursor.Ok()) cursor = g_globalCursor;
c50f1fb9 3044
f7a11f8c 3045 if (cursor.Ok())
9146082c 3046 {
3017f78d 3047 /* I now set the cursor anew in every OnInternalIdle call
b02da6b1
VZ
3048 as setting the cursor in a parent window also effects the
3049 windows above so that checking for the current cursor is
3050 not possible. */
148cd9b6 3051
9146082c 3052 if (m_wxwindow)
6a008b33 3053 {
da048e3d 3054 GdkWindow *window = GTK_PIZZA(m_wxwindow)->bin_window;
6a008b33 3055 if (window)
c50f1fb9 3056 gdk_window_set_cursor( window, cursor.GetCursor() );
6a008b33
VZ
3057
3058 if (!g_globalCursor.Ok())
3059 cursor = *wxSTANDARD_CURSOR;
3060
3061 window = m_widget->window;
5e014a0c 3062 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
9146082c 3063 gdk_window_set_cursor( window, cursor.GetCursor() );
5e014a0c 3064
6a008b33
VZ
3065 }
3066 else
3067 {
5e014a0c 3068
9146082c 3069 GdkWindow *window = m_widget->window;
5e014a0c 3070 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
9146082c 3071 gdk_window_set_cursor( window, cursor.GetCursor() );
5e014a0c 3072
6a008b33 3073 }
9146082c 3074 }
6a008b33 3075
e39af974
JS
3076 if (wxUpdateUIEvent::CanUpdate(this))
3077 UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
9390a202
RR
3078}
3079
1e6feb95 3080void wxWindowGTK::DoGetSize( int *width, int *height ) const
c801d85f 3081{
82b978d7 3082 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3083
fb1585ae
RR
3084 if (width) (*width) = m_width;
3085 if (height) (*height) = m_height;
362c6693 3086}
c801d85f 3087
1e6feb95 3088void wxWindowGTK::DoSetClientSize( int width, int height )
c801d85f 3089{
82b978d7
RD
3090 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3091
1ecc4d80 3092 if (!m_wxwindow)
c801d85f 3093 {
1ecc4d80 3094 SetSize( width, height );
c801d85f
KB
3095 }
3096 else
3097 {
1ecc4d80
RR
3098 int dw = 0;
3099 int dh = 0;
3100
1e6feb95 3101#ifndef __WXUNIVERSAL__
98d3fdbe
RR
3102 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
3103 {
5e014a0c 3104 /* when using GTK 1.2 we set the shadow border size to 2 */
6a008b33 3105 dw += 2 * 2;
98d3fdbe
RR
3106 dh += 2 * 2;
3107 }
5e014a0c
RR
3108 if (HasFlag(wxSIMPLE_BORDER))
3109 {
3110 /* when using GTK 1.2 we set the simple border size to 1 */
3111 dw += 1 * 2;
3112 dh += 1 * 2;
3113 }
1e6feb95 3114#endif // __WXUNIVERSAL__
034be888 3115
5b8a521e 3116 if (m_hasScrolling)
98d3fdbe 3117 {
324dbfec 3118 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2daa0ce9 3119
9000c624
RR
3120 GtkRequisition vscroll_req;
3121 vscroll_req.width = 2;
3122 vscroll_req.height = 2;
dd00f3f6 3123 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
9000c624 3124 (scroll_window->vscrollbar, &vscroll_req );
2daa0ce9 3125
9000c624
RR
3126 GtkRequisition hscroll_req;
3127 hscroll_req.width = 2;
3128 hscroll_req.height = 2;
dd00f3f6 3129 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
9000c624
RR
3130 (scroll_window->hscrollbar, &hscroll_req );
3131
dd00f3f6 3132 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
324dbfec 3133
1ecc4d80
RR
3134 if (scroll_window->vscrollbar_visible)
3135 {
9000c624 3136 dw += vscroll_req.width;
1ecc4d80
RR
3137 dw += scroll_class->scrollbar_spacing;
3138 }
3139
3140 if (scroll_window->hscrollbar_visible)
3141 {
9000c624 3142 dh += hscroll_req.height;
63cc5d9d 3143 dh += scroll_class->scrollbar_spacing;
1ecc4d80 3144 }
9000c624 3145 }
1ecc4d80 3146
034be888 3147 SetSize( width+dw, height+dh );
1ecc4d80 3148 }
362c6693 3149}
c801d85f 3150
1e6feb95 3151void wxWindowGTK::DoGetClientSize( int *width, int *height ) const
c801d85f 3152{
82b978d7 3153 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3154
1ecc4d80
RR
3155 if (!m_wxwindow)
3156 {
3157 if (width) (*width) = m_width;
3158 if (height) (*height) = m_height;
c801d85f
KB
3159 }
3160 else
3161 {
1ecc4d80
RR
3162 int dw = 0;
3163 int dh = 0;
3164
1e6feb95 3165#ifndef __WXUNIVERSAL__
98d3fdbe
RR
3166 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
3167 {
5e014a0c 3168 /* when using GTK 1.2 we set the shadow border size to 2 */
6a008b33 3169 dw += 2 * 2;
98d3fdbe
RR
3170 dh += 2 * 2;
3171 }
5e014a0c
RR
3172 if (HasFlag(wxSIMPLE_BORDER))
3173 {
3174 /* when using GTK 1.2 we set the simple border size to 1 */
3175 dw += 1 * 2;
3176 dh += 1 * 2;
3177 }
1e6feb95 3178#endif // __WXUNIVERSAL__
9000c624 3179
5b8a521e 3180 if (m_hasScrolling)
98d3fdbe 3181 {
6a008b33 3182 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2daa0ce9 3183
9000c624
RR
3184 GtkRequisition vscroll_req;
3185 vscroll_req.width = 2;
3186 vscroll_req.height = 2;
dd00f3f6 3187 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
9000c624 3188 (scroll_window->vscrollbar, &vscroll_req );
2daa0ce9 3189
9000c624
RR
3190 GtkRequisition hscroll_req;
3191 hscroll_req.width = 2;
3192 hscroll_req.height = 2;
dd00f3f6 3193 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
9000c624
RR
3194 (scroll_window->hscrollbar, &hscroll_req );
3195
dd00f3f6 3196 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
6a008b33 3197
1ecc4d80
RR
3198 if (scroll_window->vscrollbar_visible)
3199 {
9000c624 3200 dw += vscroll_req.width;
1ecc4d80
RR
3201 dw += scroll_class->scrollbar_spacing;
3202 }
3203
3204 if (scroll_window->hscrollbar_visible)
3205 {
9000c624 3206 dh += hscroll_req.height;
1ecc4d80
RR
3207 dh += scroll_class->scrollbar_spacing;
3208 }
6a008b33 3209 }
47d67540 3210
1ecc4d80
RR
3211 if (width) (*width) = m_width - dw;
3212 if (height) (*height) = m_height - dh;
3213 }
1e6feb95 3214
f94fca1b
RR
3215/*
3216 printf( "GetClientSize, name %s ", GetName().c_str() );
3217 if (width) printf( " width = %d", (*width) );
3218 if (height) printf( " height = %d", (*height) );
3219 printf( "\n" );
3220*/
362c6693 3221}
c801d85f 3222
1e6feb95 3223void wxWindowGTK::DoGetPosition( int *x, int *y ) const
c801d85f 3224{
82b978d7 3225 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3226
bf0c00c6
RR
3227 int dx = 0;
3228 int dy = 0;
3229 if (m_parent && m_parent->m_wxwindow)
3230 {
da048e3d 3231 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
b02da6b1
VZ
3232 dx = pizza->xoffset;
3233 dy = pizza->yoffset;
bf0c00c6 3234 }
94633ad9 3235
496beb3f
VS
3236 if (x) (*x) = m_x - dx;
3237 if (y) (*y) = m_y - dy;
362c6693 3238}
c801d85f 3239
1e6feb95 3240void wxWindowGTK::DoClientToScreen( int *x, int *y ) const
c801d85f 3241{
82b978d7 3242 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3243
a2053b27
RR
3244 if (!m_widget->window) return;
3245
43a18898
RR
3246 GdkWindow *source = (GdkWindow *) NULL;
3247 if (m_wxwindow)
da048e3d 3248 source = GTK_PIZZA(m_wxwindow)->bin_window;
43a18898
RR
3249 else
3250 source = m_widget->window;
47d67540 3251
43a18898
RR
3252 int org_x = 0;
3253 int org_y = 0;
3254 gdk_window_get_origin( source, &org_x, &org_y );
c801d85f 3255
43a18898 3256 if (!m_wxwindow)
c801d85f 3257 {
43a18898
RR
3258 if (GTK_WIDGET_NO_WINDOW (m_widget))
3259 {
3260 org_x += m_widget->allocation.x;
3261 org_y += m_widget->allocation.y;
3262 }
362c6693 3263 }
47d67540 3264
43a18898
RR
3265 if (x) *x += org_x;
3266 if (y) *y += org_y;
362c6693 3267}
c801d85f 3268
1e6feb95 3269void wxWindowGTK::DoScreenToClient( int *x, int *y ) const
c801d85f 3270{
82b978d7 3271 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
47d67540 3272
a2053b27
RR
3273 if (!m_widget->window) return;
3274
1ecc4d80
RR
3275 GdkWindow *source = (GdkWindow *) NULL;
3276 if (m_wxwindow)
da048e3d 3277 source = GTK_PIZZA(m_wxwindow)->bin_window;
1ecc4d80
RR
3278 else
3279 source = m_widget->window;
47d67540 3280
1ecc4d80
RR
3281 int org_x = 0;
3282 int org_y = 0;
3283 gdk_window_get_origin( source, &org_x, &org_y );
c801d85f 3284
1ecc4d80 3285 if (!m_wxwindow)
c801d85f 3286 {
1ecc4d80
RR
3287 if (GTK_WIDGET_NO_WINDOW (m_widget))
3288 {
3289 org_x += m_widget->allocation.x;
3290 org_y += m_widget->allocation.y;
3291 }
362c6693 3292 }
47d67540 3293
1ecc4d80
RR
3294 if (x) *x -= org_x;
3295 if (y) *y -= org_y;
362c6693 3296}
c801d85f 3297
1e6feb95 3298bool wxWindowGTK::Show( bool show )
c801d85f 3299{
0a164d4c 3300 wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
47d67540 3301
739730ca
RR
3302 if (!wxWindowBase::Show(show))
3303 {
3304 // nothing to do
0a164d4c 3305 return false;
739730ca 3306 }
8bbe427f 3307
f03fc89f
VZ
3308 if (show)
3309 gtk_widget_show( m_widget );
1ecc4d80 3310 else
f03fc89f 3311 gtk_widget_hide( m_widget );
8bbe427f 3312
2b5f62a0 3313 wxShowEvent eventShow(GetId(), show);
687706f5 3314 eventShow.SetEventObject(this);
2b5f62a0
VZ
3315
3316 GetEventHandler()->ProcessEvent(eventShow);
3317
0a164d4c 3318 return true;
362c6693 3319}
c801d85f 3320
3379ed37 3321static void wxWindowNotifyEnable(wxWindowGTK* win, bool enable)
fdca68a6
JS
3322{
3323 win->OnParentEnable(enable);
3324
3325 // Recurse, so that children have the opportunity to Do The Right Thing
3326 // and reset colours that have been messed up by a parent's (really ancestor's)
3327 // Enable call
222ed1d6 3328 for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
fdca68a6
JS
3329 node;
3330 node = node->GetNext() )
3331 {
3332 wxWindow *child = node->GetData();
3333 if (!child->IsKindOf(CLASSINFO(wxDialog)) && !child->IsKindOf(CLASSINFO(wxFrame)))
3334 wxWindowNotifyEnable(child, enable);
3335 }
3336}
3337
3379ed37 3338bool wxWindowGTK::Enable( bool enable )
c801d85f 3339{
0a164d4c 3340 wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
82b978d7 3341
739730ca
RR
3342 if (!wxWindowBase::Enable(enable))
3343 {
3344 // nothing to do
0a164d4c 3345 return false;
739730ca 3346 }
1ecc4d80 3347
f03fc89f
VZ
3348 gtk_widget_set_sensitive( m_widget, enable );
3349 if ( m_wxwindow )
3350 gtk_widget_set_sensitive( m_wxwindow, enable );
ff8bfdbb 3351
fdca68a6 3352 wxWindowNotifyEnable(this, enable);
513903c4 3353
0a164d4c 3354 return true;
362c6693 3355}
c801d85f 3356
1e6feb95 3357int wxWindowGTK::GetCharHeight() const
2f2aa628 3358{
82b978d7 3359 wxCHECK_MSG( (m_widget != NULL), 12, wxT("invalid window") );
47d67540 3360
cc402e64
VZ
3361 wxFont font = GetFont();
3362 wxCHECK_MSG( font.Ok(), 12, wxT("invalid font") );
2f2aa628 3363
bbd006c0
RR
3364 PangoContext *context = NULL;
3365 if (m_widget)
3366 context = gtk_widget_get_pango_context( m_widget );
3367
3368 if (!context)
3369 return 0;
3370
cc402e64 3371 PangoFontDescription *desc = font.GetNativeFontInfo()->description;
bbd006c0
RR
3372 PangoLayout *layout = pango_layout_new(context);
3373 pango_layout_set_font_description(layout, desc);
3374 pango_layout_set_text(layout, "H", 1);
3375 PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
3376
3377 PangoRectangle rect;
3378 pango_layout_line_get_extents(line, NULL, &rect);
3379
3380 g_object_unref( G_OBJECT( layout ) );
7de59551 3381
f69e2009 3382 return (int) PANGO_PIXELS(rect.height);
362c6693 3383}
c801d85f 3384
1e6feb95 3385int wxWindowGTK::GetCharWidth() const
c33c4050 3386{
82b978d7 3387 wxCHECK_MSG( (m_widget != NULL), 8, wxT("invalid window") );
47d67540 3388
cc402e64
VZ
3389 wxFont font = GetFont();
3390 wxCHECK_MSG( font.Ok(), 8, wxT("invalid font") );
47d67540 3391
bbd006c0
RR
3392 PangoContext *context = NULL;
3393 if (m_widget)
3394 context = gtk_widget_get_pango_context( m_widget );
3395
3396 if (!context)
3397 return 0;
3398
cc402e64 3399 PangoFontDescription *desc = font.GetNativeFontInfo()->description;
bbd006c0
RR
3400 PangoLayout *layout = pango_layout_new(context);
3401 pango_layout_set_font_description(layout, desc);
95c430aa 3402 pango_layout_set_text(layout, "g", 1);
bbd006c0
RR
3403 PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
3404
3405 PangoRectangle rect;
3406 pango_layout_line_get_extents(line, NULL, &rect);
3407
3408 g_object_unref( G_OBJECT( layout ) );
7de59551 3409
f69e2009 3410 return (int) PANGO_PIXELS(rect.width);
c33c4050
RR
3411}
3412
1e6feb95 3413void wxWindowGTK::GetTextExtent( const wxString& string,
0a164d4c
WS
3414 int *x,
3415 int *y,
3416 int *descent,
3417 int *externalLeading,
3418 const wxFont *theFont ) const
c33c4050 3419{
cc402e64 3420 wxFont fontToUse = theFont ? *theFont : GetFont();
47d67540 3421
223d09f6 3422 wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
2b5f62a0 3423
0a164d4c 3424 if (string.empty())
48d011c8 3425 {
b15ed747
RR
3426 if (x) (*x) = 0;
3427 if (y) (*y) = 0;
48d011c8
RR
3428 return;
3429 }
47d67540 3430
48d011c8
RR
3431 PangoContext *context = NULL;
3432 if (m_widget)
2b5f62a0
VZ
3433 context = gtk_widget_get_pango_context( m_widget );
3434
48d011c8
RR
3435 if (!context)
3436 {
b15ed747
RR
3437 if (x) (*x) = 0;
3438 if (y) (*y) = 0;
48d011c8
RR
3439 return;
3440 }
2b5f62a0 3441
48d011c8
RR
3442 PangoFontDescription *desc = fontToUse.GetNativeFontInfo()->description;
3443 PangoLayout *layout = pango_layout_new(context);
3444 pango_layout_set_font_description(layout, desc);
3445 {
fb3ed106 3446#if wxUSE_UNICODE
48d011c8
RR
3447 const wxCharBuffer data = wxConvUTF8.cWC2MB( string );
3448 pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data ));
fb3ed106
RR
3449#else
3450 const wxWCharBuffer wdata = wxConvLocal.cMB2WC( string );
3451 const wxCharBuffer data = wxConvUTF8.cWC2MB( wdata );
3452 pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data ));
3453#endif
48d011c8 3454 }
2b5f62a0 3455
48d011c8 3456 PangoRectangle rect;
fd43b1b3 3457 pango_layout_get_extents(layout, NULL, &rect);
2b5f62a0 3458
f69e2009
VS
3459 if (x) (*x) = (wxCoord) PANGO_PIXELS(rect.width);
3460 if (y) (*y) = (wxCoord) PANGO_PIXELS(rect.height);
48d011c8
RR
3461 if (descent)
3462 {
f69e2009
VS
3463 PangoLayoutIter *iter = pango_layout_get_iter(layout);
3464 int baseline = pango_layout_iter_get_baseline(iter);
3465 pango_layout_iter_free(iter);
3466 *descent = *y - PANGO_PIXELS(baseline);
48d011c8
RR
3467 }
3468 if (externalLeading) (*externalLeading) = 0; // ??
2b5f62a0 3469
48d011c8 3470 g_object_unref( G_OBJECT( layout ) );
c33c4050
RR
3471}
3472
1e6feb95 3473void wxWindowGTK::SetFocus()
c801d85f 3474{
82b978d7 3475 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
6cad4f1b
VZ
3476 if ( m_hasFocus )
3477 {
3478 // don't do anything if we already have focus
3479 return;
3480 }
2daa0ce9 3481
354aa1e3
RR
3482 if (m_wxwindow)
3483 {
173348db 3484 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
b231914f 3485 {
173348db 3486 gtk_widget_grab_focus (m_wxwindow);
b231914f 3487 }
354aa1e3 3488 }
b231914f 3489 else if (m_widget)
c801d85f 3490 {
eccd5602
RR
3491 if (GTK_IS_CONTAINER(m_widget))
3492 {
3493 gtk_widget_child_focus( m_widget, GTK_DIR_TAB_FORWARD );
3494 }
3495 else
173348db 3496 if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
463c1fa1 3497 {
0a164d4c 3498
d7fa7eaa 3499 if (!GTK_WIDGET_REALIZED(m_widget))
6aeb6f2a 3500 {
6cad4f1b
VZ
3501 // we can't set the focus to the widget now so we remember that
3502 // it should be focused and will do it later, during the idle
3503 // time, as soon as we can
3504 wxLogTrace(TRACE_FOCUS,
3505 _T("Delaying setting focus to %s(%s)"),
6aeb6f2a
VZ
3506 GetClassInfo()->GetClassName(), GetLabel().c_str());
3507
d7fa7eaa 3508 g_delayedFocus = this;
6aeb6f2a 3509 }
d7fa7eaa 3510 else
6aeb6f2a 3511 {
6cad4f1b
VZ
3512 wxLogTrace(TRACE_FOCUS,
3513 _T("Setting focus to %s(%s)"),
6aeb6f2a
VZ
3514 GetClassInfo()->GetClassName(), GetLabel().c_str());
3515
d7fa7eaa 3516 gtk_widget_grab_focus (m_widget);
6aeb6f2a 3517 }
463c1fa1 3518 }
0a164d4c 3519 else
ff8bfdbb 3520 {
6cad4f1b
VZ
3521 wxLogTrace(TRACE_FOCUS,
3522 _T("Can't set focus to %s(%s)"),
3523 GetClassInfo()->GetClassName(), GetLabel().c_str());
ff8bfdbb 3524 }
362c6693 3525 }
362c6693 3526}
c801d85f 3527
1e6feb95 3528bool wxWindowGTK::AcceptsFocus() const
b292e2f5 3529{
f03fc89f 3530 return m_acceptsFocus && wxWindowBase::AcceptsFocus();
b292e2f5
RR
3531}
3532
1e6feb95 3533bool wxWindowGTK::Reparent( wxWindowBase *newParentBase )
463c1fa1 3534{
0a164d4c 3535 wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
c50f1fb9 3536
1e6feb95
VZ
3537 wxWindowGTK *oldParent = m_parent,
3538 *newParent = (wxWindowGTK *)newParentBase;
a2053b27 3539
5fd11f09
RR
3540 wxASSERT( GTK_IS_WIDGET(m_widget) );
3541
f03fc89f 3542 if ( !wxWindowBase::Reparent(newParent) )
0a164d4c 3543 return false;
8bbe427f 3544
5fd11f09
RR
3545 wxASSERT( GTK_IS_WIDGET(m_widget) );
3546
3547 /* prevent GTK from deleting the widget arbitrarily */
3548 gtk_widget_ref( m_widget );
3549
8ce63e9d
RR
3550 if (oldParent)
3551 {
3017f78d 3552 gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget );
8ce63e9d 3553 }
c50f1fb9 3554
5fd11f09
RR
3555 wxASSERT( GTK_IS_WIDGET(m_widget) );
3556
8ce63e9d
RR
3557 if (newParent)
3558 {
3559 /* insert GTK representation */
3560 (*(newParent->m_insertCallback))(newParent, this);
3561 }
c50f1fb9 3562
5fd11f09
RR
3563 /* reverse: prevent GTK from deleting the widget arbitrarily */
3564 gtk_widget_unref( m_widget );
148cd9b6 3565
0a164d4c 3566 return true;
362c6693 3567}
c801d85f 3568
1e6feb95 3569void wxWindowGTK::DoAddChild(wxWindowGTK *child)
ddb6bc71 3570{
223d09f6 3571 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
ddb6bc71 3572
223d09f6 3573 wxASSERT_MSG( (child != NULL), wxT("invalid child window") );
ddb6bc71 3574
223d09f6 3575 wxASSERT_MSG( (m_insertCallback != NULL), wxT("invalid child insertion function") );
c50f1fb9 3576
ddb6bc71
RR
3577 /* add to list */
3578 AddChild( child );
c50f1fb9 3579
ddb6bc71
RR
3580 /* insert GTK representation */
3581 (*m_insertCallback)(this, child);
3582}
3583
a589495e
VS
3584void wxWindowGTK::AddChild(wxWindowBase *child)
3585{
3586 wxWindowBase::AddChild(child);
3587 m_dirtyTabOrder = true;
3588 if (g_isIdle)
3589 wxapp_install_idle_handler();
3590}
3591
3592void wxWindowGTK::RemoveChild(wxWindowBase *child)
3593{
3594 wxWindowBase::RemoveChild(child);
3595 m_dirtyTabOrder = true;
3596 if (g_isIdle)
3597 wxapp_install_idle_handler();
3598}
0a164d4c 3599
a589495e
VS
3600void wxWindowGTK::DoMoveInTabOrder(wxWindow *win, MoveKind move)
3601{
3602 wxWindowBase::DoMoveInTabOrder(win, move);
3603 m_dirtyTabOrder = true;
3604 if (g_isIdle)
3605 wxapp_install_idle_handler();
3606}
3607
2e1f5012
VZ
3608bool wxWindowGTK::GTKWidgetNeedsMnemonic() const
3609{
3610 // none needed by default
3611 return false;
3612}
3613
3614void wxWindowGTK::GTKWidgetDoSetMnemonic(GtkWidget* WXUNUSED(w))
3615{
3616 // nothing to do by default since none is needed
3617}
3618
a589495e
VS
3619void wxWindowGTK::RealizeTabOrder()
3620{
3621 if (m_wxwindow)
3622 {
12848fda 3623 if ( !m_children.empty() )
a589495e 3624 {
259858fc 3625 // we don't only construct the correct focus chain but also use
2e1f5012
VZ
3626 // this opportunity to update the mnemonic widgets for the widgets
3627 // that need them
259858fc 3628
a589495e 3629 GList *chain = NULL;
2e1f5012 3630 wxWindowGTK* mnemonicWindow = NULL;
0a164d4c 3631
12848fda
VZ
3632 for ( wxWindowList::const_iterator i = m_children.begin();
3633 i != m_children.end();
3634 ++i )
a589495e 3635 {
259858fc 3636 wxWindowGTK *win = *i;
2e1f5012
VZ
3637
3638 if ( mnemonicWindow )
259858fc
VZ
3639 {
3640 if ( win->AcceptsFocusFromKeyboard() )
3641 {
2e1f5012
VZ
3642 // wxComboBox et al. needs to focus on on a different
3643 // widget than m_widget, so if the main widget isn't
3644 // focusable try the connect widget
3645 GtkWidget* w = win->m_widget;
3646 if ( !GTK_WIDGET_CAN_FOCUS(w) )
3647 {
3648 w = win->GetConnectWidget();
3649 if ( !GTK_WIDGET_CAN_FOCUS(w) )
3650 w = NULL;
3651 }
3652
3653 if ( w )
3654 {
3655 mnemonicWindow->GTKWidgetDoSetMnemonic(w);
3656 mnemonicWindow = NULL;
3657 }
259858fc
VZ
3658 }
3659 }
2e1f5012 3660 else if ( win->GTKWidgetNeedsMnemonic() )
259858fc 3661 {
2e1f5012 3662 mnemonicWindow = win;
259858fc 3663 }
259858fc
VZ
3664
3665 chain = g_list_prepend(chain, win->m_widget);
a589495e 3666 }
0a164d4c 3667
a589495e 3668 chain = g_list_reverse(chain);
0a164d4c 3669
a589495e
VS
3670 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow), chain);
3671 g_list_free(chain);
3672 }
12848fda 3673 else // no children
a589495e
VS
3674 {
3675 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow));
3676 }
3677 }
a589495e
VS
3678}
3679
1e6feb95 3680void wxWindowGTK::Raise()
362c6693 3681{
82b978d7
RD
3682 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3683
fdfb8475
RR
3684 if (m_wxwindow && m_wxwindow->window)
3685 {
3686 gdk_window_raise( m_wxwindow->window );
3687 }
0a164d4c 3688 else if (m_widget->window)
fdfb8475
RR
3689 {
3690 gdk_window_raise( m_widget->window );
3691 }
362c6693
RR
3692}
3693
1e6feb95 3694void wxWindowGTK::Lower()
362c6693 3695{
82b978d7
RD
3696 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3697
fdfb8475
RR
3698 if (m_wxwindow && m_wxwindow->window)
3699 {
3700 gdk_window_lower( m_wxwindow->window );
3701 }
0a164d4c 3702 else if (m_widget->window)
fdfb8475
RR
3703 {
3704 gdk_window_lower( m_widget->window );
3705 }
362c6693 3706}
c801d85f 3707
1e6feb95 3708bool wxWindowGTK::SetCursor( const wxCursor &cursor )
86b29a61 3709{
0a164d4c 3710 wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
86b29a61 3711
f6bcfd97 3712 if (cursor == m_cursor)
0a164d4c 3713 return false;
f6bcfd97
BP
3714
3715 if (g_isIdle)
3716 wxapp_install_idle_handler();
1e6feb95 3717
f6bcfd97
BP
3718 if (cursor == wxNullCursor)
3719 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR );
3720 else
3721 return wxWindowBase::SetCursor( cursor );
362c6693 3722}
c801d85f 3723
1e6feb95 3724void wxWindowGTK::WarpPointer( int x, int y )
4f22cf8d 3725{
82b978d7
RD
3726 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3727
3bcc8d15
RR
3728 // We provide this function ourselves as it is
3729 // missing in GDK (top of this file).
148cd9b6 3730
ed673c6a
RR
3731 GdkWindow *window = (GdkWindow*) NULL;
3732 if (m_wxwindow)
da048e3d 3733 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a
RR
3734 else
3735 window = GetConnectWidget()->window;
148cd9b6 3736
ed673c6a
RR
3737 if (window)
3738 gdk_window_warp_pointer( window, x, y );
4f22cf8d
RR
3739}
3740
0c131a5a
VZ
3741static bool wxScrollAdjust(GtkAdjustment* adj, double change)
3742{
3743 double value_start = adj->value;
3744 double value = value_start + change;
3745 double upper = adj->upper - adj->page_size;
3746 if (value > upper)
3747 {
3748 value = upper;
3749 }
3750 // Lower bound will be checked by gtk_adjustment_set_value
3751 gtk_adjustment_set_value(adj, value);
3752 return adj->value != value_start;
3753}
3754
3755bool wxWindowGTK::ScrollLines(int lines)
3756{
3757 return
3758 m_vAdjust != NULL &&
3759 wxScrollAdjust(m_vAdjust, lines * m_vAdjust->step_increment);
3760}
3761
3762bool wxWindowGTK::ScrollPages(int pages)
3763{
3764 return
3765 m_vAdjust != NULL &&
3766 wxScrollAdjust(m_vAdjust, pages * m_vAdjust->page_increment);
3767}
3768
3769void wxWindowGTK::SetVScrollAdjustment(GtkAdjustment* adj)
3770{
3771 wxASSERT(m_vAdjust == NULL);
3772 m_vAdjust = adj;
3773}
3013a903 3774
1e6feb95 3775void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
c801d85f 3776{
a67f1484
VZ
3777 if (!m_widget)
3778 return;
3779 if (!m_widget->window)
3780 return;
2b5f62a0 3781
4e5a4c69
RR
3782 if (m_wxwindow)
3783 {
a67f1484
VZ
3784 GdkRectangle gdk_rect,
3785 *p;
4e5a4c69
RR
3786 if (rect)
3787 {
4e5a4c69
RR
3788 gdk_rect.x = rect->x;
3789 gdk_rect.y = rect->y;
3790 gdk_rect.width = rect->width;
3791 gdk_rect.height = rect->height;
a67f1484 3792 p = &gdk_rect;
4e5a4c69 3793 }
a67f1484 3794 else // invalidate everything
4e5a4c69 3795 {
a67f1484 3796 p = NULL;
4e5a4c69 3797 }
a67f1484
VZ
3798
3799 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow)->bin_window, p, TRUE );
4e5a4c69 3800 }
362c6693 3801}
c801d85f 3802
beab25bd 3803void wxWindowGTK::Update()
010afced
RR
3804{
3805 GtkUpdate();
1b965a9c
VZ
3806
3807 // when we call Update() we really want to update the window immediately on
90e572f1 3808 // screen, even if it means flushing the entire queue and hence slowing down
1b965a9c
VZ
3809 // everything -- but it should still be done, it's just that Update() should
3810 // be called very rarely
3811 gdk_flush();
010afced
RR
3812}
3813
3814void wxWindowGTK::GtkUpdate()
beab25bd 3815{
4e5a4c69
RR
3816 if (m_wxwindow && GTK_PIZZA(m_wxwindow)->bin_window)
3817 gdk_window_process_updates( GTK_PIZZA(m_wxwindow)->bin_window, FALSE );
a67f1484
VZ
3818
3819 // for consistency with other platforms (and also because it's convenient
3820 // to be able to update an entire TLW by calling Update() only once), we
3821 // should also update all our children here
3822 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
3823 node;
3824 node = node->GetNext() )
3825 {
3826 node->GetData()->GtkUpdate();
3827 }
beab25bd
RR
3828}
3829
3830void wxWindowGTK::GtkSendPaintEvents()
3831{
3bcc8d15
RR
3832 if (!m_wxwindow)
3833 {
3bcc8d15
RR
3834 m_updateRegion.Clear();
3835 return;
3836 }
beab25bd 3837
f90566f5 3838 // Clip to paint region in wxClientDC
0a164d4c 3839 m_clipPaintRegion = true;
fab591c5 3840
b15ed747
RR
3841 // widget to draw on
3842 GtkPizza *pizza = GTK_PIZZA (m_wxwindow);
2b5f62a0 3843
aac97549 3844 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM))
f90566f5
RR
3845 {
3846 // find ancestor from which to steal background
cd5e74ba 3847 wxWindow *parent = wxGetTopLevelParent((wxWindow *)this);
f90566f5 3848 if (!parent)
cc06fe74 3849 parent = (wxWindow*)this;
2b5f62a0 3850
822cf31c 3851 if (GTK_WIDGET_MAPPED(parent->m_widget))
f90566f5 3852 {
822cf31c
KH
3853 wxRegionIterator upd( m_updateRegion );
3854 while (upd)
3855 {
3856 GdkRectangle rect;
3857 rect.x = upd.GetX();
3858 rect.y = upd.GetY();
3859 rect.width = upd.GetWidth();
3860 rect.height = upd.GetHeight();
3861
3862 gtk_paint_flat_box( parent->m_widget->style,
3863 pizza->bin_window,
3864 (GtkStateType)GTK_WIDGET_STATE(m_wxwindow),
3865 GTK_SHADOW_NONE,
3866 &rect,
3867 parent->m_widget,
3868 (char *)"base",
3869 0, 0, -1, -1 );
3870
60d8e886 3871 ++upd;
822cf31c 3872 }
f90566f5
RR
3873 }
3874 }
3875 else
b15ed747 3876
b15ed747
RR
3877 {
3878 wxWindowDC dc( (wxWindow*)this );
3879 dc.SetClippingRegion( m_updateRegion );
3880
3881 wxEraseEvent erase_event( GetId(), &dc );
3882 erase_event.SetEventObject( this );
3883
3884 GetEventHandler()->ProcessEvent(erase_event);
3885 }
beab25bd
RR
3886
3887 wxNcPaintEvent nc_paint_event( GetId() );
3888 nc_paint_event.SetEventObject( this );
3889 GetEventHandler()->ProcessEvent( nc_paint_event );
3890
3891 wxPaintEvent paint_event( GetId() );
3892 paint_event.SetEventObject( this );
3893 GetEventHandler()->ProcessEvent( paint_event );
3894
0a164d4c 3895 m_clipPaintRegion = false;
c89f5c02 3896
c89f5c02 3897 m_updateRegion.Clear();
beab25bd
RR
3898}
3899
596f1d11 3900void wxWindowGTK::ClearBackground()
c801d85f 3901{
82b978d7 3902 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
362c6693 3903}
c801d85f 3904
ff8bfdbb 3905#if wxUSE_TOOLTIPS
1e6feb95 3906void wxWindowGTK::DoSetToolTip( wxToolTip *tip )
b1170810 3907{
f03fc89f 3908 wxWindowBase::DoSetToolTip(tip);
ff8bfdbb 3909
f03fc89f 3910 if (m_tooltip)
3379ed37 3911 m_tooltip->Apply( (wxWindow *)this );
b1170810
RR
3912}
3913
1e6feb95 3914void wxWindowGTK::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
b1170810 3915{
aa154cb1
RR
3916 wxString tmp( tip );
3917 gtk_tooltips_set_tip( tips, GetConnectWidget(), wxGTK_CONV(tmp), (gchar*) NULL );
301cd871 3918}
ff8bfdbb 3919#endif // wxUSE_TOOLTIPS
b1170810 3920
1e6feb95 3921bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
c801d85f 3922{
0a164d4c 3923 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
8bbe427f 3924
739730ca 3925 if (!wxWindowBase::SetBackgroundColour(colour))
44dfb5ce 3926 return false;
c50f1fb9 3927
5edef14e 3928 if (colour.Ok())
994bc575 3929 {
5edef14e
VS
3930 // We need the pixel value e.g. for background clearing.
3931 m_backgroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
994bc575 3932 }
ca298c88 3933
5edef14e 3934 // apply style change (forceStyle=true so that new style is applied
c7382f91
JS
3935 // even if the bg colour changed from valid to wxNullColour)
3936 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM)
3937 ApplyWidgetStyle(true);
ea323db3 3938
5edef14e 3939 return true;
6de97a3b
RR
3940}
3941
1e6feb95 3942bool wxWindowGTK::SetForegroundColour( const wxColour &colour )
6de97a3b 3943{
0a164d4c 3944 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
8bbe427f 3945
739730ca
RR
3946 if (!wxWindowBase::SetForegroundColour(colour))
3947 {
5edef14e 3948 return false;
739730ca 3949 }
0a164d4c 3950
5edef14e 3951 if (colour.Ok())
ea323db3 3952 {
5edef14e
VS
3953 // We need the pixel value e.g. for background clearing.
3954 m_foregroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
ea323db3 3955 }
f03fc89f 3956
5edef14e
VS
3957 // apply style change (forceStyle=true so that new style is applied
3958 // even if the bg colour changed from valid to wxNullColour):
3959 ApplyWidgetStyle(true);
3960
44dfb5ce 3961 return true;
58614078
RR
3962}
3963
2b5f62a0
VZ
3964PangoContext *wxWindowGTK::GtkGetPangoDefaultContext()
3965{
3966 return gtk_widget_get_pango_context( m_widget );
3967}
0a164d4c 3968
5edef14e 3969GtkRcStyle *wxWindowGTK::CreateWidgetStyle(bool forceStyle)
58614078 3970{
f40fdaa3 3971 // do we need to apply any changes at all?
5edef14e 3972 if ( !forceStyle &&
984e8d0b
VS
3973 !m_font.Ok() &&
3974 !m_foregroundColour.Ok() && !m_backgroundColour.Ok() )
fb65642c 3975 {
f40fdaa3 3976 return NULL;
fb65642c
RR
3977 }
3978
f40fdaa3 3979 GtkRcStyle *style = gtk_rc_style_new();
1ecc4d80 3980
984e8d0b 3981 if ( m_font.Ok() )
db434467 3982 {
0a164d4c 3983 style->font_desc =
f40fdaa3 3984 pango_font_description_copy( m_font.GetNativeFontInfo()->description );
288059b2 3985 }
1ecc4d80 3986
fe161a26 3987 if ( m_foregroundColour.Ok() )
1ecc4d80 3988 {
5edef14e 3989 GdkColor *fg = m_foregroundColour.GetColor();
0a164d4c 3990
5edef14e 3991 style->fg[GTK_STATE_NORMAL] = *fg;
f40fdaa3 3992 style->color_flags[GTK_STATE_NORMAL] = GTK_RC_FG;
0a164d4c 3993
5edef14e 3994 style->fg[GTK_STATE_PRELIGHT] = *fg;
f40fdaa3 3995 style->color_flags[GTK_STATE_PRELIGHT] = GTK_RC_FG;
0a164d4c 3996
5edef14e 3997 style->fg[GTK_STATE_ACTIVE] = *fg;
f40fdaa3 3998 style->color_flags[GTK_STATE_ACTIVE] = GTK_RC_FG;
1ecc4d80
RR
3999 }
4000
fe161a26 4001 if ( m_backgroundColour.Ok() )
1ecc4d80 4002 {
5edef14e
VS
4003 GdkColor *bg = m_backgroundColour.GetColor();
4004
4005 style->bg[GTK_STATE_NORMAL] = *bg;
4006 style->base[GTK_STATE_NORMAL] = *bg;
f40fdaa3
VS
4007 style->color_flags[GTK_STATE_NORMAL] = (GtkRcFlags)
4008 (style->color_flags[GTK_STATE_NORMAL] | GTK_RC_BG | GTK_RC_BASE);
0a164d4c 4009
5edef14e
VS
4010 style->bg[GTK_STATE_PRELIGHT] = *bg;
4011 style->base[GTK_STATE_PRELIGHT] = *bg;
f40fdaa3
VS
4012 style->color_flags[GTK_STATE_PRELIGHT] = (GtkRcFlags)
4013 (style->color_flags[GTK_STATE_PRELIGHT] | GTK_RC_BG | GTK_RC_BASE);
0a164d4c 4014
5edef14e
VS
4015 style->bg[GTK_STATE_ACTIVE] = *bg;
4016 style->base[GTK_STATE_ACTIVE] = *bg;
f40fdaa3
VS
4017 style->color_flags[GTK_STATE_ACTIVE] = (GtkRcFlags)
4018 (style->color_flags[GTK_STATE_ACTIVE] | GTK_RC_BG | GTK_RC_BASE);
0a164d4c 4019
5edef14e
VS
4020 style->bg[GTK_STATE_INSENSITIVE] = *bg;
4021 style->base[GTK_STATE_INSENSITIVE] = *bg;
f40fdaa3
VS
4022 style->color_flags[GTK_STATE_INSENSITIVE] = (GtkRcFlags)
4023 (style->color_flags[GTK_STATE_INSENSITIVE] | GTK_RC_BG | GTK_RC_BASE);
1ecc4d80 4024 }
0a164d4c 4025
f40fdaa3 4026 return style;
a81258be
RR
4027}
4028
f8e045e2 4029void wxWindowGTK::ApplyWidgetStyle(bool forceStyle)
a81258be 4030{
f8e045e2
RD
4031 GtkRcStyle *style = CreateWidgetStyle(forceStyle);
4032 if ( style )
4033 {
7074ce35 4034 DoApplyWidgetStyle(style);
f8e045e2
RD
4035 gtk_rc_style_unref(style);
4036 }
6dd18972
VS
4037
4038 // Style change may affect GTK+'s size calculation:
4039 InvalidateBestSize();
6de97a3b
RR
4040}
4041
7074ce35
VS
4042void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle *style)
4043{
4044 if (m_wxwindow)
7074ce35 4045 gtk_widget_modify_style(m_wxwindow, style);
7cb93e45
RR
4046 else
4047 gtk_widget_modify_style(m_widget, style);
7074ce35
VS
4048}
4049
c7382f91
JS
4050bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style)
4051{
4052 wxWindowBase::SetBackgroundStyle(style);
0a164d4c 4053
c7382f91
JS
4054 if (style == wxBG_STYLE_CUSTOM)
4055 {
4056 GdkWindow *window = (GdkWindow*) NULL;
4057 if (m_wxwindow)
4058 window = GTK_PIZZA(m_wxwindow)->bin_window;
4059 else
4060 window = GetConnectWidget()->window;
4061
4062 if (window)
4063 {
4064 // Make sure GDK/X11 doesn't refresh the window
4065 // automatically.
4066 gdk_window_set_back_pixmap( window, None, False );
4067#ifdef __X__
4068 Display* display = GDK_WINDOW_DISPLAY(window);
4069 XFlush(display);
4070#endif
4071 m_needsStyleChange = false;
4072 }
4073 else
4074 // Do in OnIdle, because the window is not yet available
4075 m_needsStyleChange = true;
0a164d4c 4076
c7382f91
JS
4077 // Don't apply widget style, or we get a grey background
4078 }
4079 else
4080 {
4081 // apply style change (forceStyle=true so that new style is applied
4082 // even if the bg colour changed from valid to wxNullColour):
4083 ApplyWidgetStyle(true);
4084 }
4085 return true;
4086}
7074ce35 4087
06cfab17 4088#if wxUSE_DRAG_AND_DROP
ac57418f 4089
1e6feb95 4090void wxWindowGTK::SetDropTarget( wxDropTarget *dropTarget )
c801d85f 4091{
82b978d7
RD
4092 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4093
1ecc4d80 4094 GtkWidget *dnd_widget = GetConnectWidget();
47d67540 4095
1ecc4d80 4096 if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
47d67540 4097
1ecc4d80
RR
4098 if (m_dropTarget) delete m_dropTarget;
4099 m_dropTarget = dropTarget;
47d67540 4100
1ecc4d80 4101 if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
362c6693 4102}
c801d85f 4103
f03fc89f 4104#endif // wxUSE_DRAG_AND_DROP
ac57418f 4105
1e6feb95 4106GtkWidget* wxWindowGTK::GetConnectWidget()
e3e65dac 4107{
1ecc4d80
RR
4108 GtkWidget *connect_widget = m_widget;
4109 if (m_wxwindow) connect_widget = m_wxwindow;
47d67540 4110
1ecc4d80 4111 return connect_widget;
e3e65dac 4112}
47d67540 4113
1e6feb95 4114bool wxWindowGTK::IsOwnGtkWindow( GdkWindow *window )
903f689b 4115{
148cd9b6 4116 if (m_wxwindow)
da048e3d 4117 return (window == GTK_PIZZA(m_wxwindow)->bin_window);
148cd9b6 4118
1ecc4d80 4119 return (window == m_widget->window);
903f689b
RR
4120}
4121
1e6feb95 4122bool wxWindowGTK::SetFont( const wxFont &font )
c801d85f 4123{
0a164d4c 4124 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
9c288e4d 4125
5edef14e
VS
4126 if (!wxWindowBase::SetFont(font))
4127 return false;
c801d85f 4128
5edef14e
VS
4129 // apply style change (forceStyle=true so that new style is applied
4130 // even if the font changed from valid to wxNullFont):
0a164d4c 4131 ApplyWidgetStyle(true);
5edef14e
VS
4132
4133 return true;
362c6693 4134}
c801d85f 4135
94633ad9 4136void wxWindowGTK::DoCaptureMouse()
c801d85f 4137{
82b978d7
RD
4138 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4139
ed673c6a 4140 GdkWindow *window = (GdkWindow*) NULL;
b231914f
VZ
4141 if (m_wxwindow)
4142 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a 4143 else
b231914f 4144 window = GetConnectWidget()->window;
148cd9b6 4145
e4606ed9 4146 wxCHECK_RET( window, _T("CaptureMouse() failed") );
c50f1fb9 4147
b231914f 4148 wxCursor* cursor = & m_cursor;
cca602ac
JS
4149 if (!cursor->Ok())
4150 cursor = wxSTANDARD_CURSOR;
4151
ed673c6a 4152 gdk_pointer_grab( window, FALSE,
1ecc4d80
RR
4153 (GdkEventMask)
4154 (GDK_BUTTON_PRESS_MASK |
4155 GDK_BUTTON_RELEASE_MASK |
148cd9b6 4156 GDK_POINTER_MOTION_HINT_MASK |
1ecc4d80 4157 GDK_POINTER_MOTION_MASK),
ff8bfdbb 4158 (GdkWindow *) NULL,
cca602ac 4159 cursor->GetCursor(),
b02da6b1 4160 (guint32)GDK_CURRENT_TIME );
b231914f 4161 g_captureWindow = this;
0a164d4c 4162 g_captureWindowHasMouse = true;
362c6693 4163}
c801d85f 4164
94633ad9 4165void wxWindowGTK::DoReleaseMouse()
c801d85f 4166{
82b978d7
RD
4167 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4168
e4606ed9 4169 wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") );
47d67540 4170
c43430bb
VS
4171 g_captureWindow = (wxWindowGTK*) NULL;
4172
ed673c6a 4173 GdkWindow *window = (GdkWindow*) NULL;
b231914f
VZ
4174 if (m_wxwindow)
4175 window = GTK_PIZZA(m_wxwindow)->bin_window;
ed673c6a 4176 else
b231914f 4177 window = GetConnectWidget()->window;
148cd9b6 4178
b02da6b1
VZ
4179 if (!window)
4180 return;
c50f1fb9 4181
b02da6b1 4182 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
362c6693 4183}
c801d85f 4184
1e6feb95
VZ
4185/* static */
4186wxWindow *wxWindowBase::GetCapture()
4187{
4188 return (wxWindow *)g_captureWindow;
4189}
4190
4191bool wxWindowGTK::IsRetained() const
c801d85f 4192{
0a164d4c 4193 return false;
362c6693 4194}
c801d85f 4195
1e6feb95 4196void wxWindowGTK::SetScrollbar( int orient, int pos, int thumbVisible,
cb43b372 4197 int range, bool refresh )
c801d85f 4198{
82b978d7
RD
4199 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4200
223d09f6 4201 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
c801d85f 4202
0a164d4c 4203 m_hasScrolling = true;
47d67540 4204
1ecc4d80 4205 if (orient == wxHORIZONTAL)
cb43b372 4206 {
1ecc4d80
RR
4207 float fpos = (float)pos;
4208 float frange = (float)range;
4209 float fthumb = (float)thumbVisible;
4210 if (fpos > frange-fthumb) fpos = frange-fthumb;
4211 if (fpos < 0.0) fpos = 0.0;
4212
4213 if ((fabs(frange-m_hAdjust->upper) < 0.2) &&
4214 (fabs(fthumb-m_hAdjust->page_size) < 0.2))
4215 {
4216 SetScrollPos( orient, pos, refresh );
4217 return;
4218 }
47d67540 4219
1ecc4d80 4220 m_oldHorizontalPos = fpos;
47d67540 4221
1ecc4d80
RR
4222 m_hAdjust->lower = 0.0;
4223 m_hAdjust->upper = frange;
4224 m_hAdjust->value = fpos;
4225 m_hAdjust->step_increment = 1.0;
4226 m_hAdjust->page_increment = (float)(wxMax(fthumb,0));
4227 m_hAdjust->page_size = fthumb;
cb43b372 4228 }
1ecc4d80
RR
4229 else
4230 {
4231 float fpos = (float)pos;
4232 float frange = (float)range;
4233 float fthumb = (float)thumbVisible;
4234 if (fpos > frange-fthumb) fpos = frange-fthumb;
4235 if (fpos < 0.0) fpos = 0.0;
4236
4237 if ((fabs(frange-m_vAdjust->upper) < 0.2) &&
4238 (fabs(fthumb-m_vAdjust->page_size) < 0.2))
4239 {
4240 SetScrollPos( orient, pos, refresh );
4241 return;
4242 }
47d67540 4243
1ecc4d80 4244 m_oldVerticalPos = fpos;
47d67540 4245
1ecc4d80
RR
4246 m_vAdjust->lower = 0.0;
4247 m_vAdjust->upper = frange;
4248 m_vAdjust->value = fpos;
4249 m_vAdjust->step_increment = 1.0;
4250 m_vAdjust->page_increment = (float)(wxMax(fthumb,0));
4251 m_vAdjust->page_size = fthumb;
4252 }
47d67540 4253
eb082a08 4254 if (orient == wxHORIZONTAL)
9fa72bd2 4255 g_signal_emit_by_name (m_hAdjust, "changed");
eb082a08 4256 else
9fa72bd2 4257 g_signal_emit_by_name (m_vAdjust, "changed");
362c6693 4258}
c801d85f 4259
87a3ebe9
VZ
4260void wxWindowGTK::GtkUpdateScrollbar(int orient)
4261{
4262 GtkAdjustment *adj = orient == wxHORIZONTAL ? m_hAdjust : m_vAdjust;
9fa72bd2
MR
4263 gpointer fn = orient == wxHORIZONTAL
4264 ? (gpointer) gtk_window_hscroll_callback
4265 : (gpointer) gtk_window_vscroll_callback;
87a3ebe9 4266
9fa72bd2
MR
4267 g_signal_handlers_disconnect_by_func (adj, fn, this);
4268 g_signal_emit_by_name (adj, "value_changed");
4269 g_signal_connect (adj, "value_changed", G_CALLBACK (fn), this);
87a3ebe9
VZ
4270}
4271
1e6feb95 4272void wxWindowGTK::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
c801d85f 4273{
82b978d7 4274 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
223d09f6 4275 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
1ecc4d80 4276
87a3ebe9 4277 GtkAdjustment *adj = orient == wxHORIZONTAL ? m_hAdjust : m_vAdjust;
1ecc4d80 4278
87a3ebe9
VZ
4279 float fpos = (float)pos;
4280 if (fpos > adj->upper - adj->page_size)
4281 fpos = adj->upper - adj->page_size;
4282 if (fpos < 0.0)
4283 fpos = 0.0;
4284 *(orient == wxHORIZONTAL ? &m_oldHorizontalPos : &m_oldVerticalPos) = fpos;
ff8bfdbb 4285
87a3ebe9
VZ
4286 if (fabs(fpos-adj->value) < 0.2)
4287 return;
4288 adj->value = fpos;
47d67540 4289
87a3ebe9 4290 if ( m_wxwindow->window )
47d67540 4291 {
cb43b372 4292 }
362c6693 4293}
c801d85f 4294
1e6feb95 4295int wxWindowGTK::GetScrollThumb( int orient ) const
c801d85f 4296{
82b978d7
RD
4297 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
4298
223d09f6 4299 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
47d67540 4300
1ecc4d80
RR
4301 if (orient == wxHORIZONTAL)
4302 return (int)(m_hAdjust->page_size+0.5);
4303 else
4304 return (int)(m_vAdjust->page_size+0.5);
362c6693 4305}
c801d85f 4306
1e6feb95 4307int wxWindowGTK::GetScrollPos( int orient ) const
c801d85f 4308{
82b978d7 4309 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
47d67540 4310
223d09f6 4311 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
c801d85f 4312
1ecc4d80
RR
4313 if (orient == wxHORIZONTAL)
4314 return (int)(m_hAdjust->value+0.5);
4315 else
4316 return (int)(m_vAdjust->value+0.5);
362c6693 4317}
c801d85f 4318
1e6feb95 4319int wxWindowGTK::GetScrollRange( int orient ) const
c801d85f 4320{
82b978d7 4321 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
47d67540 4322
223d09f6 4323 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
c801d85f 4324
1ecc4d80
RR
4325 if (orient == wxHORIZONTAL)
4326 return (int)(m_hAdjust->upper+0.5);
4327 else
4328 return (int)(m_vAdjust->upper+0.5);
362c6693 4329}
c801d85f 4330
1e6feb95 4331void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
c801d85f 4332{
82b978d7
RD
4333 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4334
223d09f6 4335 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
2b5f62a0 4336
f47ae6e7 4337 // No scrolling requested.
8e217128 4338 if ((dx == 0) && (dy == 0)) return;
0fc5dbf5 4339
0a164d4c 4340 m_clipPaintRegion = true;
0fc5dbf5 4341
da048e3d 4342 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
0fc5dbf5 4343
0a164d4c 4344 m_clipPaintRegion = false;
c801d85f 4345}
3723b7b1 4346
015dca24
MR
4347void wxWindowGTK::SetWindowStyleFlag( long style )
4348{
4349 // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
4350 wxWindowBase::SetWindowStyleFlag(style);
4351}
4e5a4c69 4352
3723b7b1
JS
4353// Find the wxWindow at the current mouse position, also returning the mouse
4354// position.
4355wxWindow* wxFindWindowAtPointer(wxPoint& pt)
4356{
59a12e90
JS
4357 pt = wxGetMousePosition();
4358 wxWindow* found = wxFindWindowAtPoint(pt);
4359 return found;
3723b7b1
JS
4360}
4361
4362// Get the current mouse position.
4363wxPoint wxGetMousePosition()
4364{
59a12e90
JS
4365 /* This crashes when used within wxHelpContext,
4366 so we have to use the X-specific implementation below.
4367 gint x, y;
4368 GdkModifierType *mask;
4369 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4370
4371 return wxPoint(x, y);
4372 */
4373
3723b7b1
JS
4374 int x, y;
4375 GdkWindow* windowAtPtr = gdk_window_at_pointer(& x, & y);
59a12e90 4376
37d81cc2 4377 Display *display = windowAtPtr ? GDK_WINDOW_XDISPLAY(windowAtPtr) : GDK_DISPLAY();
59a12e90
JS
4378 Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
4379 Window rootReturn, childReturn;
4380 int rootX, rootY, winX, winY;
4381 unsigned int maskReturn;
4382
4383 XQueryPointer (display,
5cd09f0b
RR
4384 rootWindow,
4385 &rootReturn,
59a12e90
JS
4386 &childReturn,
4387 &rootX, &rootY, &winX, &winY, &maskReturn);
4388 return wxPoint(rootX, rootY);
4389
3723b7b1
JS
4390}
4391
224016a8
JS
4392// Needed for implementing e.g. combobox on wxGTK within a modal dialog.
4393void wxAddGrab(wxWindow* window)
4394{
4395 gtk_grab_add( (GtkWidget*) window->GetHandle() );
4396}
4397
4398void wxRemoveGrab(wxWindow* window)
4399{
4400 gtk_grab_remove( (GtkWidget*) window->GetHandle() );
4401}
4402
4e5a4c69 4403// ----------------------------------------------------------------------------
224016a8 4404// wxWinModule
4e5a4c69
RR
4405// ----------------------------------------------------------------------------
4406
4407class wxWinModule : public wxModule
4408{
4409public:
4410 bool OnInit();
4411 void OnExit();
4412
4413private:
4414 DECLARE_DYNAMIC_CLASS(wxWinModule)
4415};
4416
4417IMPLEMENT_DYNAMIC_CLASS(wxWinModule, wxModule)
4418
4419bool wxWinModule::OnInit()
4420{
994bc575
RR
4421 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4422 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
0fc5dbf5 4423
0a164d4c 4424 return true;
4e5a4c69
RR
4425}
4426
4427void wxWinModule::OnExit()
4428{
994bc575
RR
4429 if (g_eraseGC)
4430 gdk_gc_unref( g_eraseGC );
4e5a4c69
RR
4431}
4432