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