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