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