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