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