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