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