]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/window.cpp
param type of wxWindow::Reparent() fixed in wxGTK
[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 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 *WXUNUSED(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 if (gdk_event->window != win->m_wxwindow->window)
668 return;
669
670 win->GetUpdateRegion().Union( gdk_event->area.x,
671 gdk_event->area.y,
672 gdk_event->area.width,
673 gdk_event->area.height );
674
675 if (gdk_event->count > 0)
676 return;
677
678 wxPaintEvent event( win->GetId() );
679 event.SetEventObject( win );
680 win->GetEventHandler()->ProcessEvent( event );
681
682 /*
683 wxPrintf( "OnExpose from " );
684 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
685 wxPrintf( win->GetClassInfo()->GetClassName() );
686 wxPrintf( " %d %d %d %d\n", (int)gdk_event->area.x,
687 (int)gdk_event->area.y,
688 (int)gdk_event->area.width,
689 (int)gdk_event->area.height );
690 */
691
692 win->GetUpdateRegion().Clear();
693 }
694
695 //-----------------------------------------------------------------------------
696 // "draw" of m_wxwindow
697 //-----------------------------------------------------------------------------
698
699 static void gtk_window_draw_callback( GtkWidget *WXUNUSED(widget), GdkRectangle *rect, wxWindow *win )
700 {
701 if (g_isIdle)
702 wxapp_install_idle_handler();
703
704 if (!win->m_hasVMT)
705 return;
706
707 win->GetUpdateRegion().Union( rect->x, rect->y,
708 rect->width, rect->height );
709
710 wxPaintEvent event( win->GetId() );
711 event.SetEventObject( win );
712
713 /*
714 wxPrintf( "OnDraw from " );
715 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
716 printf( win->GetClassInfo()->GetClassName() );
717 wxPrintf( " %d %d %d %d\n", (int)rect->x,
718 (int)rect->y,
719 (int)rect->width,
720 (int)rect->height );
721 */
722
723 win->GetEventHandler()->ProcessEvent( event );
724
725 win->GetUpdateRegion().Clear();
726 }
727
728 //-----------------------------------------------------------------------------
729 // "key_press_event" from any window
730 //-----------------------------------------------------------------------------
731
732 static gint gtk_window_key_press_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindow *win )
733 {
734 if (g_isIdle)
735 wxapp_install_idle_handler();
736
737 if (!win->m_hasVMT) return FALSE;
738 if (g_blockEventsOnDrag) return FALSE;
739
740 /*
741 printf( "KeyDown-ScanCode is: %d.\n", gdk_event->keyval );
742 if (gdk_event->state & GDK_SHIFT_MASK)
743 printf( "ShiftDown.\n" );
744 else
745 printf( "ShiftUp.\n" );
746 if (gdk_event->state & GDK_CONTROL_MASK)
747 printf( "ControlDown.\n" );
748 else
749 printf( "ControlUp.\n" );
750 printf( "\n" );
751 */
752 int x = 0;
753 int y = 0;
754 GdkModifierType state;
755 if (gdk_event->window) gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
756
757 long key_code = map_to_unmodified_wx_keysym( gdk_event->keyval );
758
759 /* sending unknown key events doesn't really make sense */
760 if (key_code == 0) return FALSE;
761
762 bool ret = FALSE;
763
764 wxKeyEvent event( wxEVT_KEY_DOWN );
765 event.SetTimestamp( gdk_event->time );
766 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
767 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
768 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
769 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
770 event.m_keyCode = key_code;
771 event.m_scanCode = gdk_event->keyval;
772 event.m_x = x;
773 event.m_y = y;
774 event.SetEventObject( win );
775 ret = win->GetEventHandler()->ProcessEvent( event );
776
777 key_code = map_to_wx_keysym( gdk_event->keyval );
778
779 #if wxUSE_ACCEL
780 if (!ret)
781 {
782 wxWindow *ancestor = win;
783 while (ancestor)
784 {
785 int command = ancestor->GetAcceleratorTable()->GetCommand( event );
786 if (command != -1)
787 {
788 wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
789 ret = ancestor->GetEventHandler()->ProcessEvent( command_event );
790 break;
791 }
792 ancestor = ancestor->GetParent();
793 }
794 }
795 #endif // wxUSE_ACCEL
796 /* wxMSW doesn't send char events with Alt pressed */
797 /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
798 will only be sent if it is not a menu accelerator. */
799 if ((key_code != 0) && ! ret )
800 {
801 wxKeyEvent event2( wxEVT_CHAR );
802 event2.SetTimestamp( gdk_event->time );
803 event2.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
804 event2.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
805 event2.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
806 event2.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
807 event2.m_keyCode = key_code;
808 event2.m_scanCode = gdk_event->keyval;
809 event2.m_x = x;
810 event2.m_y = y;
811 event2.SetEventObject( win );
812 ret = (ret || win->GetEventHandler()->ProcessEvent( event2 ));
813 }
814
815 /* win is a control: tab can be propagated up */
816 if ( (!ret) &&
817 ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) &&
818 (win->HasFlag(wxTE_PROCESS_TAB) == 0))
819 {
820 wxNavigationKeyEvent new_event;
821 /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
822 new_event.SetDirection( (gdk_event->keyval == GDK_Tab) );
823 /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
824 new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) );
825 new_event.SetCurrentFocus( win );
826 ret = win->GetEventHandler()->ProcessEvent( new_event );
827 }
828
829 /* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
830 if ( (!ret) &&
831 (gdk_event->keyval == GDK_Escape) )
832 {
833 wxCommandEvent new_event(wxEVT_COMMAND_BUTTON_CLICKED,wxID_CANCEL);
834 new_event.SetEventObject( win );
835 ret = win->GetEventHandler()->ProcessEvent( new_event );
836 }
837
838 #if (GTK_MINOR_VERSION > 0)
839 /* pressing F10 will activate the menu bar of the top frame */
840 if ( (!ret) &&
841 (gdk_event->keyval == GDK_F10) )
842 {
843 wxWindow *ancestor = win;
844 while (ancestor)
845 {
846 if (wxIsKindOf(ancestor,wxFrame))
847 {
848 wxFrame *frame = (wxFrame*) ancestor;
849 wxMenuBar *menubar = frame->GetMenuBar();
850 if (menubar)
851 {
852 wxNode *node = menubar->GetMenus().First();
853 if (node)
854 {
855 // doesn't work correctly
856 // wxMenu *firstMenu = (wxMenu*) node->Data();
857 // gtk_menu_item_select( GTK_MENU_ITEM(firstMenu->m_owner) );
858 // ret = TRUE;
859 break;
860 }
861 }
862 }
863 ancestor = ancestor->GetParent();
864 }
865 }
866 #endif
867
868 /*
869 Damn, I forgot why this didn't work, but it didn't work.
870
871 // win is a panel: up can be propagated to the panel
872 if ((!ret) && (win->m_wxwindow) && (win->m_parent) && (win->m_parent->AcceptsFocus()) &&
873 (gdk_event->keyval == GDK_Up))
874 {
875 win->m_parent->SetFocus();
876 ret = TRUE;
877 }
878
879 // win is a panel: left/right can be propagated to the panel
880 if ((!ret) && (win->m_wxwindow) &&
881 ((gdk_event->keyval == GDK_Right) || (gdk_event->keyval == GDK_Left) ||
882 (gdk_event->keyval == GDK_Up) || (gdk_event->keyval == GDK_Down)))
883 {
884 wxNavigationKeyEvent new_event;
885 new_event.SetDirection( (gdk_event->keyval == GDK_Right) || (gdk_event->keyval == GDK_Down) );
886 new_event.SetCurrentFocus( win );
887 ret = win->GetEventHandler()->ProcessEvent( new_event );
888 }
889 */
890
891 if (ret)
892 {
893 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
894 return TRUE;
895 }
896
897 return FALSE;
898 }
899
900 //-----------------------------------------------------------------------------
901 // "key_release_event" from any window
902 //-----------------------------------------------------------------------------
903
904 static gint gtk_window_key_release_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindow *win )
905 {
906 if (g_isIdle)
907 wxapp_install_idle_handler();
908
909 if (!win->m_hasVMT) return FALSE;
910 if (g_blockEventsOnDrag) return FALSE;
911
912 /*
913 printf( "KeyUp-ScanCode is: %d.\n", gdk_event->keyval );
914 if (gdk_event->state & GDK_SHIFT_MASK)
915 printf( "ShiftDown.\n" );
916 else
917 printf( "ShiftUp.\n" );
918 if (gdk_event->state & GDK_CONTROL_MASK)
919 printf( "ControlDown.\n" );
920 else
921 printf( "ControlUp.\n" );
922 printf( "\n" );
923 */
924
925 long key_code = map_to_unmodified_wx_keysym( gdk_event->keyval );
926
927 /* sending unknown key events doesn't really make sense */
928 if (key_code == 0) return FALSE;
929
930 int x = 0;
931 int y = 0;
932 GdkModifierType state;
933 if (gdk_event->window) gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
934
935 wxKeyEvent event( wxEVT_KEY_UP );
936 event.SetTimestamp( gdk_event->time );
937 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
938 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
939 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
940 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
941 event.m_keyCode = key_code;
942 event.m_scanCode = gdk_event->keyval;
943 event.m_x = x;
944 event.m_y = y;
945 event.SetEventObject( win );
946
947 if (win->GetEventHandler()->ProcessEvent( event ))
948 {
949 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_release_event" );
950 return TRUE;
951 }
952
953 return FALSE;
954 }
955
956 //-----------------------------------------------------------------------------
957 // "button_press_event"
958 //-----------------------------------------------------------------------------
959
960 static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindow *win )
961 {
962 if (g_isIdle)
963 wxapp_install_idle_handler();
964
965 /*
966 wxPrintf( _T("1) OnButtonPress from ") );
967 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
968 wxPrintf( win->GetClassInfo()->GetClassName() );
969 wxPrintf( _T(".\n") );
970 */
971 if (!win->m_hasVMT) return FALSE;
972 if (g_blockEventsOnDrag) return TRUE;
973 if (g_blockEventsOnScroll) return TRUE;
974
975 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
976
977 if (win->m_wxwindow)
978 {
979 if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow) && !GTK_WIDGET_HAS_FOCUS (win->m_wxwindow) )
980 {
981 gtk_widget_grab_focus (win->m_wxwindow);
982
983 /*
984 wxPrintf( _T("GrabFocus from ") );
985 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
986 wxPrintf( win->GetClassInfo()->GetClassName() );
987 wxPrintf( _T(".\n") );
988 */
989
990 }
991 }
992
993 /*
994 wxPrintf( _T("2) OnButtonPress from ") );
995 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
996 wxPrintf( win->GetClassInfo()->GetClassName() );
997 wxPrintf( _T(".\n") );
998 */
999
1000 wxEventType event_type = wxEVT_LEFT_DOWN;
1001
1002 if (gdk_event->button == 1)
1003 {
1004 switch (gdk_event->type)
1005 {
1006 case GDK_BUTTON_PRESS: event_type = wxEVT_LEFT_DOWN; break;
1007 case GDK_2BUTTON_PRESS: event_type = wxEVT_LEFT_DCLICK; break;
1008 default: break;
1009 }
1010 }
1011 else if (gdk_event->button == 2)
1012 {
1013 switch (gdk_event->type)
1014 {
1015 case GDK_BUTTON_PRESS: event_type = wxEVT_MIDDLE_DOWN; break;
1016 case GDK_2BUTTON_PRESS: event_type = wxEVT_MIDDLE_DCLICK; break;
1017 default: break;
1018 }
1019 }
1020 else if (gdk_event->button == 3)
1021 {
1022 switch (gdk_event->type)
1023 {
1024 case GDK_BUTTON_PRESS: event_type = wxEVT_RIGHT_DOWN; break;
1025 case GDK_2BUTTON_PRESS: event_type = wxEVT_RIGHT_DCLICK; break;
1026 default: break;
1027 }
1028 }
1029
1030 wxMouseEvent event( event_type );
1031 event.SetTimestamp( gdk_event->time );
1032 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1033 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1034 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1035 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1036 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1037 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1038 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1039
1040 event.m_x = (long)gdk_event->x;
1041 event.m_y = (long)gdk_event->y;
1042
1043 // Some control don't have their own X window and thus cannot get
1044 // any events.
1045
1046 if (!g_captureWindow)
1047 {
1048 wxNode *node = win->GetChildren().First();
1049 while (node)
1050 {
1051 wxWindow *child = (wxWindow*)node->Data();
1052
1053 if (child->m_isStaticBox)
1054 {
1055 // wxStaticBox is transparent in the box itself
1056 int x = event.m_x;
1057 int y = event.m_y;
1058 int xx1 = child->m_x;
1059 int yy1 = child->m_y;
1060 int xx2 = child->m_x + child->m_width;
1061 int yy2 = child->m_x + child->m_height;
1062
1063 // left
1064 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1065 // right
1066 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1067 // top
1068 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1069 // bottom
1070 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1071 {
1072 win = child;
1073 event.m_x -= child->m_x;
1074 event.m_y -= child->m_y;
1075 break;
1076 }
1077
1078 }
1079 else
1080 {
1081 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1082 (child->m_x <= event.m_x) &&
1083 (child->m_y <= event.m_y) &&
1084 (child->m_x+child->m_width >= event.m_x) &&
1085 (child->m_y+child->m_height >= event.m_y))
1086 {
1087 win = child;
1088 event.m_x -= child->m_x;
1089 event.m_y -= child->m_y;
1090 break;
1091 }
1092 }
1093 node = node->Next();
1094 }
1095 }
1096
1097 event.SetEventObject( win );
1098
1099 gs_timeLastClick = gdk_event->time;
1100
1101 if (win->GetEventHandler()->ProcessEvent( event ))
1102 {
1103 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_press_event" );
1104 return TRUE;
1105 }
1106
1107 return FALSE;
1108 }
1109
1110 //-----------------------------------------------------------------------------
1111 // "button_release_event"
1112 //-----------------------------------------------------------------------------
1113
1114 static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindow *win )
1115 {
1116 if (g_isIdle)
1117 wxapp_install_idle_handler();
1118
1119 if (!win->m_hasVMT) return FALSE;
1120 if (g_blockEventsOnDrag) return FALSE;
1121 if (g_blockEventsOnScroll) return FALSE;
1122
1123 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1124
1125 /*
1126 printf( "OnButtonRelease from " );
1127 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1128 printf( win->GetClassInfo()->GetClassName() );
1129 printf( ".\n" );
1130 */
1131
1132 wxEventType event_type = wxEVT_NULL;
1133
1134 switch (gdk_event->button)
1135 {
1136 case 1: event_type = wxEVT_LEFT_UP; break;
1137 case 2: event_type = wxEVT_MIDDLE_UP; break;
1138 case 3: event_type = wxEVT_RIGHT_UP; break;
1139 }
1140
1141 wxMouseEvent event( event_type );
1142 event.SetTimestamp( gdk_event->time );
1143 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1144 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1145 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1146 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1147 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1148 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1149 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1150 event.m_x = (long)gdk_event->x;
1151 event.m_y = (long)gdk_event->y;
1152
1153 // Some control don't have their own X window and thus cannot get
1154 // any events.
1155
1156 if (!g_captureWindow)
1157 {
1158 wxNode *node = win->GetChildren().First();
1159 while (node)
1160 {
1161 wxWindow *child = (wxWindow*)node->Data();
1162
1163 if (child->m_isStaticBox)
1164 {
1165 // wxStaticBox is transparent in the box itself
1166 int x = event.m_x;
1167 int y = event.m_y;
1168 int xx1 = child->m_x;
1169 int yy1 = child->m_y;
1170 int xx2 = child->m_x + child->m_width;
1171 int yy2 = child->m_x + child->m_height;
1172
1173 // left
1174 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1175 // right
1176 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1177 // top
1178 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1179 // bottom
1180 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1181 {
1182 win = child;
1183 event.m_x -= child->m_x;
1184 event.m_y -= child->m_y;
1185 break;
1186 }
1187
1188 }
1189 else
1190 {
1191 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1192 (child->m_x <= event.m_x) &&
1193 (child->m_y <= event.m_y) &&
1194 (child->m_x+child->m_width >= event.m_x) &&
1195 (child->m_y+child->m_height >= event.m_y))
1196 {
1197 win = child;
1198 event.m_x -= child->m_x;
1199 event.m_y -= child->m_y;
1200 break;
1201 }
1202 }
1203 node = node->Next();
1204 }
1205 }
1206
1207 event.SetEventObject( win );
1208
1209 if (win->GetEventHandler()->ProcessEvent( event ))
1210 {
1211 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_release_event" );
1212 return TRUE;
1213 }
1214
1215 return FALSE;
1216 }
1217
1218 //-----------------------------------------------------------------------------
1219 // "motion_notify_event"
1220 //-----------------------------------------------------------------------------
1221
1222 static gint gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion *gdk_event, wxWindow *win )
1223 {
1224 if (g_isIdle)
1225 wxapp_install_idle_handler();
1226
1227 if (!win->m_hasVMT) return FALSE;
1228 if (g_blockEventsOnDrag) return FALSE;
1229 if (g_blockEventsOnScroll) return FALSE;
1230
1231 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1232
1233 if (gdk_event->is_hint)
1234 {
1235 int x = 0;
1236 int y = 0;
1237 GdkModifierType state;
1238 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
1239 gdk_event->x = x;
1240 gdk_event->y = y;
1241 gdk_event->state = state;
1242 }
1243
1244 /*
1245 printf( "OnMotion from " );
1246 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1247 printf( win->GetClassInfo()->GetClassName() );
1248 printf( ".\n" );
1249 */
1250
1251 wxMouseEvent event( wxEVT_MOTION );
1252 event.SetTimestamp( gdk_event->time );
1253 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1254 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1255 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1256 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1257 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1258 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1259 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1260
1261 event.m_x = (long)gdk_event->x;
1262 event.m_y = (long)gdk_event->y;
1263
1264 // Some control don't have their own X window and thus cannot get
1265 // any events.
1266
1267 if (!g_captureWindow)
1268 {
1269 wxNode *node = win->GetChildren().First();
1270 while (node)
1271 {
1272 wxWindow *child = (wxWindow*)node->Data();
1273
1274 if (child->m_isStaticBox)
1275 {
1276 // wxStaticBox is transparent in the box itself
1277 int x = event.m_x;
1278 int y = event.m_y;
1279 int xx1 = child->m_x;
1280 int yy1 = child->m_y;
1281 int xx2 = child->m_x + child->m_width;
1282 int yy2 = child->m_x + child->m_height;
1283
1284 // left
1285 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1286 // right
1287 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1288 // top
1289 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1290 // bottom
1291 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1292 {
1293 win = child;
1294 event.m_x -= child->m_x;
1295 event.m_y -= child->m_y;
1296 break;
1297 }
1298
1299 }
1300 else
1301 {
1302 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1303 (child->m_x <= event.m_x) &&
1304 (child->m_y <= event.m_y) &&
1305 (child->m_x+child->m_width >= event.m_x) &&
1306 (child->m_y+child->m_height >= event.m_y))
1307 {
1308 win = child;
1309 event.m_x -= child->m_x;
1310 event.m_y -= child->m_y;
1311 break;
1312 }
1313 }
1314 node = node->Next();
1315 }
1316 }
1317
1318 event.SetEventObject( win );
1319
1320 if (win->GetEventHandler()->ProcessEvent( event ))
1321 {
1322 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "motion_notify_event" );
1323 return TRUE;
1324 }
1325
1326 return FALSE;
1327 }
1328
1329 //-----------------------------------------------------------------------------
1330 // "focus_in_event"
1331 //-----------------------------------------------------------------------------
1332
1333 static gint gtk_window_focus_in_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindow *win )
1334 {
1335 if (g_isIdle)
1336 wxapp_install_idle_handler();
1337
1338 if (!win->m_hasVMT) return FALSE;
1339 if (g_blockEventsOnDrag) return FALSE;
1340
1341 g_focusWindow = win;
1342
1343 if (win->m_wxwindow)
1344 {
1345 if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow))
1346 {
1347 GTK_WIDGET_SET_FLAGS (win->m_wxwindow, GTK_HAS_FOCUS);
1348 /*
1349 printf( "SetFocus flag from " );
1350 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1351 printf( win->GetClassInfo()->GetClassName() );
1352 printf( ".\n" );
1353 */
1354 }
1355 }
1356
1357
1358 /*
1359 printf( "OnSetFocus from " );
1360 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1361 printf( win->GetClassInfo()->GetClassName() );
1362 printf( " " );
1363 printf( WXSTRINGCAST win->GetLabel() );
1364 printf( ".\n" );
1365 */
1366
1367 wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() );
1368 event.SetEventObject( win );
1369
1370 if (win->GetEventHandler()->ProcessEvent( event ))
1371 {
1372 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
1373 return TRUE;
1374 }
1375
1376 return FALSE;
1377 }
1378
1379 //-----------------------------------------------------------------------------
1380 // "focus_out_event"
1381 //-----------------------------------------------------------------------------
1382
1383 static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindow *win )
1384 {
1385 if (g_isIdle)
1386 wxapp_install_idle_handler();
1387
1388 if (!win->m_hasVMT) return FALSE;
1389 if (g_blockEventsOnDrag) return FALSE;
1390
1391 if (win->m_wxwindow)
1392 {
1393 if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow))
1394 GTK_WIDGET_UNSET_FLAGS (win->m_wxwindow, GTK_HAS_FOCUS);
1395 }
1396
1397 /*
1398 printf( "OnKillFocus from " );
1399 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1400 printf( win->GetClassInfo()->GetClassName() );
1401 printf( ".\n" );
1402 */
1403
1404 wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
1405 event.SetEventObject( win );
1406
1407 if (win->GetEventHandler()->ProcessEvent( event ))
1408 {
1409 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_out_event" );
1410 return TRUE;
1411 }
1412
1413 return FALSE;
1414 }
1415
1416 //-----------------------------------------------------------------------------
1417 // "enter_notify_event"
1418 //-----------------------------------------------------------------------------
1419
1420 static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindow *win )
1421 {
1422 if (g_isIdle)
1423 wxapp_install_idle_handler();
1424
1425 if (!win->m_hasVMT) return FALSE;
1426 if (g_blockEventsOnDrag) return FALSE;
1427
1428 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1429
1430 wxMouseEvent event( wxEVT_ENTER_WINDOW );
1431 #if (GTK_MINOR_VERSION > 0)
1432 event.SetTimestamp( gdk_event->time );
1433 #endif
1434 event.SetEventObject( win );
1435
1436 int x = 0;
1437 int y = 0;
1438 GdkModifierType state = (GdkModifierType)0;
1439
1440 gdk_window_get_pointer( widget->window, &x, &y, &state );
1441
1442 event.m_shiftDown = (state & GDK_SHIFT_MASK);
1443 event.m_controlDown = (state & GDK_CONTROL_MASK);
1444 event.m_altDown = (state & GDK_MOD1_MASK);
1445 event.m_metaDown = (state & GDK_MOD2_MASK);
1446 event.m_leftDown = (state & GDK_BUTTON1_MASK);
1447 event.m_middleDown = (state & GDK_BUTTON2_MASK);
1448 event.m_rightDown = (state & GDK_BUTTON3_MASK);
1449
1450 event.m_x = (long)x;
1451 event.m_y = (long)y;
1452
1453 if (win->GetEventHandler()->ProcessEvent( event ))
1454 {
1455 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "enter_notify_event" );
1456 return TRUE;
1457 }
1458
1459 return FALSE;
1460 }
1461
1462 //-----------------------------------------------------------------------------
1463 // "leave_notify_event"
1464 //-----------------------------------------------------------------------------
1465
1466 static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindow *win )
1467 {
1468 if (g_isIdle)
1469 wxapp_install_idle_handler();
1470
1471 if (!win->m_hasVMT) return FALSE;
1472 if (g_blockEventsOnDrag) return FALSE;
1473
1474 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1475
1476 wxMouseEvent event( wxEVT_LEAVE_WINDOW );
1477 #if (GTK_MINOR_VERSION > 0)
1478 event.SetTimestamp( gdk_event->time );
1479 #endif
1480 event.SetEventObject( win );
1481
1482 int x = 0;
1483 int y = 0;
1484 GdkModifierType state = (GdkModifierType)0;
1485
1486 gdk_window_get_pointer( widget->window, &x, &y, &state );
1487
1488 event.m_shiftDown = (state & GDK_SHIFT_MASK);
1489 event.m_controlDown = (state & GDK_CONTROL_MASK);
1490 event.m_altDown = (state & GDK_MOD1_MASK);
1491 event.m_metaDown = (state & GDK_MOD2_MASK);
1492 event.m_leftDown = (state & GDK_BUTTON1_MASK);
1493 event.m_middleDown = (state & GDK_BUTTON2_MASK);
1494 event.m_rightDown = (state & GDK_BUTTON3_MASK);
1495
1496 event.m_x = (long)x;
1497 event.m_y = (long)y;
1498
1499 if (win->GetEventHandler()->ProcessEvent( event ))
1500 {
1501 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "leave_notify_event" );
1502 return TRUE;
1503 }
1504
1505 return FALSE;
1506 }
1507
1508 //-----------------------------------------------------------------------------
1509 // "value_changed" from m_vAdjust
1510 //-----------------------------------------------------------------------------
1511
1512 static void gtk_window_vscroll_callback( GtkWidget *WXUNUSED(widget), wxWindow *win )
1513 {
1514 if (g_isIdle)
1515 wxapp_install_idle_handler();
1516
1517 if (g_blockEventsOnDrag) return;
1518
1519 if (!win->m_hasVMT) return;
1520
1521 float diff = win->m_vAdjust->value - win->m_oldVerticalPos;
1522 if (fabs(diff) < 0.2) return;
1523 win->m_oldVerticalPos = win->m_vAdjust->value;
1524
1525 wxEventType command = wxEVT_NULL;
1526
1527 float line_step = win->m_vAdjust->step_increment;
1528 float page_step = win->m_vAdjust->page_increment;
1529
1530 if (win->IsScrolling())
1531 {
1532 command = wxEVT_SCROLLWIN_THUMBTRACK;
1533 }
1534 else
1535 {
1536 if (fabs(win->m_vAdjust->value-win->m_vAdjust->lower) < 0.2) command = wxEVT_SCROLLWIN_BOTTOM;
1537 else if (fabs(win->m_vAdjust->value-win->m_vAdjust->upper) < 0.2) command = wxEVT_SCROLLWIN_TOP;
1538 else if (fabs(diff-line_step) < 0.2) command = wxEVT_SCROLLWIN_LINEDOWN;
1539 else if (fabs(diff+line_step) < 0.2) command = wxEVT_SCROLLWIN_LINEUP;
1540 else if (fabs(diff-page_step) < 0.2) command = wxEVT_SCROLLWIN_PAGEDOWN;
1541 else if (fabs(diff+page_step) < 0.2) command = wxEVT_SCROLLWIN_PAGEUP;
1542 else command = wxEVT_SCROLLWIN_THUMBTRACK;
1543 }
1544
1545 int value = (int)(win->m_vAdjust->value+0.5);
1546
1547 wxScrollWinEvent event( command, value, wxVERTICAL );
1548 event.SetEventObject( win );
1549 win->GetEventHandler()->ProcessEvent( event );
1550 }
1551
1552 //-----------------------------------------------------------------------------
1553 // "value_changed" from m_hAdjust
1554 //-----------------------------------------------------------------------------
1555
1556 static void gtk_window_hscroll_callback( GtkWidget *WXUNUSED(widget), wxWindow *win )
1557 {
1558 if (g_isIdle)
1559 wxapp_install_idle_handler();
1560
1561 if (g_blockEventsOnDrag) return;
1562 if (!win->m_hasVMT) return;
1563
1564 float diff = win->m_hAdjust->value - win->m_oldHorizontalPos;
1565 if (fabs(diff) < 0.2) return;
1566 win->m_oldHorizontalPos = win->m_hAdjust->value;
1567
1568 wxEventType command = wxEVT_NULL;
1569
1570 float line_step = win->m_hAdjust->step_increment;
1571 float page_step = win->m_hAdjust->page_increment;
1572
1573 if (win->IsScrolling())
1574 {
1575 command = wxEVT_SCROLLWIN_THUMBTRACK;
1576 }
1577 else
1578 {
1579 if (fabs(win->m_hAdjust->value-win->m_hAdjust->lower) < 0.2) command = wxEVT_SCROLLWIN_BOTTOM;
1580 else if (fabs(win->m_hAdjust->value-win->m_hAdjust->upper) < 0.2) command = wxEVT_SCROLLWIN_TOP;
1581 else if (fabs(diff-line_step) < 0.2) command = wxEVT_SCROLLWIN_LINEDOWN;
1582 else if (fabs(diff+line_step) < 0.2) command = wxEVT_SCROLLWIN_LINEUP;
1583 else if (fabs(diff-page_step) < 0.2) command = wxEVT_SCROLLWIN_PAGEDOWN;
1584 else if (fabs(diff+page_step) < 0.2) command = wxEVT_SCROLLWIN_PAGEUP;
1585 else command = wxEVT_SCROLLWIN_THUMBTRACK;
1586 }
1587
1588 int value = (int)(win->m_hAdjust->value+0.5);
1589
1590 wxScrollWinEvent event( command, value, wxHORIZONTAL );
1591 event.SetEventObject( win );
1592 win->GetEventHandler()->ProcessEvent( event );
1593 }
1594
1595 //-----------------------------------------------------------------------------
1596 // "changed" from m_vAdjust
1597 //-----------------------------------------------------------------------------
1598
1599 static void gtk_window_vscroll_change_callback( GtkWidget *WXUNUSED(widget), wxWindow *win )
1600 {
1601 if (g_isIdle)
1602 wxapp_install_idle_handler();
1603
1604 if (g_blockEventsOnDrag) return;
1605 if (!win->m_hasVMT) return;
1606
1607 wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK;
1608 int value = (int)(win->m_vAdjust->value+0.5);
1609
1610 wxScrollWinEvent event( command, value, wxVERTICAL );
1611 event.SetEventObject( win );
1612 win->GetEventHandler()->ProcessEvent( event );
1613 }
1614
1615 //-----------------------------------------------------------------------------
1616 // "changed" from m_hAdjust
1617 //-----------------------------------------------------------------------------
1618
1619 static void gtk_window_hscroll_change_callback( GtkWidget *WXUNUSED(widget), wxWindow *win )
1620 {
1621 if (g_isIdle)
1622 wxapp_install_idle_handler();
1623
1624 if (g_blockEventsOnDrag) return;
1625 if (!win->m_hasVMT) return;
1626
1627 wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK;
1628 int value = (int)(win->m_hAdjust->value+0.5);
1629
1630 wxScrollWinEvent event( command, value, wxHORIZONTAL );
1631 event.SetEventObject( win );
1632 win->GetEventHandler()->ProcessEvent( event );
1633 }
1634
1635 //-----------------------------------------------------------------------------
1636 // "button_press_event" from scrollbar
1637 //-----------------------------------------------------------------------------
1638
1639 static gint gtk_scrollbar_button_press_callback( GtkRange *WXUNUSED(widget),
1640 GdkEventButton *WXUNUSED(gdk_event),
1641 wxWindow *win )
1642 {
1643 if (g_isIdle)
1644 wxapp_install_idle_handler();
1645
1646 // don't test here as we can release the mouse while being over
1647 // a different window then the slider
1648 //
1649 // if (gdk_event->window != widget->slider) return FALSE;
1650
1651 win->SetScrolling( TRUE );
1652
1653 return FALSE;
1654 }
1655
1656 //-----------------------------------------------------------------------------
1657 // "button_release_event" from scrollbar
1658 //-----------------------------------------------------------------------------
1659
1660 static gint gtk_scrollbar_button_release_callback( GtkRange *widget,
1661 GdkEventButton *WXUNUSED(gdk_event),
1662 wxWindow *win )
1663 {
1664
1665 // don't test here as we can release the mouse while being over
1666 // a different window then the slider
1667 //
1668 // if (gdk_event->window != widget->slider) return FALSE;
1669
1670 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1671
1672 if (widget == GTK_RANGE(scrolledWindow->vscrollbar))
1673 gtk_signal_emit_by_name( GTK_OBJECT(win->m_hAdjust), "value_changed" );
1674 else
1675 gtk_signal_emit_by_name( GTK_OBJECT(win->m_vAdjust), "value_changed" );
1676
1677 win->SetScrolling( FALSE );
1678
1679 return FALSE;
1680 }
1681
1682 // ----------------------------------------------------------------------------
1683 // this wxWindowBase function is implemented here (in platform-specific file)
1684 // because it is static and so couldn't be made virtual
1685 // ----------------------------------------------------------------------------
1686
1687 wxWindow *wxWindowBase::FindFocus()
1688 {
1689 return g_focusWindow;
1690 }
1691
1692 //-----------------------------------------------------------------------------
1693 // "realize" from m_widget
1694 //-----------------------------------------------------------------------------
1695
1696 /* we cannot set colours, fonts and cursors before the widget has
1697 been realized, so we do this directly after realization */
1698
1699 static gint
1700 gtk_window_realized_callback( GtkWidget * WXUNUSED(widget), wxWindow *win )
1701 {
1702 if (g_isIdle)
1703 wxapp_install_idle_handler();
1704
1705 if (win->m_delayedFont)
1706 win->SetFont( win->GetFont() );
1707
1708 if (win->m_delayedBackgroundColour)
1709 win->SetBackgroundColour( win->GetBackgroundColour() );
1710
1711 if (win->m_delayedForegroundColour)
1712 win->SetForegroundColour( win->GetForegroundColour() );
1713
1714 win->SetCursor( win->GetCursor() );
1715
1716 wxWindowCreateEvent event( win );
1717 event.SetEventObject( win );
1718 win->GetEventHandler()->ProcessEvent( event );
1719
1720 return FALSE;
1721 }
1722
1723 //-----------------------------------------------------------------------------
1724 // InsertChild for wxWindow.
1725 //-----------------------------------------------------------------------------
1726
1727 /* Callback for wxWindow. This very strange beast has to be used because
1728 * C++ has no virtual methods in a constructor. We have to emulate a
1729 * virtual function here as wxNotebook requires a different way to insert
1730 * a child in it. I had opted for creating a wxNotebookPage window class
1731 * which would have made this superfluous (such in the MDI window system),
1732 * but no-one was listening to me... */
1733
1734 static void wxInsertChildInWindow( wxWindow* parent, wxWindow* child )
1735 {
1736 gtk_myfixed_put( GTK_MYFIXED(parent->m_wxwindow),
1737 GTK_WIDGET(child->m_widget),
1738 child->m_x,
1739 child->m_y,
1740 child->m_width,
1741 child->m_height );
1742
1743 if (parent->HasFlag(wxTAB_TRAVERSAL))
1744 {
1745 /* we now allow a window to get the focus as long as it
1746 doesn't have any children. */
1747 GTK_WIDGET_UNSET_FLAGS( parent->m_wxwindow, GTK_CAN_FOCUS );
1748 }
1749 }
1750
1751 //-----------------------------------------------------------------------------
1752 // global functions
1753 //-----------------------------------------------------------------------------
1754
1755 wxWindow* wxGetActiveWindow()
1756 {
1757 return g_focusWindow;
1758 }
1759
1760 //-----------------------------------------------------------------------------
1761 // wxWindow
1762 //-----------------------------------------------------------------------------
1763
1764 IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
1765
1766 void wxWindow::Init()
1767 {
1768 // common init
1769 InitBase();
1770
1771 // GTK specific
1772 m_widget = (GtkWidget *) NULL;
1773 m_wxwindow = (GtkWidget *) NULL;
1774
1775 // position/size
1776 m_x = 0;
1777 m_y = 0;
1778 m_width = 0;
1779 m_height = 0;
1780
1781 m_sizeSet = FALSE;
1782 m_hasVMT = FALSE;
1783 m_needParent = TRUE;
1784 m_isBeingDeleted = FALSE;
1785
1786 m_hasScrolling = FALSE;
1787 m_isScrolling = FALSE;
1788
1789 m_hAdjust = (GtkAdjustment*) NULL;
1790 m_vAdjust = (GtkAdjustment*) NULL;
1791 m_oldHorizontalPos = 0.0;
1792 m_oldVerticalPos = 0.0;
1793
1794 m_resizing = FALSE;
1795 m_scrollGC = (GdkGC*) NULL;
1796 m_widgetStyle = (GtkStyle*) NULL;
1797
1798 m_insertCallback = (wxInsertChildFunction) NULL;
1799
1800 m_isStaticBox = FALSE;
1801 m_isRadioButton = FALSE;
1802 m_acceptsFocus = FALSE;
1803 }
1804
1805 wxWindow::wxWindow()
1806 {
1807 Init();
1808 }
1809
1810 wxWindow::wxWindow( wxWindow *parent, wxWindowID id,
1811 const wxPoint &pos, const wxSize &size,
1812 long style, const wxString &name )
1813 {
1814 Init();
1815
1816 Create( parent, id, pos, size, style, name );
1817 }
1818
1819 bool wxWindow::Create( wxWindow *parent, wxWindowID id,
1820 const wxPoint &pos, const wxSize &size,
1821 long style, const wxString &name )
1822 {
1823 if (!PreCreation( parent, pos, size ) ||
1824 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
1825 {
1826 wxFAIL_MSG( _T("wxWindow creation failed") );
1827 return FALSE;
1828 }
1829
1830 m_insertCallback = wxInsertChildInWindow;
1831
1832 m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
1833 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
1834
1835 #ifdef __WXDEBUG__
1836 debug_focus_in( m_widget, _T("wxWindow::m_widget"), name );
1837 #endif
1838
1839 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
1840
1841 #ifdef __WXDEBUG__
1842 debug_focus_in( scrolledWindow->hscrollbar, _T("wxWindow::hsrcollbar"), name );
1843 debug_focus_in( scrolledWindow->vscrollbar, _T("wxWindow::vsrcollbar"), name );
1844 #endif
1845
1846 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(m_widget)->klass );
1847 scroll_class->scrollbar_spacing = 0;
1848
1849 gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
1850
1851 m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->hscrollbar) );
1852 m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->vscrollbar) );
1853
1854 m_wxwindow = gtk_myfixed_new();
1855
1856 #ifdef __WXDEBUG__
1857 debug_focus_in( m_wxwindow, _T("wxWindow::m_wxwindow"), name );
1858 #endif
1859
1860 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
1861
1862 #if (GTK_MINOR_VERSION > 0)
1863 GtkMyFixed *myfixed = GTK_MYFIXED(m_wxwindow);
1864
1865 if (HasFlag(wxRAISED_BORDER))
1866 {
1867 gtk_myfixed_set_shadow_type( myfixed, GTK_SHADOW_OUT );
1868 }
1869 else if (HasFlag(wxSUNKEN_BORDER))
1870 {
1871 gtk_myfixed_set_shadow_type( myfixed, GTK_SHADOW_IN );
1872 }
1873 else
1874 {
1875 gtk_myfixed_set_shadow_type( myfixed, GTK_SHADOW_NONE );
1876 }
1877 #else // GTK_MINOR_VERSION == 0
1878 GtkViewport *viewport = GTK_VIEWPORT(scrolledWindow->viewport);
1879
1880 if (HasFlag(wxRAISED_BORDER))
1881 {
1882 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_OUT );
1883 }
1884 else if (HasFlag(wxSUNKEN_BORDER))
1885 {
1886 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_IN );
1887 }
1888 else
1889 {
1890 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_NONE );
1891 }
1892 #endif // GTK_MINOR_VERSION
1893
1894 if (HasFlag(wxTAB_TRAVERSAL))
1895 {
1896 /* we now allow a window to get the focus as long as it
1897 doesn't have any children. */
1898 GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
1899 m_acceptsFocus = FALSE;
1900 }
1901 else
1902 {
1903 GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
1904 m_acceptsFocus = TRUE;
1905 }
1906
1907 #if (GTK_MINOR_VERSION == 0)
1908 // shut the viewport up
1909 gtk_viewport_set_hadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
1910 gtk_viewport_set_vadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
1911 #endif // GTK_MINOR_VERSION == 0
1912
1913 // I _really_ don't want scrollbars in the beginning
1914 m_vAdjust->lower = 0.0;
1915 m_vAdjust->upper = 1.0;
1916 m_vAdjust->value = 0.0;
1917 m_vAdjust->step_increment = 1.0;
1918 m_vAdjust->page_increment = 1.0;
1919 m_vAdjust->page_size = 5.0;
1920 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
1921 m_hAdjust->lower = 0.0;
1922 m_hAdjust->upper = 1.0;
1923 m_hAdjust->value = 0.0;
1924 m_hAdjust->step_increment = 1.0;
1925 m_hAdjust->page_increment = 1.0;
1926 m_hAdjust->page_size = 5.0;
1927 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
1928
1929 // these handlers block mouse events to any window during scrolling such as
1930 // motion events and prevent GTK and wxWindows from fighting over where the
1931 // slider should be
1932
1933 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_press_event",
1934 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
1935
1936 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_press_event",
1937 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
1938
1939 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_release_event",
1940 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
1941
1942 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_release_event",
1943 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
1944
1945 // these handlers get notified when screen updates are required either when
1946 // scrolling or when the window size (and therefore scrollbar configuration)
1947 // has changed
1948
1949 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
1950 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
1951 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
1952 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
1953
1954 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "changed",
1955 (GtkSignalFunc) gtk_window_hscroll_change_callback, (gpointer) this );
1956 gtk_signal_connect(GTK_OBJECT(m_vAdjust), "changed",
1957 (GtkSignalFunc) gtk_window_vscroll_change_callback, (gpointer) this );
1958
1959 gtk_widget_show( m_wxwindow );
1960
1961 if (m_parent)
1962 m_parent->DoAddChild( this );
1963
1964 PostCreation();
1965
1966 Show( TRUE );
1967
1968 return TRUE;
1969 }
1970
1971 wxWindow::~wxWindow()
1972 {
1973 m_isBeingDeleted = TRUE;
1974 m_hasVMT = FALSE;
1975
1976 if (m_widget)
1977 Show( FALSE );
1978
1979 DestroyChildren();
1980
1981 if (m_parent)
1982 m_parent->RemoveChild( this );
1983
1984 if (m_widgetStyle)
1985 {
1986 gtk_style_unref( m_widgetStyle );
1987 m_widgetStyle = (GtkStyle*) NULL;
1988 }
1989
1990 if (m_scrollGC)
1991 {
1992 gdk_gc_unref( m_scrollGC );
1993 m_scrollGC = (GdkGC*) NULL;
1994 }
1995
1996 if (m_wxwindow)
1997 {
1998 gtk_widget_destroy( m_wxwindow );
1999 m_wxwindow = (GtkWidget*) NULL;
2000 }
2001
2002 if (m_widget)
2003 {
2004 gtk_widget_destroy( m_widget );
2005 m_widget = (GtkWidget*) NULL;
2006 }
2007 }
2008
2009 bool wxWindow::PreCreation( wxWindow *parent, const wxPoint &pos, const wxSize &size )
2010 {
2011 wxCHECK_MSG( !m_needParent || parent, FALSE, _T("Need complete parent.") );
2012
2013 /* this turns -1 into 20 so that a minimal window is
2014 visible even although -1,-1 has been given as the
2015 size of the window. the same trick is used in other
2016 ports and should make debugging easier */
2017 m_width = WidthDefault(size.x);
2018 m_height = HeightDefault(size.y);
2019
2020 m_x = (int)pos.x;
2021 m_y = (int)pos.y;
2022
2023 /* some reasonable defaults */
2024 if (!parent)
2025 {
2026 if (m_x == -1)
2027 {
2028 m_x = (gdk_screen_width () - m_width) / 2;
2029 if (m_x < 10) m_x = 10;
2030 }
2031 if (m_y == -1)
2032 {
2033 m_y = (gdk_screen_height () - m_height) / 2;
2034 if (m_y < 10) m_y = 10;
2035 }
2036 }
2037
2038 return TRUE;
2039 }
2040
2041 void wxWindow::PostCreation()
2042 {
2043 wxASSERT_MSG( (m_widget != NULL), _T("invalid window") );
2044
2045 if (m_wxwindow)
2046 {
2047 /* these get reported to wxWindows -> wxPaintEvent */
2048 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
2049 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
2050
2051 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
2052 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
2053
2054 #if (GTK_MINOR_VERSION > 0)
2055 /* these are called when the "sunken" or "raised" borders are drawn */
2056 gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
2057 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
2058
2059 gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
2060 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
2061 #endif
2062 }
2063
2064 GtkWidget *connect_widget = GetConnectWidget();
2065
2066 ConnectWidget( connect_widget );
2067
2068 /* we cannot set colours, fonts and cursors before the widget has
2069 been realized, so we do this directly after realization */
2070 gtk_signal_connect( GTK_OBJECT(connect_widget), "realize",
2071 GTK_SIGNAL_FUNC(gtk_window_realized_callback), (gpointer) this );
2072
2073 m_hasVMT = TRUE;
2074 }
2075
2076 void wxWindow::ConnectWidget( GtkWidget *widget )
2077 {
2078 gtk_signal_connect( GTK_OBJECT(widget), "key_press_event",
2079 GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this );
2080
2081 gtk_signal_connect( GTK_OBJECT(widget), "key_release_event",
2082 GTK_SIGNAL_FUNC(gtk_window_key_release_callback), (gpointer)this );
2083
2084 gtk_signal_connect( GTK_OBJECT(widget), "button_press_event",
2085 GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
2086
2087 gtk_signal_connect( GTK_OBJECT(widget), "button_release_event",
2088 GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
2089
2090 gtk_signal_connect( GTK_OBJECT(widget), "motion_notify_event",
2091 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
2092
2093 gtk_signal_connect( GTK_OBJECT(widget), "focus_in_event",
2094 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
2095
2096 gtk_signal_connect( GTK_OBJECT(widget), "focus_out_event",
2097 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
2098
2099 gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event",
2100 GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
2101
2102 gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
2103 GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
2104 }
2105
2106 bool wxWindow::Destroy()
2107 {
2108 wxASSERT_MSG( (m_widget != NULL), _T("invalid window") );
2109
2110 m_hasVMT = FALSE;
2111
2112 return wxWindowBase::Destroy();
2113 }
2114
2115 void wxWindow::DoSetSize( int x, int y, int width, int height, int sizeFlags )
2116 {
2117 wxASSERT_MSG( (m_widget != NULL), _T("invalid window") );
2118 wxASSERT_MSG( (m_parent != NULL), _T("wxWindow::SetSize requires parent.\n") );
2119
2120 if (m_resizing) return; /* I don't like recursions */
2121 m_resizing = TRUE;
2122
2123 if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
2124 {
2125 /* don't set the size for children of wxNotebook, just take the values. */
2126 m_x = x;
2127 m_y = y;
2128 m_width = width;
2129 m_height = height;
2130 }
2131 else
2132 {
2133 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
2134 {
2135 if (x != -1) m_x = x;
2136 if (y != -1) m_y = y;
2137 if (width != -1) m_width = width;
2138 if (height != -1) m_height = height;
2139 }
2140 else
2141 {
2142 m_x = x;
2143 m_y = y;
2144 m_width = width;
2145 m_height = height;
2146 }
2147
2148 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
2149 {
2150 if (width == -1) m_width = 80;
2151 }
2152
2153 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
2154 {
2155 if (height == -1) m_height = 26;
2156 }
2157
2158 if ((m_minWidth != -1) && (m_width < m_minWidth)) m_width = m_minWidth;
2159 if ((m_minHeight != -1) && (m_height < m_minHeight)) m_height = m_minHeight;
2160 if ((m_maxWidth != -1) && (m_width > m_maxWidth)) m_width = m_maxWidth;
2161 if ((m_maxHeight != -1) && (m_height > m_maxHeight)) m_height = m_maxHeight;
2162
2163 int border = 0;
2164 int bottom_border = 0;
2165
2166 if (GTK_WIDGET_CAN_DEFAULT(m_widget))
2167 {
2168 /* the default button has a border around it */
2169 border = 6;
2170 bottom_border = 5;
2171 }
2172
2173 /* this is the result of hours of debugging: the following code
2174 means that if we have a m_wxwindow and we set the size of
2175 m_widget, m_widget (which is a GtkScrolledWindow) does NOT
2176 automatically propagate its size down to its m_wxwindow,
2177 which is its client area. therefore, we have to tell the
2178 client area directly that it has to resize itself.
2179 this will lead to that m_widget (GtkScrolledWindow) will
2180 calculate how much size it needs for scrollbars etc and
2181 it will then call XXX_size_allocate of its child, which
2182 is m_wxwindow. m_wxwindow in turn will do the same with its
2183 children and so on. problems can arise if this happens
2184 before all the children have been realized as some widgets
2185 stupidy need to be realized during XXX_size_allocate (e.g.
2186 GtkNotebook) and they will segv if called otherwise. this
2187 emergency is tested in gtk_myfixed_size_allocate. Normally
2188 this shouldn't be needed and only gtk_widget_queue_resize()
2189 should be enough to provoke a resize at the next appropriate
2190 moment, but this seems to fail, e.g. when a wxNotebook contains
2191 a wxSplitterWindow: the splitter window's children won't
2192 show up properly resized then. */
2193
2194 gtk_myfixed_set_size( GTK_MYFIXED(m_parent->m_wxwindow),
2195 m_widget,
2196 m_x-border,
2197 m_y-border,
2198 m_width+2*border,
2199 m_height+border+bottom_border );
2200 }
2201
2202 m_sizeSet = TRUE;
2203
2204 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
2205 event.SetEventObject( this );
2206 GetEventHandler()->ProcessEvent( event );
2207
2208 m_resizing = FALSE;
2209 }
2210
2211 void wxWindow::OnInternalIdle()
2212 {
2213 wxCursor cursor = m_cursor;
2214 if (g_globalCursor.Ok()) cursor = g_globalCursor;
2215
2216 if (cursor.Ok() && m_currentGdkCursor != cursor)
2217 {
2218 m_currentGdkCursor = cursor;
2219
2220 if (m_wxwindow)
2221 {
2222 GdkWindow *window = m_wxwindow->window;
2223 if (window)
2224 gdk_window_set_cursor( window, cursor.GetCursor() );
2225
2226 if (!g_globalCursor.Ok())
2227 cursor = *wxSTANDARD_CURSOR;
2228
2229 window = m_widget->window;
2230 if (window)
2231 gdk_window_set_cursor( window, cursor.GetCursor() );
2232 }
2233 else
2234 {
2235 GdkWindow *window = m_widget->window;
2236 if (window)
2237 gdk_window_set_cursor( window, cursor.GetCursor() );
2238 }
2239 }
2240
2241 UpdateWindowUI();
2242 }
2243
2244 void wxWindow::DoGetSize( int *width, int *height ) const
2245 {
2246 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2247
2248 if (width) (*width) = m_width;
2249 if (height) (*height) = m_height;
2250 }
2251
2252 void wxWindow::DoSetClientSize( int width, int height )
2253 {
2254 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2255
2256 if (!m_wxwindow)
2257 {
2258 SetSize( width, height );
2259 }
2260 else
2261 {
2262 int dw = 0;
2263 int dh = 0;
2264
2265 #if (GTK_MINOR_VERSION == 0)
2266 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
2267 {
2268 if (HasScrolling())
2269 {
2270 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2271 #if 0 // unused - if this is ok, just remove this line (VZ)
2272 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(m_widget)->klass );
2273 #endif // 0
2274
2275 GtkWidget *viewport = scroll_window->viewport;
2276 GtkStyleClass *viewport_class = viewport->style->klass;
2277
2278 dw += 2 * viewport_class->xthickness;
2279 dh += 2 * viewport_class->ythickness;
2280 }
2281 }
2282 #else
2283 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
2284 {
2285 /* when using GTK 1.2 we set the border size to 2 */
2286 dw += 2 * 2;
2287 dh += 2 * 2;
2288 }
2289 #endif
2290
2291 if (HasScrolling())
2292 {
2293 /*
2294 GtkWidget *hscrollbar = scroll_window->hscrollbar;
2295 GtkWidget *vscrollbar = scroll_window->vscrollbar;
2296
2297 we use this instead: range.slider_width = 11 + 2*2pts edge
2298 */
2299
2300 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2301 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(m_widget)->klass );
2302
2303 if (scroll_window->vscrollbar_visible)
2304 {
2305 dw += 15; /* dw += vscrollbar->allocation.width; */
2306 dw += scroll_class->scrollbar_spacing;
2307 }
2308
2309 if (scroll_window->hscrollbar_visible)
2310 {
2311 dh += 15; /* dh += hscrollbar->allocation.height; */
2312 dh += scroll_class->scrollbar_spacing;
2313 }
2314 }
2315
2316 SetSize( width+dw, height+dh );
2317 }
2318 }
2319
2320 void wxWindow::DoGetClientSize( int *width, int *height ) const
2321 {
2322 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2323
2324 if (!m_wxwindow)
2325 {
2326 if (width) (*width) = m_width;
2327 if (height) (*height) = m_height;
2328 }
2329 else
2330 {
2331 int dw = 0;
2332 int dh = 0;
2333
2334 #if (GTK_MINOR_VERSION == 0)
2335 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
2336 {
2337 if (HasScrolling())
2338 {
2339 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2340 #if 0 // unused - if this is ok, just remove this line (VZ)
2341 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(m_widget)->klass );
2342 #endif // 0
2343
2344 GtkWidget *viewport = scroll_window->viewport;
2345 GtkStyleClass *viewport_class = viewport->style->klass;
2346
2347 dw += 2 * viewport_class->xthickness;
2348 dh += 2 * viewport_class->ythickness;
2349 }
2350 }
2351 #else
2352 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
2353 {
2354 /* when using GTK 1.2 we set the border size to 2 */
2355 dw += 2 * 2;
2356 dh += 2 * 2;
2357 }
2358 #endif
2359 if (HasScrolling())
2360 {
2361 /*
2362 GtkWidget *hscrollbar = scroll_window->hscrollbar;
2363 GtkWidget *vscrollbar = scroll_window->vscrollbar;
2364
2365 we use this instead: range.slider_width = 11 + 2*2pts edge
2366 */
2367
2368 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2369 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(m_widget)->klass );
2370
2371 if (scroll_window->vscrollbar_visible)
2372 {
2373 dw += 15; /* dw += vscrollbar->allocation.width; */
2374 dw += scroll_class->scrollbar_spacing;
2375 }
2376
2377 if (scroll_window->hscrollbar_visible)
2378 {
2379 dh += 15; /* dh += hscrollbar->allocation.height; */
2380 dh += scroll_class->scrollbar_spacing;
2381 }
2382 }
2383
2384 if (width) (*width) = m_width - dw;
2385 if (height) (*height) = m_height - dh;
2386 }
2387 }
2388
2389 void wxWindow::DoGetPosition( int *x, int *y ) const
2390 {
2391 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2392
2393 if (x) (*x) = m_x;
2394 if (y) (*y) = m_y;
2395 }
2396
2397 void wxWindow::DoClientToScreen( int *x, int *y ) const
2398 {
2399 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2400
2401 if (!m_widget->window) return;
2402
2403 GdkWindow *source = (GdkWindow *) NULL;
2404 if (m_wxwindow)
2405 source = m_wxwindow->window;
2406 else
2407 source = m_widget->window;
2408
2409 int org_x = 0;
2410 int org_y = 0;
2411 gdk_window_get_origin( source, &org_x, &org_y );
2412
2413 if (!m_wxwindow)
2414 {
2415 if (GTK_WIDGET_NO_WINDOW (m_widget))
2416 {
2417 org_x += m_widget->allocation.x;
2418 org_y += m_widget->allocation.y;
2419 }
2420 }
2421
2422 if (x) *x += org_x;
2423 if (y) *y += org_y;
2424 }
2425
2426 void wxWindow::DoScreenToClient( int *x, int *y ) const
2427 {
2428 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2429
2430 if (!m_widget->window) return;
2431
2432 GdkWindow *source = (GdkWindow *) NULL;
2433 if (m_wxwindow)
2434 source = m_wxwindow->window;
2435 else
2436 source = m_widget->window;
2437
2438 int org_x = 0;
2439 int org_y = 0;
2440 gdk_window_get_origin( source, &org_x, &org_y );
2441
2442 if (!m_wxwindow)
2443 {
2444 if (GTK_WIDGET_NO_WINDOW (m_widget))
2445 {
2446 org_x += m_widget->allocation.x;
2447 org_y += m_widget->allocation.y;
2448 }
2449 }
2450
2451 if (x) *x -= org_x;
2452 if (y) *y -= org_y;
2453 }
2454
2455 bool wxWindow::Show( bool show )
2456 {
2457 wxCHECK_MSG( (m_widget != NULL), FALSE, _T("invalid window") );
2458
2459 if (!wxWindowBase::Show(show))
2460 {
2461 // nothing to do
2462 return FALSE;
2463 }
2464
2465 if (show)
2466 gtk_widget_show( m_widget );
2467 else
2468 gtk_widget_hide( m_widget );
2469
2470 return TRUE;
2471 }
2472
2473 bool wxWindow::Enable( bool enable )
2474 {
2475 wxCHECK_MSG( (m_widget != NULL), FALSE, _T("invalid window") );
2476
2477 if (!wxWindowBase::Enable(enable))
2478 {
2479 // nothing to do
2480 return FALSE;
2481 }
2482
2483 gtk_widget_set_sensitive( m_widget, enable );
2484 if ( m_wxwindow )
2485 gtk_widget_set_sensitive( m_wxwindow, enable );
2486
2487 return TRUE;
2488 }
2489
2490 int wxWindow::GetCharHeight() const
2491 {
2492 wxCHECK_MSG( (m_widget != NULL), 12, _T("invalid window") );
2493
2494 wxCHECK_MSG( m_font.Ok(), 12, _T("invalid font") );
2495
2496 GdkFont *font = m_font.GetInternalFont( 1.0 );
2497
2498 return font->ascent + font->descent;
2499 }
2500
2501 int wxWindow::GetCharWidth() const
2502 {
2503 wxCHECK_MSG( (m_widget != NULL), 8, _T("invalid window") );
2504
2505 wxCHECK_MSG( m_font.Ok(), 8, _T("invalid font") );
2506
2507 GdkFont *font = m_font.GetInternalFont( 1.0 );
2508
2509 return gdk_string_width( font, "H" );
2510 }
2511
2512 void wxWindow::GetTextExtent( const wxString& string,
2513 int *x,
2514 int *y,
2515 int *descent,
2516 int *externalLeading,
2517 const wxFont *theFont ) const
2518 {
2519 wxFont fontToUse = m_font;
2520 if (theFont) fontToUse = *theFont;
2521
2522 wxCHECK_RET( fontToUse.Ok(), _T("invalid font") );
2523
2524 GdkFont *font = fontToUse.GetInternalFont( 1.0 );
2525 if (x) (*x) = gdk_string_width( font, string.mbc_str() );
2526 if (y) (*y) = font->ascent + font->descent;
2527 if (descent) (*descent) = font->descent;
2528 if (externalLeading) (*externalLeading) = 0; // ??
2529 }
2530
2531 void wxWindow::SetFocus()
2532 {
2533 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2534
2535 GtkWidget *connect_widget = GetConnectWidget();
2536 if (connect_widget)
2537 {
2538 if (GTK_WIDGET_CAN_FOCUS(connect_widget) /*&& !GTK_WIDGET_HAS_FOCUS (connect_widget)*/ )
2539 {
2540 gtk_widget_grab_focus (connect_widget);
2541 }
2542 else if (GTK_IS_CONTAINER(connect_widget))
2543 {
2544 gtk_container_focus( GTK_CONTAINER(connect_widget), GTK_DIR_TAB_FORWARD );
2545 }
2546 else
2547 {
2548 }
2549 }
2550 }
2551
2552 bool wxWindow::AcceptsFocus() const
2553 {
2554 return m_acceptsFocus && wxWindowBase::AcceptsFocus();
2555 }
2556
2557 bool wxWindow::Reparent( wxWindowBase *newParentBase )
2558 {
2559 wxCHECK_MSG( (m_widget != NULL), FALSE, _T("invalid window") );
2560
2561 wxWindow *oldParent = m_parent,
2562 *newParent = (wxWindow *)newParentBase;
2563
2564 if ( !wxWindowBase::Reparent(newParent) )
2565 return FALSE;
2566
2567 if (oldParent)
2568 {
2569 gtk_container_remove( GTK_CONTAINER(oldParent->m_wxwindow), m_widget );
2570 }
2571
2572 if (newParent)
2573 {
2574 /* insert GTK representation */
2575 (*(newParent->m_insertCallback))(newParent, this);
2576 }
2577
2578 return TRUE;
2579 }
2580
2581 void wxWindow::DoAddChild(wxWindow *child)
2582 {
2583 wxASSERT_MSG( (m_widget != NULL), _T("invalid window") );
2584
2585 wxASSERT_MSG( (child != NULL), _T("invalid child window") );
2586
2587 wxASSERT_MSG( (m_insertCallback != NULL), _T("invalid child insertion function") );
2588
2589 /* add to list */
2590 AddChild( child );
2591
2592 /* insert GTK representation */
2593 (*m_insertCallback)(this, child);
2594 }
2595
2596 void wxWindow::Raise()
2597 {
2598 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2599
2600 if (!m_widget->window) return;
2601
2602 gdk_window_raise( m_widget->window );
2603 }
2604
2605 void wxWindow::Lower()
2606 {
2607 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2608
2609 if (!m_widget->window) return;
2610
2611 gdk_window_lower( m_widget->window );
2612 }
2613
2614 bool wxWindow::SetCursor( const wxCursor &cursor )
2615 {
2616 wxCHECK_MSG( (m_widget != NULL), FALSE, _T("invalid window") );
2617
2618 if (!wxWindowBase::SetCursor(cursor))
2619 {
2620 // don't leave if the GTK widget has just
2621 // been realized
2622 if (!m_delayedCursor) return FALSE;
2623 }
2624
2625 GtkWidget *connect_widget = GetConnectWidget();
2626 if (!connect_widget->window)
2627 {
2628 // indicate that a new style has been set
2629 // but it couldn't get applied as the
2630 // widget hasn't been realized yet.
2631 m_delayedCursor = TRUE;
2632
2633 // pretend we have done something
2634 return TRUE;
2635 }
2636
2637 // gdk_window_set_cursor( connect_widget->window, GetCursor().GetCursor() );
2638
2639 // cursor was set
2640 return TRUE;
2641 }
2642
2643 void wxWindow::WarpPointer( int x, int y )
2644 {
2645 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2646
2647 GtkWidget *connect_widget = GetConnectWidget();
2648 if (connect_widget->window)
2649 {
2650 /* we provide this function ourselves as it is
2651 missing in GDK */
2652 gdk_window_warp_pointer( connect_widget->window, x, y );
2653 }
2654 }
2655
2656 void wxWindow::Refresh( bool eraseBackground, const wxRect *rect )
2657 {
2658 wxCHECK_RET( (m_widget != NULL), _T("invalid window") );
2659
2660 if (!m_widget->window) return;
2661
2662 if (eraseBackground && m_wxwindow && m_wxwindow->window)
2663 {
2664 if (rect)
2665 {
2666 gdk_window_clear_area( m_wxwindow->window,
2667 rect->x, rect->y,
2668 rect->width, rect->height );
2669 }
2670 else
2671 {
2672 gdk_window_clear( m_wxwindow->window );
2673 }
2674 }
2675
2676 if (!rect)
2677 {
2678 if (m_wxwindow)
2679 gtk_widget_draw( m_wxwindow, (GdkRectangle*) NULL );
2680 else
2681 gtk_widget_draw( m_widget, (GdkRectangle*) NULL );
2682 }
2683 else
2684 {
2685 GdkRectangle gdk_rect;
2686 gdk_rect.x = rect->x;
2687 gdk_rect.y = rect->y;
2688 gdk_rect.width = rect->width;
2689 gdk_rect.height = rect->height;
2690
2691 if (m_wxwindow)
2692 gtk_widget_draw( m_wxwindow, &gdk_rect );
2693 else
2694 gtk_widget_draw( m_widget, &gdk_rect );
2695 }
2696 }
2697
2698 void wxWindow::Clear()
2699 {
2700 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
2701
2702 if (!m_widget->window) return;
2703
2704 if (m_wxwindow && m_wxwindow->window)
2705 {
2706 gdk_window_clear( m_wxwindow->window );
2707 }
2708 }
2709
2710 #if wxUSE_TOOLTIPS
2711 void wxWindow::DoSetToolTip( wxToolTip *tip )
2712 {
2713 wxWindowBase::DoSetToolTip(tip);
2714
2715 if (m_tooltip)
2716 m_tooltip->Apply( this );
2717 }
2718
2719 void wxWindow::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
2720 {
2721 gtk_tooltips_set_tip( tips, GetConnectWidget(), wxConvCurrent->cWX2MB(tip), (gchar*) NULL );
2722 }
2723 #endif // wxUSE_TOOLTIPS
2724
2725 bool wxWindow::SetBackgroundColour( const wxColour &colour )
2726 {
2727 wxCHECK_MSG( m_widget != NULL, FALSE, _T("invalid window") );
2728
2729 if (!wxWindowBase::SetBackgroundColour(colour))
2730 {
2731 // don't leave if the GTK widget has just
2732 // been realized
2733 if (!m_delayedBackgroundColour) return FALSE;
2734 }
2735
2736 GtkWidget *connect_widget = GetConnectWidget();
2737 if (!connect_widget->window)
2738 {
2739 // indicate that a new style has been set
2740 // but it couldn't get applied as the
2741 // widget hasn't been realized yet.
2742 m_delayedBackgroundColour = TRUE;
2743
2744 // pretend we have done something
2745 return TRUE;
2746 }
2747
2748 if (m_wxwindow && m_wxwindow->window)
2749 {
2750 /* wxMSW doesn't clear the window here. I don't do that either to
2751 provide compatibility. call Clear() to do the job. */
2752
2753 m_backgroundColour.CalcPixel( gdk_window_get_colormap( m_wxwindow->window ) );
2754 gdk_window_set_background( m_wxwindow->window, m_backgroundColour.GetColor() );
2755 }
2756
2757 wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
2758 if (sysbg == m_backgroundColour)
2759 {
2760 m_backgroundColour = wxNullColour;
2761 ApplyWidgetStyle();
2762 m_backgroundColour = sysbg;
2763 }
2764 else
2765 {
2766 ApplyWidgetStyle();
2767 }
2768
2769 return TRUE;
2770 }
2771
2772 bool wxWindow::SetForegroundColour( const wxColour &colour )
2773 {
2774 wxCHECK_MSG( m_widget != NULL, FALSE, _T("invalid window") );
2775
2776 if (!wxWindowBase::SetForegroundColour(colour))
2777 {
2778 // don't leave if the GTK widget has just
2779 // been realized
2780 if (!m_delayedForegroundColour) return FALSE;
2781 }
2782
2783 GtkWidget *connect_widget = GetConnectWidget();
2784 if (!connect_widget->window)
2785 {
2786 // indicate that a new style has been set
2787 // but it couldn't get applied as the
2788 // widget hasn't been realized yet.
2789 m_delayedForegroundColour = TRUE;
2790
2791 // pretend we have done something
2792 return TRUE;
2793 }
2794
2795 wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
2796 if ( sysbg == m_backgroundColour )
2797 {
2798 m_backgroundColour = wxNullColour;
2799 ApplyWidgetStyle();
2800 m_backgroundColour = sysbg;
2801 }
2802 else
2803 {
2804 ApplyWidgetStyle();
2805 }
2806
2807 return TRUE;
2808 }
2809
2810 GtkStyle *wxWindow::GetWidgetStyle()
2811 {
2812 if (m_widgetStyle) gtk_style_unref( m_widgetStyle );
2813
2814 m_widgetStyle = gtk_style_copy( gtk_widget_get_style( m_widget ) );
2815
2816 return m_widgetStyle;
2817 }
2818
2819 void wxWindow::SetWidgetStyle()
2820 {
2821 GtkStyle *style = GetWidgetStyle();
2822
2823 gdk_font_unref( style->font );
2824 style->font = gdk_font_ref( m_font.GetInternalFont( 1.0 ) );
2825
2826 if (m_foregroundColour.Ok())
2827 {
2828 m_foregroundColour.CalcPixel( gdk_window_get_colormap( m_widget->window ) );
2829 style->fg[GTK_STATE_NORMAL] = *m_foregroundColour.GetColor();
2830 style->fg[GTK_STATE_PRELIGHT] = *m_foregroundColour.GetColor();
2831 style->fg[GTK_STATE_ACTIVE] = *m_foregroundColour.GetColor();
2832 }
2833
2834 if (m_backgroundColour.Ok())
2835 {
2836 m_backgroundColour.CalcPixel( gdk_window_get_colormap( m_widget->window ) );
2837 style->bg[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
2838 style->base[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
2839 style->bg[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
2840 style->base[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
2841 style->bg[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
2842 style->base[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
2843 style->bg[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
2844 style->base[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
2845 }
2846 }
2847
2848 void wxWindow::ApplyWidgetStyle()
2849 {
2850 }
2851
2852 //-----------------------------------------------------------------------------
2853 // Pop-up menu stuff
2854 //-----------------------------------------------------------------------------
2855
2856 static void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting )
2857 {
2858 *is_waiting = FALSE;
2859 }
2860
2861 static void SetInvokingWindow( wxMenu *menu, wxWindow *win )
2862 {
2863 menu->SetInvokingWindow( win );
2864 wxNode *node = menu->GetItems().First();
2865 while (node)
2866 {
2867 wxMenuItem *menuitem = (wxMenuItem*)node->Data();
2868 if (menuitem->IsSubMenu())
2869 {
2870 SetInvokingWindow( menuitem->GetSubMenu(), win );
2871 }
2872 node = node->Next();
2873 }
2874 }
2875
2876 static gint gs_pop_x = 0;
2877 static gint gs_pop_y = 0;
2878
2879 static void pop_pos_callback( GtkMenu * WXUNUSED(menu),
2880 gint *x, gint *y,
2881 wxWindow *win )
2882 {
2883 win->ClientToScreen( &gs_pop_x, &gs_pop_y );
2884 *x = gs_pop_x;
2885 *y = gs_pop_y;
2886 }
2887
2888 bool wxWindow::DoPopupMenu( wxMenu *menu, int x, int y )
2889 {
2890 wxCHECK_MSG( m_widget != NULL, FALSE, _T("invalid window") );
2891
2892 wxCHECK_MSG( menu != NULL, FALSE, _T("invalid popup-menu") );
2893
2894 SetInvokingWindow( menu, this );
2895
2896 menu->UpdateUI();
2897
2898 gs_pop_x = x;
2899 gs_pop_y = y;
2900
2901 bool is_waiting = TRUE;
2902
2903 gtk_signal_connect( GTK_OBJECT(menu->m_menu), "hide",
2904 GTK_SIGNAL_FUNC(gtk_pop_hide_callback), (gpointer)&is_waiting );
2905
2906 gtk_menu_popup(
2907 GTK_MENU(menu->m_menu),
2908 (GtkWidget *) NULL, // parent menu shell
2909 (GtkWidget *) NULL, // parent menu item
2910 (GtkMenuPositionFunc) pop_pos_callback,
2911 (gpointer) this, // client data
2912 0, // button used to activate it
2913 0 //gs_timeLastClick // the time of activation
2914 );
2915
2916 while (is_waiting)
2917 {
2918 while (gtk_events_pending())
2919 gtk_main_iteration();
2920 }
2921
2922 return TRUE;
2923 }
2924
2925 #if wxUSE_DRAG_AND_DROP
2926
2927 void wxWindow::SetDropTarget( wxDropTarget *dropTarget )
2928 {
2929 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
2930
2931 GtkWidget *dnd_widget = GetConnectWidget();
2932
2933 if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
2934
2935 if (m_dropTarget) delete m_dropTarget;
2936 m_dropTarget = dropTarget;
2937
2938 if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
2939 }
2940
2941 #endif // wxUSE_DRAG_AND_DROP
2942
2943 GtkWidget* wxWindow::GetConnectWidget()
2944 {
2945 GtkWidget *connect_widget = m_widget;
2946 if (m_wxwindow) connect_widget = m_wxwindow;
2947
2948 return connect_widget;
2949 }
2950
2951 bool wxWindow::IsOwnGtkWindow( GdkWindow *window )
2952 {
2953 if (m_wxwindow) return (window == m_wxwindow->window);
2954 return (window == m_widget->window);
2955 }
2956
2957 bool wxWindow::SetFont( const wxFont &font )
2958 {
2959 wxCHECK_MSG( m_widget != NULL, FALSE, _T( "invalid window") );
2960
2961 if (!wxWindowBase::SetFont(font))
2962 {
2963 // don't leave if the GTK widget has just
2964 // been realized
2965 if (!m_delayedFont) return FALSE;
2966 }
2967
2968 GtkWidget *connect_widget = GetConnectWidget();
2969 if (!connect_widget->window)
2970 {
2971 // indicate that a new style has been set
2972 // but it couldn't get applied as the
2973 // widget hasn't been realized yet.
2974 m_delayedFont = TRUE;
2975
2976 // pretend we have done something
2977 return TRUE;
2978 }
2979
2980 wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
2981 if ( sysbg == m_backgroundColour )
2982 {
2983 m_backgroundColour = wxNullColour;
2984 ApplyWidgetStyle();
2985 m_backgroundColour = sysbg;
2986 }
2987 else
2988 {
2989 ApplyWidgetStyle();
2990 }
2991
2992 return TRUE;
2993 }
2994
2995 void wxWindow::CaptureMouse()
2996 {
2997 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
2998
2999 wxCHECK_RET( g_captureWindow == NULL, _T("CaptureMouse called twice") );
3000
3001 GtkWidget *connect_widget = GetConnectWidget();
3002 if (!connect_widget->window) return;
3003
3004 gdk_pointer_grab( connect_widget->window, FALSE,
3005 (GdkEventMask)
3006 (GDK_BUTTON_PRESS_MASK |
3007 GDK_BUTTON_RELEASE_MASK |
3008 GDK_POINTER_MOTION_MASK),
3009 (GdkWindow *) NULL,
3010 m_cursor.GetCursor(),
3011 GDK_CURRENT_TIME );
3012 g_captureWindow = this;
3013 }
3014
3015 void wxWindow::ReleaseMouse()
3016 {
3017 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
3018
3019 wxCHECK_RET( g_captureWindow, _T("ReleaseMouse called twice") );
3020
3021 GtkWidget *connect_widget = GetConnectWidget();
3022 if (!connect_widget->window) return;
3023
3024 gdk_pointer_ungrab ( GDK_CURRENT_TIME );
3025 g_captureWindow = (wxWindow*) NULL;
3026 }
3027
3028 bool wxWindow::IsRetained() const
3029 {
3030 return FALSE;
3031 }
3032
3033 void wxWindow::SetScrollbar( int orient, int pos, int thumbVisible,
3034 int range, bool refresh )
3035 {
3036 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
3037
3038 wxCHECK_RET( m_wxwindow != NULL, _T("window needs client area for scrolling") );
3039
3040 m_hasScrolling = TRUE;
3041
3042 if (orient == wxHORIZONTAL)
3043 {
3044 float fpos = (float)pos;
3045 float frange = (float)range;
3046 float fthumb = (float)thumbVisible;
3047 if (fpos > frange-fthumb) fpos = frange-fthumb;
3048 if (fpos < 0.0) fpos = 0.0;
3049
3050 if ((fabs(frange-m_hAdjust->upper) < 0.2) &&
3051 (fabs(fthumb-m_hAdjust->page_size) < 0.2))
3052 {
3053 SetScrollPos( orient, pos, refresh );
3054 return;
3055 }
3056
3057 m_oldHorizontalPos = fpos;
3058
3059 m_hAdjust->lower = 0.0;
3060 m_hAdjust->upper = frange;
3061 m_hAdjust->value = fpos;
3062 m_hAdjust->step_increment = 1.0;
3063 m_hAdjust->page_increment = (float)(wxMax(fthumb,0));
3064 m_hAdjust->page_size = fthumb;
3065 }
3066 else
3067 {
3068 float fpos = (float)pos;
3069 float frange = (float)range;
3070 float fthumb = (float)thumbVisible;
3071 if (fpos > frange-fthumb) fpos = frange-fthumb;
3072 if (fpos < 0.0) fpos = 0.0;
3073
3074 if ((fabs(frange-m_vAdjust->upper) < 0.2) &&
3075 (fabs(fthumb-m_vAdjust->page_size) < 0.2))
3076 {
3077 SetScrollPos( orient, pos, refresh );
3078 return;
3079 }
3080
3081 m_oldVerticalPos = fpos;
3082
3083 m_vAdjust->lower = 0.0;
3084 m_vAdjust->upper = frange;
3085 m_vAdjust->value = fpos;
3086 m_vAdjust->step_increment = 1.0;
3087 m_vAdjust->page_increment = (float)(wxMax(fthumb,0));
3088 m_vAdjust->page_size = fthumb;
3089 }
3090
3091 if (orient == wxHORIZONTAL)
3092 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
3093 else
3094 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
3095 }
3096
3097 void wxWindow::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
3098 {
3099 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
3100
3101 wxCHECK_RET( m_wxwindow != NULL, _T("window needs client area for scrolling") );
3102
3103 if (orient == wxHORIZONTAL)
3104 {
3105 float fpos = (float)pos;
3106 if (fpos > m_hAdjust->upper - m_hAdjust->page_size) fpos = m_hAdjust->upper - m_hAdjust->page_size;
3107 if (fpos < 0.0) fpos = 0.0;
3108 m_oldHorizontalPos = fpos;
3109
3110 if (fabs(fpos-m_hAdjust->value) < 0.2) return;
3111 m_hAdjust->value = fpos;
3112 }
3113 else
3114 {
3115 float fpos = (float)pos;
3116 if (fpos > m_vAdjust->upper - m_vAdjust->page_size) fpos = m_vAdjust->upper - m_vAdjust->page_size;
3117 if (fpos < 0.0) fpos = 0.0;
3118 m_oldVerticalPos = fpos;
3119
3120 if (fabs(fpos-m_vAdjust->value) < 0.2) return;
3121 m_vAdjust->value = fpos;
3122 }
3123
3124 if (!m_isScrolling) /* prevent recursion */
3125 {
3126 if (m_wxwindow->window)
3127 {
3128 if (orient == wxHORIZONTAL)
3129 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
3130 else
3131 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
3132 }
3133 }
3134 }
3135
3136 int wxWindow::GetScrollThumb( int orient ) const
3137 {
3138 wxCHECK_MSG( m_widget != NULL, 0, _T("invalid window") );
3139
3140 wxCHECK_MSG( m_wxwindow != NULL, 0, _T("window needs client area for scrolling") );
3141
3142 if (orient == wxHORIZONTAL)
3143 return (int)(m_hAdjust->page_size+0.5);
3144 else
3145 return (int)(m_vAdjust->page_size+0.5);
3146 }
3147
3148 int wxWindow::GetScrollPos( int orient ) const
3149 {
3150 wxCHECK_MSG( m_widget != NULL, 0, _T("invalid window") );
3151
3152 wxCHECK_MSG( m_wxwindow != NULL, 0, _T("window needs client area for scrolling") );
3153
3154 if (orient == wxHORIZONTAL)
3155 return (int)(m_hAdjust->value+0.5);
3156 else
3157 return (int)(m_vAdjust->value+0.5);
3158 }
3159
3160 int wxWindow::GetScrollRange( int orient ) const
3161 {
3162 wxCHECK_MSG( m_widget != NULL, 0, _T("invalid window") );
3163
3164 wxCHECK_MSG( m_wxwindow != NULL, 0, _T("window needs client area for scrolling") );
3165
3166 if (orient == wxHORIZONTAL)
3167 return (int)(m_hAdjust->upper+0.5);
3168 else
3169 return (int)(m_vAdjust->upper+0.5);
3170 }
3171
3172 void wxWindow::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
3173 {
3174 wxCHECK_RET( m_widget != NULL, _T("invalid window") );
3175
3176 wxCHECK_RET( m_wxwindow != NULL, _T("window needs client area for scrolling") );
3177
3178 if (!m_scrollGC)
3179 {
3180 m_scrollGC = gdk_gc_new( m_wxwindow->window );
3181 gdk_gc_set_exposures( m_scrollGC, TRUE );
3182 }
3183
3184 wxNode *node = m_children.First();
3185 while (node)
3186 {
3187 wxWindow *child = (wxWindow*) node->Data();
3188 int sx = 0;
3189 int sy = 0;
3190 child->GetSize( &sx, &sy );
3191 child->SetSize( child->m_x + dx, child->m_y + dy, sx, sy, wxSIZE_ALLOW_MINUS_ONE );
3192 node = node->Next();
3193 }
3194
3195 int cw = 0;
3196 int ch = 0;
3197 GetClientSize( &cw, &ch );
3198 int w = cw - abs(dx);
3199 int h = ch - abs(dy);
3200
3201 if ((h < 0) || (w < 0))
3202 {
3203 Refresh();
3204 }
3205 else
3206 {
3207 int s_x = 0;
3208 int s_y = 0;
3209 if (dx < 0) s_x = -dx;
3210 if (dy < 0) s_y = -dy;
3211 int d_x = 0;
3212 int d_y = 0;
3213 if (dx > 0) d_x = dx;
3214 if (dy > 0) d_y = dy;
3215
3216 gdk_window_copy_area( m_wxwindow->window, m_scrollGC, d_x, d_y,
3217 m_wxwindow->window, s_x, s_y, w, h );
3218
3219 wxRect rect;
3220 if (dx < 0) rect.x = cw+dx; else rect.x = 0;
3221 if (dy < 0) rect.y = ch+dy; else rect.y = 0;
3222 if (dy != 0) rect.width = cw; else rect.width = abs(dx);
3223 if (dx != 0) rect.height = ch; else rect.height = abs(dy);
3224
3225 Refresh( TRUE, &rect );
3226 }
3227 }
3228
3229 void wxWindow::SetScrolling(bool scroll)
3230 {
3231 m_isScrolling = g_blockEventsOnScroll = scroll;
3232 }