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