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