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