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