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