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