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