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