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