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