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