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