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