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