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