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