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