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