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