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