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