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