]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/window.cpp
fixes from the 2.2 branch
[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 // this is supposed to take care of extra (and unneeded) frame repaints
778 if (win->GetChildren().GetCount() == 0)
779 return;
780
781 /*
782 if (win->GetName() == wxT("panel"))
783 {
784 wxPrintf( wxT("OnDraw from ") );
785 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
786 wxPrintf( win->GetClassInfo()->GetClassName() );
787 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect->x,
788 (int)rect->y,
789 (int)rect->width,
790 (int)rect->height );
791 }
792 */
793
794 GtkPizza *pizza = GTK_PIZZA (widget);
795
796 if (win->GetThemeEnabled())
797 {
798 wxWindow *parent = win->GetParent();
799 while (parent && !parent->IsTopLevel())
800 parent = parent->GetParent();
801 if (!parent)
802 parent = win;
803
804 gtk_paint_flat_box (parent->m_widget->style, pizza->bin_window, GTK_STATE_NORMAL,
805 GTK_SHADOW_NONE, rect, parent->m_widget, "base", 0, 0, -1, -1);
806 }
807
808
809 if (!(GTK_WIDGET_APP_PAINTABLE (widget)) &&
810 (pizza->clear_on_draw))
811 {
812 gdk_window_clear_area( pizza->bin_window,
813 rect->x, rect->y, rect->width, rect->height);
814 }
815
816 win->GetUpdateRegion().Union( rect->x, rect->y, rect->width, rect->height );
817
818 win->m_clipPaintRegion = TRUE;
819
820 wxEraseEvent eevent( win->GetId() );
821 eevent.SetEventObject( win );
822 win->GetEventHandler()->ProcessEvent(eevent);
823
824 wxPaintEvent event( win->GetId() );
825 event.SetEventObject( win );
826 win->GetEventHandler()->ProcessEvent( event );
827
828 win->GetUpdateRegion().Clear();
829
830 win->m_clipPaintRegion = FALSE;
831
832
833 GList *children = pizza->children;
834 while (children)
835 {
836 GtkPizzaChild *child = (GtkPizzaChild*) children->data;
837 children = children->next;
838
839 GdkRectangle child_area;
840 if (gtk_widget_intersect (child->widget, rect, &child_area))
841 {
842 gtk_widget_draw (child->widget, &child_area /* (GdkRectangle*) NULL*/ );
843 }
844 }
845 }
846
847 //-----------------------------------------------------------------------------
848 // "key_press_event" from any window
849 //-----------------------------------------------------------------------------
850
851 static gint gtk_window_key_press_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindow *win )
852 {
853 DEBUG_MAIN_THREAD
854
855 if (g_isIdle)
856 wxapp_install_idle_handler();
857
858 if (!win->m_hasVMT) return FALSE;
859 if (g_blockEventsOnDrag) return FALSE;
860
861
862 /*
863 wxString tmp;
864 tmp += (char)gdk_event->keyval;
865 printf( "KeyDown-Code is: %s.\n", tmp.c_str() );
866 printf( "KeyDown-ScanCode is: %d.\n", gdk_event->keyval );
867 */
868
869 int x = 0;
870 int y = 0;
871 GdkModifierType state;
872 if (gdk_event->window) gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
873
874 bool ret = FALSE;
875
876 long key_code = map_to_unmodified_wx_keysym( gdk_event->keyval );
877 /* sending unknown key events doesn't really make sense */
878 if (key_code == 0) return FALSE;
879
880 wxKeyEvent event( wxEVT_KEY_DOWN );
881 event.SetTimestamp( gdk_event->time );
882 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
883 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
884 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
885 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
886 event.m_keyCode = key_code;
887 event.m_scanCode = gdk_event->keyval;
888 event.m_x = x;
889 event.m_y = y;
890 event.SetEventObject( win );
891 ret = win->GetEventHandler()->ProcessEvent( event );
892
893 #if wxUSE_ACCEL
894 if (!ret)
895 {
896 wxWindow *ancestor = win;
897 while (ancestor)
898 {
899 int command = ancestor->GetAcceleratorTable()->GetCommand( event );
900 if (command != -1)
901 {
902 wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
903 ret = ancestor->GetEventHandler()->ProcessEvent( command_event );
904 break;
905 }
906 if (ancestor->IsTopLevel())
907 break;
908 ancestor = ancestor->GetParent();
909 }
910 }
911 #endif // wxUSE_ACCEL
912
913 /* wxMSW doesn't send char events with Alt pressed */
914 /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
915 will only be sent if it is not in an accelerator table. */
916 key_code = map_to_wx_keysym( gdk_event->keyval );
917
918 if ( (!ret) &&
919 (key_code != 0))
920 {
921 wxKeyEvent event2( wxEVT_CHAR );
922 event2.SetTimestamp( gdk_event->time );
923 event2.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
924 event2.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
925 event2.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
926 event2.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
927 event2.m_keyCode = key_code;
928 event2.m_scanCode = gdk_event->keyval;
929 event2.m_x = x;
930 event2.m_y = y;
931 event2.SetEventObject( win );
932 ret = win->GetEventHandler()->ProcessEvent( event2 );
933 }
934
935 /* win is a control: tab can be propagated up */
936 if ( (!ret) &&
937 ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) &&
938 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
939 // have this style, yet choose not to process this particular TAB in which
940 // case TAB must still work as a navigational character
941 #if 0
942 (!win->HasFlag(wxTE_PROCESS_TAB)) &&
943 #endif // 0
944 (win->GetParent()) &&
945 (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) )
946 {
947 wxNavigationKeyEvent new_event;
948 new_event.SetEventObject( win->GetParent() );
949 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
950 new_event.SetDirection( (gdk_event->keyval == GDK_Tab) );
951 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
952 new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) );
953 new_event.SetCurrentFocus( win );
954 ret = win->GetParent()->GetEventHandler()->ProcessEvent( new_event );
955 }
956
957 /* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
958 if ( (!ret) &&
959 (gdk_event->keyval == GDK_Escape) )
960 {
961 wxCommandEvent new_event(wxEVT_COMMAND_BUTTON_CLICKED,wxID_CANCEL);
962 new_event.SetEventObject( win );
963 ret = win->GetEventHandler()->ProcessEvent( new_event );
964 }
965
966 #if (GTK_MINOR_VERSION > 0)
967 /* Pressing F10 will activate the menu bar of the top frame. */
968 /* Doesn't work. */
969 /*
970 if ( (!ret) &&
971 (gdk_event->keyval == GDK_F10) )
972 {
973 wxWindow *ancestor = win;
974 while (ancestor)
975 {
976 if (wxIsKindOf(ancestor,wxFrame))
977 {
978 wxFrame *frame = (wxFrame*) ancestor;
979 wxMenuBar *menubar = frame->GetMenuBar();
980 if (menubar)
981 {
982 wxNode *node = menubar->GetMenus().First();
983 if (node)
984 {
985 wxMenu *firstMenu = (wxMenu*) node->Data();
986 gtk_menu_item_select( GTK_MENU_ITEM(firstMenu->m_owner) );
987 ret = TRUE;
988 break;
989 }
990 }
991 }
992 ancestor = ancestor->GetParent();
993 }
994 }
995 */
996 #endif
997
998 if (ret)
999 {
1000 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
1001 return TRUE;
1002 }
1003
1004 return FALSE;
1005 }
1006
1007 //-----------------------------------------------------------------------------
1008 // "key_release_event" from any window
1009 //-----------------------------------------------------------------------------
1010
1011 static gint gtk_window_key_release_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindow *win )
1012 {
1013 DEBUG_MAIN_THREAD
1014
1015 if (g_isIdle)
1016 wxapp_install_idle_handler();
1017
1018 if (!win->m_hasVMT) return FALSE;
1019 if (g_blockEventsOnDrag) return FALSE;
1020
1021 /*
1022 printf( "KeyUp-ScanCode is: %d.\n", gdk_event->keyval );
1023 if (gdk_event->state & GDK_SHIFT_MASK)
1024 printf( "ShiftDown.\n" );
1025 else
1026 printf( "ShiftUp.\n" );
1027 if (gdk_event->state & GDK_CONTROL_MASK)
1028 printf( "ControlDown.\n" );
1029 else
1030 printf( "ControlUp.\n" );
1031 printf( "\n" );
1032 */
1033
1034 long key_code = map_to_unmodified_wx_keysym( gdk_event->keyval );
1035
1036 /* sending unknown key events doesn't really make sense */
1037 if (key_code == 0) return FALSE;
1038
1039 int x = 0;
1040 int y = 0;
1041 GdkModifierType state;
1042 if (gdk_event->window) gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
1043
1044 wxKeyEvent event( wxEVT_KEY_UP );
1045 event.SetTimestamp( gdk_event->time );
1046 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1047 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1048 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1049 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1050 event.m_keyCode = key_code;
1051 event.m_scanCode = gdk_event->keyval;
1052 event.m_x = x;
1053 event.m_y = y;
1054 event.SetEventObject( win );
1055
1056 if (win->GetEventHandler()->ProcessEvent( event ))
1057 {
1058 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_release_event" );
1059 return TRUE;
1060 }
1061
1062 return FALSE;
1063 }
1064
1065 // ----------------------------------------------------------------------------
1066 // mouse event processing helper
1067 // ----------------------------------------------------------------------------
1068
1069 static void AdjustEventButtonState(wxMouseEvent& event)
1070 {
1071 // GDK reports the old state of the button for a button press event, but
1072 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1073 // for a LEFT_DOWN event, not FALSE, so we will invert
1074 // left/right/middleDown for the corresponding click events
1075 switch ( event.GetEventType() )
1076 {
1077 case wxEVT_LEFT_DOWN:
1078 case wxEVT_LEFT_DCLICK:
1079 case wxEVT_LEFT_UP:
1080 event.m_leftDown = !event.m_leftDown;
1081 break;
1082
1083 case wxEVT_MIDDLE_DOWN:
1084 case wxEVT_MIDDLE_DCLICK:
1085 case wxEVT_MIDDLE_UP:
1086 event.m_middleDown = !event.m_middleDown;
1087 break;
1088
1089 case wxEVT_RIGHT_DOWN:
1090 case wxEVT_RIGHT_DCLICK:
1091 case wxEVT_RIGHT_UP:
1092 event.m_rightDown = !event.m_rightDown;
1093 break;
1094 }
1095 }
1096
1097 //-----------------------------------------------------------------------------
1098 // "button_press_event"
1099 //-----------------------------------------------------------------------------
1100
1101 static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindow *win )
1102 {
1103 DEBUG_MAIN_THREAD
1104
1105 if (g_isIdle)
1106 wxapp_install_idle_handler();
1107
1108 /*
1109 wxPrintf( wxT("1) OnButtonPress from ") );
1110 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1111 wxPrintf( win->GetClassInfo()->GetClassName() );
1112 wxPrintf( wxT(".\n") );
1113 */
1114 if (!win->m_hasVMT) return FALSE;
1115 if (g_blockEventsOnDrag) return TRUE;
1116 if (g_blockEventsOnScroll) return TRUE;
1117
1118 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1119
1120 if (win->m_wxwindow)
1121 {
1122 if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow) && !GTK_WIDGET_HAS_FOCUS (win->m_wxwindow) )
1123 {
1124 gtk_widget_grab_focus (win->m_wxwindow);
1125
1126 /*
1127 wxPrintf( wxT("GrabFocus from ") );
1128 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1129 wxPrintf( win->GetClassInfo()->GetClassName() );
1130 wxPrintf( wxT(".\n") );
1131 */
1132
1133 }
1134 }
1135
1136 wxEventType event_type = wxEVT_NULL;
1137
1138 if (gdk_event->button == 1)
1139 {
1140 switch (gdk_event->type)
1141 {
1142 case GDK_BUTTON_PRESS: event_type = wxEVT_LEFT_DOWN; break;
1143 case GDK_2BUTTON_PRESS: event_type = wxEVT_LEFT_DCLICK; break;
1144 default: break;
1145 }
1146 }
1147 else if (gdk_event->button == 2)
1148 {
1149 switch (gdk_event->type)
1150 {
1151 case GDK_BUTTON_PRESS: event_type = wxEVT_MIDDLE_DOWN; break;
1152 case GDK_2BUTTON_PRESS: event_type = wxEVT_MIDDLE_DCLICK; break;
1153 default: break;
1154 }
1155 }
1156 else if (gdk_event->button == 3)
1157 {
1158 switch (gdk_event->type)
1159 {
1160 case GDK_BUTTON_PRESS: event_type = wxEVT_RIGHT_DOWN; break;
1161 case GDK_2BUTTON_PRESS: event_type = wxEVT_RIGHT_DCLICK; break;
1162 default: break;
1163 }
1164 }
1165
1166 if ( event_type == wxEVT_NULL )
1167 {
1168 // unknown mouse button or click type
1169 return FALSE;
1170 }
1171
1172 wxMouseEvent event( event_type );
1173 event.SetTimestamp( gdk_event->time );
1174 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1175 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1176 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1177 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1178 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1179 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1180 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1181
1182 event.m_x = (wxCoord)gdk_event->x;
1183 event.m_y = (wxCoord)gdk_event->y;
1184
1185 AdjustEventButtonState(event);
1186
1187 // Some control don't have their own X window and thus cannot get
1188 // any events.
1189
1190 if (!g_captureWindow)
1191 {
1192 wxCoord x = event.m_x;
1193 wxCoord y = event.m_y;
1194 if (win->m_wxwindow)
1195 {
1196 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1197 x += pizza->xoffset;
1198 y += pizza->yoffset;
1199 }
1200
1201 wxNode *node = win->GetChildren().First();
1202 while (node)
1203 {
1204 wxWindow *child = (wxWindow*)node->Data();
1205
1206 node = node->Next();
1207 if (!child->IsShown())
1208 continue;
1209
1210 if (child->m_isStaticBox)
1211 {
1212 // wxStaticBox is transparent in the box itself
1213 int xx1 = child->m_x;
1214 int yy1 = child->m_y;
1215 int xx2 = child->m_x + child->m_width;
1216 int yy2 = child->m_x + child->m_height;
1217
1218 // left
1219 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1220 // right
1221 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1222 // top
1223 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1224 // bottom
1225 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1226 {
1227 win = child;
1228 event.m_x -= child->m_x;
1229 event.m_y -= child->m_y;
1230 break;
1231 }
1232
1233 }
1234 else
1235 {
1236 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1237 (child->m_x <= x) &&
1238 (child->m_y <= y) &&
1239 (child->m_x+child->m_width >= x) &&
1240 (child->m_y+child->m_height >= y))
1241 {
1242 win = child;
1243 event.m_x -= child->m_x;
1244 event.m_y -= child->m_y;
1245 break;
1246 }
1247 }
1248 }
1249 }
1250
1251 event.SetEventObject( win );
1252
1253 gs_timeLastClick = gdk_event->time;
1254
1255 /*
1256 wxPrintf( wxT("2) OnButtonPress from ") );
1257 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1258 wxPrintf( win->GetClassInfo()->GetClassName() );
1259 wxPrintf( wxT(".\n") );
1260 */
1261
1262 if (win->GetEventHandler()->ProcessEvent( event ))
1263 {
1264 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_press_event" );
1265 return TRUE;
1266 }
1267
1268 return FALSE;
1269 }
1270
1271 //-----------------------------------------------------------------------------
1272 // "button_release_event"
1273 //-----------------------------------------------------------------------------
1274
1275 static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindow *win )
1276 {
1277 DEBUG_MAIN_THREAD
1278
1279 if (g_isIdle)
1280 wxapp_install_idle_handler();
1281
1282 if (!win->m_hasVMT) return FALSE;
1283 if (g_blockEventsOnDrag) return FALSE;
1284 if (g_blockEventsOnScroll) return FALSE;
1285
1286 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1287
1288 /*
1289 printf( "OnButtonRelease from " );
1290 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1291 printf( win->GetClassInfo()->GetClassName() );
1292 printf( ".\n" );
1293 */
1294
1295 wxEventType event_type = wxEVT_NULL;
1296
1297 switch (gdk_event->button)
1298 {
1299 case 1: event_type = wxEVT_LEFT_UP; break;
1300 case 2: event_type = wxEVT_MIDDLE_UP; break;
1301 case 3: event_type = wxEVT_RIGHT_UP; break;
1302 default: return FALSE;
1303 }
1304
1305 wxMouseEvent event( event_type );
1306 event.SetTimestamp( gdk_event->time );
1307 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1308 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1309 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1310 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1311 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1312 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1313 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1314 event.m_x = (wxCoord)gdk_event->x;
1315 event.m_y = (wxCoord)gdk_event->y;
1316
1317 AdjustEventButtonState(event);
1318
1319 // Some control don't have their own X window and thus cannot get
1320 // any events.
1321
1322 if (!g_captureWindow)
1323 {
1324 wxCoord x = event.m_x;
1325 wxCoord y = event.m_y;
1326 if (win->m_wxwindow)
1327 {
1328 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1329 x += pizza->xoffset;
1330 y += pizza->yoffset;
1331 }
1332
1333 wxNode *node = win->GetChildren().First();
1334 while (node)
1335 {
1336 wxWindow *child = (wxWindow*)node->Data();
1337
1338 node = node->Next();
1339 if (!child->IsShown())
1340 continue;
1341
1342 if (child->m_isStaticBox)
1343 {
1344 // wxStaticBox is transparent in the box itself
1345 int xx1 = child->m_x;
1346 int yy1 = child->m_y;
1347 int xx2 = child->m_x + child->m_width;
1348 int yy2 = child->m_x + child->m_height;
1349
1350 // left
1351 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1352 // right
1353 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1354 // top
1355 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1356 // bottom
1357 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1358 {
1359 win = child;
1360 event.m_x -= child->m_x;
1361 event.m_y -= child->m_y;
1362 break;
1363 }
1364
1365 }
1366 else
1367 {
1368 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1369 (child->m_x <= x) &&
1370 (child->m_y <= y) &&
1371 (child->m_x+child->m_width >= x) &&
1372 (child->m_y+child->m_height >= y))
1373 {
1374 win = child;
1375 event.m_x -= child->m_x;
1376 event.m_y -= child->m_y;
1377 break;
1378 }
1379 }
1380 }
1381 }
1382
1383 event.SetEventObject( win );
1384
1385 if (win->GetEventHandler()->ProcessEvent( event ))
1386 {
1387 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_release_event" );
1388 return TRUE;
1389 }
1390
1391 return FALSE;
1392 }
1393
1394 //-----------------------------------------------------------------------------
1395 // "motion_notify_event"
1396 //-----------------------------------------------------------------------------
1397
1398 static gint gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion *gdk_event, wxWindow *win )
1399 {
1400 DEBUG_MAIN_THREAD
1401
1402 if (g_isIdle)
1403 wxapp_install_idle_handler();
1404
1405 if (!win->m_hasVMT) return FALSE;
1406 if (g_blockEventsOnDrag) return FALSE;
1407 if (g_blockEventsOnScroll) return FALSE;
1408
1409 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1410
1411 if (gdk_event->is_hint)
1412 {
1413 int x = 0;
1414 int y = 0;
1415 GdkModifierType state;
1416 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
1417 gdk_event->x = x;
1418 gdk_event->y = y;
1419 }
1420
1421 /*
1422 printf( "OnMotion from " );
1423 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1424 printf( win->GetClassInfo()->GetClassName() );
1425 printf( ".\n" );
1426 */
1427
1428 wxMouseEvent event( wxEVT_MOTION );
1429 event.SetTimestamp( gdk_event->time );
1430 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1431 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1432 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1433 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1434 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1435 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1436 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1437
1438 event.m_x = (wxCoord)gdk_event->x;
1439 event.m_y = (wxCoord)gdk_event->y;
1440
1441 // Some control don't have their own X window and thus cannot get
1442 // any events.
1443
1444 if (!g_captureWindow)
1445 {
1446 wxCoord x = event.m_x;
1447 wxCoord y = event.m_y;
1448 if (win->m_wxwindow)
1449 {
1450 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1451 x += pizza->xoffset;
1452 y += pizza->yoffset;
1453 }
1454
1455 wxNode *node = win->GetChildren().First();
1456 while (node)
1457 {
1458 wxWindow *child = (wxWindow*)node->Data();
1459
1460 node = node->Next();
1461 if (!child->IsShown())
1462 continue;
1463
1464 if (child->m_isStaticBox)
1465 {
1466 // wxStaticBox is transparent in the box itself
1467 int xx1 = child->m_x;
1468 int yy1 = child->m_y;
1469 int xx2 = child->m_x + child->m_width;
1470 int yy2 = child->m_x + child->m_height;
1471
1472 // left
1473 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1474 // right
1475 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1476 // top
1477 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1478 // bottom
1479 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1480 {
1481 win = child;
1482 event.m_x -= child->m_x;
1483 event.m_y -= child->m_y;
1484 break;
1485 }
1486
1487 }
1488 else
1489 {
1490 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1491 (child->m_x <= x) &&
1492 (child->m_y <= y) &&
1493 (child->m_x+child->m_width >= x) &&
1494 (child->m_y+child->m_height >= y))
1495 {
1496 win = child;
1497 event.m_x -= child->m_x;
1498 event.m_y -= child->m_y;
1499 break;
1500 }
1501 }
1502 }
1503 }
1504
1505 event.SetEventObject( win );
1506
1507 if (win->GetEventHandler()->ProcessEvent( event ))
1508 {
1509 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "motion_notify_event" );
1510 return TRUE;
1511 }
1512
1513 return FALSE;
1514 }
1515
1516 //-----------------------------------------------------------------------------
1517 // "focus_in_event"
1518 //-----------------------------------------------------------------------------
1519
1520 static gint gtk_window_focus_in_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindow *win )
1521 {
1522 DEBUG_MAIN_THREAD
1523
1524 if (g_isIdle)
1525 wxapp_install_idle_handler();
1526
1527 if (!win->m_hasVMT) return FALSE;
1528 if (g_blockEventsOnDrag) return FALSE;
1529
1530 switch ( g_sendActivateEvent )
1531 {
1532 case -1:
1533 // we've got focus from outside, synthtize wxActivateEvent
1534 g_sendActivateEvent = 1;
1535 break;
1536
1537 case 0:
1538 // another our window just lost focus, it was already ours before
1539 // - don't send any wxActivateEvent
1540 g_sendActivateEvent = -1;
1541 break;
1542 }
1543
1544 g_focusWindow = win;
1545
1546 /*
1547 printf( "OnSetFocus from " );
1548 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1549 printf( win->GetClassInfo()->GetClassName() );
1550 printf( " " );
1551 printf( WXSTRINGCAST win->GetLabel() );
1552 printf( ".\n" );
1553 */
1554
1555 wxPanel *panel = wxDynamicCast(win->GetParent(), wxPanel);
1556 if (panel)
1557 {
1558 panel->SetLastFocus(win);
1559 }
1560
1561 #ifdef HAVE_XIM
1562 if (win->m_ic)
1563 gdk_im_begin(win->m_ic, win->m_wxwindow->window);
1564 #endif
1565
1566 #ifdef wxUSE_CARET
1567 // caret needs to be informed about focus change
1568 wxCaret *caret = win->GetCaret();
1569 if ( caret )
1570 {
1571 caret->OnSetFocus();
1572 }
1573 #endif // wxUSE_CARET
1574
1575 wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() );
1576 event.SetEventObject( win );
1577
1578 if (win->GetEventHandler()->ProcessEvent( event ))
1579 {
1580 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
1581 return TRUE;
1582 }
1583
1584 return FALSE;
1585 }
1586
1587 //-----------------------------------------------------------------------------
1588 // "focus_out_event"
1589 //-----------------------------------------------------------------------------
1590
1591 static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindow *win )
1592 {
1593 DEBUG_MAIN_THREAD
1594
1595 if (g_isIdle)
1596 wxapp_install_idle_handler();
1597
1598 if (!win->m_hasVMT) return FALSE;
1599 if (g_blockEventsOnDrag) return FALSE;
1600
1601 // if the focus goes out of our app alltogether, OnIdle() will send
1602 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1603 // g_sendActivateEvent to -1
1604 g_sendActivateEvent = 0;
1605
1606 wxWindow *winFocus = FindFocusedChild(win);
1607 if ( winFocus )
1608 win = winFocus;
1609
1610 g_focusWindow = (wxWindow *)NULL;
1611
1612 /*
1613 printf( "OnKillFocus from " );
1614 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1615 printf( win->GetClassInfo()->GetClassName() );
1616 printf( ".\n" );
1617 */
1618
1619 #ifdef HAVE_XIM
1620 if (win->m_ic)
1621 gdk_im_end();
1622 #endif
1623
1624 #ifdef wxUSE_CARET
1625 // caret needs to be informed about focus change
1626 wxCaret *caret = win->GetCaret();
1627 if ( caret )
1628 {
1629 caret->OnKillFocus();
1630 }
1631 #endif // wxUSE_CARET
1632
1633 wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
1634 event.SetEventObject( win );
1635
1636 if (win->GetEventHandler()->ProcessEvent( event ))
1637 {
1638 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_out_event" );
1639 return TRUE;
1640 }
1641
1642 return FALSE;
1643 }
1644
1645 //-----------------------------------------------------------------------------
1646 // "enter_notify_event"
1647 //-----------------------------------------------------------------------------
1648
1649 static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindow *win )
1650 {
1651 DEBUG_MAIN_THREAD
1652
1653 if (g_isIdle)
1654 wxapp_install_idle_handler();
1655
1656 if (!win->m_hasVMT) return FALSE;
1657 if (g_blockEventsOnDrag) return FALSE;
1658
1659 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1660
1661 wxMouseEvent event( wxEVT_ENTER_WINDOW );
1662 #if (GTK_MINOR_VERSION > 0)
1663 event.SetTimestamp( gdk_event->time );
1664 #endif
1665 event.SetEventObject( win );
1666
1667 int x = 0;
1668 int y = 0;
1669 GdkModifierType state = (GdkModifierType)0;
1670
1671 gdk_window_get_pointer( widget->window, &x, &y, &state );
1672
1673 event.m_shiftDown = (state & GDK_SHIFT_MASK);
1674 event.m_controlDown = (state & GDK_CONTROL_MASK);
1675 event.m_altDown = (state & GDK_MOD1_MASK);
1676 event.m_metaDown = (state & GDK_MOD2_MASK);
1677 event.m_leftDown = (state & GDK_BUTTON1_MASK);
1678 event.m_middleDown = (state & GDK_BUTTON2_MASK);
1679 event.m_rightDown = (state & GDK_BUTTON3_MASK);
1680
1681 event.m_x = x;
1682 event.m_y = y;
1683
1684 if (win->GetEventHandler()->ProcessEvent( event ))
1685 {
1686 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "enter_notify_event" );
1687 return TRUE;
1688 }
1689
1690 return FALSE;
1691 }
1692
1693 //-----------------------------------------------------------------------------
1694 // "leave_notify_event"
1695 //-----------------------------------------------------------------------------
1696
1697 static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindow *win )
1698 {
1699 DEBUG_MAIN_THREAD
1700
1701 if (g_isIdle)
1702 wxapp_install_idle_handler();
1703
1704 if (!win->m_hasVMT) return FALSE;
1705 if (g_blockEventsOnDrag) return FALSE;
1706
1707 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1708
1709 wxMouseEvent event( wxEVT_LEAVE_WINDOW );
1710 #if (GTK_MINOR_VERSION > 0)
1711 event.SetTimestamp( gdk_event->time );
1712 #endif
1713 event.SetEventObject( win );
1714
1715 int x = 0;
1716 int y = 0;
1717 GdkModifierType state = (GdkModifierType)0;
1718
1719 gdk_window_get_pointer( widget->window, &x, &y, &state );
1720
1721 event.m_shiftDown = (state & GDK_SHIFT_MASK);
1722 event.m_controlDown = (state & GDK_CONTROL_MASK);
1723 event.m_altDown = (state & GDK_MOD1_MASK);
1724 event.m_metaDown = (state & GDK_MOD2_MASK);
1725 event.m_leftDown = (state & GDK_BUTTON1_MASK);
1726 event.m_middleDown = (state & GDK_BUTTON2_MASK);
1727 event.m_rightDown = (state & GDK_BUTTON3_MASK);
1728
1729 event.m_x = x;
1730 event.m_y = y;
1731
1732 if (win->GetEventHandler()->ProcessEvent( event ))
1733 {
1734 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "leave_notify_event" );
1735 return TRUE;
1736 }
1737
1738 return FALSE;
1739 }
1740
1741 //-----------------------------------------------------------------------------
1742 // "value_changed" from m_vAdjust
1743 //-----------------------------------------------------------------------------
1744
1745 static void gtk_window_vscroll_callback( GtkAdjustment *adjust, wxWindow *win )
1746 {
1747 DEBUG_MAIN_THREAD
1748
1749 if (g_isIdle)
1750 wxapp_install_idle_handler();
1751
1752 if (g_blockEventsOnDrag) return;
1753
1754 if (!win->m_hasVMT) return;
1755
1756 float diff = adjust->value - win->m_oldVerticalPos;
1757 if (fabs(diff) < 0.2) return;
1758
1759 win->m_oldVerticalPos = adjust->value;
1760
1761 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1762 GtkRange *range = GTK_RANGE( scrolledWindow->vscrollbar );
1763
1764 wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK;
1765 if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP;
1766 else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN;
1767 else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP;
1768 else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN;
1769
1770 int value = (int)(adjust->value+0.5);
1771
1772 wxScrollWinEvent event( command, value, wxVERTICAL );
1773 event.SetEventObject( win );
1774 win->GetEventHandler()->ProcessEvent( event );
1775 }
1776
1777 //-----------------------------------------------------------------------------
1778 // "value_changed" from m_hAdjust
1779 //-----------------------------------------------------------------------------
1780
1781 static void gtk_window_hscroll_callback( GtkAdjustment *adjust, wxWindow *win )
1782 {
1783 DEBUG_MAIN_THREAD
1784
1785 if (g_isIdle)
1786 wxapp_install_idle_handler();
1787
1788 if (g_blockEventsOnDrag) return;
1789 if (!win->m_hasVMT) return;
1790
1791 float diff = adjust->value - win->m_oldHorizontalPos;
1792 if (fabs(diff) < 0.2) return;
1793
1794 win->m_oldHorizontalPos = adjust->value;
1795
1796 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1797 GtkRange *range = GTK_RANGE( scrolledWindow->hscrollbar );
1798
1799 wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK;
1800 if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP;
1801 else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN;
1802 else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP;
1803 else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN;
1804
1805 int value = (int)(adjust->value+0.5);
1806
1807 wxScrollWinEvent event( command, value, wxHORIZONTAL );
1808 event.SetEventObject( win );
1809 win->GetEventHandler()->ProcessEvent( event );
1810 }
1811
1812 //-----------------------------------------------------------------------------
1813 // "button_press_event" from scrollbar
1814 //-----------------------------------------------------------------------------
1815
1816 static gint gtk_scrollbar_button_press_callback( GtkRange *widget,
1817 GdkEventButton *gdk_event,
1818 wxWindow *win)
1819 {
1820 DEBUG_MAIN_THREAD
1821
1822 if (g_isIdle)
1823 wxapp_install_idle_handler();
1824
1825
1826 g_blockEventsOnScroll = TRUE;
1827 win->m_isScrolling = (gdk_event->window == widget->slider);
1828
1829 return FALSE;
1830 }
1831
1832 //-----------------------------------------------------------------------------
1833 // "button_release_event" from scrollbar
1834 //-----------------------------------------------------------------------------
1835
1836 static gint gtk_scrollbar_button_release_callback( GtkRange *widget,
1837 GdkEventButton *WXUNUSED(gdk_event),
1838 wxWindow *win)
1839 {
1840 DEBUG_MAIN_THREAD
1841
1842 // don't test here as we can release the mouse while being over
1843 // a different window than the slider
1844 //
1845 // if (gdk_event->window != widget->slider) return FALSE;
1846
1847 g_blockEventsOnScroll = FALSE;
1848
1849 if (win->m_isScrolling)
1850 {
1851 wxEventType command = wxEVT_SCROLLWIN_THUMBRELEASE;
1852 int value = -1;
1853 int dir = -1;
1854
1855 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1856 if (widget == GTK_RANGE(scrolledWindow->hscrollbar))
1857 {
1858 value = (int)(win->m_hAdjust->value+0.5);
1859 dir = wxHORIZONTAL;
1860 }
1861 if (widget == GTK_RANGE(scrolledWindow->vscrollbar))
1862 {
1863 value = (int)(win->m_vAdjust->value+0.5);
1864 dir = wxVERTICAL;
1865 }
1866
1867 wxScrollWinEvent event( command, value, dir );
1868 event.SetEventObject( win );
1869 win->GetEventHandler()->ProcessEvent( event );
1870 }
1871
1872 win->m_isScrolling = FALSE;
1873
1874 return FALSE;
1875 }
1876
1877 // ----------------------------------------------------------------------------
1878 // this wxWindowBase function is implemented here (in platform-specific file)
1879 // because it is static and so couldn't be made virtual
1880 // ----------------------------------------------------------------------------
1881
1882 wxWindow *wxWindowBase::FindFocus()
1883 {
1884 return g_focusWindow;
1885 }
1886
1887 //-----------------------------------------------------------------------------
1888 // "realize" from m_widget
1889 //-----------------------------------------------------------------------------
1890
1891 /* We cannot set colours and fonts before the widget has
1892 been realized, so we do this directly after realization. */
1893
1894 static gint
1895 gtk_window_realized_callback( GtkWidget *WXUNUSED(m_widget), wxWindow *win )
1896 {
1897 DEBUG_MAIN_THREAD
1898
1899 if (g_isIdle)
1900 wxapp_install_idle_handler();
1901
1902 if (win->m_delayedBackgroundColour)
1903 win->SetBackgroundColour( win->GetBackgroundColour() );
1904
1905 if (win->m_delayedForegroundColour)
1906 win->SetForegroundColour( win->GetForegroundColour() );
1907
1908 wxWindowCreateEvent event( win );
1909 event.SetEventObject( win );
1910 win->GetEventHandler()->ProcessEvent( event );
1911
1912 return FALSE;
1913 }
1914
1915 //-----------------------------------------------------------------------------
1916 // "size_allocate"
1917 //-----------------------------------------------------------------------------
1918
1919 static
1920 void gtk_window_size_callback( GtkWidget *WXUNUSED(widget),
1921 GtkAllocation *WXUNUSED(alloc),
1922 wxWindow *win )
1923 {
1924 if (g_isIdle)
1925 wxapp_install_idle_handler();
1926
1927 if (!win->m_hasScrolling) return;
1928
1929 int client_width = 0;
1930 int client_height = 0;
1931 win->GetClientSize( &client_width, &client_height );
1932 if ((client_width == win->m_oldClientWidth) && (client_height == win->m_oldClientHeight))
1933 return;
1934
1935 win->m_oldClientWidth = client_width;
1936 win->m_oldClientHeight = client_height;
1937
1938 if (!win->m_nativeSizeEvent)
1939 {
1940 wxSizeEvent event( win->GetSize(), win->GetId() );
1941 event.SetEventObject( win );
1942 win->GetEventHandler()->ProcessEvent( event );
1943 }
1944 }
1945
1946
1947 #ifdef HAVE_XIM
1948 #define WXUNUSED_UNLESS_XIM(param) param
1949 #else
1950 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
1951 #endif
1952
1953 /* Resize XIM window */
1954
1955 static
1956 void gtk_wxwindow_size_callback( GtkWidget* WXUNUSED_UNLESS_XIM(widget),
1957 GtkAllocation* WXUNUSED_UNLESS_XIM(alloc),
1958 wxWindow* WXUNUSED_UNLESS_XIM(win) )
1959 {
1960 if (g_isIdle)
1961 wxapp_install_idle_handler();
1962
1963 #ifdef HAVE_XIM
1964 if (!win->m_ic)
1965 return;
1966
1967 if (gdk_ic_get_style (win->m_ic) & GDK_IM_PREEDIT_POSITION)
1968 {
1969 gint width, height;
1970
1971 gdk_window_get_size (widget->window, &width, &height);
1972 win->m_icattr->preedit_area.width = width;
1973 win->m_icattr->preedit_area.height = height;
1974 gdk_ic_set_attr (win->m_ic, win->m_icattr, GDK_IC_PREEDIT_AREA);
1975 }
1976 #endif // HAVE_XIM
1977 }
1978
1979 //-----------------------------------------------------------------------------
1980 // "realize" from m_wxwindow
1981 //-----------------------------------------------------------------------------
1982
1983 /* Initialize XIM support */
1984
1985 static gint
1986 gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget),
1987 wxWindow * WXUNUSED_UNLESS_XIM(win) )
1988 {
1989 if (g_isIdle)
1990 wxapp_install_idle_handler();
1991
1992 #ifdef HAVE_XIM
1993 if (win->m_ic) return FALSE;
1994 if (!widget) return FALSE;
1995 if (!gdk_im_ready()) return FALSE;
1996
1997 win->m_icattr = gdk_ic_attr_new();
1998 if (!win->m_icattr) return FALSE;
1999
2000 gint width, height;
2001 GdkEventMask mask;
2002 GdkColormap *colormap;
2003 GdkICAttr *attr = win->m_icattr;
2004 unsigned attrmask = GDK_IC_ALL_REQ;
2005 GdkIMStyle style;
2006 GdkIMStyle supported_style = (GdkIMStyle)
2007 (GDK_IM_PREEDIT_NONE |
2008 GDK_IM_PREEDIT_NOTHING |
2009 GDK_IM_PREEDIT_POSITION |
2010 GDK_IM_STATUS_NONE |
2011 GDK_IM_STATUS_NOTHING);
2012
2013 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
2014 supported_style = (GdkIMStyle)(supported_style & ~GDK_IM_PREEDIT_POSITION);
2015
2016 attr->style = style = gdk_im_decide_style (supported_style);
2017 attr->client_window = widget->window;
2018
2019 if ((colormap = gtk_widget_get_colormap (widget)) !=
2020 gtk_widget_get_default_colormap ())
2021 {
2022 attrmask |= GDK_IC_PREEDIT_COLORMAP;
2023 attr->preedit_colormap = colormap;
2024 }
2025
2026 attrmask |= GDK_IC_PREEDIT_FOREGROUND;
2027 attrmask |= GDK_IC_PREEDIT_BACKGROUND;
2028 attr->preedit_foreground = widget->style->fg[GTK_STATE_NORMAL];
2029 attr->preedit_background = widget->style->base[GTK_STATE_NORMAL];
2030
2031 switch (style & GDK_IM_PREEDIT_MASK)
2032 {
2033 case GDK_IM_PREEDIT_POSITION:
2034 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
2035 {
2036 g_warning ("over-the-spot style requires fontset");
2037 break;
2038 }
2039
2040 gdk_window_get_size (widget->window, &width, &height);
2041
2042 attrmask |= GDK_IC_PREEDIT_POSITION_REQ;
2043 attr->spot_location.x = 0;
2044 attr->spot_location.y = height;
2045 attr->preedit_area.x = 0;
2046 attr->preedit_area.y = 0;
2047 attr->preedit_area.width = width;
2048 attr->preedit_area.height = height;
2049 attr->preedit_fontset = widget->style->font;
2050
2051 break;
2052 }
2053
2054 win->m_ic = gdk_ic_new (attr, (GdkICAttributesType)attrmask);
2055
2056 if (win->m_ic == NULL)
2057 g_warning ("Can't create input context.");
2058 else
2059 {
2060 mask = gdk_window_get_events (widget->window);
2061 mask = (GdkEventMask)(mask | gdk_ic_get_events (win->m_ic));
2062 gdk_window_set_events (widget->window, mask);
2063
2064 if (GTK_WIDGET_HAS_FOCUS(widget))
2065 gdk_im_begin (win->m_ic, widget->window);
2066 }
2067 #endif
2068
2069 return FALSE;
2070 }
2071
2072 //-----------------------------------------------------------------------------
2073 // InsertChild for wxWindow.
2074 //-----------------------------------------------------------------------------
2075
2076 /* Callback for wxWindow. This very strange beast has to be used because
2077 * C++ has no virtual methods in a constructor. We have to emulate a
2078 * virtual function here as wxNotebook requires a different way to insert
2079 * a child in it. I had opted for creating a wxNotebookPage window class
2080 * which would have made this superfluous (such in the MDI window system),
2081 * but no-one was listening to me... */
2082
2083 static void wxInsertChildInWindow( wxWindow* parent, wxWindow* child )
2084 {
2085 /* the window might have been scrolled already, do we
2086 have to adapt the position */
2087 GtkPizza *pizza = GTK_PIZZA(parent->m_wxwindow);
2088 child->m_x += pizza->xoffset;
2089 child->m_y += pizza->yoffset;
2090
2091 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
2092 GTK_WIDGET(child->m_widget),
2093 child->m_x,
2094 child->m_y,
2095 child->m_width,
2096 child->m_height );
2097 }
2098
2099 //-----------------------------------------------------------------------------
2100 // global functions
2101 //-----------------------------------------------------------------------------
2102
2103 wxWindow* wxGetActiveWindow()
2104 {
2105 return g_focusWindow;
2106 }
2107
2108 //-----------------------------------------------------------------------------
2109 // wxWindow
2110 //-----------------------------------------------------------------------------
2111
2112 IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
2113
2114 void wxWindow::Init()
2115 {
2116 // common init
2117 InitBase();
2118
2119 // GTK specific
2120 m_widget = (GtkWidget *) NULL;
2121 m_wxwindow = (GtkWidget *) NULL;
2122
2123 // position/size
2124 m_x = 0;
2125 m_y = 0;
2126 m_width = 0;
2127 m_height = 0;
2128
2129 m_sizeSet = FALSE;
2130 m_hasVMT = FALSE;
2131 m_needParent = TRUE;
2132 m_isBeingDeleted = FALSE;
2133
2134 m_noExpose = FALSE;
2135 m_nativeSizeEvent = FALSE;
2136
2137 m_hasScrolling = FALSE;
2138 m_isScrolling = FALSE;
2139
2140 m_hAdjust = (GtkAdjustment*) NULL;
2141 m_vAdjust = (GtkAdjustment*) NULL;
2142 m_oldHorizontalPos = 0.0;
2143 m_oldVerticalPos = 0.0;
2144
2145 m_resizing = FALSE;
2146 m_widgetStyle = (GtkStyle*) NULL;
2147
2148 m_insertCallback = (wxInsertChildFunction) NULL;
2149
2150 m_isStaticBox = FALSE;
2151 m_isRadioButton = FALSE;
2152 m_isFrame = FALSE;
2153 m_acceptsFocus = FALSE;
2154
2155 m_clipPaintRegion = FALSE;
2156
2157 m_cursor = *wxSTANDARD_CURSOR;
2158
2159 m_delayedForegroundColour = FALSE;
2160 m_delayedBackgroundColour = FALSE;
2161
2162 #ifdef HAVE_XIM
2163 m_ic = (GdkIC*) NULL;
2164 m_icattr = (GdkICAttr*) NULL;
2165 #endif
2166 }
2167
2168 wxWindow::wxWindow()
2169 {
2170 Init();
2171 }
2172
2173 wxWindow::wxWindow( wxWindow *parent, wxWindowID id,
2174 const wxPoint &pos, const wxSize &size,
2175 long style, const wxString &name )
2176 {
2177 Init();
2178
2179 Create( parent, id, pos, size, style, name );
2180 }
2181
2182 bool wxWindow::Create( wxWindow *parent, wxWindowID id,
2183 const wxPoint &pos, const wxSize &size,
2184 long style, const wxString &name )
2185 {
2186 if (!PreCreation( parent, pos, size ) ||
2187 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
2188 {
2189 wxFAIL_MSG( wxT("wxWindow creation failed") );
2190 return FALSE;
2191 }
2192
2193 m_insertCallback = wxInsertChildInWindow;
2194
2195 m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
2196 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
2197
2198 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
2199
2200 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
2201 scroll_class->scrollbar_spacing = 0;
2202
2203 gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
2204
2205 m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->hscrollbar) );
2206 m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->vscrollbar) );
2207
2208 m_wxwindow = gtk_pizza_new();
2209
2210 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
2211
2212 #if (GTK_MINOR_VERSION > 0)
2213 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
2214
2215 if (HasFlag(wxRAISED_BORDER))
2216 {
2217 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_OUT );
2218 }
2219 else if (HasFlag(wxSUNKEN_BORDER))
2220 {
2221 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_IN );
2222 }
2223 else if (HasFlag(wxSIMPLE_BORDER))
2224 {
2225 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_THIN );
2226 }
2227 else
2228 {
2229 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_NONE );
2230 }
2231 #else // GTK_MINOR_VERSION == 0
2232 GtkViewport *viewport = GTK_VIEWPORT(scrolledWindow->viewport);
2233
2234 if (HasFlag(wxRAISED_BORDER))
2235 {
2236 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_OUT );
2237 }
2238 else if (HasFlag(wxSUNKEN_BORDER))
2239 {
2240 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_IN );
2241 }
2242 else
2243 {
2244 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_NONE );
2245 }
2246 #endif // GTK_MINOR_VERSION
2247
2248 GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
2249 m_acceptsFocus = TRUE;
2250
2251 #if (GTK_MINOR_VERSION == 0)
2252 // shut the viewport up
2253 gtk_viewport_set_hadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
2254 gtk_viewport_set_vadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
2255 #endif // GTK_MINOR_VERSION == 0
2256
2257 // I _really_ don't want scrollbars in the beginning
2258 m_vAdjust->lower = 0.0;
2259 m_vAdjust->upper = 1.0;
2260 m_vAdjust->value = 0.0;
2261 m_vAdjust->step_increment = 1.0;
2262 m_vAdjust->page_increment = 1.0;
2263 m_vAdjust->page_size = 5.0;
2264 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
2265 m_hAdjust->lower = 0.0;
2266 m_hAdjust->upper = 1.0;
2267 m_hAdjust->value = 0.0;
2268 m_hAdjust->step_increment = 1.0;
2269 m_hAdjust->page_increment = 1.0;
2270 m_hAdjust->page_size = 5.0;
2271 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
2272
2273 // these handlers block mouse events to any window during scrolling such as
2274 // motion events and prevent GTK and wxWindows from fighting over where the
2275 // slider should be
2276
2277 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_press_event",
2278 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2279
2280 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_press_event",
2281 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2282
2283 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_release_event",
2284 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2285
2286 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_release_event",
2287 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2288
2289 // these handlers get notified when screen updates are required either when
2290 // scrolling or when the window size (and therefore scrollbar configuration)
2291 // has changed
2292
2293 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
2294 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
2295 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
2296 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
2297
2298 gtk_widget_show( m_wxwindow );
2299
2300 if (m_parent)
2301 m_parent->DoAddChild( this );
2302
2303 PostCreation();
2304
2305 Show( TRUE );
2306
2307 return TRUE;
2308 }
2309
2310 wxWindow::~wxWindow()
2311 {
2312 m_isBeingDeleted = TRUE;
2313 m_hasVMT = FALSE;
2314
2315 if (m_widget)
2316 Show( FALSE );
2317
2318 DestroyChildren();
2319
2320 if (m_parent)
2321 m_parent->RemoveChild( this );
2322
2323 #ifdef HAVE_XIM
2324 if (m_ic)
2325 gdk_ic_destroy (m_ic);
2326 if (m_icattr)
2327 gdk_ic_attr_destroy (m_icattr);
2328 #endif
2329
2330 if (m_widgetStyle)
2331 {
2332 #if DISABLE_STYLE_IF_BROKEN_THEME
2333 // don't delete if it's a pixmap theme style
2334 if (!m_widgetStyle->engine_data)
2335 gtk_style_unref( m_widgetStyle );
2336 #endif
2337 m_widgetStyle = (GtkStyle*) NULL;
2338 }
2339
2340 if (m_wxwindow)
2341 {
2342 gtk_widget_destroy( m_wxwindow );
2343 m_wxwindow = (GtkWidget*) NULL;
2344 }
2345
2346 if (m_widget)
2347 {
2348 gtk_widget_destroy( m_widget );
2349 m_widget = (GtkWidget*) NULL;
2350 }
2351 }
2352
2353 bool wxWindow::PreCreation( wxWindow *parent, const wxPoint &pos, const wxSize &size )
2354 {
2355 wxCHECK_MSG( !m_needParent || parent, FALSE, wxT("Need complete parent.") );
2356
2357 /* this turns -1 into 20 so that a minimal window is
2358 visible even although -1,-1 has been given as the
2359 size of the window. the same trick is used in other
2360 ports and should make debugging easier */
2361 m_width = WidthDefault(size.x);
2362 m_height = HeightDefault(size.y);
2363
2364 m_x = (int)pos.x;
2365 m_y = (int)pos.y;
2366
2367 /* some reasonable defaults */
2368 if (!parent)
2369 {
2370 if (m_x == -1)
2371 {
2372 m_x = (gdk_screen_width () - m_width) / 2;
2373 if (m_x < 10) m_x = 10;
2374 }
2375 if (m_y == -1)
2376 {
2377 m_y = (gdk_screen_height () - m_height) / 2;
2378 if (m_y < 10) m_y = 10;
2379 }
2380 }
2381
2382 return TRUE;
2383 }
2384
2385 void wxWindow::PostCreation()
2386 {
2387 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2388
2389 if (m_wxwindow)
2390 {
2391 if (!m_noExpose)
2392 {
2393 /* these get reported to wxWindows -> wxPaintEvent */
2394
2395 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow), TRUE );
2396
2397 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "event",
2398 GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this );
2399
2400 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
2401 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
2402
2403 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
2404 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
2405 }
2406
2407 #if (GTK_MINOR_VERSION > 0)
2408 /* these are called when the "sunken" or "raised" borders are drawn */
2409 gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
2410 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
2411
2412 gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
2413 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
2414 #endif
2415 }
2416
2417 if (m_wxwindow && m_needParent)
2418 {
2419 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "focus_in_event",
2420 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
2421
2422 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "focus_out_event",
2423 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
2424 }
2425 else
2426 {
2427 // For dialogs and frames, we are interested mainly in
2428 // m_widget's focus.
2429
2430 gtk_signal_connect( GTK_OBJECT(m_widget), "focus_in_event",
2431 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
2432
2433 gtk_signal_connect( GTK_OBJECT(m_widget), "focus_out_event",
2434 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
2435 }
2436
2437 GtkWidget *connect_widget = GetConnectWidget();
2438
2439 ConnectWidget( connect_widget );
2440
2441 /* We cannot set colours, fonts and cursors before the widget has
2442 been realized, so we do this directly after realization */
2443 gtk_signal_connect( GTK_OBJECT(connect_widget), "realize",
2444 GTK_SIGNAL_FUNC(gtk_window_realized_callback), (gpointer) this );
2445
2446 if (m_wxwindow)
2447 {
2448 /* Catch native resize events. */
2449 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2450 GTK_SIGNAL_FUNC(gtk_window_size_callback), (gpointer)this );
2451
2452 /* Initialize XIM support. */
2453 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "realize",
2454 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback), (gpointer) this );
2455
2456 /* And resize XIM window. */
2457 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2458 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this );
2459 }
2460
2461 m_hasVMT = TRUE;
2462 }
2463
2464 void wxWindow::ConnectWidget( GtkWidget *widget )
2465 {
2466 gtk_signal_connect( GTK_OBJECT(widget), "key_press_event",
2467 GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this );
2468
2469 gtk_signal_connect( GTK_OBJECT(widget), "key_release_event",
2470 GTK_SIGNAL_FUNC(gtk_window_key_release_callback), (gpointer)this );
2471
2472 gtk_signal_connect( GTK_OBJECT(widget), "button_press_event",
2473 GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
2474
2475 gtk_signal_connect( GTK_OBJECT(widget), "button_release_event",
2476 GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
2477
2478 gtk_signal_connect( GTK_OBJECT(widget), "motion_notify_event",
2479 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
2480
2481 gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event",
2482 GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
2483
2484 gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
2485 GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
2486 }
2487
2488 bool wxWindow::Destroy()
2489 {
2490 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2491
2492 m_hasVMT = FALSE;
2493
2494 return wxWindowBase::Destroy();
2495 }
2496
2497 void wxWindow::DoMoveWindow(int x, int y, int width, int height)
2498 {
2499 gtk_pizza_set_size( GTK_PIZZA(m_parent->m_wxwindow), m_widget, x, y, width, height );
2500 }
2501
2502 void wxWindow::DoSetSize( int x, int y, int width, int height, int sizeFlags )
2503 {
2504 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2505 wxASSERT_MSG( (m_parent != NULL), wxT("wxWindow::SetSize requires parent.\n") );
2506
2507 if (m_resizing) return; /* I don't like recursions */
2508 m_resizing = TRUE;
2509
2510 if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
2511 {
2512 /* don't set the size for children of wxNotebook, just take the values. */
2513 m_x = x;
2514 m_y = y;
2515 m_width = width;
2516 m_height = height;
2517 }
2518 else
2519 {
2520 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
2521
2522 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
2523 {
2524 if (x != -1) m_x = x + pizza->xoffset;
2525 if (y != -1) m_y = y + pizza->yoffset;
2526 if (width != -1) m_width = width;
2527 if (height != -1) m_height = height;
2528 }
2529 else
2530 {
2531 m_x = x + pizza->xoffset;
2532 m_y = y + pizza->yoffset;
2533 m_width = width;
2534 m_height = height;
2535 }
2536
2537 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
2538 {
2539 if (width == -1) m_width = 80;
2540 }
2541
2542 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
2543 {
2544 if (height == -1) m_height = 26;
2545 }
2546
2547 if ((m_minWidth != -1) && (m_width < m_minWidth)) m_width = m_minWidth;
2548 if ((m_minHeight != -1) && (m_height < m_minHeight)) m_height = m_minHeight;
2549 if ((m_maxWidth != -1) && (m_width > m_maxWidth)) m_width = m_maxWidth;
2550 if ((m_maxHeight != -1) && (m_height > m_maxHeight)) m_height = m_maxHeight;
2551
2552 int border = 0;
2553 int bottom_border = 0;
2554
2555 if (GTK_WIDGET_CAN_DEFAULT(m_widget))
2556 {
2557 /* the default button has a border around it */
2558 border = 6;
2559 bottom_border = 5;
2560 }
2561
2562 DoMoveWindow( m_x-border,
2563 m_y-border,
2564 m_width+2*border,
2565 m_height+border+bottom_border );
2566 }
2567
2568 if (m_hasScrolling)
2569 {
2570 /* Sometimes the client area changes size without the
2571 whole windows's size changing, but if the whole
2572 windows's size doesn't change, no wxSizeEvent will
2573 normally be sent. Here we add an extra test if
2574 the client test has been changed and this will
2575 be used then. */
2576 GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
2577 }
2578
2579 /*
2580 wxPrintf( "OnSize sent from " );
2581 if (GetClassInfo() && GetClassInfo()->GetClassName())
2582 wxPrintf( GetClassInfo()->GetClassName() );
2583 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2584 */
2585
2586 if (!m_nativeSizeEvent)
2587 {
2588 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
2589 event.SetEventObject( this );
2590 GetEventHandler()->ProcessEvent( event );
2591 }
2592
2593 m_resizing = FALSE;
2594 }
2595
2596 void wxWindow::OnInternalIdle()
2597 {
2598 if ( g_sendActivateEvent != -1 )
2599 {
2600 bool activate = g_sendActivateEvent != 0;
2601
2602 // do it only once
2603 g_sendActivateEvent = -1;
2604
2605 wxActivateEvent event(wxEVT_ACTIVATE, activate, GetId());
2606 event.SetEventObject(this);
2607
2608 (void)GetEventHandler()->ProcessEvent(event);
2609 }
2610
2611 wxCursor cursor = m_cursor;
2612 if (g_globalCursor.Ok()) cursor = g_globalCursor;
2613
2614 if (cursor.Ok())
2615 {
2616 /* I now set the cursor anew in every OnInternalIdle call
2617 as setting the cursor in a parent window also effects the
2618 windows above so that checking for the current cursor is
2619 not possible. */
2620
2621 if (m_wxwindow)
2622 {
2623 GdkWindow *window = GTK_PIZZA(m_wxwindow)->bin_window;
2624 if (window)
2625 gdk_window_set_cursor( window, cursor.GetCursor() );
2626
2627 if (!g_globalCursor.Ok())
2628 cursor = *wxSTANDARD_CURSOR;
2629
2630 window = m_widget->window;
2631 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
2632 gdk_window_set_cursor( window, cursor.GetCursor() );
2633
2634 }
2635 else
2636 {
2637
2638 GdkWindow *window = m_widget->window;
2639 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
2640 gdk_window_set_cursor( window, cursor.GetCursor() );
2641
2642 }
2643 }
2644
2645 UpdateWindowUI();
2646 }
2647
2648 void wxWindow::DoGetSize( int *width, int *height ) const
2649 {
2650 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2651
2652 if (width) (*width) = m_width;
2653 if (height) (*height) = m_height;
2654 }
2655
2656 void wxWindow::DoSetClientSize( int width, int height )
2657 {
2658 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2659
2660 if (!m_wxwindow)
2661 {
2662 SetSize( width, height );
2663 }
2664 else
2665 {
2666 int dw = 0;
2667 int dh = 0;
2668
2669 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
2670 {
2671 /* when using GTK 1.2 we set the shadow border size to 2 */
2672 dw += 2 * 2;
2673 dh += 2 * 2;
2674 }
2675 if (HasFlag(wxSIMPLE_BORDER))
2676 {
2677 /* when using GTK 1.2 we set the simple border size to 1 */
2678 dw += 1 * 2;
2679 dh += 1 * 2;
2680 }
2681
2682 if (m_hasScrolling)
2683 {
2684 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2685
2686 GtkRequisition vscroll_req;
2687 vscroll_req.width = 2;
2688 vscroll_req.height = 2;
2689 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
2690 (scroll_window->vscrollbar, &vscroll_req );
2691
2692 GtkRequisition hscroll_req;
2693 hscroll_req.width = 2;
2694 hscroll_req.height = 2;
2695 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
2696 (scroll_window->hscrollbar, &hscroll_req );
2697
2698 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
2699
2700 if (scroll_window->vscrollbar_visible)
2701 {
2702 dw += vscroll_req.width;
2703 dw += scroll_class->scrollbar_spacing;
2704 }
2705
2706 if (scroll_window->hscrollbar_visible)
2707 {
2708 dh += hscroll_req.height;
2709 dh += scroll_class->scrollbar_spacing;
2710 }
2711 }
2712
2713 SetSize( width+dw, height+dh );
2714 }
2715 }
2716
2717 void wxWindow::DoGetClientSize( int *width, int *height ) const
2718 {
2719 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2720
2721 if (!m_wxwindow)
2722 {
2723 if (width) (*width) = m_width;
2724 if (height) (*height) = m_height;
2725 }
2726 else
2727 {
2728 int dw = 0;
2729 int dh = 0;
2730
2731 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
2732 {
2733 /* when using GTK 1.2 we set the shadow border size to 2 */
2734 dw += 2 * 2;
2735 dh += 2 * 2;
2736 }
2737 if (HasFlag(wxSIMPLE_BORDER))
2738 {
2739 /* when using GTK 1.2 we set the simple border size to 1 */
2740 dw += 1 * 2;
2741 dh += 1 * 2;
2742 }
2743
2744 if (m_hasScrolling)
2745 {
2746 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2747
2748 GtkRequisition vscroll_req;
2749 vscroll_req.width = 2;
2750 vscroll_req.height = 2;
2751 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
2752 (scroll_window->vscrollbar, &vscroll_req );
2753
2754 GtkRequisition hscroll_req;
2755 hscroll_req.width = 2;
2756 hscroll_req.height = 2;
2757 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
2758 (scroll_window->hscrollbar, &hscroll_req );
2759
2760 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
2761
2762 if (scroll_window->vscrollbar_visible)
2763 {
2764 dw += vscroll_req.width;
2765 dw += scroll_class->scrollbar_spacing;
2766 }
2767
2768 if (scroll_window->hscrollbar_visible)
2769 {
2770 dh += hscroll_req.height;
2771 dh += scroll_class->scrollbar_spacing;
2772 }
2773 }
2774
2775 if (width) (*width) = m_width - dw;
2776 if (height) (*height) = m_height - dh;
2777 }
2778 }
2779
2780 void wxWindow::DoGetPosition( int *x, int *y ) const
2781 {
2782 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2783
2784 int dx = 0;
2785 int dy = 0;
2786 if (m_parent && m_parent->m_wxwindow)
2787 {
2788 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
2789 dx = pizza->xoffset;
2790 dy = pizza->yoffset;
2791 }
2792
2793 if (x) (*x) = m_x - dx;
2794 if (y) (*y) = m_y - dy;
2795 }
2796
2797 void wxWindow::DoClientToScreen( int *x, int *y ) const
2798 {
2799 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2800
2801 if (!m_widget->window) return;
2802
2803 GdkWindow *source = (GdkWindow *) NULL;
2804 if (m_wxwindow)
2805 source = GTK_PIZZA(m_wxwindow)->bin_window;
2806 else
2807 source = m_widget->window;
2808
2809 int org_x = 0;
2810 int org_y = 0;
2811 gdk_window_get_origin( source, &org_x, &org_y );
2812
2813 if (!m_wxwindow)
2814 {
2815 if (GTK_WIDGET_NO_WINDOW (m_widget))
2816 {
2817 org_x += m_widget->allocation.x;
2818 org_y += m_widget->allocation.y;
2819 }
2820 }
2821
2822 if (x) *x += org_x;
2823 if (y) *y += org_y;
2824 }
2825
2826 void wxWindow::DoScreenToClient( int *x, int *y ) const
2827 {
2828 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2829
2830 if (!m_widget->window) return;
2831
2832 GdkWindow *source = (GdkWindow *) NULL;
2833 if (m_wxwindow)
2834 source = GTK_PIZZA(m_wxwindow)->bin_window;
2835 else
2836 source = m_widget->window;
2837
2838 int org_x = 0;
2839 int org_y = 0;
2840 gdk_window_get_origin( source, &org_x, &org_y );
2841
2842 if (!m_wxwindow)
2843 {
2844 if (GTK_WIDGET_NO_WINDOW (m_widget))
2845 {
2846 org_x += m_widget->allocation.x;
2847 org_y += m_widget->allocation.y;
2848 }
2849 }
2850
2851 if (x) *x -= org_x;
2852 if (y) *y -= org_y;
2853 }
2854
2855 bool wxWindow::Show( bool show )
2856 {
2857 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
2858
2859 if (!wxWindowBase::Show(show))
2860 {
2861 // nothing to do
2862 return FALSE;
2863 }
2864
2865 if (show)
2866 gtk_widget_show( m_widget );
2867 else
2868 gtk_widget_hide( m_widget );
2869
2870 return TRUE;
2871 }
2872
2873 bool wxWindow::Enable( bool enable )
2874 {
2875 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
2876
2877 if (!wxWindowBase::Enable(enable))
2878 {
2879 // nothing to do
2880 return FALSE;
2881 }
2882
2883 gtk_widget_set_sensitive( m_widget, enable );
2884 if ( m_wxwindow )
2885 gtk_widget_set_sensitive( m_wxwindow, enable );
2886
2887 return TRUE;
2888 }
2889
2890 int wxWindow::GetCharHeight() const
2891 {
2892 wxCHECK_MSG( (m_widget != NULL), 12, wxT("invalid window") );
2893
2894 wxCHECK_MSG( m_font.Ok(), 12, wxT("invalid font") );
2895
2896 GdkFont *font = m_font.GetInternalFont( 1.0 );
2897
2898 return font->ascent + font->descent;
2899 }
2900
2901 int wxWindow::GetCharWidth() const
2902 {
2903 wxCHECK_MSG( (m_widget != NULL), 8, wxT("invalid window") );
2904
2905 wxCHECK_MSG( m_font.Ok(), 8, wxT("invalid font") );
2906
2907 GdkFont *font = m_font.GetInternalFont( 1.0 );
2908
2909 return gdk_string_width( font, "H" );
2910 }
2911
2912 void wxWindow::GetTextExtent( const wxString& string,
2913 int *x,
2914 int *y,
2915 int *descent,
2916 int *externalLeading,
2917 const wxFont *theFont ) const
2918 {
2919 wxFont fontToUse = m_font;
2920 if (theFont) fontToUse = *theFont;
2921
2922 wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
2923
2924 GdkFont *font = fontToUse.GetInternalFont( 1.0 );
2925 if (x) (*x) = gdk_string_width( font, string.mbc_str() );
2926 if (y) (*y) = font->ascent + font->descent;
2927 if (descent) (*descent) = font->descent;
2928 if (externalLeading) (*externalLeading) = 0; // ??
2929 }
2930
2931 void wxWindow::SetFocus()
2932 {
2933 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2934
2935 if (m_wxwindow)
2936 {
2937 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
2938 gtk_widget_grab_focus (m_wxwindow);
2939 return;
2940 }
2941
2942 if (m_widget)
2943 {
2944 if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
2945 {
2946 gtk_widget_grab_focus (m_widget);
2947 }
2948 else if (GTK_IS_CONTAINER(m_widget))
2949 {
2950 gtk_container_focus( GTK_CONTAINER(m_widget), GTK_DIR_TAB_FORWARD );
2951 }
2952 else
2953 {
2954 // ?
2955 }
2956 }
2957 }
2958
2959 bool wxWindow::AcceptsFocus() const
2960 {
2961 return m_acceptsFocus && wxWindowBase::AcceptsFocus();
2962 }
2963
2964 bool wxWindow::Reparent( wxWindowBase *newParentBase )
2965 {
2966 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
2967
2968 wxWindow *oldParent = m_parent,
2969 *newParent = (wxWindow *)newParentBase;
2970
2971 wxASSERT( GTK_IS_WIDGET(m_widget) );
2972
2973 if ( !wxWindowBase::Reparent(newParent) )
2974 return FALSE;
2975
2976 wxASSERT( GTK_IS_WIDGET(m_widget) );
2977
2978 /* prevent GTK from deleting the widget arbitrarily */
2979 gtk_widget_ref( m_widget );
2980
2981 if (oldParent)
2982 {
2983 gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget );
2984 }
2985
2986 wxASSERT( GTK_IS_WIDGET(m_widget) );
2987
2988 if (newParent)
2989 {
2990 /* insert GTK representation */
2991 (*(newParent->m_insertCallback))(newParent, this);
2992 }
2993
2994 /* reverse: prevent GTK from deleting the widget arbitrarily */
2995 gtk_widget_unref( m_widget );
2996
2997 return TRUE;
2998 }
2999
3000 void wxWindow::DoAddChild(wxWindow *child)
3001 {
3002 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
3003
3004 wxASSERT_MSG( (child != NULL), wxT("invalid child window") );
3005
3006 wxASSERT_MSG( (m_insertCallback != NULL), wxT("invalid child insertion function") );
3007
3008 /* add to list */
3009 AddChild( child );
3010
3011 /* insert GTK representation */
3012 (*m_insertCallback)(this, child);
3013 }
3014
3015 void wxWindow::Raise()
3016 {
3017 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3018
3019 if (!m_widget->window) return;
3020
3021 gdk_window_raise( m_widget->window );
3022 }
3023
3024 void wxWindow::Lower()
3025 {
3026 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3027
3028 if (!m_widget->window) return;
3029
3030 gdk_window_lower( m_widget->window );
3031 }
3032
3033 bool wxWindow::SetCursor( const wxCursor &cursor )
3034 {
3035 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3036
3037 if (cursor == m_cursor)
3038 return FALSE;
3039
3040 if (g_isIdle)
3041 wxapp_install_idle_handler();
3042
3043 if (cursor == wxNullCursor)
3044 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR );
3045 else
3046 return wxWindowBase::SetCursor( cursor );
3047 }
3048
3049 void wxWindow::WarpPointer( int x, int y )
3050 {
3051 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3052
3053 /* we provide this function ourselves as it is
3054 missing in GDK (top of this file) */
3055
3056 GdkWindow *window = (GdkWindow*) NULL;
3057 if (m_wxwindow)
3058 window = GTK_PIZZA(m_wxwindow)->bin_window;
3059 else
3060 window = GetConnectWidget()->window;
3061
3062 if (window)
3063 gdk_window_warp_pointer( window, x, y );
3064 }
3065
3066 void wxWindow::Refresh( bool eraseBackground, const wxRect *rect )
3067 {
3068 if (!m_widget) return;
3069 if (!m_widget->window) return;
3070
3071 if (eraseBackground && m_wxwindow && m_wxwindow->window)
3072 {
3073 if (rect)
3074 {
3075 gdk_window_clear_area( GTK_PIZZA(m_wxwindow)->bin_window,
3076 rect->x, rect->y,
3077 rect->width, rect->height );
3078 }
3079 else
3080 {
3081 gdk_window_clear( GTK_PIZZA(m_wxwindow)->bin_window );
3082 }
3083 }
3084
3085 /* there is no GTK equivalent of "draw only, don't clear" so we
3086 invent our own in the GtkPizza widget */
3087
3088 if (!rect)
3089 {
3090 if (m_wxwindow)
3091 {
3092
3093 /*
3094 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
3095 gboolean old_clear = pizza->clear_on_draw;
3096 gtk_pizza_set_clear( pizza, FALSE );
3097 gtk_widget_draw( m_wxwindow, (GdkRectangle*) NULL );
3098 gtk_pizza_set_clear( pizza, old_clear );
3099 */
3100 GdkEventExpose gdk_event;
3101 gdk_event.type = GDK_EXPOSE;
3102 gdk_event.window = GTK_PIZZA(m_wxwindow)->bin_window;
3103 gdk_event.count = 0;
3104 gdk_event.area.x = 0;
3105 gdk_event.area.y = 0;
3106 gdk_event.area.width = m_wxwindow->allocation.width;
3107 gdk_event.area.height = m_wxwindow->allocation.height;
3108 gtk_window_expose_callback( m_wxwindow, &gdk_event, this );
3109
3110 }
3111 else
3112 {
3113 gtk_widget_draw( m_widget, (GdkRectangle*) NULL );
3114 }
3115 }
3116 else
3117 {
3118
3119 if (m_wxwindow)
3120 {
3121 /*
3122 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
3123 gboolean old_clear = pizza->clear_on_draw;
3124 gtk_pizza_set_clear( pizza, FALSE );
3125
3126 GdkRectangle gdk_rect;
3127 gdk_rect.x = rect->x;
3128 gdk_rect.y = rect->y;
3129 gdk_rect.width = rect->width;
3130 gdk_rect.height = rect->height;
3131 gtk_widget_draw( m_wxwindow, &gdk_rect );
3132 gtk_window_draw_callback( m_wxwindow, &gdk_rect, this );
3133
3134 gtk_pizza_set_clear( pizza, old_clear );
3135 */
3136 GdkEventExpose gdk_event;
3137 gdk_event.type = GDK_EXPOSE;
3138 gdk_event.window = GTK_PIZZA(m_wxwindow)->bin_window;
3139 gdk_event.count = 0;
3140 gdk_event.area.x = rect->x;
3141 gdk_event.area.y = rect->y;
3142 gdk_event.area.width = rect->width;
3143 gdk_event.area.height = rect->height;
3144 gtk_window_expose_callback( m_wxwindow, &gdk_event, this );
3145 }
3146 else
3147 {
3148 GdkRectangle gdk_rect;
3149 gdk_rect.x = rect->x;
3150 gdk_rect.y = rect->y;
3151 gdk_rect.width = rect->width;
3152 gdk_rect.height = rect->height;
3153 gtk_widget_draw( m_widget, &gdk_rect );
3154 }
3155 }
3156 }
3157
3158 void wxWindow::Clear()
3159 {
3160 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3161
3162 if (!m_widget->window) return;
3163
3164 if (m_wxwindow && m_wxwindow->window)
3165 {
3166 // gdk_window_clear( m_wxwindow->window );
3167 }
3168 }
3169
3170 #if wxUSE_TOOLTIPS
3171 void wxWindow::DoSetToolTip( wxToolTip *tip )
3172 {
3173 wxWindowBase::DoSetToolTip(tip);
3174
3175 if (m_tooltip)
3176 m_tooltip->Apply( this );
3177 }
3178
3179 void wxWindow::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
3180 {
3181 gtk_tooltips_set_tip( tips, GetConnectWidget(), wxConvCurrent->cWX2MB(tip), (gchar*) NULL );
3182 }
3183 #endif // wxUSE_TOOLTIPS
3184
3185 bool wxWindow::SetBackgroundColour( const wxColour &colour )
3186 {
3187 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3188
3189 if (!wxWindowBase::SetBackgroundColour(colour))
3190 {
3191 // don't leave if the GTK widget has just
3192 // been realized
3193 if (!m_delayedBackgroundColour) return FALSE;
3194 }
3195
3196 GdkWindow *window = (GdkWindow*) NULL;
3197 if (m_wxwindow)
3198 window = GTK_PIZZA(m_wxwindow)->bin_window;
3199 else
3200 window = GetConnectWidget()->window;
3201
3202 if (!window)
3203 {
3204 // indicate that a new style has been set
3205 // but it couldn't get applied as the
3206 // widget hasn't been realized yet.
3207 m_delayedBackgroundColour = TRUE;
3208 }
3209
3210 if ((m_wxwindow) &&
3211 (m_wxwindow->window) &&
3212 (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE)))
3213 {
3214 /* wxMSW doesn't clear the window here. I don't do that either to
3215 provide compatibility. call Clear() to do the job. */
3216
3217 m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
3218 gdk_window_set_background( window, m_backgroundColour.GetColor() );
3219 }
3220
3221 ApplyWidgetStyle();
3222
3223 return TRUE;
3224 }
3225
3226 bool wxWindow::SetForegroundColour( const wxColour &colour )
3227 {
3228 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3229
3230 if (!wxWindowBase::SetForegroundColour(colour))
3231 {
3232 // don't leave if the GTK widget has just
3233 // been realized
3234 if (!m_delayedForegroundColour) return FALSE;
3235 }
3236
3237 GdkWindow *window = (GdkWindow*) NULL;
3238 if (m_wxwindow)
3239 window = GTK_PIZZA(m_wxwindow)->bin_window;
3240 else
3241 window = GetConnectWidget()->window;
3242
3243 if (!window)
3244 {
3245 // indicate that a new style has been set
3246 // but it couldn't get applied as the
3247 // widget hasn't been realized yet.
3248 m_delayedForegroundColour = TRUE;
3249 }
3250
3251 ApplyWidgetStyle();
3252
3253 return TRUE;
3254 }
3255
3256 GtkStyle *wxWindow::GetWidgetStyle()
3257 {
3258 if (m_widgetStyle)
3259 {
3260 GtkStyle *remake = gtk_style_copy( m_widgetStyle );
3261 #ifdef __WXGTK20__
3262 /* FIXME: is this necessary? */
3263 _G_TYPE_IGC(remake, GtkObjectClass) = _G_TYPE_IGC(m_widgetStyle, GtkObjectClass);
3264 #else
3265 remake->klass = m_widgetStyle->klass;
3266 #endif
3267
3268 gtk_style_unref( m_widgetStyle );
3269 m_widgetStyle = remake;
3270 }
3271 else
3272 {
3273 GtkStyle *def = gtk_rc_get_style( m_widget );
3274
3275 if (!def)
3276 def = gtk_widget_get_default_style();
3277
3278 m_widgetStyle = gtk_style_copy( def );
3279 #ifdef __WXGTK20__
3280 /* FIXME: is this necessary? */
3281 _G_TYPE_IGC(m_widgetStyle, GtkObjectClass) = _G_TYPE_IGC(def, GtkObjectClass);
3282 #else
3283 m_widgetStyle->klass = def->klass;
3284 #endif
3285 }
3286
3287 return m_widgetStyle;
3288 }
3289
3290 void wxWindow::SetWidgetStyle()
3291 {
3292 #if DISABLE_STYLE_IF_BROKEN_THEM
3293 if (m_widget->style->engine_data)
3294 {
3295 static bool s_warningPrinted = FALSE;
3296 if (!s_warningPrinted)
3297 {
3298 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3299 s_warningPrinted = TRUE;
3300 }
3301 m_widgetStyle = m_widget->style;
3302 return;
3303 }
3304 #endif
3305
3306 GtkStyle *style = GetWidgetStyle();
3307
3308 if (m_font != wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT ))
3309 {
3310 gdk_font_unref( style->font );
3311 style->font = gdk_font_ref( m_font.GetInternalFont( 1.0 ) );
3312 }
3313
3314 if (m_foregroundColour.Ok())
3315 {
3316 m_foregroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
3317 if (m_foregroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNTEXT))
3318 {
3319 style->fg[GTK_STATE_NORMAL] = *m_foregroundColour.GetColor();
3320 style->fg[GTK_STATE_PRELIGHT] = *m_foregroundColour.GetColor();
3321 style->fg[GTK_STATE_ACTIVE] = *m_foregroundColour.GetColor();
3322 }
3323 else
3324 {
3325 // Try to restore the gtk default style. This is still a little
3326 // oversimplified for what is probably really needed here for controls
3327 // other than buttons, but is better than not being able to (re)set a
3328 // control's foreground colour to *wxBLACK -- RL
3329 GtkStyle *def = gtk_rc_get_style( m_widget );
3330
3331 if (!def)
3332 def = gtk_widget_get_default_style();
3333
3334 style->fg[GTK_STATE_NORMAL] = def->fg[GTK_STATE_NORMAL];
3335 style->fg[GTK_STATE_PRELIGHT] = def->fg[GTK_STATE_PRELIGHT];
3336 style->fg[GTK_STATE_ACTIVE] = def->fg[GTK_STATE_ACTIVE];
3337 }
3338 }
3339
3340 if (m_backgroundColour.Ok())
3341 {
3342 m_backgroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
3343 if (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE))
3344 {
3345 style->bg[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
3346 style->base[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
3347 style->bg[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
3348 style->base[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
3349 style->bg[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
3350 style->base[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
3351 style->bg[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
3352 style->base[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
3353 }
3354 else
3355 {
3356 // Try to restore the gtk default style. This is still a little
3357 // oversimplified for what is probably really needed here for controls
3358 // other than buttons, but is better than not being able to (re)set a
3359 // control's background colour to default grey and means resetting a
3360 // button to wxSYS_COLOUR_BTNFACE will restore its usual highlighting
3361 // behavior -- RL
3362 GtkStyle *def = gtk_rc_get_style( m_widget );
3363
3364 if (!def)
3365 def = gtk_widget_get_default_style();
3366
3367 style->bg[GTK_STATE_NORMAL] = def->bg[GTK_STATE_NORMAL];
3368 style->base[GTK_STATE_NORMAL] = def->base[GTK_STATE_NORMAL];
3369 style->bg[GTK_STATE_PRELIGHT] = def->bg[GTK_STATE_PRELIGHT];
3370 style->base[GTK_STATE_PRELIGHT] = def->base[GTK_STATE_PRELIGHT];
3371 style->bg[GTK_STATE_ACTIVE] = def->bg[GTK_STATE_ACTIVE];
3372 style->base[GTK_STATE_ACTIVE] = def->base[GTK_STATE_ACTIVE];
3373 style->bg[GTK_STATE_INSENSITIVE] = def->bg[GTK_STATE_INSENSITIVE];
3374 style->base[GTK_STATE_INSENSITIVE] = def->base[GTK_STATE_INSENSITIVE];
3375 }
3376 }
3377 }
3378
3379 void wxWindow::ApplyWidgetStyle()
3380 {
3381 }
3382
3383 //-----------------------------------------------------------------------------
3384 // Pop-up menu stuff
3385 //-----------------------------------------------------------------------------
3386
3387 static void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting )
3388 {
3389 *is_waiting = FALSE;
3390 }
3391
3392 static void SetInvokingWindow( wxMenu *menu, wxWindow *win )
3393 {
3394 menu->SetInvokingWindow( win );
3395 wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
3396 while (node)
3397 {
3398 wxMenuItem *menuitem = node->GetData();
3399 if (menuitem->IsSubMenu())
3400 {
3401 SetInvokingWindow( menuitem->GetSubMenu(), win );
3402 }
3403
3404 node = node->GetNext();
3405 }
3406 }
3407
3408 static gint gs_pop_x = 0;
3409 static gint gs_pop_y = 0;
3410
3411 static void pop_pos_callback( GtkMenu * WXUNUSED(menu),
3412 gint *x, gint *y,
3413 wxWindow *win )
3414 {
3415 win->ClientToScreen( &gs_pop_x, &gs_pop_y );
3416 *x = gs_pop_x;
3417 *y = gs_pop_y;
3418 }
3419
3420 bool wxWindow::DoPopupMenu( wxMenu *menu, int x, int y )
3421 {
3422 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3423
3424 wxCHECK_MSG( menu != NULL, FALSE, wxT("invalid popup-menu") );
3425
3426 SetInvokingWindow( menu, this );
3427
3428 menu->UpdateUI();
3429
3430 gs_pop_x = x;
3431 gs_pop_y = y;
3432
3433 bool is_waiting = TRUE;
3434
3435 gtk_signal_connect( GTK_OBJECT(menu->m_menu), "hide",
3436 GTK_SIGNAL_FUNC(gtk_pop_hide_callback), (gpointer)&is_waiting );
3437
3438 gtk_menu_popup(
3439 GTK_MENU(menu->m_menu),
3440 (GtkWidget *) NULL, // parent menu shell
3441 (GtkWidget *) NULL, // parent menu item
3442 (GtkMenuPositionFunc) pop_pos_callback,
3443 (gpointer) this, // client data
3444 0, // button used to activate it
3445 gs_timeLastClick // the time of activation
3446 );
3447
3448 while (is_waiting)
3449 {
3450 while (gtk_events_pending())
3451 gtk_main_iteration();
3452 }
3453
3454 return TRUE;
3455 }
3456
3457 #if wxUSE_DRAG_AND_DROP
3458
3459 void wxWindow::SetDropTarget( wxDropTarget *dropTarget )
3460 {
3461 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3462
3463 GtkWidget *dnd_widget = GetConnectWidget();
3464
3465 if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
3466
3467 if (m_dropTarget) delete m_dropTarget;
3468 m_dropTarget = dropTarget;
3469
3470 if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
3471 }
3472
3473 #endif // wxUSE_DRAG_AND_DROP
3474
3475 GtkWidget* wxWindow::GetConnectWidget()
3476 {
3477 GtkWidget *connect_widget = m_widget;
3478 if (m_wxwindow) connect_widget = m_wxwindow;
3479
3480 return connect_widget;
3481 }
3482
3483 bool wxWindow::IsOwnGtkWindow( GdkWindow *window )
3484 {
3485 if (m_wxwindow)
3486 return (window == GTK_PIZZA(m_wxwindow)->bin_window);
3487
3488 return (window == m_widget->window);
3489 }
3490
3491 bool wxWindow::SetFont( const wxFont &font )
3492 {
3493 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3494
3495 if (!wxWindowBase::SetFont(font))
3496 {
3497 return FALSE;
3498 }
3499
3500 wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
3501 if ( sysbg == m_backgroundColour )
3502 {
3503 m_backgroundColour = wxNullColour;
3504 ApplyWidgetStyle();
3505 m_backgroundColour = sysbg;
3506 }
3507 else
3508 {
3509 ApplyWidgetStyle();
3510 }
3511
3512 return TRUE;
3513 }
3514
3515 void wxWindow::CaptureMouse()
3516 {
3517 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3518
3519 wxCHECK_RET( g_captureWindow == NULL, wxT("CaptureMouse called twice") );
3520
3521 GdkWindow *window = (GdkWindow*) NULL;
3522 if (m_wxwindow)
3523 window = GTK_PIZZA(m_wxwindow)->bin_window;
3524 else
3525 window = GetConnectWidget()->window;
3526
3527 if (!window) return;
3528
3529 wxCursor* cursor = & m_cursor;
3530 if (!cursor->Ok())
3531 cursor = wxSTANDARD_CURSOR;
3532
3533 gdk_pointer_grab( window, FALSE,
3534 (GdkEventMask)
3535 (GDK_BUTTON_PRESS_MASK |
3536 GDK_BUTTON_RELEASE_MASK |
3537 GDK_POINTER_MOTION_HINT_MASK |
3538 GDK_POINTER_MOTION_MASK),
3539 (GdkWindow *) NULL,
3540 cursor->GetCursor(),
3541 (guint32)GDK_CURRENT_TIME );
3542 g_captureWindow = this;
3543 }
3544
3545 void wxWindow::ReleaseMouse()
3546 {
3547 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3548
3549 wxCHECK_RET( g_captureWindow, wxT("ReleaseMouse called twice") );
3550
3551 GdkWindow *window = (GdkWindow*) NULL;
3552 if (m_wxwindow)
3553 window = GTK_PIZZA(m_wxwindow)->bin_window;
3554 else
3555 window = GetConnectWidget()->window;
3556
3557 if (!window)
3558 return;
3559
3560 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
3561 g_captureWindow = (wxWindow*) NULL;
3562 }
3563
3564 bool wxWindow::IsRetained() const
3565 {
3566 return FALSE;
3567 }
3568
3569 void wxWindow::SetScrollbar( int orient, int pos, int thumbVisible,
3570 int range, bool refresh )
3571 {
3572 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3573
3574 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
3575
3576 m_hasScrolling = TRUE;
3577
3578 if (orient == wxHORIZONTAL)
3579 {
3580 float fpos = (float)pos;
3581 float frange = (float)range;
3582 float fthumb = (float)thumbVisible;
3583 if (fpos > frange-fthumb) fpos = frange-fthumb;
3584 if (fpos < 0.0) fpos = 0.0;
3585
3586 if ((fabs(frange-m_hAdjust->upper) < 0.2) &&
3587 (fabs(fthumb-m_hAdjust->page_size) < 0.2))
3588 {
3589 SetScrollPos( orient, pos, refresh );
3590 return;
3591 }
3592
3593 m_oldHorizontalPos = fpos;
3594
3595 m_hAdjust->lower = 0.0;
3596 m_hAdjust->upper = frange;
3597 m_hAdjust->value = fpos;
3598 m_hAdjust->step_increment = 1.0;
3599 m_hAdjust->page_increment = (float)(wxMax(fthumb,0));
3600 m_hAdjust->page_size = fthumb;
3601 }
3602 else
3603 {
3604 float fpos = (float)pos;
3605 float frange = (float)range;
3606 float fthumb = (float)thumbVisible;
3607 if (fpos > frange-fthumb) fpos = frange-fthumb;
3608 if (fpos < 0.0) fpos = 0.0;
3609
3610 if ((fabs(frange-m_vAdjust->upper) < 0.2) &&
3611 (fabs(fthumb-m_vAdjust->page_size) < 0.2))
3612 {
3613 SetScrollPos( orient, pos, refresh );
3614 return;
3615 }
3616
3617 m_oldVerticalPos = fpos;
3618
3619 m_vAdjust->lower = 0.0;
3620 m_vAdjust->upper = frange;
3621 m_vAdjust->value = fpos;
3622 m_vAdjust->step_increment = 1.0;
3623 m_vAdjust->page_increment = (float)(wxMax(fthumb,0));
3624 m_vAdjust->page_size = fthumb;
3625 }
3626
3627 if (orient == wxHORIZONTAL)
3628 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
3629 else
3630 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
3631 }
3632
3633 void wxWindow::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
3634 {
3635 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3636
3637 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
3638
3639 if (orient == wxHORIZONTAL)
3640 {
3641 float fpos = (float)pos;
3642 if (fpos > m_hAdjust->upper - m_hAdjust->page_size) fpos = m_hAdjust->upper - m_hAdjust->page_size;
3643 if (fpos < 0.0) fpos = 0.0;
3644 m_oldHorizontalPos = fpos;
3645
3646 if (fabs(fpos-m_hAdjust->value) < 0.2) return;
3647 m_hAdjust->value = fpos;
3648 }
3649 else
3650 {
3651 float fpos = (float)pos;
3652 if (fpos > m_vAdjust->upper - m_vAdjust->page_size) fpos = m_vAdjust->upper - m_vAdjust->page_size;
3653 if (fpos < 0.0) fpos = 0.0;
3654 m_oldVerticalPos = fpos;
3655
3656 if (fabs(fpos-m_vAdjust->value) < 0.2) return;
3657 m_vAdjust->value = fpos;
3658 }
3659
3660 if (m_wxwindow->window)
3661 {
3662 if (orient == wxHORIZONTAL)
3663 {
3664 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust),
3665 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
3666
3667 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
3668
3669 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
3670 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
3671 }
3672 else
3673 {
3674 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust),
3675 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
3676
3677 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
3678
3679 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
3680 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
3681 }
3682 }
3683 }
3684
3685 int wxWindow::GetScrollThumb( int orient ) const
3686 {
3687 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
3688
3689 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
3690
3691 if (orient == wxHORIZONTAL)
3692 return (int)(m_hAdjust->page_size+0.5);
3693 else
3694 return (int)(m_vAdjust->page_size+0.5);
3695 }
3696
3697 int wxWindow::GetScrollPos( int orient ) const
3698 {
3699 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
3700
3701 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
3702
3703 if (orient == wxHORIZONTAL)
3704 return (int)(m_hAdjust->value+0.5);
3705 else
3706 return (int)(m_vAdjust->value+0.5);
3707 }
3708
3709 int wxWindow::GetScrollRange( int orient ) const
3710 {
3711 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
3712
3713 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
3714
3715 if (orient == wxHORIZONTAL)
3716 return (int)(m_hAdjust->upper+0.5);
3717 else
3718 return (int)(m_vAdjust->upper+0.5);
3719 }
3720
3721 void wxWindow::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
3722 {
3723 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3724
3725 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
3726
3727 if ((dx == 0) && (dy == 0)) return;
3728
3729 m_clipPaintRegion = TRUE;
3730 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
3731 m_clipPaintRegion = FALSE;
3732
3733 /*
3734 if (m_children.GetCount() > 0)
3735 {
3736 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
3737 }
3738 else
3739 {
3740 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
3741
3742 pizza->xoffset -= dx;
3743 pizza->yoffset -= dy;
3744
3745 GdkGC *m_scrollGC = gdk_gc_new( pizza->bin_window );
3746 gdk_gc_set_exposures( m_scrollGC, TRUE );
3747
3748 int cw = 0;
3749 int ch = 0;
3750 GetClientSize( &cw, &ch );
3751 int w = cw - abs(dx);
3752 int h = ch - abs(dy);
3753
3754 if ((h < 0) || (w < 0))
3755 {
3756 Refresh();
3757 }
3758 else
3759 {
3760 int s_x = 0;
3761 int s_y = 0;
3762 if (dx < 0) s_x = -dx;
3763 if (dy < 0) s_y = -dy;
3764 int d_x = 0;
3765 int d_y = 0;
3766 if (dx > 0) d_x = dx;
3767 if (dy > 0) d_y = dy;
3768
3769 gdk_window_copy_area( pizza->bin_window, m_scrollGC, d_x, d_y,
3770 pizza->bin_window, s_x, s_y, w, h );
3771
3772 wxRect rect;
3773 if (dx < 0) rect.x = cw+dx; else rect.x = 0;
3774 if (dy < 0) rect.y = ch+dy; else rect.y = 0;
3775 if (dy != 0) rect.width = cw; else rect.width = abs(dx);
3776 if (dx != 0) rect.height = ch; else rect.height = abs(dy);
3777
3778 Refresh( TRUE, &rect );
3779 }
3780
3781 gdk_gc_unref( m_scrollGC );
3782 }
3783 */
3784 }
3785
3786 // Find the wxWindow at the current mouse position, also returning the mouse
3787 // position.
3788 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
3789 {
3790 pt = wxGetMousePosition();
3791 wxWindow* found = wxFindWindowAtPoint(pt);
3792 return found;
3793 }
3794
3795 // Get the current mouse position.
3796 wxPoint wxGetMousePosition()
3797 {
3798 /* This crashes when used within wxHelpContext,
3799 so we have to use the X-specific implementation below.
3800 gint x, y;
3801 GdkModifierType *mask;
3802 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
3803
3804 return wxPoint(x, y);
3805 */
3806
3807 int x, y;
3808 GdkWindow* windowAtPtr = gdk_window_at_pointer(& x, & y);
3809 if (!windowAtPtr)
3810 return wxPoint(-999, -999);
3811
3812 Display *display = GDK_WINDOW_XDISPLAY(windowAtPtr);
3813 Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
3814 Window rootReturn, childReturn;
3815 int rootX, rootY, winX, winY;
3816 unsigned int maskReturn;
3817
3818 XQueryPointer (display,
3819 rootWindow,
3820 &rootReturn,
3821 &childReturn,
3822 &rootX, &rootY, &winX, &winY, &maskReturn);
3823 return wxPoint(rootX, rootY);
3824
3825 }
3826