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