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