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