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