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