]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/window.cpp
Fiddled with wxFindWindowAtPoint to make it work with notebooks and static boxes
[wxWidgets.git] / src / gtk / window.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10
11 #ifdef __GNUG__
12 #pragma implementation "window.h"
13 #endif
14
15 #ifdef __VMS
16 #define XWarpPointer XWARPPOINTER
17 #endif
18
19 #include "wx/defs.h"
20 #include "wx/window.h"
21 #include "wx/dc.h"
22 #include "wx/frame.h"
23 #include "wx/app.h"
24 #include "wx/layout.h"
25 #include "wx/utils.h"
26 #include "wx/dialog.h"
27 #include "wx/msgdlg.h"
28
29 #if wxUSE_DRAG_AND_DROP
30 #include "wx/dnd.h"
31 #endif
32
33 #if wxUSE_TOOLTIPS
34 #include "wx/tooltip.h"
35 #endif
36
37 #if wxUSE_CARET
38 #include "wx/caret.h"
39 #endif // wxUSE_CARET
40
41 #include "wx/menu.h"
42 #include "wx/statusbr.h"
43 #include "wx/intl.h"
44 #include "wx/settings.h"
45 #include "wx/log.h"
46
47 #ifdef __WXDEBUG__
48 #include "wx/thread.h"
49 #endif
50
51 #include <math.h>
52
53 #include <gdk/gdk.h>
54 #include <gtk/gtk.h>
55 #include <gdk/gdkprivate.h>
56 #include <gdk/gdkkeysyms.h>
57 #include <gdk/gdkx.h>
58
59 #include <gtk/gtk.h>
60 #include <gtk/gtkprivate.h>
61
62 #include "wx/gtk/win_gtk.h"
63
64 //-----------------------------------------------------------------------------
65 // documentation on internals
66 //-----------------------------------------------------------------------------
67
68 /*
69 I have been asked several times about writing some documentation about
70 the GTK port of wxWindows, especially its internal structures. Obviously,
71 you cannot understand wxGTK without knowing a little about the GTK, but
72 some more information about what the wxWindow, which is the base class
73 for all other window classes, does seems required as well.
74
75 I)
76
77 What does wxWindow do? It contains the common interface for the following
78 jobs of its descendants:
79
80 1) Define the rudimentary behaviour common to all window classes, such as
81 resizing, intercepting user input (so as to make it possible to use these
82 events for special purposes in a derived class), window names etc.
83
84 2) Provide the possibility to contain and manage children, if the derived
85 class is allowed to contain children, which holds true for those window
86 classes which do not display a native GTK widget. To name them, these
87 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
88 work classes are a special case and are handled a bit differently from
89 the rest. The same holds true for the wxNotebook class.
90
91 3) Provide the possibility to draw into a client area of a window. This,
92 too, only holds true for classes that do not display a native GTK widget
93 as above.
94
95 4) Provide the entire mechanism for scrolling widgets. This actual inter-
96 face for this is usually in wxScrolledWindow, but the GTK implementation
97 is in this class.
98
99 5) A multitude of helper or extra methods for special purposes, such as
100 Drag'n'Drop, managing validators etc.
101
102 6) Display a border (sunken, raised, simple or none).
103
104 Normally one might expect, that one wxWindows window would always correspond
105 to one GTK widget. Under GTK, there is no such allround widget that has all
106 the functionality. Moreover, the GTK defines a client area as a different
107 widget from the actual widget you are handling. Last but not least some
108 special classes (e.g. wxFrame) handle different categories of widgets and
109 still have the possibility to draw something in the client area.
110 It was therefore required to write a special purpose GTK widget, that would
111 represent a client area in the sense of wxWindows capable to do the jobs
112 2), 3) and 4). I have written this class and it resides in win_gtk.c of
113 this directory.
114
115 All windows must have a widget, with which they interact with other under-
116 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
117 thw wxWindow class has a member variable called m_widget which holds a
118 pointer to this widget. When the window class represents a GTK native widget,
119 this is (in most cases) the only GTK widget the class manages. E.g. the
120 wxStatitText class handles only a GtkLabel widget a pointer to which you
121 can find in m_widget (defined in wxWindow)
122
123 When the class has a client area for drawing into and for containing children
124 it has to handle the client area widget (of the type GtkPizza, defined in
125 win_gtk.c), but there could be any number of widgets, handled by a class
126 The common rule for all windows is only, that the widget that interacts with
127 the rest of GTK must be referenced in m_widget and all other widgets must be
128 children of this widget on the GTK level. The top-most widget, which also
129 represents the client area, must be in the m_wxwindow field and must be of
130 the type GtkPizza.
131
132 As I said, the window classes that display a GTK native widget only have
133 one widget, so in the case of e.g. the wxButton class m_widget holds a
134 pointer to a GtkButton widget. But windows with client areas (for drawing
135 and children) have a m_widget field that is a pointer to a GtkScrolled-
136 Window and a m_wxwindow field that is pointer to a GtkPizza and this
137 one is (in the GTK sense) a child of the GtkScrolledWindow.
138
139 If the m_wxwindow field is set, then all input to this widget is inter-
140 cepted and sent to the wxWindows class. If not, all input to the widget
141 that gets pointed to by m_widget gets intercepted and sent to the class.
142
143 II)
144
145 The design of scrolling in wxWindows is markedly different from that offered
146 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
147 clicking on a scrollbar belonging to scrolled window will inevitably move
148 the window. In wxWindows, the scrollbar will only emit an event, send this
149 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
150 which actually moves the window and its subchildren. Note that GtkPizza
151 memorizes how much it has been scrolled but that wxWindows forgets this
152 so that the two coordinates systems have to be kept in synch. This is done
153 in various places using the pizza->xoffset and pizza->yoffset values.
154
155 III)
156
157 Singularily the most broken code in GTK is the code that is supposes to
158 inform subwindows (child windows) about new positions. Very often, duplicate
159 events are sent without changes in size or position, equally often no
160 events are sent at all (All this is due to a bug in the GtkContainer code
161 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
162 GTK's own system and it simply waits for size events for toplevel windows
163 and then iterates down the respective size events to all window. This has
164 the disadvantage, that windows might get size events before the GTK widget
165 actually has the reported size. This doesn't normally pose any problem, but
166 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
167 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
168 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
169 window that is used for OpenGl output really has that size (as reported by
170 GTK).
171
172 IV)
173
174 If someone at some point of time feels the immense desire to have a look at,
175 change or attempt to optimse the Refresh() logic, this person will need an
176 intimate understanding of what a "draw" and what an "expose" events are and
177 what there are used for, in particular when used in connection with GTK's
178 own windowless widgets. Beware.
179
180 V)
181
182 Cursors, too, have been a constant source of pleasure. The main difficulty
183 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
184 for the parent. To prevent this from doing too much harm, I use idle time
185 to set the cursor over and over again, starting from the toplevel windows
186 and ending with the youngest generation (speaking of parent and child windows).
187 Also don't forget that cursors (like much else) are connected to GdkWindows,
188 not GtkWidgets and that the "window" field of a GtkWidget might very well
189 point to the GdkWindow of the parent widget (-> "window less widget") and
190 that the two obviously have very different meanings.
191
192 */
193
194 //-----------------------------------------------------------------------------
195 // data
196 //-----------------------------------------------------------------------------
197
198 extern wxList wxPendingDelete;
199 extern bool g_blockEventsOnDrag;
200 extern bool g_blockEventsOnScroll;
201 extern wxCursor g_globalCursor;
202 static wxWindow *g_captureWindow = (wxWindow*) NULL;
203
204 /* extern */ wxWindow *g_focusWindow = (wxWindow*) NULL;
205
206 // if we detect that the app has got/lost the focus, we set this variable to
207 // either TRUE or FALSE and an activate event will be sent during the next
208 // OnIdle() call and it is reset to -1: this value means that we shouldn't
209 // send any activate events at all
210 static int g_sendActivateEvent = -1;
211
212 /* hack: we need something to pass to gtk_menu_popup, so we store the time of
213 the last click here */
214 static guint32 gs_timeLastClick = 0;
215
216 extern bool g_mainThreadLocked;
217
218 //-----------------------------------------------------------------------------
219 // debug
220 //-----------------------------------------------------------------------------
221
222 #define DISABLE_STYLE_IF_BROKEN_THEME 1
223
224 #ifdef __WXDEBUG__
225
226 #if wxUSE_THREADS
227 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
228 #else
229 # define DEBUG_MAIN_THREAD
230 #endif
231
232 static gint gtk_debug_focus_in_callback( GtkWidget *WXUNUSED(widget),
233 GdkEvent *WXUNUSED(event),
234 const wxChar *WXUNUSED(name) )
235 {
236 /*
237 static bool s_done = FALSE;
238 if ( !s_done )
239 {
240 wxLog::AddTraceMask("focus");
241 s_done = TRUE;
242 }
243 wxLogTrace(wxT("FOCUS NOW AT: %s"), name);
244 */
245
246 return FALSE;
247 }
248
249 void debug_focus_in( GtkWidget* widget, const wxChar* name, const wxChar *window )
250 {
251 // suppress warnings about gtk_debug_focus_in_callback being unused with
252 // this "if ( 0 )"
253 if ( 0 )
254 {
255 wxString tmp = name;
256 tmp += wxT(" FROM ");
257 tmp += window;
258
259 wxChar *s = new wxChar[tmp.Length()+1];
260
261 wxStrcpy( s, tmp );
262
263 gtk_signal_connect( GTK_OBJECT(widget), "focus_in_event",
264 GTK_SIGNAL_FUNC(gtk_debug_focus_in_callback), (gpointer)s );
265 }
266 }
267
268 #else
269 #define DEBUG_MAIN_THREAD
270 #endif // Debug
271
272 //-----------------------------------------------------------------------------
273 // missing gdk functions
274 //-----------------------------------------------------------------------------
275
276 void
277 gdk_window_warp_pointer (GdkWindow *window,
278 gint x,
279 gint y)
280 {
281 #ifndef __WXGTK20__
282 GdkWindowPrivate *priv;
283 #endif
284
285 if (!window)
286 window = GDK_ROOT_PARENT();
287
288 #ifdef __WXGTK20__
289 if (!GDK_WINDOW_DESTROYED(window))
290 {
291 XWarpPointer (GDK_WINDOW_XDISPLAY(window),
292 None, /* not source window -> move from anywhere */
293 GDK_WINDOW_XID(window), /* dest window */
294 0, 0, 0, 0, /* not source window -> move from anywhere */
295 x, y );
296 }
297 #else
298 priv = (GdkWindowPrivate*) window;
299
300 if (!priv->destroyed)
301 {
302 XWarpPointer (priv->xdisplay,
303 None, /* not source window -> move from anywhere */
304 priv->xwindow, /* dest window */
305 0, 0, 0, 0, /* not source window -> move from anywhere */
306 x, y );
307 }
308 #endif
309 }
310
311 //-----------------------------------------------------------------------------
312 // idle system
313 //-----------------------------------------------------------------------------
314
315 extern void wxapp_install_idle_handler();
316 extern bool g_isIdle;
317
318 //-----------------------------------------------------------------------------
319 // local code (see below)
320 //-----------------------------------------------------------------------------
321
322 // returns the child of win which currently has focus or NULL if not found
323 static wxWindow *FindFocusedChild(wxWindow *win)
324 {
325 wxWindow *winFocus = wxWindow::FindFocus();
326 if ( !winFocus )
327 return (wxWindow *)NULL;
328
329 if ( winFocus == win )
330 return win;
331
332 for ( wxWindowList::Node *node = win->GetChildren().GetFirst();
333 node;
334 node = node->GetNext() )
335 {
336 wxWindow *child = FindFocusedChild(node->GetData());
337 if ( child )
338 return child;
339 }
340
341 return (wxWindow *)NULL;
342 }
343
344 static void draw_frame( GtkWidget *widget, wxWindow *win )
345 {
346 if (!win->m_hasVMT)
347 return;
348
349 int dw = 0;
350 int dh = 0;
351
352 if (win->m_hasScrolling)
353 {
354 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(widget);
355
356 GtkRequisition vscroll_req;
357 vscroll_req.width = 2;
358 vscroll_req.height = 2;
359 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
360 (scroll_window->vscrollbar, &vscroll_req );
361
362 GtkRequisition hscroll_req;
363 hscroll_req.width = 2;
364 hscroll_req.height = 2;
365 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
366 (scroll_window->hscrollbar, &hscroll_req );
367
368 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget) );
369
370 if (scroll_window->vscrollbar_visible)
371 {
372 dw += vscroll_req.width;
373 dw += scroll_class->scrollbar_spacing;
374 }
375
376 if (scroll_window->hscrollbar_visible)
377 {
378 dh += hscroll_req.height;
379 dh += scroll_class->scrollbar_spacing;
380 }
381 }
382
383 int dx = 0;
384 int dy = 0;
385 if (GTK_WIDGET_NO_WINDOW (widget))
386 {
387 dx += widget->allocation.x;
388 dy += widget->allocation.y;
389 }
390
391 if (win->HasFlag(wxRAISED_BORDER))
392 {
393 gtk_draw_shadow( widget->style,
394 widget->window,
395 GTK_STATE_NORMAL,
396 GTK_SHADOW_OUT,
397 dx, dy,
398 widget->allocation.width-dw, widget->allocation.height-dh );
399 return;
400 }
401
402 if (win->HasFlag(wxSUNKEN_BORDER))
403 {
404 gtk_draw_shadow( widget->style,
405 widget->window,
406 GTK_STATE_NORMAL,
407 GTK_SHADOW_IN,
408 dx, dy,
409 widget->allocation.width-dw, widget->allocation.height-dh );
410 return;
411 }
412
413 if (win->HasFlag(wxSIMPLE_BORDER))
414 {
415 GdkGC *gc;
416 gc = gdk_gc_new( widget->window );
417 gdk_gc_set_foreground( gc, &widget->style->black );
418 gdk_draw_rectangle( widget->window, gc, FALSE,
419 dx, dy,
420 widget->allocation.width-dw-1, widget->allocation.height-dh-1 );
421 gdk_gc_unref( gc );
422 return;
423 }
424 }
425
426 //-----------------------------------------------------------------------------
427 // "expose_event" of m_widget
428 //-----------------------------------------------------------------------------
429
430 gint gtk_window_own_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindow *win )
431 {
432 if (gdk_event->count > 0) return FALSE;
433
434 draw_frame( widget, win );
435
436 return TRUE;
437 }
438
439 //-----------------------------------------------------------------------------
440 // "draw" of m_widget
441 //-----------------------------------------------------------------------------
442
443 static void gtk_window_own_draw_callback( GtkWidget *widget, GdkRectangle *WXUNUSED(rect), wxWindow *win )
444 {
445 draw_frame( widget, win );
446 }
447
448 //-----------------------------------------------------------------------------
449 // key code mapping routines
450 //-----------------------------------------------------------------------------
451
452 static long map_to_unmodified_wx_keysym( KeySym keysym )
453 {
454 guint key_code = 0;
455
456 switch (keysym)
457 {
458 case GDK_Shift_L:
459 case GDK_Shift_R: key_code = WXK_SHIFT; break;
460 case GDK_Control_L:
461 case GDK_Control_R: key_code = WXK_CONTROL; break;
462 case GDK_Meta_L:
463 case GDK_Meta_R:
464 case GDK_Alt_L:
465 case GDK_Alt_R:
466 case GDK_Super_L:
467 case GDK_Super_R: key_code = WXK_ALT; break;
468 case GDK_Menu: key_code = WXK_MENU; break;
469 case GDK_Help: key_code = WXK_HELP; break;
470 case GDK_BackSpace: key_code = WXK_BACK; break;
471 case GDK_ISO_Left_Tab:
472 case GDK_Tab: key_code = WXK_TAB; break;
473 case GDK_Linefeed: key_code = WXK_RETURN; break;
474 case GDK_Clear: key_code = WXK_CLEAR; break;
475 case GDK_Return: key_code = WXK_RETURN; break;
476 case GDK_Pause: key_code = WXK_PAUSE; break;
477 case GDK_Scroll_Lock: key_code = WXK_SCROLL; break;
478 case GDK_Escape: key_code = WXK_ESCAPE; break;
479 case GDK_Delete: key_code = WXK_DELETE; break;
480 case GDK_Home: key_code = WXK_HOME; break;
481 case GDK_Left: key_code = WXK_LEFT; break;
482 case GDK_Up: key_code = WXK_UP; break;
483 case GDK_Right: key_code = WXK_RIGHT; break;
484 case GDK_Down: key_code = WXK_DOWN; break;
485 case GDK_Prior: key_code = WXK_PRIOR; break;
486 // case GDK_Page_Up: key_code = WXK_PAGEUP; break;
487 case GDK_Next: key_code = WXK_NEXT; break;
488 // case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
489 case GDK_End: key_code = WXK_END; break;
490 case GDK_Begin: key_code = WXK_HOME; break;
491 case GDK_Select: key_code = WXK_SELECT; break;
492 case GDK_Print: key_code = WXK_PRINT; break;
493 case GDK_Execute: key_code = WXK_EXECUTE; break;
494 case GDK_Insert: key_code = WXK_INSERT; break;
495 case GDK_Num_Lock: key_code = WXK_NUMLOCK; break;
496
497 case GDK_KP_0: key_code = WXK_NUMPAD0; break;
498 case GDK_KP_1: key_code = WXK_NUMPAD1; break;
499 case GDK_KP_2: key_code = WXK_NUMPAD2; break;
500 case GDK_KP_3: key_code = WXK_NUMPAD3; break;
501 case GDK_KP_4: key_code = WXK_NUMPAD4; break;
502 case GDK_KP_5: key_code = WXK_NUMPAD5; break;
503 case GDK_KP_6: key_code = WXK_NUMPAD6; break;
504 case GDK_KP_7: key_code = WXK_NUMPAD7; break;
505 case GDK_KP_8: key_code = WXK_NUMPAD8; break;
506 case GDK_KP_9: key_code = WXK_NUMPAD9; break;
507 case GDK_KP_Space: key_code = WXK_NUMPAD_SPACE; break;
508 case GDK_KP_Tab: key_code = WXK_NUMPAD_TAB; break;
509 case GDK_KP_Enter: key_code = WXK_NUMPAD_ENTER; break;
510 case GDK_KP_F1: key_code = WXK_NUMPAD_F1; break;
511 case GDK_KP_F2: key_code = WXK_NUMPAD_F2; break;
512 case GDK_KP_F3: key_code = WXK_NUMPAD_F3; break;
513 case GDK_KP_F4: key_code = WXK_NUMPAD_F4; break;
514 case GDK_KP_Home: key_code = WXK_NUMPAD_HOME; break;
515 case GDK_KP_Left: key_code = WXK_NUMPAD_LEFT; break;
516 case GDK_KP_Up: key_code = WXK_NUMPAD_UP; break;
517 case GDK_KP_Right: key_code = WXK_NUMPAD_RIGHT; break;
518 case GDK_KP_Down: key_code = WXK_NUMPAD_DOWN; break;
519 case GDK_KP_Prior: key_code = WXK_NUMPAD_PRIOR; break;
520 // case GDK_KP_Page_Up: key_code = WXK_NUMPAD_PAGEUP; break;
521 case GDK_KP_Next: key_code = WXK_NUMPAD_NEXT; break;
522 // case GDK_KP_Page_Down: key_code = WXK_NUMPAD_PAGEDOWN; break;
523 case GDK_KP_End: key_code = WXK_NUMPAD_END; break;
524 case GDK_KP_Begin: key_code = WXK_NUMPAD_BEGIN; break;
525 case GDK_KP_Insert: key_code = WXK_NUMPAD_INSERT; break;
526 case GDK_KP_Delete: key_code = WXK_NUMPAD_DELETE; break;
527 case GDK_KP_Equal: key_code = WXK_NUMPAD_EQUAL; break;
528 case GDK_KP_Multiply: key_code = WXK_NUMPAD_MULTIPLY; break;
529 case GDK_KP_Add: key_code = WXK_NUMPAD_ADD; break;
530 case GDK_KP_Separator: key_code = WXK_NUMPAD_SEPARATOR; break;
531 case GDK_KP_Subtract: key_code = WXK_NUMPAD_SUBTRACT; break;
532 case GDK_KP_Decimal: key_code = WXK_NUMPAD_DECIMAL; break;
533 case GDK_KP_Divide: key_code = WXK_NUMPAD_DIVIDE; break;
534
535 case GDK_F1: key_code = WXK_F1; break;
536 case GDK_F2: key_code = WXK_F2; break;
537 case GDK_F3: key_code = WXK_F3; break;
538 case GDK_F4: key_code = WXK_F4; break;
539 case GDK_F5: key_code = WXK_F5; break;
540 case GDK_F6: key_code = WXK_F6; break;
541 case GDK_F7: key_code = WXK_F7; break;
542 case GDK_F8: key_code = WXK_F8; break;
543 case GDK_F9: key_code = WXK_F9; break;
544 case GDK_F10: key_code = WXK_F10; break;
545 case GDK_F11: key_code = WXK_F11; break;
546 case GDK_F12: key_code = WXK_F12; break;
547 default:
548 {
549 if ((keysym & 0xF000) == 0)
550 {
551 guint upper = gdk_keyval_to_upper( (guint)keysym );
552 keysym = (upper != 0 ? upper : keysym ); /* to be MSW compatible */
553 key_code = (guint)keysym;
554 }
555 }
556 }
557
558 return (key_code);
559 }
560
561 static long map_to_wx_keysym( KeySym keysym )
562 {
563 guint key_code = 0;
564
565 switch (keysym)
566 {
567 case GDK_Menu: key_code = WXK_MENU; break;
568 case GDK_Help: key_code = WXK_HELP; break;
569 case GDK_BackSpace: key_code = WXK_BACK; break;
570 case GDK_ISO_Left_Tab:
571 case GDK_Tab: key_code = WXK_TAB; break;
572 case GDK_Linefeed: key_code = WXK_RETURN; break;
573 case GDK_Clear: key_code = WXK_CLEAR; break;
574 case GDK_Return: key_code = WXK_RETURN; break;
575 case GDK_Pause: key_code = WXK_PAUSE; break;
576 case GDK_Scroll_Lock: key_code = WXK_SCROLL; break;
577 case GDK_Escape: key_code = WXK_ESCAPE; break;
578 case GDK_Delete: key_code = WXK_DELETE; break;
579 case GDK_Home: key_code = WXK_HOME; break;
580 case GDK_Left: key_code = WXK_LEFT; break;
581 case GDK_Up: key_code = WXK_UP; break;
582 case GDK_Right: key_code = WXK_RIGHT; break;
583 case GDK_Down: key_code = WXK_DOWN; break;
584 case GDK_Prior: key_code = WXK_PRIOR; break;
585 // case GDK_Page_Up: key_code = WXK_PAGEUP; break;
586 case GDK_Next: key_code = WXK_NEXT; break;
587 // case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
588 case GDK_End: key_code = WXK_END; break;
589 case GDK_Begin: key_code = WXK_HOME; break;
590 case GDK_Select: key_code = WXK_SELECT; break;
591 case GDK_Print: key_code = WXK_PRINT; break;
592 case GDK_Execute: key_code = WXK_EXECUTE; break;
593 case GDK_Insert: key_code = WXK_INSERT; break;
594 case GDK_Num_Lock: key_code = WXK_NUMLOCK; break;
595
596 case GDK_KP_0: key_code = '0'; break;
597 case GDK_KP_1: key_code = '1'; break;
598 case GDK_KP_2: key_code = '2'; break;
599 case GDK_KP_3: key_code = '3'; break;
600 case GDK_KP_4: key_code = '4'; break;
601 case GDK_KP_5: key_code = '5'; break;
602 case GDK_KP_6: key_code = '6'; break;
603 case GDK_KP_7: key_code = '7'; break;
604 case GDK_KP_8: key_code = '8'; break;
605 case GDK_KP_9: key_code = '9'; break;
606 case GDK_KP_Space: key_code = ' '; break;
607 case GDK_KP_Tab: key_code = WXK_TAB; break; /* or '\t' ??? */
608 case GDK_KP_Enter: key_code = WXK_RETURN; break; /* or '\r' ??? */
609 case GDK_KP_F1: key_code = WXK_NUMPAD_F1; break;
610 case GDK_KP_F2: key_code = WXK_NUMPAD_F2; break;
611 case GDK_KP_F3: key_code = WXK_NUMPAD_F3; break;
612 case GDK_KP_F4: key_code = WXK_NUMPAD_F4; break;
613 case GDK_KP_Home: key_code = WXK_HOME; break;
614 case GDK_KP_Left: key_code = WXK_LEFT; break;
615 case GDK_KP_Up: key_code = WXK_UP; break;
616 case GDK_KP_Right: key_code = WXK_RIGHT; break;
617 case GDK_KP_Down: key_code = WXK_DOWN; break;
618 case GDK_KP_Prior: key_code = WXK_PRIOR; break;
619 // case GDK_KP_Page_Up: key_code = WXK_PAGEUP; break;
620 case GDK_KP_Next: key_code = WXK_NEXT; break;
621 // case GDK_KP_Page_Down: key_code = WXK_PAGEDOWN; break;
622 case GDK_KP_End: key_code = WXK_END; break;
623 case GDK_KP_Begin: key_code = WXK_HOME; break;
624 case GDK_KP_Insert: key_code = WXK_INSERT; break;
625 case GDK_KP_Delete: key_code = WXK_DELETE; break;
626 case GDK_KP_Equal: key_code = '='; break;
627 case GDK_KP_Multiply: key_code = '*'; break;
628 case GDK_KP_Add: key_code = '+'; break;
629 case GDK_KP_Separator: key_code = ','; break;
630 case GDK_KP_Subtract: key_code = '-'; break;
631 case GDK_KP_Decimal: key_code = '.'; break;
632 case GDK_KP_Divide: key_code = '/'; break;
633
634 case GDK_F1: key_code = WXK_F1; break;
635 case GDK_F2: key_code = WXK_F2; break;
636 case GDK_F3: key_code = WXK_F3; break;
637 case GDK_F4: key_code = WXK_F4; break;
638 case GDK_F5: key_code = WXK_F5; break;
639 case GDK_F6: key_code = WXK_F6; break;
640 case GDK_F7: key_code = WXK_F7; break;
641 case GDK_F8: key_code = WXK_F8; break;
642 case GDK_F9: key_code = WXK_F9; break;
643 case GDK_F10: key_code = WXK_F10; break;
644 case GDK_F11: key_code = WXK_F11; break;
645 case GDK_F12: key_code = WXK_F12; break;
646 default:
647 {
648 if ((keysym & 0xF000) == 0)
649 {
650 key_code = (guint)keysym;
651 }
652 }
653 }
654
655 return (key_code);
656 }
657
658 //-----------------------------------------------------------------------------
659 // "expose_event" of m_wxwindow
660 //-----------------------------------------------------------------------------
661
662 static int gtk_window_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindow *win )
663 {
664 DEBUG_MAIN_THREAD
665
666 if (g_isIdle)
667 wxapp_install_idle_handler();
668
669 /*
670 if (win->GetName() == wxT("panel"))
671 {
672 wxPrintf( wxT("OnExpose from ") );
673 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
674 wxPrintf( win->GetClassInfo()->GetClassName() );
675 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event->area.x,
676 (int)gdk_event->area.y,
677 (int)gdk_event->area.width,
678 (int)gdk_event->area.height );
679 }
680 */
681
682 GtkPizza *pizza = GTK_PIZZA (widget);
683
684 if (win->GetThemeEnabled())
685 {
686 wxWindow *parent = win->GetParent();
687 while (parent && !parent->IsTopLevel())
688 parent = parent->GetParent();
689 if (!parent)
690 parent = win;
691
692 gtk_paint_flat_box (parent->m_widget->style, pizza->bin_window, GTK_STATE_NORMAL,
693 GTK_SHADOW_NONE, &gdk_event->area, parent->m_widget, "base", 0, 0, -1, -1);
694 }
695
696 win->GetUpdateRegion().Union( gdk_event->area.x,
697 gdk_event->area.y,
698 gdk_event->area.width,
699 gdk_event->area.height );
700
701 if (gdk_event->count == 0)
702 {
703 wxEraseEvent eevent( win->GetId() );
704 eevent.SetEventObject( win );
705 win->GetEventHandler()->ProcessEvent(eevent);
706
707 wxPaintEvent event( win->GetId() );
708 event.SetEventObject( win );
709 win->GetEventHandler()->ProcessEvent( event );
710
711 win->GetUpdateRegion().Clear();
712 }
713
714 /* The following code will result in all window-less widgets
715 being redrawn if the wxWindows class is given a chance to
716 paint *anything* because it will then be allowed to paint
717 over the window-less widgets */
718
719 GList *children = pizza->children;
720 while (children)
721 {
722 GtkPizzaChild *child = (GtkPizzaChild*) children->data;
723 children = children->next;
724
725 GdkEventExpose child_event = *gdk_event;
726
727 if (GTK_WIDGET_NO_WINDOW (child->widget) &&
728 GTK_WIDGET_DRAWABLE (child->widget) /* &&
729 gtk_widget_intersect (child->widget, &gdk_event->area, &child_event.area)*/ )
730 {
731 child_event.area.x = child->widget->allocation.x;
732 child_event.area.y = child->widget->allocation.y;
733 child_event.area.width = child->widget->allocation.width;
734 child_event.area.height = child->widget->allocation.height;
735 gtk_widget_event (child->widget, (GdkEvent*) &child_event);
736 }
737 }
738
739 return TRUE;
740 }
741
742 //-----------------------------------------------------------------------------
743 // "event" of m_wxwindow
744 //-----------------------------------------------------------------------------
745
746 /* GTK thinks it is clever and filters out a certain amount of "unneeded"
747 expose events. We need them, of course, so we override the main event
748 procedure in GtkWidget by giving our own handler for all system events.
749 There, we look for expose events ourselves whereas all other events are
750 handled normally. */
751
752 gint gtk_window_event_event_callback( GtkWidget *widget, GdkEventExpose *event, wxWindow *win )
753 {
754 if (event->type == GDK_EXPOSE)
755 {
756 gint ret = gtk_window_expose_callback( widget, event, win );
757 return ret;
758 }
759
760 return FALSE;
761 }
762
763 //-----------------------------------------------------------------------------
764 // "draw" of m_wxwindow
765 //-----------------------------------------------------------------------------
766
767 /* This callback is a complete replacement of the gtk_pizza_draw() function,
768 which disabled. */
769
770 static void gtk_window_draw_callback( GtkWidget *widget, GdkRectangle *rect, wxWindow *win )
771 {
772 DEBUG_MAIN_THREAD
773
774 if (g_isIdle)
775 wxapp_install_idle_handler();
776
777 /*
778 if (win->GetName() == wxT("panel"))
779 {
780 wxPrintf( wxT("OnDraw from ") );
781 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
782 wxPrintf( win->GetClassInfo()->GetClassName() );
783 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect->x,
784 (int)rect->y,
785 (int)rect->width,
786 (int)rect->height );
787 }
788 */
789
790 GtkPizza *pizza = GTK_PIZZA (widget);
791
792 if (win->GetThemeEnabled())
793 {
794 wxWindow *parent = win->GetParent();
795 while (parent && !parent->IsTopLevel())
796 parent = parent->GetParent();
797 if (!parent)
798 parent = win;
799
800 gtk_paint_flat_box (parent->m_widget->style, pizza->bin_window, GTK_STATE_NORMAL,
801 GTK_SHADOW_NONE, rect, parent->m_widget, "base", 0, 0, -1, -1);
802 }
803
804
805 if (!(GTK_WIDGET_APP_PAINTABLE (widget)) &&
806 (pizza->clear_on_draw))
807 {
808 gdk_window_clear_area( pizza->bin_window,
809 rect->x, rect->y, rect->width, rect->height);
810 }
811
812 win->GetUpdateRegion().Union( rect->x, rect->y, rect->width, rect->height );
813
814 win->m_clipPaintRegion = TRUE;
815
816 wxEraseEvent eevent( win->GetId() );
817 eevent.SetEventObject( win );
818 win->GetEventHandler()->ProcessEvent(eevent);
819
820 wxPaintEvent event( win->GetId() );
821 event.SetEventObject( win );
822 win->GetEventHandler()->ProcessEvent( event );
823
824 win->GetUpdateRegion().Clear();
825
826 win->m_clipPaintRegion = FALSE;
827
828
829 GList *children = pizza->children;
830 while (children)
831 {
832 GtkPizzaChild *child = (GtkPizzaChild*) children->data;
833 children = children->next;
834
835 GdkRectangle child_area;
836 if (gtk_widget_intersect (child->widget, rect, &child_area))
837 {
838 gtk_widget_draw (child->widget, &child_area /* (GdkRectangle*) NULL*/ );
839 }
840 }
841 }
842
843 //-----------------------------------------------------------------------------
844 // "key_press_event" from any window
845 //-----------------------------------------------------------------------------
846
847 static gint gtk_window_key_press_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindow *win )
848 {
849 DEBUG_MAIN_THREAD
850
851 if (g_isIdle)
852 wxapp_install_idle_handler();
853
854 if (!win->m_hasVMT) return FALSE;
855 if (g_blockEventsOnDrag) return FALSE;
856
857
858 /*
859 wxString tmp;
860 tmp += (char)gdk_event->keyval;
861 printf( "KeyDown-Code is: %s.\n", tmp.c_str() );
862 printf( "KeyDown-ScanCode is: %d.\n", gdk_event->keyval );
863 */
864
865 int x = 0;
866 int y = 0;
867 GdkModifierType state;
868 if (gdk_event->window) gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
869
870 bool ret = FALSE;
871
872 long key_code = map_to_unmodified_wx_keysym( gdk_event->keyval );
873 /* sending unknown key events doesn't really make sense */
874 if (key_code == 0) return FALSE;
875
876 wxKeyEvent event( wxEVT_KEY_DOWN );
877 event.SetTimestamp( gdk_event->time );
878 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
879 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
880 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
881 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
882 event.m_keyCode = key_code;
883 event.m_scanCode = gdk_event->keyval;
884 event.m_x = x;
885 event.m_y = y;
886 event.SetEventObject( win );
887 ret = win->GetEventHandler()->ProcessEvent( event );
888
889 #if wxUSE_ACCEL
890 if (!ret)
891 {
892 wxWindow *ancestor = win;
893 while (ancestor)
894 {
895 int command = ancestor->GetAcceleratorTable()->GetCommand( event );
896 if (command != -1)
897 {
898 wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
899 ret = ancestor->GetEventHandler()->ProcessEvent( command_event );
900 break;
901 }
902 if (ancestor->IsTopLevel())
903 break;
904 ancestor = ancestor->GetParent();
905 }
906 }
907 #endif // wxUSE_ACCEL
908
909 /* wxMSW doesn't send char events with Alt pressed */
910 /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
911 will only be sent if it is not in an accelerator table. */
912 key_code = map_to_wx_keysym( gdk_event->keyval );
913
914 if ( (!ret) &&
915 (key_code != 0))
916 {
917 wxKeyEvent event2( wxEVT_CHAR );
918 event2.SetTimestamp( gdk_event->time );
919 event2.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
920 event2.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
921 event2.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
922 event2.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
923 event2.m_keyCode = key_code;
924 event2.m_scanCode = gdk_event->keyval;
925 event2.m_x = x;
926 event2.m_y = y;
927 event2.SetEventObject( win );
928 ret = win->GetEventHandler()->ProcessEvent( event2 );
929 }
930
931 /* win is a control: tab can be propagated up */
932 if ( (!ret) &&
933 ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) &&
934 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
935 // have this style, yet choose not to process this particular TAB in which
936 // case TAB must still work as a navigational character
937 #if 0
938 (!win->HasFlag(wxTE_PROCESS_TAB)) &&
939 #endif // 0
940 (win->GetParent()) &&
941 (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) )
942 {
943 wxNavigationKeyEvent new_event;
944 new_event.SetEventObject( win->GetParent() );
945 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
946 new_event.SetDirection( (gdk_event->keyval == GDK_Tab) );
947 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
948 new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) );
949 new_event.SetCurrentFocus( win );
950 ret = win->GetParent()->GetEventHandler()->ProcessEvent( new_event );
951 }
952
953 /* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
954 if ( (!ret) &&
955 (gdk_event->keyval == GDK_Escape) )
956 {
957 wxCommandEvent new_event(wxEVT_COMMAND_BUTTON_CLICKED,wxID_CANCEL);
958 new_event.SetEventObject( win );
959 ret = win->GetEventHandler()->ProcessEvent( new_event );
960 }
961
962 #if (GTK_MINOR_VERSION > 0)
963 /* Pressing F10 will activate the menu bar of the top frame. */
964 /* Doesn't work. */
965 /*
966 if ( (!ret) &&
967 (gdk_event->keyval == GDK_F10) )
968 {
969 wxWindow *ancestor = win;
970 while (ancestor)
971 {
972 if (wxIsKindOf(ancestor,wxFrame))
973 {
974 wxFrame *frame = (wxFrame*) ancestor;
975 wxMenuBar *menubar = frame->GetMenuBar();
976 if (menubar)
977 {
978 wxNode *node = menubar->GetMenus().First();
979 if (node)
980 {
981 wxMenu *firstMenu = (wxMenu*) node->Data();
982 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu->m_owner) );
983 ret = TRUE;
984 break;
985 }
986 }
987 }
988 ancestor = ancestor->GetParent();
989 }
990 }
991 */
992 #endif
993
994 if (ret)
995 {
996 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
997 return TRUE;
998 }
999
1000 return FALSE;
1001 }
1002
1003 //-----------------------------------------------------------------------------
1004 // "key_release_event" from any window
1005 //-----------------------------------------------------------------------------
1006
1007 static gint gtk_window_key_release_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindow *win )
1008 {
1009 DEBUG_MAIN_THREAD
1010
1011 if (g_isIdle)
1012 wxapp_install_idle_handler();
1013
1014 if (!win->m_hasVMT) return FALSE;
1015 if (g_blockEventsOnDrag) return FALSE;
1016
1017 /*
1018 printf( "KeyUp-ScanCode is: %d.\n", gdk_event->keyval );
1019 if (gdk_event->state & GDK_SHIFT_MASK)
1020 printf( "ShiftDown.\n" );
1021 else
1022 printf( "ShiftUp.\n" );
1023 if (gdk_event->state & GDK_CONTROL_MASK)
1024 printf( "ControlDown.\n" );
1025 else
1026 printf( "ControlUp.\n" );
1027 printf( "\n" );
1028 */
1029
1030 long key_code = map_to_unmodified_wx_keysym( gdk_event->keyval );
1031
1032 /* sending unknown key events doesn't really make sense */
1033 if (key_code == 0) return FALSE;
1034
1035 int x = 0;
1036 int y = 0;
1037 GdkModifierType state;
1038 if (gdk_event->window) gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
1039
1040 wxKeyEvent event( wxEVT_KEY_UP );
1041 event.SetTimestamp( gdk_event->time );
1042 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1043 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1044 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1045 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1046 event.m_keyCode = key_code;
1047 event.m_scanCode = gdk_event->keyval;
1048 event.m_x = x;
1049 event.m_y = y;
1050 event.SetEventObject( win );
1051
1052 if (win->GetEventHandler()->ProcessEvent( event ))
1053 {
1054 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_release_event" );
1055 return TRUE;
1056 }
1057
1058 return FALSE;
1059 }
1060
1061 // ----------------------------------------------------------------------------
1062 // mouse event processing helper
1063 // ----------------------------------------------------------------------------
1064
1065 static void AdjustEventButtonState(wxMouseEvent& event)
1066 {
1067 // GDK reports the old state of the button for a button press event, but
1068 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1069 // for a LEFT_DOWN event, not FALSE, so we will invert
1070 // left/right/middleDown for the corresponding click events
1071 switch ( event.GetEventType() )
1072 {
1073 case wxEVT_LEFT_DOWN:
1074 case wxEVT_LEFT_DCLICK:
1075 case wxEVT_LEFT_UP:
1076 event.m_leftDown = !event.m_leftDown;
1077 break;
1078
1079 case wxEVT_MIDDLE_DOWN:
1080 case wxEVT_MIDDLE_DCLICK:
1081 case wxEVT_MIDDLE_UP:
1082 event.m_middleDown = !event.m_middleDown;
1083 break;
1084
1085 case wxEVT_RIGHT_DOWN:
1086 case wxEVT_RIGHT_DCLICK:
1087 case wxEVT_RIGHT_UP:
1088 event.m_rightDown = !event.m_rightDown;
1089 break;
1090 }
1091 }
1092
1093 //-----------------------------------------------------------------------------
1094 // "button_press_event"
1095 //-----------------------------------------------------------------------------
1096
1097 static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindow *win )
1098 {
1099 DEBUG_MAIN_THREAD
1100
1101 if (g_isIdle)
1102 wxapp_install_idle_handler();
1103
1104 /*
1105 wxPrintf( wxT("1) OnButtonPress from ") );
1106 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1107 wxPrintf( win->GetClassInfo()->GetClassName() );
1108 wxPrintf( wxT(".\n") );
1109 */
1110 if (!win->m_hasVMT) return FALSE;
1111 if (g_blockEventsOnDrag) return TRUE;
1112 if (g_blockEventsOnScroll) return TRUE;
1113
1114 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1115
1116 if (win->m_wxwindow)
1117 {
1118 if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow) && !GTK_WIDGET_HAS_FOCUS (win->m_wxwindow) )
1119 {
1120 gtk_widget_grab_focus (win->m_wxwindow);
1121
1122 /*
1123 wxPrintf( wxT("GrabFocus from ") );
1124 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1125 wxPrintf( win->GetClassInfo()->GetClassName() );
1126 wxPrintf( wxT(".\n") );
1127 */
1128
1129 }
1130 }
1131
1132 wxEventType event_type = wxEVT_NULL;
1133
1134 if (gdk_event->button == 1)
1135 {
1136 switch (gdk_event->type)
1137 {
1138 case GDK_BUTTON_PRESS: event_type = wxEVT_LEFT_DOWN; break;
1139 case GDK_2BUTTON_PRESS: event_type = wxEVT_LEFT_DCLICK; break;
1140 default: break;
1141 }
1142 }
1143 else if (gdk_event->button == 2)
1144 {
1145 switch (gdk_event->type)
1146 {
1147 case GDK_BUTTON_PRESS: event_type = wxEVT_MIDDLE_DOWN; break;
1148 case GDK_2BUTTON_PRESS: event_type = wxEVT_MIDDLE_DCLICK; break;
1149 default: break;
1150 }
1151 }
1152 else if (gdk_event->button == 3)
1153 {
1154 switch (gdk_event->type)
1155 {
1156 case GDK_BUTTON_PRESS: event_type = wxEVT_RIGHT_DOWN; break;
1157 case GDK_2BUTTON_PRESS: event_type = wxEVT_RIGHT_DCLICK; break;
1158 default: break;
1159 }
1160 }
1161
1162 if ( event_type == wxEVT_NULL )
1163 {
1164 // unknown mouse button or click type
1165 return FALSE;
1166 }
1167
1168 wxMouseEvent event( event_type );
1169 event.SetTimestamp( gdk_event->time );
1170 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1171 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1172 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1173 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1174 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1175 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1176 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1177
1178 event.m_x = (wxCoord)gdk_event->x;
1179 event.m_y = (wxCoord)gdk_event->y;
1180
1181 AdjustEventButtonState(event);
1182
1183 // Some control don't have their own X window and thus cannot get
1184 // any events.
1185
1186 if (!g_captureWindow)
1187 {
1188 wxCoord x = event.m_x;
1189 wxCoord y = event.m_y;
1190 if (win->m_wxwindow)
1191 {
1192 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1193 x += pizza->xoffset;
1194 y += pizza->yoffset;
1195 }
1196
1197 wxNode *node = win->GetChildren().First();
1198 while (node)
1199 {
1200 wxWindow *child = (wxWindow*)node->Data();
1201
1202 node = node->Next();
1203 if (!child->IsShown())
1204 continue;
1205
1206 if (child->m_isStaticBox)
1207 {
1208 // wxStaticBox is transparent in the box itself
1209 int xx1 = child->m_x;
1210 int yy1 = child->m_y;
1211 int xx2 = child->m_x + child->m_width;
1212 int yy2 = child->m_x + child->m_height;
1213
1214 // left
1215 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1216 // right
1217 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1218 // top
1219 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1220 // bottom
1221 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1222 {
1223 win = child;
1224 event.m_x -= child->m_x;
1225 event.m_y -= child->m_y;
1226 break;
1227 }
1228
1229 }
1230 else
1231 {
1232 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1233 (child->m_x <= x) &&
1234 (child->m_y <= y) &&
1235 (child->m_x+child->m_width >= x) &&
1236 (child->m_y+child->m_height >= y))
1237 {
1238 win = child;
1239 event.m_x -= child->m_x;
1240 event.m_y -= child->m_y;
1241 break;
1242 }
1243 }
1244 }
1245 }
1246
1247 event.SetEventObject( win );
1248
1249 gs_timeLastClick = gdk_event->time;
1250
1251 /*
1252 wxPrintf( wxT("2) OnButtonPress from ") );
1253 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1254 wxPrintf( win->GetClassInfo()->GetClassName() );
1255 wxPrintf( wxT(".\n") );
1256 */
1257
1258 if (win->GetEventHandler()->ProcessEvent( event ))
1259 {
1260 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_press_event" );
1261 return TRUE;
1262 }
1263
1264 return FALSE;
1265 }
1266
1267 //-----------------------------------------------------------------------------
1268 // "button_release_event"
1269 //-----------------------------------------------------------------------------
1270
1271 static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindow *win )
1272 {
1273 DEBUG_MAIN_THREAD
1274
1275 if (g_isIdle)
1276 wxapp_install_idle_handler();
1277
1278 if (!win->m_hasVMT) return FALSE;
1279 if (g_blockEventsOnDrag) return FALSE;
1280 if (g_blockEventsOnScroll) return FALSE;
1281
1282 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1283
1284 /*
1285 printf( "OnButtonRelease from " );
1286 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1287 printf( win->GetClassInfo()->GetClassName() );
1288 printf( ".\n" );
1289 */
1290
1291 wxEventType event_type = wxEVT_NULL;
1292
1293 switch (gdk_event->button)
1294 {
1295 case 1: event_type = wxEVT_LEFT_UP; break;
1296 case 2: event_type = wxEVT_MIDDLE_UP; break;
1297 case 3: event_type = wxEVT_RIGHT_UP; break;
1298 default: return FALSE;
1299 }
1300
1301 wxMouseEvent event( event_type );
1302 event.SetTimestamp( gdk_event->time );
1303 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1304 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1305 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1306 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1307 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1308 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1309 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1310 event.m_x = (wxCoord)gdk_event->x;
1311 event.m_y = (wxCoord)gdk_event->y;
1312
1313 AdjustEventButtonState(event);
1314
1315 // Some control don't have their own X window and thus cannot get
1316 // any events.
1317
1318 if (!g_captureWindow)
1319 {
1320 wxCoord x = event.m_x;
1321 wxCoord y = event.m_y;
1322 if (win->m_wxwindow)
1323 {
1324 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1325 x += pizza->xoffset;
1326 y += pizza->yoffset;
1327 }
1328
1329 wxNode *node = win->GetChildren().First();
1330 while (node)
1331 {
1332 wxWindow *child = (wxWindow*)node->Data();
1333
1334 node = node->Next();
1335 if (!child->IsShown())
1336 continue;
1337
1338 if (child->m_isStaticBox)
1339 {
1340 // wxStaticBox is transparent in the box itself
1341 int xx1 = child->m_x;
1342 int yy1 = child->m_y;
1343 int xx2 = child->m_x + child->m_width;
1344 int yy2 = child->m_x + child->m_height;
1345
1346 // left
1347 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1348 // right
1349 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1350 // top
1351 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1352 // bottom
1353 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1354 {
1355 win = child;
1356 event.m_x -= child->m_x;
1357 event.m_y -= child->m_y;
1358 break;
1359 }
1360
1361 }
1362 else
1363 {
1364 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1365 (child->m_x <= x) &&
1366 (child->m_y <= y) &&
1367 (child->m_x+child->m_width >= x) &&
1368 (child->m_y+child->m_height >= y))
1369 {
1370 win = child;
1371 event.m_x -= child->m_x;
1372 event.m_y -= child->m_y;
1373 break;
1374 }
1375 }
1376 }
1377 }
1378
1379 event.SetEventObject( win );
1380
1381 if (win->GetEventHandler()->ProcessEvent( event ))
1382 {
1383 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_release_event" );
1384 return TRUE;
1385 }
1386
1387 return FALSE;
1388 }
1389
1390 //-----------------------------------------------------------------------------
1391 // "motion_notify_event"
1392 //-----------------------------------------------------------------------------
1393
1394 static gint gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion *gdk_event, wxWindow *win )
1395 {
1396 DEBUG_MAIN_THREAD
1397
1398 if (g_isIdle)
1399 wxapp_install_idle_handler();
1400
1401 if (!win->m_hasVMT) return FALSE;
1402 if (g_blockEventsOnDrag) return FALSE;
1403 if (g_blockEventsOnScroll) return FALSE;
1404
1405 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1406
1407 if (gdk_event->is_hint)
1408 {
1409 int x = 0;
1410 int y = 0;
1411 GdkModifierType state;
1412 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
1413 gdk_event->x = x;
1414 gdk_event->y = y;
1415 }
1416
1417 /*
1418 printf( "OnMotion from " );
1419 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1420 printf( win->GetClassInfo()->GetClassName() );
1421 printf( ".\n" );
1422 */
1423
1424 wxMouseEvent event( wxEVT_MOTION );
1425 event.SetTimestamp( gdk_event->time );
1426 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1427 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1428 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1429 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1430 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1431 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1432 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1433
1434 event.m_x = (wxCoord)gdk_event->x;
1435 event.m_y = (wxCoord)gdk_event->y;
1436
1437 // Some control don't have their own X window and thus cannot get
1438 // any events.
1439
1440 if (!g_captureWindow)
1441 {
1442 wxCoord x = event.m_x;
1443 wxCoord y = event.m_y;
1444 if (win->m_wxwindow)
1445 {
1446 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1447 x += pizza->xoffset;
1448 y += pizza->yoffset;
1449 }
1450
1451 wxNode *node = win->GetChildren().First();
1452 while (node)
1453 {
1454 wxWindow *child = (wxWindow*)node->Data();
1455
1456 node = node->Next();
1457 if (!child->IsShown())
1458 continue;
1459
1460 if (child->m_isStaticBox)
1461 {
1462 // wxStaticBox is transparent in the box itself
1463 int xx1 = child->m_x;
1464 int yy1 = child->m_y;
1465 int xx2 = child->m_x + child->m_width;
1466 int yy2 = child->m_x + child->m_height;
1467
1468 // left
1469 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1470 // right
1471 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1472 // top
1473 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1474 // bottom
1475 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1476 {
1477 win = child;
1478 event.m_x -= child->m_x;
1479 event.m_y -= child->m_y;
1480 break;
1481 }
1482
1483 }
1484 else
1485 {
1486 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1487 (child->m_x <= x) &&
1488 (child->m_y <= y) &&
1489 (child->m_x+child->m_width >= x) &&
1490 (child->m_y+child->m_height >= y))
1491 {
1492 win = child;
1493 event.m_x -= child->m_x;
1494 event.m_y -= child->m_y;
1495 break;
1496 }
1497 }
1498 }
1499 }
1500
1501 event.SetEventObject( win );
1502
1503 if (win->GetEventHandler()->ProcessEvent( event ))
1504 {
1505 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "motion_notify_event" );
1506 return TRUE;
1507 }
1508
1509 return FALSE;
1510 }
1511
1512 //-----------------------------------------------------------------------------
1513 // "focus_in_event"
1514 //-----------------------------------------------------------------------------
1515
1516 static gint gtk_window_focus_in_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindow *win )
1517 {
1518 DEBUG_MAIN_THREAD
1519
1520 if (g_isIdle)
1521 wxapp_install_idle_handler();
1522
1523 if (!win->m_hasVMT) return FALSE;
1524 if (g_blockEventsOnDrag) return FALSE;
1525
1526 switch ( g_sendActivateEvent )
1527 {
1528 case -1:
1529 // we've got focus from outside, synthtize wxActivateEvent
1530 g_sendActivateEvent = 1;
1531 break;
1532
1533 case 0:
1534 // another our window just lost focus, it was already ours before
1535 // - don't send any wxActivateEvent
1536 g_sendActivateEvent = -1;
1537 break;
1538 }
1539
1540 g_focusWindow = win;
1541
1542 /*
1543 printf( "OnSetFocus from " );
1544 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1545 printf( win->GetClassInfo()->GetClassName() );
1546 printf( " " );
1547 printf( WXSTRINGCAST win->GetLabel() );
1548 printf( ".\n" );
1549 */
1550
1551 wxPanel *panel = wxDynamicCast(win->GetParent(), wxPanel);
1552 if (panel)
1553 {
1554 panel->SetLastFocus(win);
1555 }
1556
1557 #ifdef HAVE_XIM
1558 if (win->m_ic)
1559 gdk_im_begin(win->m_ic, win->m_wxwindow->window);
1560 #endif
1561
1562 #ifdef wxUSE_CARET
1563 // caret needs to be informed about focus change
1564 wxCaret *caret = win->GetCaret();
1565 if ( caret )
1566 {
1567 caret->OnSetFocus();
1568 }
1569 #endif // wxUSE_CARET
1570
1571 wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() );
1572 event.SetEventObject( win );
1573
1574 if (win->GetEventHandler()->ProcessEvent( event ))
1575 {
1576 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
1577 return TRUE;
1578 }
1579
1580 return FALSE;
1581 }
1582
1583 //-----------------------------------------------------------------------------
1584 // "focus_out_event"
1585 //-----------------------------------------------------------------------------
1586
1587 static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindow *win )
1588 {
1589 DEBUG_MAIN_THREAD
1590
1591 if (g_isIdle)
1592 wxapp_install_idle_handler();
1593
1594 if (!win->m_hasVMT) return FALSE;
1595 if (g_blockEventsOnDrag) return FALSE;
1596
1597 // if the focus goes out of our app alltogether, OnIdle() will send
1598 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1599 // g_sendActivateEvent to -1
1600 g_sendActivateEvent = 0;
1601
1602 wxWindow *winFocus = FindFocusedChild(win);
1603 if ( winFocus )
1604 win = winFocus;
1605
1606 g_focusWindow = (wxWindow *)NULL;
1607
1608 /*
1609 printf( "OnKillFocus from " );
1610 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1611 printf( win->GetClassInfo()->GetClassName() );
1612 printf( ".\n" );
1613 */
1614
1615 #ifdef HAVE_XIM
1616 if (win->m_ic)
1617 gdk_im_end();
1618 #endif
1619
1620 #ifdef wxUSE_CARET
1621 // caret needs to be informed about focus change
1622 wxCaret *caret = win->GetCaret();
1623 if ( caret )
1624 {
1625 caret->OnKillFocus();
1626 }
1627 #endif // wxUSE_CARET
1628
1629 wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
1630 event.SetEventObject( win );
1631
1632 if (win->GetEventHandler()->ProcessEvent( event ))
1633 {
1634 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_out_event" );
1635 return TRUE;
1636 }
1637
1638 return FALSE;
1639 }
1640
1641 //-----------------------------------------------------------------------------
1642 // "enter_notify_event"
1643 //-----------------------------------------------------------------------------
1644
1645 static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindow *win )
1646 {
1647 DEBUG_MAIN_THREAD
1648
1649 if (g_isIdle)
1650 wxapp_install_idle_handler();
1651
1652 if (!win->m_hasVMT) return FALSE;
1653 if (g_blockEventsOnDrag) return FALSE;
1654
1655 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1656
1657 wxMouseEvent event( wxEVT_ENTER_WINDOW );
1658 #if (GTK_MINOR_VERSION > 0)
1659 event.SetTimestamp( gdk_event->time );
1660 #endif
1661 event.SetEventObject( win );
1662
1663 int x = 0;
1664 int y = 0;
1665 GdkModifierType state = (GdkModifierType)0;
1666
1667 gdk_window_get_pointer( widget->window, &x, &y, &state );
1668
1669 event.m_shiftDown = (state & GDK_SHIFT_MASK);
1670 event.m_controlDown = (state & GDK_CONTROL_MASK);
1671 event.m_altDown = (state & GDK_MOD1_MASK);
1672 event.m_metaDown = (state & GDK_MOD2_MASK);
1673 event.m_leftDown = (state & GDK_BUTTON1_MASK);
1674 event.m_middleDown = (state & GDK_BUTTON2_MASK);
1675 event.m_rightDown = (state & GDK_BUTTON3_MASK);
1676
1677 event.m_x = x;
1678 event.m_y = y;
1679
1680 if (win->GetEventHandler()->ProcessEvent( event ))
1681 {
1682 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "enter_notify_event" );
1683 return TRUE;
1684 }
1685
1686 return FALSE;
1687 }
1688
1689 //-----------------------------------------------------------------------------
1690 // "leave_notify_event"
1691 //-----------------------------------------------------------------------------
1692
1693 static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindow *win )
1694 {
1695 DEBUG_MAIN_THREAD
1696
1697 if (g_isIdle)
1698 wxapp_install_idle_handler();
1699
1700 if (!win->m_hasVMT) return FALSE;
1701 if (g_blockEventsOnDrag) return FALSE;
1702
1703 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1704
1705 wxMouseEvent event( wxEVT_LEAVE_WINDOW );
1706 #if (GTK_MINOR_VERSION > 0)
1707 event.SetTimestamp( gdk_event->time );
1708 #endif
1709 event.SetEventObject( win );
1710
1711 int x = 0;
1712 int y = 0;
1713 GdkModifierType state = (GdkModifierType)0;
1714
1715 gdk_window_get_pointer( widget->window, &x, &y, &state );
1716
1717 event.m_shiftDown = (state & GDK_SHIFT_MASK);
1718 event.m_controlDown = (state & GDK_CONTROL_MASK);
1719 event.m_altDown = (state & GDK_MOD1_MASK);
1720 event.m_metaDown = (state & GDK_MOD2_MASK);
1721 event.m_leftDown = (state & GDK_BUTTON1_MASK);
1722 event.m_middleDown = (state & GDK_BUTTON2_MASK);
1723 event.m_rightDown = (state & GDK_BUTTON3_MASK);
1724
1725 event.m_x = x;
1726 event.m_y = y;
1727
1728 if (win->GetEventHandler()->ProcessEvent( event ))
1729 {
1730 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "leave_notify_event" );
1731 return TRUE;
1732 }
1733
1734 return FALSE;
1735 }
1736
1737 //-----------------------------------------------------------------------------
1738 // "value_changed" from m_vAdjust
1739 //-----------------------------------------------------------------------------
1740
1741 static void gtk_window_vscroll_callback( GtkAdjustment *adjust, wxWindow *win )
1742 {
1743 DEBUG_MAIN_THREAD
1744
1745 if (g_isIdle)
1746 wxapp_install_idle_handler();
1747
1748 if (g_blockEventsOnDrag) return;
1749
1750 if (!win->m_hasVMT) return;
1751
1752 float diff = adjust->value - win->m_oldVerticalPos;
1753 if (fabs(diff) < 0.2) return;
1754
1755 win->m_oldVerticalPos = adjust->value;
1756
1757 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1758 GtkRange *range = GTK_RANGE( scrolledWindow->vscrollbar );
1759
1760 wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK;
1761 if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP;
1762 else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN;
1763 else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP;
1764 else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN;
1765
1766 int value = (int)(adjust->value+0.5);
1767
1768 wxScrollWinEvent event( command, value, wxVERTICAL );
1769 event.SetEventObject( win );
1770 win->GetEventHandler()->ProcessEvent( event );
1771 }
1772
1773 //-----------------------------------------------------------------------------
1774 // "value_changed" from m_hAdjust
1775 //-----------------------------------------------------------------------------
1776
1777 static void gtk_window_hscroll_callback( GtkAdjustment *adjust, wxWindow *win )
1778 {
1779 DEBUG_MAIN_THREAD
1780
1781 if (g_isIdle)
1782 wxapp_install_idle_handler();
1783
1784 if (g_blockEventsOnDrag) return;
1785 if (!win->m_hasVMT) return;
1786
1787 float diff = adjust->value - win->m_oldHorizontalPos;
1788 if (fabs(diff) < 0.2) return;
1789
1790 win->m_oldHorizontalPos = adjust->value;
1791
1792 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1793 GtkRange *range = GTK_RANGE( scrolledWindow->hscrollbar );
1794
1795 wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK;
1796 if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP;
1797 else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN;
1798 else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP;
1799 else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN;
1800
1801 int value = (int)(adjust->value+0.5);
1802
1803 wxScrollWinEvent event( command, value, wxHORIZONTAL );
1804 event.SetEventObject( win );
1805 win->GetEventHandler()->ProcessEvent( event );
1806 }
1807
1808 //-----------------------------------------------------------------------------
1809 // "button_press_event" from scrollbar
1810 //-----------------------------------------------------------------------------
1811
1812 static gint gtk_scrollbar_button_press_callback( GtkRange *widget,
1813 GdkEventButton *gdk_event,
1814 wxWindow *win)
1815 {
1816 DEBUG_MAIN_THREAD
1817
1818 if (g_isIdle)
1819 wxapp_install_idle_handler();
1820
1821
1822 g_blockEventsOnScroll = TRUE;
1823 win->m_isScrolling = (gdk_event->window == widget->slider);
1824
1825 return FALSE;
1826 }
1827
1828 //-----------------------------------------------------------------------------
1829 // "button_release_event" from scrollbar
1830 //-----------------------------------------------------------------------------
1831
1832 static gint gtk_scrollbar_button_release_callback( GtkRange *widget,
1833 GdkEventButton *WXUNUSED(gdk_event),
1834 wxWindow *win)
1835 {
1836 DEBUG_MAIN_THREAD
1837
1838 // don't test here as we can release the mouse while being over
1839 // a different window than the slider
1840 //
1841 // if (gdk_event->window != widget->slider) return FALSE;
1842
1843 g_blockEventsOnScroll = FALSE;
1844
1845 if (win->m_isScrolling)
1846 {
1847 wxEventType command = wxEVT_SCROLLWIN_THUMBRELEASE;
1848 int value = -1;
1849 int dir = -1;
1850
1851 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1852 if (widget == GTK_RANGE(scrolledWindow->hscrollbar))
1853 {
1854 value = (int)(win->m_hAdjust->value+0.5);
1855 dir = wxHORIZONTAL;
1856 }
1857 if (widget == GTK_RANGE(scrolledWindow->vscrollbar))
1858 {
1859 value = (int)(win->m_vAdjust->value+0.5);
1860 dir = wxVERTICAL;
1861 }
1862
1863 wxScrollWinEvent event( command, value, dir );
1864 event.SetEventObject( win );
1865 win->GetEventHandler()->ProcessEvent( event );
1866 }
1867
1868 win->m_isScrolling = FALSE;
1869
1870 return FALSE;
1871 }
1872
1873 // ----------------------------------------------------------------------------
1874 // this wxWindowBase function is implemented here (in platform-specific file)
1875 // because it is static and so couldn't be made virtual
1876 // ----------------------------------------------------------------------------
1877
1878 wxWindow *wxWindowBase::FindFocus()
1879 {
1880 return g_focusWindow;
1881 }
1882
1883 //-----------------------------------------------------------------------------
1884 // "realize" from m_widget
1885 //-----------------------------------------------------------------------------
1886
1887 /* We cannot set colours and fonts before the widget has
1888 been realized, so we do this directly after realization. */
1889
1890 static gint
1891 gtk_window_realized_callback( GtkWidget *WXUNUSED(m_widget), wxWindow *win )
1892 {
1893 DEBUG_MAIN_THREAD
1894
1895 if (g_isIdle)
1896 wxapp_install_idle_handler();
1897
1898 if (win->m_delayedBackgroundColour)
1899 win->SetBackgroundColour( win->GetBackgroundColour() );
1900
1901 if (win->m_delayedForegroundColour)
1902 win->SetForegroundColour( win->GetForegroundColour() );
1903
1904 wxWindowCreateEvent event( win );
1905 event.SetEventObject( win );
1906 win->GetEventHandler()->ProcessEvent( event );
1907
1908 return FALSE;
1909 }
1910
1911 //-----------------------------------------------------------------------------
1912 // "size_allocate"
1913 //-----------------------------------------------------------------------------
1914
1915 static
1916 void gtk_window_size_callback( GtkWidget *WXUNUSED(widget),
1917 GtkAllocation *WXUNUSED(alloc),
1918 wxWindow *win )
1919 {
1920 if (g_isIdle)
1921 wxapp_install_idle_handler();
1922
1923 if (!win->m_hasScrolling) return;
1924
1925 int client_width = 0;
1926 int client_height = 0;
1927 win->GetClientSize( &client_width, &client_height );
1928 if ((client_width == win->m_oldClientWidth) && (client_height == win->m_oldClientHeight))
1929 return;
1930
1931 win->m_oldClientWidth = client_width;
1932 win->m_oldClientHeight = client_height;
1933
1934 if (!win->m_nativeSizeEvent)
1935 {
1936 wxSizeEvent event( win->GetSize(), win->GetId() );
1937 event.SetEventObject( win );
1938 win->GetEventHandler()->ProcessEvent( event );
1939 }
1940 }
1941
1942
1943 #ifdef HAVE_XIM
1944 #define WXUNUSED_UNLESS_XIM(param) param
1945 #else
1946 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
1947 #endif
1948
1949 /* Resize XIM window */
1950
1951 static
1952 void gtk_wxwindow_size_callback( GtkWidget* WXUNUSED_UNLESS_XIM(widget),
1953 GtkAllocation* WXUNUSED_UNLESS_XIM(alloc),
1954 wxWindow* WXUNUSED_UNLESS_XIM(win) )
1955 {
1956 if (g_isIdle)
1957 wxapp_install_idle_handler();
1958
1959 #ifdef HAVE_XIM
1960 if (!win->m_ic)
1961 return;
1962
1963 if (gdk_ic_get_style (win->m_ic) & GDK_IM_PREEDIT_POSITION)
1964 {
1965 gint width, height;
1966
1967 gdk_window_get_size (widget->window, &width, &height);
1968 win->m_icattr->preedit_area.width = width;
1969 win->m_icattr->preedit_area.height = height;
1970 gdk_ic_set_attr (win->m_ic, win->m_icattr, GDK_IC_PREEDIT_AREA);
1971 }
1972 #endif // HAVE_XIM
1973 }
1974
1975 //-----------------------------------------------------------------------------
1976 // "realize" from m_wxwindow
1977 //-----------------------------------------------------------------------------
1978
1979 /* Initialize XIM support */
1980
1981 static gint
1982 gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget),
1983 wxWindow * WXUNUSED_UNLESS_XIM(win) )
1984 {
1985 if (g_isIdle)
1986 wxapp_install_idle_handler();
1987
1988 #ifdef HAVE_XIM
1989 if (win->m_ic) return FALSE;
1990 if (!widget) return FALSE;
1991 if (!gdk_im_ready()) return FALSE;
1992
1993 win->m_icattr = gdk_ic_attr_new();
1994 if (!win->m_icattr) return FALSE;
1995
1996 gint width, height;
1997 GdkEventMask mask;
1998 GdkColormap *colormap;
1999 GdkICAttr *attr = win->m_icattr;
2000 unsigned attrmask = GDK_IC_ALL_REQ;
2001 GdkIMStyle style;
2002 GdkIMStyle supported_style = (GdkIMStyle)
2003 (GDK_IM_PREEDIT_NONE |
2004 GDK_IM_PREEDIT_NOTHING |
2005 GDK_IM_PREEDIT_POSITION |
2006 GDK_IM_STATUS_NONE |
2007 GDK_IM_STATUS_NOTHING);
2008
2009 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
2010 supported_style = (GdkIMStyle)(supported_style & ~GDK_IM_PREEDIT_POSITION);
2011
2012 attr->style = style = gdk_im_decide_style (supported_style);
2013 attr->client_window = widget->window;
2014
2015 if ((colormap = gtk_widget_get_colormap (widget)) !=
2016 gtk_widget_get_default_colormap ())
2017 {
2018 attrmask |= GDK_IC_PREEDIT_COLORMAP;
2019 attr->preedit_colormap = colormap;
2020 }
2021
2022 attrmask |= GDK_IC_PREEDIT_FOREGROUND;
2023 attrmask |= GDK_IC_PREEDIT_BACKGROUND;
2024 attr->preedit_foreground = widget->style->fg[GTK_STATE_NORMAL];
2025 attr->preedit_background = widget->style->base[GTK_STATE_NORMAL];
2026
2027 switch (style & GDK_IM_PREEDIT_MASK)
2028 {
2029 case GDK_IM_PREEDIT_POSITION:
2030 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
2031 {
2032 g_warning ("over-the-spot style requires fontset");
2033 break;
2034 }
2035
2036 gdk_window_get_size (widget->window, &width, &height);
2037
2038 attrmask |= GDK_IC_PREEDIT_POSITION_REQ;
2039 attr->spot_location.x = 0;
2040 attr->spot_location.y = height;
2041 attr->preedit_area.x = 0;
2042 attr->preedit_area.y = 0;
2043 attr->preedit_area.width = width;
2044 attr->preedit_area.height = height;
2045 attr->preedit_fontset = widget->style->font;
2046
2047 break;
2048 }
2049
2050 win->m_ic = gdk_ic_new (attr, (GdkICAttributesType)attrmask);
2051
2052 if (win->m_ic == NULL)
2053 g_warning ("Can't create input context.");
2054 else
2055 {
2056 mask = gdk_window_get_events (widget->window);
2057 mask = (GdkEventMask)(mask | gdk_ic_get_events (win->m_ic));
2058 gdk_window_set_events (widget->window, mask);
2059
2060 if (GTK_WIDGET_HAS_FOCUS(widget))
2061 gdk_im_begin (win->m_ic, widget->window);
2062 }
2063 #endif
2064
2065 return FALSE;
2066 }
2067
2068 //-----------------------------------------------------------------------------
2069 // InsertChild for wxWindow.
2070 //-----------------------------------------------------------------------------
2071
2072 /* Callback for wxWindow. This very strange beast has to be used because
2073 * C++ has no virtual methods in a constructor. We have to emulate a
2074 * virtual function here as wxNotebook requires a different way to insert
2075 * a child in it. I had opted for creating a wxNotebookPage window class
2076 * which would have made this superfluous (such in the MDI window system),
2077 * but no-one was listening to me... */
2078
2079 static void wxInsertChildInWindow( wxWindow* parent, wxWindow* child )
2080 {
2081 /* the window might have been scrolled already, do we
2082 have to adapt the position */
2083 GtkPizza *pizza = GTK_PIZZA(parent->m_wxwindow);
2084 child->m_x += pizza->xoffset;
2085 child->m_y += pizza->yoffset;
2086
2087 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
2088 GTK_WIDGET(child->m_widget),
2089 child->m_x,
2090 child->m_y,
2091 child->m_width,
2092 child->m_height );
2093 }
2094
2095 //-----------------------------------------------------------------------------
2096 // global functions
2097 //-----------------------------------------------------------------------------
2098
2099 wxWindow* wxGetActiveWindow()
2100 {
2101 return g_focusWindow;
2102 }
2103
2104 //-----------------------------------------------------------------------------
2105 // wxWindow
2106 //-----------------------------------------------------------------------------
2107
2108 IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
2109
2110 void wxWindow::Init()
2111 {
2112 // common init
2113 InitBase();
2114
2115 // GTK specific
2116 m_widget = (GtkWidget *) NULL;
2117 m_wxwindow = (GtkWidget *) NULL;
2118
2119 // position/size
2120 m_x = 0;
2121 m_y = 0;
2122 m_width = 0;
2123 m_height = 0;
2124
2125 m_sizeSet = FALSE;
2126 m_hasVMT = FALSE;
2127 m_needParent = TRUE;
2128 m_isBeingDeleted = FALSE;
2129
2130 m_noExpose = FALSE;
2131 m_nativeSizeEvent = FALSE;
2132
2133 m_hasScrolling = FALSE;
2134 m_isScrolling = FALSE;
2135
2136 m_hAdjust = (GtkAdjustment*) NULL;
2137 m_vAdjust = (GtkAdjustment*) NULL;
2138 m_oldHorizontalPos = 0.0;
2139 m_oldVerticalPos = 0.0;
2140
2141 m_resizing = FALSE;
2142 m_widgetStyle = (GtkStyle*) NULL;
2143
2144 m_insertCallback = (wxInsertChildFunction) NULL;
2145
2146 m_isStaticBox = FALSE;
2147 m_isRadioButton = FALSE;
2148 m_isFrame = FALSE;
2149 m_acceptsFocus = FALSE;
2150
2151 m_clipPaintRegion = FALSE;
2152
2153 m_cursor = *wxSTANDARD_CURSOR;
2154
2155 m_delayedForegroundColour = FALSE;
2156 m_delayedBackgroundColour = FALSE;
2157
2158 #ifdef HAVE_XIM
2159 m_ic = (GdkIC*) NULL;
2160 m_icattr = (GdkICAttr*) NULL;
2161 #endif
2162 }
2163
2164 wxWindow::wxWindow()
2165 {
2166 Init();
2167 }
2168
2169 wxWindow::wxWindow( wxWindow *parent, wxWindowID id,
2170 const wxPoint &pos, const wxSize &size,
2171 long style, const wxString &name )
2172 {
2173 Init();
2174
2175 Create( parent, id, pos, size, style, name );
2176 }
2177
2178 bool wxWindow::Create( wxWindow *parent, wxWindowID id,
2179 const wxPoint &pos, const wxSize &size,
2180 long style, const wxString &name )
2181 {
2182 if (!PreCreation( parent, pos, size ) ||
2183 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
2184 {
2185 wxFAIL_MSG( wxT("wxWindow creation failed") );
2186 return FALSE;
2187 }
2188
2189 m_insertCallback = wxInsertChildInWindow;
2190
2191 m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
2192 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
2193
2194 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
2195
2196 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
2197 scroll_class->scrollbar_spacing = 0;
2198
2199 gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
2200
2201 m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->hscrollbar) );
2202 m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->vscrollbar) );
2203
2204 m_wxwindow = gtk_pizza_new();
2205
2206 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
2207
2208 #if (GTK_MINOR_VERSION > 0)
2209 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
2210
2211 if (HasFlag(wxRAISED_BORDER))
2212 {
2213 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_OUT );
2214 }
2215 else if (HasFlag(wxSUNKEN_BORDER))
2216 {
2217 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_IN );
2218 }
2219 else if (HasFlag(wxSIMPLE_BORDER))
2220 {
2221 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_THIN );
2222 }
2223 else
2224 {
2225 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_NONE );
2226 }
2227 #else // GTK_MINOR_VERSION == 0
2228 GtkViewport *viewport = GTK_VIEWPORT(scrolledWindow->viewport);
2229
2230 if (HasFlag(wxRAISED_BORDER))
2231 {
2232 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_OUT );
2233 }
2234 else if (HasFlag(wxSUNKEN_BORDER))
2235 {
2236 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_IN );
2237 }
2238 else
2239 {
2240 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_NONE );
2241 }
2242 #endif // GTK_MINOR_VERSION
2243
2244 GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
2245 m_acceptsFocus = TRUE;
2246
2247 #if (GTK_MINOR_VERSION == 0)
2248 // shut the viewport up
2249 gtk_viewport_set_hadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
2250 gtk_viewport_set_vadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
2251 #endif // GTK_MINOR_VERSION == 0
2252
2253 // I _really_ don't want scrollbars in the beginning
2254 m_vAdjust->lower = 0.0;
2255 m_vAdjust->upper = 1.0;
2256 m_vAdjust->value = 0.0;
2257 m_vAdjust->step_increment = 1.0;
2258 m_vAdjust->page_increment = 1.0;
2259 m_vAdjust->page_size = 5.0;
2260 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
2261 m_hAdjust->lower = 0.0;
2262 m_hAdjust->upper = 1.0;
2263 m_hAdjust->value = 0.0;
2264 m_hAdjust->step_increment = 1.0;
2265 m_hAdjust->page_increment = 1.0;
2266 m_hAdjust->page_size = 5.0;
2267 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
2268
2269 // these handlers block mouse events to any window during scrolling such as
2270 // motion events and prevent GTK and wxWindows from fighting over where the
2271 // slider should be
2272
2273 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_press_event",
2274 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2275
2276 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_press_event",
2277 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2278
2279 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_release_event",
2280 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2281
2282 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_release_event",
2283 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2284
2285 // these handlers get notified when screen updates are required either when
2286 // scrolling or when the window size (and therefore scrollbar configuration)
2287 // has changed
2288
2289 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
2290 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
2291 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
2292 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
2293
2294 gtk_widget_show( m_wxwindow );
2295
2296 if (m_parent)
2297 m_parent->DoAddChild( this );
2298
2299 PostCreation();
2300
2301 Show( TRUE );
2302
2303 return TRUE;
2304 }
2305
2306 wxWindow::~wxWindow()
2307 {
2308 m_isBeingDeleted = TRUE;
2309 m_hasVMT = FALSE;
2310
2311 if (m_widget)
2312 Show( FALSE );
2313
2314 DestroyChildren();
2315
2316 if (m_parent)
2317 m_parent->RemoveChild( this );
2318
2319 #ifdef HAVE_XIM
2320 if (m_ic)
2321 gdk_ic_destroy (m_ic);
2322 if (m_icattr)
2323 gdk_ic_attr_destroy (m_icattr);
2324 #endif
2325
2326 if (m_widgetStyle)
2327 {
2328 #if DISABLE_STYLE_IF_BROKEN_THEME
2329 // don't delete if it's a pixmap theme style
2330 if (!m_widgetStyle->engine_data)
2331 gtk_style_unref( m_widgetStyle );
2332 #endif
2333 m_widgetStyle = (GtkStyle*) NULL;
2334 }
2335
2336 if (m_wxwindow)
2337 {
2338 gtk_widget_destroy( m_wxwindow );
2339 m_wxwindow = (GtkWidget*) NULL;
2340 }
2341
2342 if (m_widget)
2343 {
2344 gtk_widget_destroy( m_widget );
2345 m_widget = (GtkWidget*) NULL;
2346 }
2347 }
2348
2349 bool wxWindow::PreCreation( wxWindow *parent, const wxPoint &pos, const wxSize &size )
2350 {
2351 wxCHECK_MSG( !m_needParent || parent, FALSE, wxT("Need complete parent.") );
2352
2353 /* this turns -1 into 20 so that a minimal window is
2354 visible even although -1,-1 has been given as the
2355 size of the window. the same trick is used in other
2356 ports and should make debugging easier */
2357 m_width = WidthDefault(size.x);
2358 m_height = HeightDefault(size.y);
2359
2360 m_x = (int)pos.x;
2361 m_y = (int)pos.y;
2362
2363 /* some reasonable defaults */
2364 if (!parent)
2365 {
2366 if (m_x == -1)
2367 {
2368 m_x = (gdk_screen_width () - m_width) / 2;
2369 if (m_x < 10) m_x = 10;
2370 }
2371 if (m_y == -1)
2372 {
2373 m_y = (gdk_screen_height () - m_height) / 2;
2374 if (m_y < 10) m_y = 10;
2375 }
2376 }
2377
2378 return TRUE;
2379 }
2380
2381 void wxWindow::PostCreation()
2382 {
2383 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2384
2385 if (m_wxwindow)
2386 {
2387 if (!m_noExpose)
2388 {
2389 /* these get reported to wxWindows -> wxPaintEvent */
2390
2391 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow), TRUE );
2392
2393 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "event",
2394 GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this );
2395
2396 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
2397 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
2398
2399 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
2400 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
2401 }
2402
2403 #if (GTK_MINOR_VERSION > 0)
2404 /* these are called when the "sunken" or "raised" borders are drawn */
2405 gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
2406 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
2407
2408 gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
2409 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
2410 #endif
2411 }
2412
2413 if (m_wxwindow && m_needParent)
2414 {
2415 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "focus_in_event",
2416 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
2417
2418 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "focus_out_event",
2419 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
2420 }
2421 else
2422 {
2423 // For dialogs and frames, we are interested mainly in
2424 // m_widget's focus.
2425
2426 gtk_signal_connect( GTK_OBJECT(m_widget), "focus_in_event",
2427 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
2428
2429 gtk_signal_connect( GTK_OBJECT(m_widget), "focus_out_event",
2430 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
2431 }
2432
2433 GtkWidget *connect_widget = GetConnectWidget();
2434
2435 ConnectWidget( connect_widget );
2436
2437 /* We cannot set colours, fonts and cursors before the widget has
2438 been realized, so we do this directly after realization */
2439 gtk_signal_connect( GTK_OBJECT(connect_widget), "realize",
2440 GTK_SIGNAL_FUNC(gtk_window_realized_callback), (gpointer) this );
2441
2442 if (m_wxwindow)
2443 {
2444 /* Catch native resize events. */
2445 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2446 GTK_SIGNAL_FUNC(gtk_window_size_callback), (gpointer)this );
2447
2448 /* Initialize XIM support. */
2449 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "realize",
2450 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback), (gpointer) this );
2451
2452 /* And resize XIM window. */
2453 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2454 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this );
2455 }
2456
2457 m_hasVMT = TRUE;
2458 }
2459
2460 void wxWindow::ConnectWidget( GtkWidget *widget )
2461 {
2462 gtk_signal_connect( GTK_OBJECT(widget), "key_press_event",
2463 GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this );
2464
2465 gtk_signal_connect( GTK_OBJECT(widget), "key_release_event",
2466 GTK_SIGNAL_FUNC(gtk_window_key_release_callback), (gpointer)this );
2467
2468 gtk_signal_connect( GTK_OBJECT(widget), "button_press_event",
2469 GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
2470
2471 gtk_signal_connect( GTK_OBJECT(widget), "button_release_event",
2472 GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
2473
2474 gtk_signal_connect( GTK_OBJECT(widget), "motion_notify_event",
2475 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
2476
2477 gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event",
2478 GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
2479
2480 gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
2481 GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
2482 }
2483
2484 bool wxWindow::Destroy()
2485 {
2486 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2487
2488 m_hasVMT = FALSE;
2489
2490 return wxWindowBase::Destroy();
2491 }
2492
2493 void wxWindow::DoMoveWindow(int x, int y, int width, int height)
2494 {
2495 gtk_pizza_set_size( GTK_PIZZA(m_parent->m_wxwindow), m_widget, x, y, width, height );
2496 }
2497
2498 void wxWindow::DoSetSize( int x, int y, int width, int height, int sizeFlags )
2499 {
2500 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2501 wxASSERT_MSG( (m_parent != NULL), wxT("wxWindow::SetSize requires parent.\n") );
2502
2503 if (m_resizing) return; /* I don't like recursions */
2504 m_resizing = TRUE;
2505
2506 if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
2507 {
2508 /* don't set the size for children of wxNotebook, just take the values. */
2509 m_x = x;
2510 m_y = y;
2511 m_width = width;
2512 m_height = height;
2513 }
2514 else
2515 {
2516 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
2517
2518 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
2519 {
2520 if (x != -1) m_x = x + pizza->xoffset;
2521 if (y != -1) m_y = y + pizza->yoffset;
2522 if (width != -1) m_width = width;
2523 if (height != -1) m_height = height;
2524 }
2525 else
2526 {
2527 m_x = x + pizza->xoffset;
2528 m_y = y + pizza->yoffset;
2529 m_width = width;
2530 m_height = height;
2531 }
2532
2533 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
2534 {
2535 if (width == -1) m_width = 80;
2536 }
2537
2538 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
2539 {
2540 if (height == -1) m_height = 26;
2541 }
2542
2543 if ((m_minWidth != -1) && (m_width < m_minWidth)) m_width = m_minWidth;
2544 if ((m_minHeight != -1) && (m_height < m_minHeight)) m_height = m_minHeight;
2545 if ((m_maxWidth != -1) && (m_width > m_maxWidth)) m_width = m_maxWidth;
2546 if ((m_maxHeight != -1) && (m_height > m_maxHeight)) m_height = m_maxHeight;
2547
2548 int border = 0;
2549 int bottom_border = 0;
2550
2551 if (GTK_WIDGET_CAN_DEFAULT(m_widget))
2552 {
2553 /* the default button has a border around it */
2554 border = 6;
2555 bottom_border = 5;
2556 }
2557
2558 DoMoveWindow( m_x-border,
2559 m_y-border,
2560 m_width+2*border,
2561 m_height+border+bottom_border );
2562 }
2563
2564 if (m_hasScrolling)
2565 {
2566 /* Sometimes the client area changes size without the
2567 whole windows's size changing, but if the whole
2568 windows's size doesn't change, no wxSizeEvent will
2569 normally be sent. Here we add an extra test if
2570 the client test has been changed and this will
2571 be used then. */
2572 GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
2573 }
2574
2575 /*
2576 wxPrintf( "OnSize sent from " );
2577 if (GetClassInfo() && GetClassInfo()->GetClassName())
2578 wxPrintf( GetClassInfo()->GetClassName() );
2579 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2580 */
2581
2582 if (!m_nativeSizeEvent)
2583 {
2584 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
2585 event.SetEventObject( this );
2586 GetEventHandler()->ProcessEvent( event );
2587 }
2588
2589 m_resizing = FALSE;
2590 }
2591
2592 void wxWindow::OnInternalIdle()
2593 {
2594 if ( g_sendActivateEvent != -1 )
2595 {
2596 bool activate = g_sendActivateEvent != 0;
2597
2598 // do it only once
2599 g_sendActivateEvent = -1;
2600
2601 wxActivateEvent event(wxEVT_ACTIVATE, activate, GetId());
2602 event.SetEventObject(this);
2603
2604 (void)GetEventHandler()->ProcessEvent(event);
2605 }
2606
2607 wxCursor cursor = m_cursor;
2608 if (g_globalCursor.Ok()) cursor = g_globalCursor;
2609
2610 if (cursor.Ok())
2611 {
2612 /* I now set the cursor anew in every OnInternalIdle call
2613 as setting the cursor in a parent window also effects the
2614 windows above so that checking for the current cursor is
2615 not possible. */
2616
2617 if (m_wxwindow)
2618 {
2619 GdkWindow *window = GTK_PIZZA(m_wxwindow)->bin_window;
2620 if (window)
2621 gdk_window_set_cursor( window, cursor.GetCursor() );
2622
2623 if (!g_globalCursor.Ok())
2624 cursor = *wxSTANDARD_CURSOR;
2625
2626 window = m_widget->window;
2627 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
2628 gdk_window_set_cursor( window, cursor.GetCursor() );
2629
2630 }
2631 else
2632 {
2633
2634 GdkWindow *window = m_widget->window;
2635 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
2636 gdk_window_set_cursor( window, cursor.GetCursor() );
2637
2638 }
2639 }
2640
2641 UpdateWindowUI();
2642 }
2643
2644 void wxWindow::DoGetSize( int *width, int *height ) const
2645 {
2646 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2647
2648 if (width) (*width) = m_width;
2649 if (height) (*height) = m_height;
2650 }
2651
2652 void wxWindow::DoSetClientSize( int width, int height )
2653 {
2654 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2655
2656 if (!m_wxwindow)
2657 {
2658 SetSize( width, height );
2659 }
2660 else
2661 {
2662 int dw = 0;
2663 int dh = 0;
2664
2665 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
2666 {
2667 /* when using GTK 1.2 we set the shadow border size to 2 */
2668 dw += 2 * 2;
2669 dh += 2 * 2;
2670 }
2671 if (HasFlag(wxSIMPLE_BORDER))
2672 {
2673 /* when using GTK 1.2 we set the simple border size to 1 */
2674 dw += 1 * 2;
2675 dh += 1 * 2;
2676 }
2677
2678 if (m_hasScrolling)
2679 {
2680 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2681
2682 GtkRequisition vscroll_req;
2683 vscroll_req.width = 2;
2684 vscroll_req.height = 2;
2685 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
2686 (scroll_window->vscrollbar, &vscroll_req );
2687
2688 GtkRequisition hscroll_req;
2689 hscroll_req.width = 2;
2690 hscroll_req.height = 2;
2691 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
2692 (scroll_window->hscrollbar, &hscroll_req );
2693
2694 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
2695
2696 if (scroll_window->vscrollbar_visible)
2697 {
2698 dw += vscroll_req.width;
2699 dw += scroll_class->scrollbar_spacing;
2700 }
2701
2702 if (scroll_window->hscrollbar_visible)
2703 {
2704 dh += hscroll_req.height;
2705 dh += scroll_class->scrollbar_spacing;
2706 }
2707 }
2708
2709 SetSize( width+dw, height+dh );
2710 }
2711 }
2712
2713 void wxWindow::DoGetClientSize( int *width, int *height ) const
2714 {
2715 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2716
2717 if (!m_wxwindow)
2718 {
2719 if (width) (*width) = m_width;
2720 if (height) (*height) = m_height;
2721 }
2722 else
2723 {
2724 int dw = 0;
2725 int dh = 0;
2726
2727 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
2728 {
2729 /* when using GTK 1.2 we set the shadow border size to 2 */
2730 dw += 2 * 2;
2731 dh += 2 * 2;
2732 }
2733 if (HasFlag(wxSIMPLE_BORDER))
2734 {
2735 /* when using GTK 1.2 we set the simple border size to 1 */
2736 dw += 1 * 2;
2737 dh += 1 * 2;
2738 }
2739
2740 if (m_hasScrolling)
2741 {
2742 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2743
2744 GtkRequisition vscroll_req;
2745 vscroll_req.width = 2;
2746 vscroll_req.height = 2;
2747 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
2748 (scroll_window->vscrollbar, &vscroll_req );
2749
2750 GtkRequisition hscroll_req;
2751 hscroll_req.width = 2;
2752 hscroll_req.height = 2;
2753 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
2754 (scroll_window->hscrollbar, &hscroll_req );
2755
2756 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
2757
2758 if (scroll_window->vscrollbar_visible)
2759 {
2760 dw += vscroll_req.width;
2761 dw += scroll_class->scrollbar_spacing;
2762 }
2763
2764 if (scroll_window->hscrollbar_visible)
2765 {
2766 dh += hscroll_req.height;
2767 dh += scroll_class->scrollbar_spacing;
2768 }
2769 }
2770
2771 if (width) (*width) = m_width - dw;
2772 if (height) (*height) = m_height - dh;
2773 }
2774 }
2775
2776 void wxWindow::DoGetPosition( int *x, int *y ) const
2777 {
2778 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2779
2780 int dx = 0;
2781 int dy = 0;
2782 if (m_parent && m_parent->m_wxwindow)
2783 {
2784 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
2785 dx = pizza->xoffset;
2786 dy = pizza->yoffset;
2787 }
2788
2789 if (x) (*x) = m_x - dx;
2790 if (y) (*y) = m_y - dy;
2791 }
2792
2793 void wxWindow::DoClientToScreen( int *x, int *y ) const
2794 {
2795 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2796
2797 if (!m_widget->window) return;
2798
2799 GdkWindow *source = (GdkWindow *) NULL;
2800 if (m_wxwindow)
2801 source = GTK_PIZZA(m_wxwindow)->bin_window;
2802 else
2803 source = m_widget->window;
2804
2805 int org_x = 0;
2806 int org_y = 0;
2807 gdk_window_get_origin( source, &org_x, &org_y );
2808
2809 if (!m_wxwindow)
2810 {
2811 if (GTK_WIDGET_NO_WINDOW (m_widget))
2812 {
2813 org_x += m_widget->allocation.x;
2814 org_y += m_widget->allocation.y;
2815 }
2816 }
2817
2818 if (x) *x += org_x;
2819 if (y) *y += org_y;
2820 }
2821
2822 void wxWindow::DoScreenToClient( int *x, int *y ) const
2823 {
2824 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2825
2826 if (!m_widget->window) return;
2827
2828 GdkWindow *source = (GdkWindow *) NULL;
2829 if (m_wxwindow)
2830 source = GTK_PIZZA(m_wxwindow)->bin_window;
2831 else
2832 source = m_widget->window;
2833
2834 int org_x = 0;
2835 int org_y = 0;
2836 gdk_window_get_origin( source, &org_x, &org_y );
2837
2838 if (!m_wxwindow)
2839 {
2840 if (GTK_WIDGET_NO_WINDOW (m_widget))
2841 {
2842 org_x += m_widget->allocation.x;
2843 org_y += m_widget->allocation.y;
2844 }
2845 }
2846
2847 if (x) *x -= org_x;
2848 if (y) *y -= org_y;
2849 }
2850
2851 bool wxWindow::Show( bool show )
2852 {
2853 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
2854
2855 if (!wxWindowBase::Show(show))
2856 {
2857 // nothing to do
2858 return FALSE;
2859 }
2860
2861 if (show)
2862 gtk_widget_show( m_widget );
2863 else
2864 gtk_widget_hide( m_widget );
2865
2866 return TRUE;
2867 }
2868
2869 bool wxWindow::Enable( bool enable )
2870 {
2871 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
2872
2873 if (!wxWindowBase::Enable(enable))
2874 {
2875 // nothing to do
2876 return FALSE;
2877 }
2878
2879 gtk_widget_set_sensitive( m_widget, enable );
2880 if ( m_wxwindow )
2881 gtk_widget_set_sensitive( m_wxwindow, enable );
2882
2883 return TRUE;
2884 }
2885
2886 int wxWindow::GetCharHeight() const
2887 {
2888 wxCHECK_MSG( (m_widget != NULL), 12, wxT("invalid window") );
2889
2890 wxCHECK_MSG( m_font.Ok(), 12, wxT("invalid font") );
2891
2892 GdkFont *font = m_font.GetInternalFont( 1.0 );
2893
2894 return font->ascent + font->descent;
2895 }
2896
2897 int wxWindow::GetCharWidth() const
2898 {
2899 wxCHECK_MSG( (m_widget != NULL), 8, wxT("invalid window") );
2900
2901 wxCHECK_MSG( m_font.Ok(), 8, wxT("invalid font") );
2902
2903 GdkFont *font = m_font.GetInternalFont( 1.0 );
2904
2905 return gdk_string_width( font, "H" );
2906 }
2907
2908 void wxWindow::GetTextExtent( const wxString& string,
2909 int *x,
2910 int *y,
2911 int *descent,
2912 int *externalLeading,
2913 const wxFont *theFont ) const
2914 {
2915 wxFont fontToUse = m_font;
2916 if (theFont) fontToUse = *theFont;
2917
2918 wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
2919
2920 GdkFont *font = fontToUse.GetInternalFont( 1.0 );
2921 if (x) (*x) = gdk_string_width( font, string.mbc_str() );
2922 if (y) (*y) = font->ascent + font->descent;
2923 if (descent) (*descent) = font->descent;
2924 if (externalLeading) (*externalLeading) = 0; // ??
2925 }
2926
2927 void wxWindow::SetFocus()
2928 {
2929 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2930
2931 if (m_wxwindow)
2932 {
2933 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
2934 gtk_widget_grab_focus (m_wxwindow);
2935 return;
2936 }
2937
2938 if (m_widget)
2939 {
2940 if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
2941 {
2942 gtk_widget_grab_focus (m_widget);
2943 }
2944 else if (GTK_IS_CONTAINER(m_widget))
2945 {
2946 gtk_container_focus( GTK_CONTAINER(m_widget), GTK_DIR_TAB_FORWARD );
2947 }
2948 else
2949 {
2950 // ?
2951 }
2952 }
2953 }
2954
2955 bool wxWindow::AcceptsFocus() const
2956 {
2957 return m_acceptsFocus && wxWindowBase::AcceptsFocus();
2958 }
2959
2960 bool wxWindow::Reparent( wxWindowBase *newParentBase )
2961 {
2962 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
2963
2964 wxWindow *oldParent = m_parent,
2965 *newParent = (wxWindow *)newParentBase;
2966
2967 wxASSERT( GTK_IS_WIDGET(m_widget) );
2968
2969 if ( !wxWindowBase::Reparent(newParent) )
2970 return FALSE;
2971
2972 wxASSERT( GTK_IS_WIDGET(m_widget) );
2973
2974 /* prevent GTK from deleting the widget arbitrarily */
2975 gtk_widget_ref( m_widget );
2976
2977 if (oldParent)
2978 {
2979 gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget );
2980 }
2981
2982 wxASSERT( GTK_IS_WIDGET(m_widget) );
2983
2984 if (newParent)
2985 {
2986 /* insert GTK representation */
2987 (*(newParent->m_insertCallback))(newParent, this);
2988 }
2989
2990 /* reverse: prevent GTK from deleting the widget arbitrarily */
2991 gtk_widget_unref( m_widget );
2992
2993 return TRUE;
2994 }
2995
2996 void wxWindow::DoAddChild(wxWindow *child)
2997 {
2998 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2999
3000 wxASSERT_MSG( (child != NULL), wxT("invalid child window") );
3001
3002 wxASSERT_MSG( (m_insertCallback != NULL), wxT("invalid child insertion function") );
3003
3004 /* add to list */
3005 AddChild( child );
3006
3007 /* insert GTK representation */
3008 (*m_insertCallback)(this, child);
3009 }
3010
3011 void wxWindow::Raise()
3012 {
3013 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3014
3015 if (!m_widget->window) return;
3016
3017 gdk_window_raise( m_widget->window );
3018 }
3019
3020 void wxWindow::Lower()
3021 {
3022 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3023
3024 if (!m_widget->window) return;
3025
3026 gdk_window_lower( m_widget->window );
3027 }
3028
3029 bool wxWindow::SetCursor( const wxCursor &cursor )
3030 {
3031 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3032
3033 if (cursor == m_cursor)
3034 return FALSE;
3035
3036 if (g_isIdle)
3037 wxapp_install_idle_handler();
3038
3039 if (cursor == wxNullCursor)
3040 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR );
3041 else
3042 return wxWindowBase::SetCursor( cursor );
3043 }
3044
3045 void wxWindow::WarpPointer( int x, int y )
3046 {
3047 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3048
3049 /* we provide this function ourselves as it is
3050 missing in GDK (top of this file) */
3051
3052 GdkWindow *window = (GdkWindow*) NULL;
3053 if (m_wxwindow)
3054 window = GTK_PIZZA(m_wxwindow)->bin_window;
3055 else
3056 window = GetConnectWidget()->window;
3057
3058 if (window)
3059 gdk_window_warp_pointer( window, x, y );
3060 }
3061
3062 void wxWindow::Refresh( bool eraseBackground, const wxRect *rect )
3063 {
3064 if (!m_widget) return;
3065 if (!m_widget->window) return;
3066
3067 if (eraseBackground && m_wxwindow && m_wxwindow->window)
3068 {
3069 if (rect)
3070 {
3071 gdk_window_clear_area( GTK_PIZZA(m_wxwindow)->bin_window,
3072 rect->x, rect->y,
3073 rect->width, rect->height );
3074 }
3075 else
3076 {
3077 gdk_window_clear( GTK_PIZZA(m_wxwindow)->bin_window );
3078 }
3079 }
3080
3081 /* there is no GTK equivalent of "draw only, don't clear" so we
3082 invent our own in the GtkPizza widget */
3083
3084 if (!rect)
3085 {
3086 if (m_wxwindow)
3087 {
3088
3089 /*
3090 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
3091 gboolean old_clear = pizza->clear_on_draw;
3092 gtk_pizza_set_clear( pizza, FALSE );
3093 gtk_widget_draw( m_wxwindow, (GdkRectangle*) NULL );
3094 gtk_pizza_set_clear( pizza, old_clear );
3095 */
3096 GdkEventExpose gdk_event;
3097 gdk_event.type = GDK_EXPOSE;
3098 gdk_event.window = GTK_PIZZA(m_wxwindow)->bin_window;
3099 gdk_event.count = 0;
3100 gdk_event.area.x = 0;
3101 gdk_event.area.y = 0;
3102 gdk_event.area.width = m_wxwindow->allocation.width;
3103 gdk_event.area.height = m_wxwindow->allocation.height;
3104 gtk_window_expose_callback( m_wxwindow, &gdk_event, this );
3105
3106 }
3107 else
3108 {
3109 gtk_widget_draw( m_widget, (GdkRectangle*) NULL );
3110 }
3111 }
3112 else
3113 {
3114
3115 if (m_wxwindow)
3116 {
3117 /*
3118 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
3119 gboolean old_clear = pizza->clear_on_draw;
3120 gtk_pizza_set_clear( pizza, FALSE );
3121
3122 GdkRectangle gdk_rect;
3123 gdk_rect.x = rect->x;
3124 gdk_rect.y = rect->y;
3125 gdk_rect.width = rect->width;
3126 gdk_rect.height = rect->height;
3127 gtk_widget_draw( m_wxwindow, &gdk_rect );
3128 gtk_window_draw_callback( m_wxwindow, &gdk_rect, this );
3129
3130 gtk_pizza_set_clear( pizza, old_clear );
3131 */
3132 GdkEventExpose gdk_event;
3133 gdk_event.type = GDK_EXPOSE;
3134 gdk_event.window = GTK_PIZZA(m_wxwindow)->bin_window;
3135 gdk_event.count = 0;
3136 gdk_event.area.x = rect->x;
3137 gdk_event.area.y = rect->y;
3138 gdk_event.area.width = rect->width;
3139 gdk_event.area.height = rect->height;
3140 gtk_window_expose_callback( m_wxwindow, &gdk_event, this );
3141 }
3142 else
3143 {
3144 GdkRectangle gdk_rect;
3145 gdk_rect.x = rect->x;
3146 gdk_rect.y = rect->y;
3147 gdk_rect.width = rect->width;
3148 gdk_rect.height = rect->height;
3149 gtk_widget_draw( m_widget, &gdk_rect );
3150 }
3151 }
3152 }
3153
3154 void wxWindow::Clear()
3155 {
3156 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3157
3158 if (!m_widget->window) return;
3159
3160 if (m_wxwindow && m_wxwindow->window)
3161 {
3162 // gdk_window_clear( m_wxwindow->window );
3163 }
3164 }
3165
3166 #if wxUSE_TOOLTIPS
3167 void wxWindow::DoSetToolTip( wxToolTip *tip )
3168 {
3169 wxWindowBase::DoSetToolTip(tip);
3170
3171 if (m_tooltip)
3172 m_tooltip->Apply( this );
3173 }
3174
3175 void wxWindow::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
3176 {
3177 gtk_tooltips_set_tip( tips, GetConnectWidget(), wxConvCurrent->cWX2MB(tip), (gchar*) NULL );
3178 }
3179 #endif // wxUSE_TOOLTIPS
3180
3181 bool wxWindow::SetBackgroundColour( const wxColour &colour )
3182 {
3183 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3184
3185 if (!wxWindowBase::SetBackgroundColour(colour))
3186 {
3187 // don't leave if the GTK widget has just
3188 // been realized
3189 if (!m_delayedBackgroundColour) return FALSE;
3190 }
3191
3192 GdkWindow *window = (GdkWindow*) NULL;
3193 if (m_wxwindow)
3194 window = GTK_PIZZA(m_wxwindow)->bin_window;
3195 else
3196 window = GetConnectWidget()->window;
3197
3198 if (!window)
3199 {
3200 // indicate that a new style has been set
3201 // but it couldn't get applied as the
3202 // widget hasn't been realized yet.
3203 m_delayedBackgroundColour = TRUE;
3204 }
3205
3206 if ((m_wxwindow) &&
3207 (m_wxwindow->window) &&
3208 (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE)))
3209 {
3210 /* wxMSW doesn't clear the window here. I don't do that either to
3211 provide compatibility. call Clear() to do the job. */
3212
3213 m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
3214 gdk_window_set_background( window, m_backgroundColour.GetColor() );
3215 }
3216
3217 ApplyWidgetStyle();
3218
3219 return TRUE;
3220 }
3221
3222 bool wxWindow::SetForegroundColour( const wxColour &colour )
3223 {
3224 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3225
3226 if (!wxWindowBase::SetForegroundColour(colour))
3227 {
3228 // don't leave if the GTK widget has just
3229 // been realized
3230 if (!m_delayedForegroundColour) return FALSE;
3231 }
3232
3233 GdkWindow *window = (GdkWindow*) NULL;
3234 if (m_wxwindow)
3235 window = GTK_PIZZA(m_wxwindow)->bin_window;
3236 else
3237 window = GetConnectWidget()->window;
3238
3239 if (!window)
3240 {
3241 // indicate that a new style has been set
3242 // but it couldn't get applied as the
3243 // widget hasn't been realized yet.
3244 m_delayedForegroundColour = TRUE;
3245 }
3246
3247 ApplyWidgetStyle();
3248
3249 return TRUE;
3250 }
3251
3252 GtkStyle *wxWindow::GetWidgetStyle()
3253 {
3254 if (m_widgetStyle)
3255 {
3256 GtkStyle *remake = gtk_style_copy( m_widgetStyle );
3257 #ifdef __WXGTK20__
3258 /* FIXME: is this necessary? */
3259 _G_TYPE_IGC(remake, GtkObjectClass) = _G_TYPE_IGC(m_widgetStyle, GtkObjectClass);
3260 #else
3261 remake->klass = m_widgetStyle->klass;
3262 #endif
3263
3264 gtk_style_unref( m_widgetStyle );
3265 m_widgetStyle = remake;
3266 }
3267 else
3268 {
3269 GtkStyle *def = gtk_rc_get_style( m_widget );
3270
3271 if (!def)
3272 def = gtk_widget_get_default_style();
3273
3274 m_widgetStyle = gtk_style_copy( def );
3275 #ifdef __WXGTK20__
3276 /* FIXME: is this necessary? */
3277 _G_TYPE_IGC(m_widgetStyle, GtkObjectClass) = _G_TYPE_IGC(def, GtkObjectClass);
3278 #else
3279 m_widgetStyle->klass = def->klass;
3280 #endif
3281 }
3282
3283 return m_widgetStyle;
3284 }
3285
3286 void wxWindow::SetWidgetStyle()
3287 {
3288 #if DISABLE_STYLE_IF_BROKEN_THEM
3289 if (m_widget->style->engine_data)
3290 {
3291 static bool s_warningPrinted = FALSE;
3292 if (!s_warningPrinted)
3293 {
3294 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3295 s_warningPrinted = TRUE;
3296 }
3297 m_widgetStyle = m_widget->style;
3298 return;
3299 }
3300 #endif
3301
3302 GtkStyle *style = GetWidgetStyle();
3303
3304 if (m_font != wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT ))
3305 {
3306 gdk_font_unref( style->font );
3307 style->font = gdk_font_ref( m_font.GetInternalFont( 1.0 ) );
3308 }
3309
3310 if (m_foregroundColour.Ok())
3311 {
3312 m_foregroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
3313 if (m_foregroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNTEXT))
3314 {
3315 style->fg[GTK_STATE_NORMAL] = *m_foregroundColour.GetColor();
3316 style->fg[GTK_STATE_PRELIGHT] = *m_foregroundColour.GetColor();
3317 style->fg[GTK_STATE_ACTIVE] = *m_foregroundColour.GetColor();
3318 }
3319 else
3320 {
3321 // Try to restore the gtk default style. This is still a little
3322 // oversimplified for what is probably really needed here for controls
3323 // other than buttons, but is better than not being able to (re)set a
3324 // control's foreground colour to *wxBLACK -- RL
3325 GtkStyle *def = gtk_rc_get_style( m_widget );
3326
3327 if (!def)
3328 def = gtk_widget_get_default_style();
3329
3330 style->fg[GTK_STATE_NORMAL] = def->fg[GTK_STATE_NORMAL];
3331 style->fg[GTK_STATE_PRELIGHT] = def->fg[GTK_STATE_PRELIGHT];
3332 style->fg[GTK_STATE_ACTIVE] = def->fg[GTK_STATE_ACTIVE];
3333 }
3334 }
3335
3336 if (m_backgroundColour.Ok())
3337 {
3338 m_backgroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
3339 if (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE))
3340 {
3341 style->bg[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
3342 style->base[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
3343 style->bg[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
3344 style->base[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
3345 style->bg[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
3346 style->base[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
3347 style->bg[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
3348 style->base[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
3349 }
3350 else
3351 {
3352 // Try to restore the gtk default style. This is still a little
3353 // oversimplified for what is probably really needed here for controls
3354 // other than buttons, but is better than not being able to (re)set a
3355 // control's background colour to default grey and means resetting a
3356 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
3357 // behavior -- RL
3358 GtkStyle *def = gtk_rc_get_style( m_widget );
3359
3360 if (!def)
3361 def = gtk_widget_get_default_style();
3362
3363 style->bg[GTK_STATE_NORMAL] = def->bg[GTK_STATE_NORMAL];
3364 style->base[GTK_STATE_NORMAL] = def->base[GTK_STATE_NORMAL];
3365 style->bg[GTK_STATE_PRELIGHT] = def->bg[GTK_STATE_PRELIGHT];
3366 style->base[GTK_STATE_PRELIGHT] = def->base[GTK_STATE_PRELIGHT];
3367 style->bg[GTK_STATE_ACTIVE] = def->bg[GTK_STATE_ACTIVE];
3368 style->base[GTK_STATE_ACTIVE] = def->base[GTK_STATE_ACTIVE];
3369 style->bg[GTK_STATE_INSENSITIVE] = def->bg[GTK_STATE_INSENSITIVE];
3370 style->base[GTK_STATE_INSENSITIVE] = def->base[GTK_STATE_INSENSITIVE];
3371 }
3372 }
3373 }
3374
3375 void wxWindow::ApplyWidgetStyle()
3376 {
3377 }
3378
3379 //-----------------------------------------------------------------------------
3380 // Pop-up menu stuff
3381 //-----------------------------------------------------------------------------
3382
3383 static void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting )
3384 {
3385 *is_waiting = FALSE;
3386 }
3387
3388 static void SetInvokingWindow( wxMenu *menu, wxWindow *win )
3389 {
3390 menu->SetInvokingWindow( win );
3391 wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
3392 while (node)
3393 {
3394 wxMenuItem *menuitem = node->GetData();
3395 if (menuitem->IsSubMenu())
3396 {
3397 SetInvokingWindow( menuitem->GetSubMenu(), win );
3398 }
3399
3400 node = node->GetNext();
3401 }
3402 }
3403
3404 static gint gs_pop_x = 0;
3405 static gint gs_pop_y = 0;
3406
3407 static void pop_pos_callback( GtkMenu * WXUNUSED(menu),
3408 gint *x, gint *y,
3409 wxWindow *win )
3410 {
3411 win->ClientToScreen( &gs_pop_x, &gs_pop_y );
3412 *x = gs_pop_x;
3413 *y = gs_pop_y;
3414 }
3415
3416 bool wxWindow::DoPopupMenu( wxMenu *menu, int x, int y )
3417 {
3418 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3419
3420 wxCHECK_MSG( menu != NULL, FALSE, wxT("invalid popup-menu") );
3421
3422 SetInvokingWindow( menu, this );
3423
3424 menu->UpdateUI();
3425
3426 gs_pop_x = x;
3427 gs_pop_y = y;
3428
3429 bool is_waiting = TRUE;
3430
3431 gtk_signal_connect( GTK_OBJECT(menu->m_menu), "hide",
3432 GTK_SIGNAL_FUNC(gtk_pop_hide_callback), (gpointer)&is_waiting );
3433
3434 gtk_menu_popup(
3435 GTK_MENU(menu->m_menu),
3436 (GtkWidget *) NULL, // parent menu shell
3437 (GtkWidget *) NULL, // parent menu item
3438 (GtkMenuPositionFunc) pop_pos_callback,
3439 (gpointer) this, // client data
3440 0, // button used to activate it
3441 gs_timeLastClick // the time of activation
3442 );
3443
3444 while (is_waiting)
3445 {
3446 while (gtk_events_pending())
3447 gtk_main_iteration();
3448 }
3449
3450 return TRUE;
3451 }
3452
3453 #if wxUSE_DRAG_AND_DROP
3454
3455 void wxWindow::SetDropTarget( wxDropTarget *dropTarget )
3456 {
3457 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3458
3459 GtkWidget *dnd_widget = GetConnectWidget();
3460
3461 if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
3462
3463 if (m_dropTarget) delete m_dropTarget;
3464 m_dropTarget = dropTarget;
3465
3466 if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
3467 }
3468
3469 #endif // wxUSE_DRAG_AND_DROP
3470
3471 GtkWidget* wxWindow::GetConnectWidget()
3472 {
3473 GtkWidget *connect_widget = m_widget;
3474 if (m_wxwindow) connect_widget = m_wxwindow;
3475
3476 return connect_widget;
3477 }
3478
3479 bool wxWindow::IsOwnGtkWindow( GdkWindow *window )
3480 {
3481 if (m_wxwindow)
3482 return (window == GTK_PIZZA(m_wxwindow)->bin_window);
3483
3484 return (window == m_widget->window);
3485 }
3486
3487 bool wxWindow::SetFont( const wxFont &font )
3488 {
3489 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3490
3491 if (!wxWindowBase::SetFont(font))
3492 {
3493 return FALSE;
3494 }
3495
3496 wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
3497 if ( sysbg == m_backgroundColour )
3498 {
3499 m_backgroundColour = wxNullColour;
3500 ApplyWidgetStyle();
3501 m_backgroundColour = sysbg;
3502 }
3503 else
3504 {
3505 ApplyWidgetStyle();
3506 }
3507
3508 return TRUE;
3509 }
3510
3511 void wxWindow::CaptureMouse()
3512 {
3513 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3514
3515 wxCHECK_RET( g_captureWindow == NULL, wxT("CaptureMouse called twice") );
3516
3517 GdkWindow *window = (GdkWindow*) NULL;
3518 if (m_wxwindow)
3519 window = GTK_PIZZA(m_wxwindow)->bin_window;
3520 else
3521 window = GetConnectWidget()->window;
3522
3523 if (!window) return;
3524
3525 wxCursor* cursor = & m_cursor;
3526 if (!cursor->Ok())
3527 cursor = wxSTANDARD_CURSOR;
3528
3529 gdk_pointer_grab( window, FALSE,
3530 (GdkEventMask)
3531 (GDK_BUTTON_PRESS_MASK |
3532 GDK_BUTTON_RELEASE_MASK |
3533 GDK_POINTER_MOTION_HINT_MASK |
3534 GDK_POINTER_MOTION_MASK),
3535 (GdkWindow *) NULL,
3536 cursor->GetCursor(),
3537 (guint32)GDK_CURRENT_TIME );
3538 g_captureWindow = this;
3539 }
3540
3541 void wxWindow::ReleaseMouse()
3542 {
3543 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3544
3545 wxCHECK_RET( g_captureWindow, wxT("ReleaseMouse called twice") );
3546
3547 GdkWindow *window = (GdkWindow*) NULL;
3548 if (m_wxwindow)
3549 window = GTK_PIZZA(m_wxwindow)->bin_window;
3550 else
3551 window = GetConnectWidget()->window;
3552
3553 if (!window)
3554 return;
3555
3556 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
3557 g_captureWindow = (wxWindow*) NULL;
3558 }
3559
3560 bool wxWindow::IsRetained() const
3561 {
3562 return FALSE;
3563 }
3564
3565 void wxWindow::SetScrollbar( int orient, int pos, int thumbVisible,
3566 int range, bool refresh )
3567 {
3568 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3569
3570 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
3571
3572 m_hasScrolling = TRUE;
3573
3574 if (orient == wxHORIZONTAL)
3575 {
3576 float fpos = (float)pos;
3577 float frange = (float)range;
3578 float fthumb = (float)thumbVisible;
3579 if (fpos > frange-fthumb) fpos = frange-fthumb;
3580 if (fpos < 0.0) fpos = 0.0;
3581
3582 if ((fabs(frange-m_hAdjust->upper) < 0.2) &&
3583 (fabs(fthumb-m_hAdjust->page_size) < 0.2))
3584 {
3585 SetScrollPos( orient, pos, refresh );
3586 return;
3587 }
3588
3589 m_oldHorizontalPos = fpos;
3590
3591 m_hAdjust->lower = 0.0;
3592 m_hAdjust->upper = frange;
3593 m_hAdjust->value = fpos;
3594 m_hAdjust->step_increment = 1.0;
3595 m_hAdjust->page_increment = (float)(wxMax(fthumb,0));
3596 m_hAdjust->page_size = fthumb;
3597 }
3598 else
3599 {
3600 float fpos = (float)pos;
3601 float frange = (float)range;
3602 float fthumb = (float)thumbVisible;
3603 if (fpos > frange-fthumb) fpos = frange-fthumb;
3604 if (fpos < 0.0) fpos = 0.0;
3605
3606 if ((fabs(frange-m_vAdjust->upper) < 0.2) &&
3607 (fabs(fthumb-m_vAdjust->page_size) < 0.2))
3608 {
3609 SetScrollPos( orient, pos, refresh );
3610 return;
3611 }
3612
3613 m_oldVerticalPos = fpos;
3614
3615 m_vAdjust->lower = 0.0;
3616 m_vAdjust->upper = frange;
3617 m_vAdjust->value = fpos;
3618 m_vAdjust->step_increment = 1.0;
3619 m_vAdjust->page_increment = (float)(wxMax(fthumb,0));
3620 m_vAdjust->page_size = fthumb;
3621 }
3622
3623 if (orient == wxHORIZONTAL)
3624 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
3625 else
3626 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
3627 }
3628
3629 void wxWindow::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
3630 {
3631 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3632
3633 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
3634
3635 if (orient == wxHORIZONTAL)
3636 {
3637 float fpos = (float)pos;
3638 if (fpos > m_hAdjust->upper - m_hAdjust->page_size) fpos = m_hAdjust->upper - m_hAdjust->page_size;
3639 if (fpos < 0.0) fpos = 0.0;
3640 m_oldHorizontalPos = fpos;
3641
3642 if (fabs(fpos-m_hAdjust->value) < 0.2) return;
3643 m_hAdjust->value = fpos;
3644 }
3645 else
3646 {
3647 float fpos = (float)pos;
3648 if (fpos > m_vAdjust->upper - m_vAdjust->page_size) fpos = m_vAdjust->upper - m_vAdjust->page_size;
3649 if (fpos < 0.0) fpos = 0.0;
3650 m_oldVerticalPos = fpos;
3651
3652 if (fabs(fpos-m_vAdjust->value) < 0.2) return;
3653 m_vAdjust->value = fpos;
3654 }
3655
3656 if (m_wxwindow->window)
3657 {
3658 if (orient == wxHORIZONTAL)
3659 {
3660 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust),
3661 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
3662
3663 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
3664
3665 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
3666 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
3667 }
3668 else
3669 {
3670 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust),
3671 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
3672
3673 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
3674
3675 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
3676 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
3677 }
3678 }
3679 }
3680
3681 int wxWindow::GetScrollThumb( int orient ) const
3682 {
3683 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
3684
3685 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
3686
3687 if (orient == wxHORIZONTAL)
3688 return (int)(m_hAdjust->page_size+0.5);
3689 else
3690 return (int)(m_vAdjust->page_size+0.5);
3691 }
3692
3693 int wxWindow::GetScrollPos( int orient ) const
3694 {
3695 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
3696
3697 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
3698
3699 if (orient == wxHORIZONTAL)
3700 return (int)(m_hAdjust->value+0.5);
3701 else
3702 return (int)(m_vAdjust->value+0.5);
3703 }
3704
3705 int wxWindow::GetScrollRange( int orient ) const
3706 {
3707 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
3708
3709 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
3710
3711 if (orient == wxHORIZONTAL)
3712 return (int)(m_hAdjust->upper+0.5);
3713 else
3714 return (int)(m_vAdjust->upper+0.5);
3715 }
3716
3717 void wxWindow::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
3718 {
3719 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3720
3721 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
3722
3723 if ((dx == 0) && (dy == 0)) return;
3724
3725 m_clipPaintRegion = TRUE;
3726 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
3727 m_clipPaintRegion = FALSE;
3728
3729 /*
3730 if (m_children.GetCount() > 0)
3731 {
3732 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
3733 }
3734 else
3735 {
3736 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
3737
3738 pizza->xoffset -= dx;
3739 pizza->yoffset -= dy;
3740
3741 GdkGC *m_scrollGC = gdk_gc_new( pizza->bin_window );
3742 gdk_gc_set_exposures( m_scrollGC, TRUE );
3743
3744 int cw = 0;
3745 int ch = 0;
3746 GetClientSize( &cw, &ch );
3747 int w = cw - abs(dx);
3748 int h = ch - abs(dy);
3749
3750 if ((h < 0) || (w < 0))
3751 {
3752 Refresh();
3753 }
3754 else
3755 {
3756 int s_x = 0;
3757 int s_y = 0;
3758 if (dx < 0) s_x = -dx;
3759 if (dy < 0) s_y = -dy;
3760 int d_x = 0;
3761 int d_y = 0;
3762 if (dx > 0) d_x = dx;
3763 if (dy > 0) d_y = dy;
3764
3765 gdk_window_copy_area( pizza->bin_window, m_scrollGC, d_x, d_y,
3766 pizza->bin_window, s_x, s_y, w, h );
3767
3768 wxRect rect;
3769 if (dx < 0) rect.x = cw+dx; else rect.x = 0;
3770 if (dy < 0) rect.y = ch+dy; else rect.y = 0;
3771 if (dy != 0) rect.width = cw; else rect.width = abs(dx);
3772 if (dx != 0) rect.height = ch; else rect.height = abs(dy);
3773
3774 Refresh( TRUE, &rect );
3775 }
3776
3777 gdk_gc_unref( m_scrollGC );
3778 }
3779 */
3780 }
3781
3782 // Find the wxWindow at the current mouse position, also returning the mouse
3783 // position.
3784 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
3785 {
3786 pt = wxGetMousePosition();
3787 wxWindow* found = wxFindWindowAtPoint(pt);
3788 return found;
3789 }
3790
3791 // Get the current mouse position.
3792 wxPoint wxGetMousePosition()
3793 {
3794 /* This crashes when used within wxHelpContext,
3795 so we have to use the X-specific implementation below.
3796 gint x, y;
3797 GdkModifierType *mask;
3798 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
3799
3800 return wxPoint(x, y);
3801 */
3802
3803 int x, y;
3804 GdkWindow* windowAtPtr = gdk_window_at_pointer(& x, & y);
3805 if (!windowAtPtr)
3806 return wxPoint(-999, -999);
3807
3808 Display *display = GDK_WINDOW_XDISPLAY(windowAtPtr);
3809 Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
3810 Window rootReturn, childReturn;
3811 int rootX, rootY, winX, winY;
3812 unsigned int maskReturn;
3813
3814 XQueryPointer (display,
3815 rootWindow,
3816 &rootReturn,
3817 &childReturn,
3818 &rootX, &rootY, &winX, &winY, &maskReturn);
3819 return wxPoint(rootX, rootY);
3820
3821 }
3822