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