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