]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/gtk1/window.cpp
fix for goofed up grid borders when scrolling/refreshing
[wxWidgets.git] / src / gtk1 / window.cpp
... / ...
CommitLineData
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
187extern wxList wxPendingDelete;
188extern bool g_blockEventsOnDrag;
189extern bool g_blockEventsOnScroll;
190extern wxCursor g_globalCursor;
191static 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
199static 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 */
203static guint32 gs_timeLastClick = 0;
204
205extern 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
219static 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
236void 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
263void
264gdk_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
289extern void wxapp_install_idle_handler();
290extern bool g_isIdle;
291
292//-----------------------------------------------------------------------------
293// local code (see below)
294//-----------------------------------------------------------------------------
295
296static 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
382static 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
392static 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
401static 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
510static 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
611static 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
651static 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
690static 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
844static 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// mouse event processing helper
900// ----------------------------------------------------------------------------
901
902static void AdjustEventButtonState(wxMouseEvent& event)
903{
904 // GDK reports the old state of the button for a button press event, but
905 // for compatibility with MSW and common sense we want m_leftDown be TRUE
906 // for a LEFT_DOWN event, not FALSE, so we will invert
907 // left/right/middleDown for the corresponding click events
908 switch ( event.GetEventType() )
909 {
910 case wxEVT_LEFT_DOWN:
911 case wxEVT_LEFT_DCLICK:
912 case wxEVT_LEFT_UP:
913 event.m_leftDown = !event.m_leftDown;
914 break;
915
916 case wxEVT_MIDDLE_DOWN:
917 case wxEVT_MIDDLE_DCLICK:
918 case wxEVT_MIDDLE_UP:
919 event.m_middleDown = !event.m_middleDown;
920 break;
921
922 case wxEVT_RIGHT_DOWN:
923 case wxEVT_RIGHT_DCLICK:
924 case wxEVT_RIGHT_UP:
925 event.m_rightDown = !event.m_rightDown;
926 break;
927 }
928}
929
930//-----------------------------------------------------------------------------
931// "button_press_event"
932//-----------------------------------------------------------------------------
933
934static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindow *win )
935{
936 DEBUG_MAIN_THREAD
937
938 if (g_isIdle)
939 wxapp_install_idle_handler();
940
941/*
942 wxPrintf( wxT("1) OnButtonPress from ") );
943 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
944 wxPrintf( win->GetClassInfo()->GetClassName() );
945 wxPrintf( wxT(".\n") );
946*/
947 if (!win->m_hasVMT) return FALSE;
948 if (g_blockEventsOnDrag) return TRUE;
949 if (g_blockEventsOnScroll) return TRUE;
950
951 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
952
953 if (win->m_wxwindow)
954 {
955 if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow) && !GTK_WIDGET_HAS_FOCUS (win->m_wxwindow) )
956 {
957 gtk_widget_grab_focus (win->m_wxwindow);
958
959/*
960 wxPrintf( wxT("GrabFocus from ") );
961 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
962 wxPrintf( win->GetClassInfo()->GetClassName() );
963 wxPrintf( wxT(".\n") );
964*/
965
966 }
967 }
968
969 wxEventType event_type = wxEVT_NULL;
970
971 if (gdk_event->button == 1)
972 {
973 switch (gdk_event->type)
974 {
975 case GDK_BUTTON_PRESS: event_type = wxEVT_LEFT_DOWN; break;
976 case GDK_2BUTTON_PRESS: event_type = wxEVT_LEFT_DCLICK; break;
977 default: break;
978 }
979 }
980 else if (gdk_event->button == 2)
981 {
982 switch (gdk_event->type)
983 {
984 case GDK_BUTTON_PRESS: event_type = wxEVT_MIDDLE_DOWN; break;
985 case GDK_2BUTTON_PRESS: event_type = wxEVT_MIDDLE_DCLICK; break;
986 default: break;
987 }
988 }
989 else if (gdk_event->button == 3)
990 {
991 switch (gdk_event->type)
992 {
993 case GDK_BUTTON_PRESS: event_type = wxEVT_RIGHT_DOWN; break;
994 case GDK_2BUTTON_PRESS: event_type = wxEVT_RIGHT_DCLICK; break;
995 default: break;
996 }
997 }
998
999 if ( event_type == wxEVT_NULL )
1000 {
1001 // unknown mouse button or click type
1002 return FALSE;
1003 }
1004
1005 wxMouseEvent event( event_type );
1006 event.SetTimestamp( gdk_event->time );
1007 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1008 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1009 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1010 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1011 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1012 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1013 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1014
1015 event.m_x = (wxCoord)gdk_event->x;
1016 event.m_y = (wxCoord)gdk_event->y;
1017
1018 AdjustEventButtonState(event);
1019
1020 // Some control don't have their own X window and thus cannot get
1021 // any events.
1022
1023 if (!g_captureWindow)
1024 {
1025 wxCoord x = event.m_x;
1026 wxCoord y = event.m_y;
1027 if (win->m_wxwindow)
1028 {
1029 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1030 x += pizza->xoffset;
1031 y += pizza->yoffset;
1032 }
1033
1034 wxNode *node = win->GetChildren().First();
1035 while (node)
1036 {
1037 wxWindow *child = (wxWindow*)node->Data();
1038
1039 node = node->Next();
1040 if (!child->IsShown())
1041 continue;
1042
1043 if (child->m_isStaticBox)
1044 {
1045 // wxStaticBox is transparent in the box itself
1046 int xx1 = child->m_x;
1047 int yy1 = child->m_y;
1048 int xx2 = child->m_x + child->m_width;
1049 int yy2 = child->m_x + child->m_height;
1050
1051 // left
1052 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1053 // right
1054 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1055 // top
1056 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1057 // bottom
1058 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1059 {
1060 win = child;
1061 event.m_x -= child->m_x;
1062 event.m_y -= child->m_y;
1063 break;
1064 }
1065
1066 }
1067 else
1068 {
1069 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1070 (child->m_x <= x) &&
1071 (child->m_y <= y) &&
1072 (child->m_x+child->m_width >= x) &&
1073 (child->m_y+child->m_height >= y))
1074 {
1075 win = child;
1076 event.m_x -= child->m_x;
1077 event.m_y -= child->m_y;
1078 break;
1079 }
1080 }
1081 }
1082 }
1083
1084 event.SetEventObject( win );
1085
1086 gs_timeLastClick = gdk_event->time;
1087
1088/*
1089 wxPrintf( wxT("2) OnButtonPress from ") );
1090 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1091 wxPrintf( win->GetClassInfo()->GetClassName() );
1092 wxPrintf( wxT(".\n") );
1093*/
1094
1095 if (win->GetEventHandler()->ProcessEvent( event ))
1096 {
1097 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_press_event" );
1098 return TRUE;
1099 }
1100
1101 return FALSE;
1102}
1103
1104//-----------------------------------------------------------------------------
1105// "button_release_event"
1106//-----------------------------------------------------------------------------
1107
1108static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindow *win )
1109{
1110 DEBUG_MAIN_THREAD
1111
1112 if (g_isIdle)
1113 wxapp_install_idle_handler();
1114
1115 if (!win->m_hasVMT) return FALSE;
1116 if (g_blockEventsOnDrag) return FALSE;
1117 if (g_blockEventsOnScroll) return FALSE;
1118
1119 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1120
1121/*
1122 printf( "OnButtonRelease from " );
1123 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1124 printf( win->GetClassInfo()->GetClassName() );
1125 printf( ".\n" );
1126*/
1127
1128 wxEventType event_type = wxEVT_NULL;
1129
1130 switch (gdk_event->button)
1131 {
1132 case 1: event_type = wxEVT_LEFT_UP; break;
1133 case 2: event_type = wxEVT_MIDDLE_UP; break;
1134 case 3: event_type = wxEVT_RIGHT_UP; break;
1135 default: return FALSE;
1136 }
1137
1138 wxMouseEvent event( event_type );
1139 event.SetTimestamp( gdk_event->time );
1140 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1141 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1142 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1143 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1144 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1145 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1146 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1147 event.m_x = (wxCoord)gdk_event->x;
1148 event.m_y = (wxCoord)gdk_event->y;
1149
1150 AdjustEventButtonState(event);
1151
1152 // Some control don't have their own X window and thus cannot get
1153 // any events.
1154
1155 if (!g_captureWindow)
1156 {
1157 wxCoord x = event.m_x;
1158 wxCoord y = event.m_y;
1159 if (win->m_wxwindow)
1160 {
1161 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1162 x += pizza->xoffset;
1163 y += pizza->yoffset;
1164 }
1165
1166 wxNode *node = win->GetChildren().First();
1167 while (node)
1168 {
1169 wxWindow *child = (wxWindow*)node->Data();
1170
1171 node = node->Next();
1172 if (!child->IsShown())
1173 continue;
1174
1175 if (child->m_isStaticBox)
1176 {
1177 // wxStaticBox is transparent in the box itself
1178 int xx1 = child->m_x;
1179 int yy1 = child->m_y;
1180 int xx2 = child->m_x + child->m_width;
1181 int yy2 = child->m_x + child->m_height;
1182
1183 // left
1184 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1185 // right
1186 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1187 // top
1188 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1189 // bottom
1190 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1191 {
1192 win = child;
1193 event.m_x -= child->m_x;
1194 event.m_y -= child->m_y;
1195 break;
1196 }
1197
1198 }
1199 else
1200 {
1201 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1202 (child->m_x <= x) &&
1203 (child->m_y <= y) &&
1204 (child->m_x+child->m_width >= x) &&
1205 (child->m_y+child->m_height >= y))
1206 {
1207 win = child;
1208 event.m_x -= child->m_x;
1209 event.m_y -= child->m_y;
1210 break;
1211 }
1212 }
1213 }
1214 }
1215
1216 event.SetEventObject( win );
1217
1218 if (win->GetEventHandler()->ProcessEvent( event ))
1219 {
1220 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_release_event" );
1221 return TRUE;
1222 }
1223
1224 return FALSE;
1225}
1226
1227//-----------------------------------------------------------------------------
1228// "motion_notify_event"
1229//-----------------------------------------------------------------------------
1230
1231static gint gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion *gdk_event, wxWindow *win )
1232{
1233 DEBUG_MAIN_THREAD
1234
1235 if (g_isIdle)
1236 wxapp_install_idle_handler();
1237
1238 if (!win->m_hasVMT) return FALSE;
1239 if (g_blockEventsOnDrag) return FALSE;
1240 if (g_blockEventsOnScroll) return FALSE;
1241
1242 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1243
1244 if (gdk_event->is_hint)
1245 {
1246 int x = 0;
1247 int y = 0;
1248 GdkModifierType state;
1249 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
1250 gdk_event->x = x;
1251 gdk_event->y = y;
1252 }
1253
1254/*
1255 printf( "OnMotion from " );
1256 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1257 printf( win->GetClassInfo()->GetClassName() );
1258 printf( ".\n" );
1259*/
1260
1261 wxMouseEvent event( wxEVT_MOTION );
1262 event.SetTimestamp( gdk_event->time );
1263 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1264 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1265 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1266 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1267 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1268 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1269 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1270
1271 event.m_x = (wxCoord)gdk_event->x;
1272 event.m_y = (wxCoord)gdk_event->y;
1273
1274 // Some control don't have their own X window and thus cannot get
1275 // any events.
1276
1277 if (!g_captureWindow)
1278 {
1279 wxCoord x = event.m_x;
1280 wxCoord y = event.m_y;
1281 if (win->m_wxwindow)
1282 {
1283 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1284 x += pizza->xoffset;
1285 y += pizza->yoffset;
1286 }
1287
1288 wxNode *node = win->GetChildren().First();
1289 while (node)
1290 {
1291 wxWindow *child = (wxWindow*)node->Data();
1292
1293 node = node->Next();
1294 if (!child->IsShown())
1295 continue;
1296
1297 if (child->m_isStaticBox)
1298 {
1299 // wxStaticBox is transparent in the box itself
1300 int xx1 = child->m_x;
1301 int yy1 = child->m_y;
1302 int xx2 = child->m_x + child->m_width;
1303 int yy2 = child->m_x + child->m_height;
1304
1305 // left
1306 if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
1307 // right
1308 ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
1309 // top
1310 ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
1311 // bottom
1312 ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
1313 {
1314 win = child;
1315 event.m_x -= child->m_x;
1316 event.m_y -= child->m_y;
1317 break;
1318 }
1319
1320 }
1321 else
1322 {
1323 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1324 (child->m_x <= x) &&
1325 (child->m_y <= y) &&
1326 (child->m_x+child->m_width >= x) &&
1327 (child->m_y+child->m_height >= y))
1328 {
1329 win = child;
1330 event.m_x -= child->m_x;
1331 event.m_y -= child->m_y;
1332 break;
1333 }
1334 }
1335 }
1336 }
1337
1338 event.SetEventObject( win );
1339
1340 if (win->GetEventHandler()->ProcessEvent( event ))
1341 {
1342 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "motion_notify_event" );
1343 return TRUE;
1344 }
1345
1346 return FALSE;
1347}
1348
1349//-----------------------------------------------------------------------------
1350// "focus_in_event"
1351//-----------------------------------------------------------------------------
1352
1353static gint gtk_window_focus_in_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindow *win )
1354{
1355 DEBUG_MAIN_THREAD
1356
1357 if (g_isIdle)
1358 wxapp_install_idle_handler();
1359
1360 if (!win->m_hasVMT) return FALSE;
1361 if (g_blockEventsOnDrag) return FALSE;
1362
1363 switch ( g_sendActivateEvent )
1364 {
1365 case -1:
1366 // we've got focus from outside, synthtize wxActivateEvent
1367 g_sendActivateEvent = 1;
1368 break;
1369
1370 case 0:
1371 // another our window just lost focus, it was already ours before
1372 // - don't send any wxActivateEvent
1373 g_sendActivateEvent = -1;
1374 break;
1375 }
1376
1377 g_focusWindow = win;
1378
1379/*
1380 printf( "OnSetFocus from " );
1381 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1382 printf( win->GetClassInfo()->GetClassName() );
1383 printf( " " );
1384 printf( WXSTRINGCAST win->GetLabel() );
1385 printf( ".\n" );
1386*/
1387
1388 wxPanel *panel = wxDynamicCast(win->GetParent(), wxPanel);
1389 if (panel)
1390 {
1391 panel->SetLastFocus(win);
1392 }
1393
1394#ifdef HAVE_XIM
1395 if (win->m_ic)
1396 gdk_im_begin(win->m_ic, win->m_wxwindow->window);
1397#endif
1398
1399 wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() );
1400 event.SetEventObject( win );
1401
1402 if (win->GetEventHandler()->ProcessEvent( event ))
1403 {
1404 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
1405 return TRUE;
1406 }
1407
1408 return FALSE;
1409}
1410
1411//-----------------------------------------------------------------------------
1412// "focus_out_event"
1413//-----------------------------------------------------------------------------
1414
1415static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindow *win )
1416{
1417 DEBUG_MAIN_THREAD
1418
1419 if (g_isIdle)
1420 wxapp_install_idle_handler();
1421
1422 if (!win->m_hasVMT) return FALSE;
1423 if (g_blockEventsOnDrag) return FALSE;
1424
1425 // if the focus goes out of our app alltogether, OnIdle() will send
1426 // wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
1427 // g_sendActivateEvent to -1
1428 g_sendActivateEvent = 0;
1429
1430 g_focusWindow = (wxWindow *)NULL;
1431
1432/*
1433 printf( "OnKillFocus from " );
1434 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1435 printf( win->GetClassInfo()->GetClassName() );
1436 printf( ".\n" );
1437*/
1438
1439#ifdef HAVE_XIM
1440 if (win->m_ic)
1441 gdk_im_end();
1442#endif
1443
1444 wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
1445 event.SetEventObject( win );
1446
1447 if (win->GetEventHandler()->ProcessEvent( event ))
1448 {
1449 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_out_event" );
1450 return TRUE;
1451 }
1452
1453 return FALSE;
1454}
1455
1456//-----------------------------------------------------------------------------
1457// "enter_notify_event"
1458//-----------------------------------------------------------------------------
1459
1460static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindow *win )
1461{
1462 DEBUG_MAIN_THREAD
1463
1464 if (g_isIdle)
1465 wxapp_install_idle_handler();
1466
1467 if (!win->m_hasVMT) return FALSE;
1468 if (g_blockEventsOnDrag) return FALSE;
1469
1470 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1471
1472 wxMouseEvent event( wxEVT_ENTER_WINDOW );
1473#if (GTK_MINOR_VERSION > 0)
1474 event.SetTimestamp( gdk_event->time );
1475#endif
1476 event.SetEventObject( win );
1477
1478 int x = 0;
1479 int y = 0;
1480 GdkModifierType state = (GdkModifierType)0;
1481
1482 gdk_window_get_pointer( widget->window, &x, &y, &state );
1483
1484 event.m_shiftDown = (state & GDK_SHIFT_MASK);
1485 event.m_controlDown = (state & GDK_CONTROL_MASK);
1486 event.m_altDown = (state & GDK_MOD1_MASK);
1487 event.m_metaDown = (state & GDK_MOD2_MASK);
1488 event.m_leftDown = (state & GDK_BUTTON1_MASK);
1489 event.m_middleDown = (state & GDK_BUTTON2_MASK);
1490 event.m_rightDown = (state & GDK_BUTTON3_MASK);
1491
1492 event.m_x = x;
1493 event.m_y = y;
1494
1495 if (win->GetEventHandler()->ProcessEvent( event ))
1496 {
1497 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "enter_notify_event" );
1498 return TRUE;
1499 }
1500
1501 return FALSE;
1502}
1503
1504//-----------------------------------------------------------------------------
1505// "leave_notify_event"
1506//-----------------------------------------------------------------------------
1507
1508static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindow *win )
1509{
1510 DEBUG_MAIN_THREAD
1511
1512 if (g_isIdle)
1513 wxapp_install_idle_handler();
1514
1515 if (!win->m_hasVMT) return FALSE;
1516 if (g_blockEventsOnDrag) return FALSE;
1517
1518 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1519
1520 wxMouseEvent event( wxEVT_LEAVE_WINDOW );
1521#if (GTK_MINOR_VERSION > 0)
1522 event.SetTimestamp( gdk_event->time );
1523#endif
1524 event.SetEventObject( win );
1525
1526 int x = 0;
1527 int y = 0;
1528 GdkModifierType state = (GdkModifierType)0;
1529
1530 gdk_window_get_pointer( widget->window, &x, &y, &state );
1531
1532 event.m_shiftDown = (state & GDK_SHIFT_MASK);
1533 event.m_controlDown = (state & GDK_CONTROL_MASK);
1534 event.m_altDown = (state & GDK_MOD1_MASK);
1535 event.m_metaDown = (state & GDK_MOD2_MASK);
1536 event.m_leftDown = (state & GDK_BUTTON1_MASK);
1537 event.m_middleDown = (state & GDK_BUTTON2_MASK);
1538 event.m_rightDown = (state & GDK_BUTTON3_MASK);
1539
1540 event.m_x = x;
1541 event.m_y = y;
1542
1543 if (win->GetEventHandler()->ProcessEvent( event ))
1544 {
1545 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "leave_notify_event" );
1546 return TRUE;
1547 }
1548
1549 return FALSE;
1550}
1551
1552//-----------------------------------------------------------------------------
1553// "value_changed" from m_vAdjust
1554//-----------------------------------------------------------------------------
1555
1556static void gtk_window_vscroll_callback( GtkAdjustment *adjust, wxWindow *win )
1557{
1558 DEBUG_MAIN_THREAD
1559
1560 if (g_isIdle)
1561 wxapp_install_idle_handler();
1562
1563 if (g_blockEventsOnDrag) return;
1564
1565 if (!win->m_hasVMT) return;
1566
1567 float diff = adjust->value - win->m_oldVerticalPos;
1568 if (fabs(diff) < 0.2) return;
1569
1570 win->m_oldVerticalPos = adjust->value;
1571
1572 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1573 GtkRange *range = GTK_RANGE( scrolledWindow->vscrollbar );
1574
1575 wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK;
1576 if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP;
1577 else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN;
1578 else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP;
1579 else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN;
1580
1581 int value = (int)(adjust->value+0.5);
1582
1583 wxScrollWinEvent event( command, value, wxVERTICAL );
1584 event.SetEventObject( win );
1585 win->GetEventHandler()->ProcessEvent( event );
1586}
1587
1588//-----------------------------------------------------------------------------
1589// "value_changed" from m_hAdjust
1590//-----------------------------------------------------------------------------
1591
1592static void gtk_window_hscroll_callback( GtkAdjustment *adjust, wxWindow *win )
1593{
1594 DEBUG_MAIN_THREAD
1595
1596 if (g_isIdle)
1597 wxapp_install_idle_handler();
1598
1599 if (g_blockEventsOnDrag) return;
1600 if (!win->m_hasVMT) return;
1601
1602 float diff = adjust->value - win->m_oldHorizontalPos;
1603 if (fabs(diff) < 0.2) return;
1604
1605 win->m_oldHorizontalPos = adjust->value;
1606
1607 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1608 GtkRange *range = GTK_RANGE( scrolledWindow->hscrollbar );
1609
1610 wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK;
1611 if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP;
1612 else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN;
1613 else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP;
1614 else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN;
1615
1616 int value = (int)(adjust->value+0.5);
1617
1618 wxScrollWinEvent event( command, value, wxHORIZONTAL );
1619 event.SetEventObject( win );
1620 win->GetEventHandler()->ProcessEvent( event );
1621}
1622
1623//-----------------------------------------------------------------------------
1624// "button_press_event" from scrollbar
1625//-----------------------------------------------------------------------------
1626
1627static gint gtk_scrollbar_button_press_callback( GtkRange *widget,
1628 GdkEventButton *gdk_event,
1629 wxWindow *win)
1630{
1631 DEBUG_MAIN_THREAD
1632
1633 if (g_isIdle)
1634 wxapp_install_idle_handler();
1635
1636 g_blockEventsOnScroll = TRUE;
1637 win->m_isScrolling = (gdk_event->window == widget->slider);
1638
1639 return FALSE;
1640}
1641
1642//-----------------------------------------------------------------------------
1643// "button_release_event" from scrollbar
1644//-----------------------------------------------------------------------------
1645
1646static gint gtk_scrollbar_button_release_callback( GtkRange *widget,
1647 GdkEventButton *WXUNUSED(gdk_event),
1648 wxWindow *win)
1649{
1650 DEBUG_MAIN_THREAD
1651
1652// don't test here as we can release the mouse while being over
1653// a different window than the slider
1654//
1655// if (gdk_event->window != widget->slider) return FALSE;
1656
1657 g_blockEventsOnScroll = FALSE;
1658
1659 if (win->m_isScrolling)
1660 {
1661 wxEventType command = wxEVT_SCROLL_THUMBRELEASE;
1662 int value = -1;
1663 int dir = -1;
1664
1665 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
1666 if (widget == GTK_RANGE(scrolledWindow->hscrollbar))
1667 {
1668 value = (int)(win->m_hAdjust->value+0.5);
1669 dir = wxHORIZONTAL;
1670 }
1671 if (widget == GTK_RANGE(scrolledWindow->vscrollbar))
1672 {
1673 value = (int)(win->m_vAdjust->value+0.5);
1674 dir = wxVERTICAL;
1675 }
1676
1677 wxScrollWinEvent event( command, value, dir );
1678 event.SetEventObject( win );
1679 win->GetEventHandler()->ProcessEvent( event );
1680 }
1681
1682 win->m_isScrolling = FALSE;
1683
1684 return FALSE;
1685}
1686
1687// ----------------------------------------------------------------------------
1688// this wxWindowBase function is implemented here (in platform-specific file)
1689// because it is static and so couldn't be made virtual
1690// ----------------------------------------------------------------------------
1691
1692wxWindow *wxWindowBase::FindFocus()
1693{
1694 return g_focusWindow;
1695}
1696
1697//-----------------------------------------------------------------------------
1698// "realize" from m_widget
1699//-----------------------------------------------------------------------------
1700
1701/* We cannot set colours and fonts before the widget has
1702 been realized, so we do this directly after realization. */
1703
1704static gint
1705gtk_window_realized_callback( GtkWidget *WXUNUSED(m_widget), wxWindow *win )
1706{
1707 DEBUG_MAIN_THREAD
1708
1709 if (g_isIdle)
1710 wxapp_install_idle_handler();
1711
1712 if (win->m_delayedBackgroundColour)
1713 win->SetBackgroundColour( win->GetBackgroundColour() );
1714
1715 if (win->m_delayedForegroundColour)
1716 win->SetForegroundColour( win->GetForegroundColour() );
1717
1718 wxWindowCreateEvent event( win );
1719 event.SetEventObject( win );
1720 win->GetEventHandler()->ProcessEvent( event );
1721
1722 return FALSE;
1723}
1724
1725//-----------------------------------------------------------------------------
1726// "size_allocate"
1727//-----------------------------------------------------------------------------
1728
1729static
1730void gtk_window_size_callback( GtkWidget *WXUNUSED(widget),
1731 GtkAllocation *WXUNUSED(alloc),
1732 wxWindow *win )
1733{
1734 if (g_isIdle)
1735 wxapp_install_idle_handler();
1736
1737 if (!win->m_hasScrolling) return;
1738
1739 int client_width = 0;
1740 int client_height = 0;
1741 win->GetClientSize( &client_width, &client_height );
1742 if ((client_width == win->m_oldClientWidth) && (client_height == win->m_oldClientHeight))
1743 return;
1744
1745 win->m_oldClientWidth = client_width;
1746 win->m_oldClientHeight = client_height;
1747
1748 if (!win->m_nativeSizeEvent)
1749 {
1750 wxSizeEvent event( win->GetSize(), win->GetId() );
1751 event.SetEventObject( win );
1752 win->GetEventHandler()->ProcessEvent( event );
1753 }
1754}
1755
1756
1757#ifdef HAVE_XIM
1758 #define WXUNUSED_UNLESS_XIM(param) param
1759#else
1760 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
1761#endif
1762
1763/* Resize XIM window */
1764
1765static
1766void gtk_wxwindow_size_callback( GtkWidget* WXUNUSED_UNLESS_XIM(widget),
1767 GtkAllocation* WXUNUSED_UNLESS_XIM(alloc),
1768 wxWindow* WXUNUSED_UNLESS_XIM(win) )
1769{
1770 if (g_isIdle)
1771 wxapp_install_idle_handler();
1772
1773#ifdef HAVE_XIM
1774 if (!win->m_ic)
1775 return;
1776
1777 if (gdk_ic_get_style (win->m_ic) & GDK_IM_PREEDIT_POSITION)
1778 {
1779 gint width, height;
1780
1781 gdk_window_get_size (widget->window, &width, &height);
1782 win->m_icattr->preedit_area.width = width;
1783 win->m_icattr->preedit_area.height = height;
1784 gdk_ic_set_attr (win->m_ic, win->m_icattr, GDK_IC_PREEDIT_AREA);
1785 }
1786#endif // HAVE_XIM
1787}
1788
1789//-----------------------------------------------------------------------------
1790// "realize" from m_wxwindow
1791//-----------------------------------------------------------------------------
1792
1793/* Initialize XIM support */
1794
1795static gint
1796gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget),
1797 wxWindow * WXUNUSED_UNLESS_XIM(win) )
1798{
1799 if (g_isIdle)
1800 wxapp_install_idle_handler();
1801
1802#ifdef HAVE_XIM
1803 if (win->m_ic) return FALSE;
1804 if (!widget) return FALSE;
1805 if (!gdk_im_ready()) return FALSE;
1806
1807 win->m_icattr = gdk_ic_attr_new();
1808 if (!win->m_icattr) return FALSE;
1809
1810 gint width, height;
1811 GdkEventMask mask;
1812 GdkColormap *colormap;
1813 GdkICAttr *attr = win->m_icattr;
1814 unsigned attrmask = GDK_IC_ALL_REQ;
1815 GdkIMStyle style;
1816 GdkIMStyle supported_style = (GdkIMStyle)
1817 (GDK_IM_PREEDIT_NONE |
1818 GDK_IM_PREEDIT_NOTHING |
1819 GDK_IM_PREEDIT_POSITION |
1820 GDK_IM_STATUS_NONE |
1821 GDK_IM_STATUS_NOTHING);
1822
1823 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
1824 supported_style = (GdkIMStyle)(supported_style & ~GDK_IM_PREEDIT_POSITION);
1825
1826 attr->style = style = gdk_im_decide_style (supported_style);
1827 attr->client_window = widget->window;
1828
1829 if ((colormap = gtk_widget_get_colormap (widget)) !=
1830 gtk_widget_get_default_colormap ())
1831 {
1832 attrmask |= GDK_IC_PREEDIT_COLORMAP;
1833 attr->preedit_colormap = colormap;
1834 }
1835
1836 attrmask |= GDK_IC_PREEDIT_FOREGROUND;
1837 attrmask |= GDK_IC_PREEDIT_BACKGROUND;
1838 attr->preedit_foreground = widget->style->fg[GTK_STATE_NORMAL];
1839 attr->preedit_background = widget->style->base[GTK_STATE_NORMAL];
1840
1841 switch (style & GDK_IM_PREEDIT_MASK)
1842 {
1843 case GDK_IM_PREEDIT_POSITION:
1844 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
1845 {
1846 g_warning ("over-the-spot style requires fontset");
1847 break;
1848 }
1849
1850 gdk_window_get_size (widget->window, &width, &height);
1851
1852 attrmask |= GDK_IC_PREEDIT_POSITION_REQ;
1853 attr->spot_location.x = 0;
1854 attr->spot_location.y = height;
1855 attr->preedit_area.x = 0;
1856 attr->preedit_area.y = 0;
1857 attr->preedit_area.width = width;
1858 attr->preedit_area.height = height;
1859 attr->preedit_fontset = widget->style->font;
1860
1861 break;
1862 }
1863
1864 win->m_ic = gdk_ic_new (attr, (GdkICAttributesType)attrmask);
1865
1866 if (win->m_ic == NULL)
1867 g_warning ("Can't create input context.");
1868 else
1869 {
1870 mask = gdk_window_get_events (widget->window);
1871 mask = (GdkEventMask)(mask | gdk_ic_get_events (win->m_ic));
1872 gdk_window_set_events (widget->window, mask);
1873
1874 if (GTK_WIDGET_HAS_FOCUS(widget))
1875 gdk_im_begin (win->m_ic, widget->window);
1876 }
1877#endif
1878
1879 return FALSE;
1880}
1881
1882//-----------------------------------------------------------------------------
1883// InsertChild for wxWindow.
1884//-----------------------------------------------------------------------------
1885
1886/* Callback for wxWindow. This very strange beast has to be used because
1887 * C++ has no virtual methods in a constructor. We have to emulate a
1888 * virtual function here as wxNotebook requires a different way to insert
1889 * a child in it. I had opted for creating a wxNotebookPage window class
1890 * which would have made this superfluous (such in the MDI window system),
1891 * but no-one was listening to me... */
1892
1893static void wxInsertChildInWindow( wxWindow* parent, wxWindow* child )
1894{
1895 /* the window might have been scrolled already, do we
1896 have to adapt the position */
1897 GtkPizza *pizza = GTK_PIZZA(parent->m_wxwindow);
1898 child->m_x += pizza->xoffset;
1899 child->m_y += pizza->yoffset;
1900
1901 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
1902 GTK_WIDGET(child->m_widget),
1903 child->m_x,
1904 child->m_y,
1905 child->m_width,
1906 child->m_height );
1907}
1908
1909//-----------------------------------------------------------------------------
1910// global functions
1911//-----------------------------------------------------------------------------
1912
1913wxWindow* wxGetActiveWindow()
1914{
1915 return g_focusWindow;
1916}
1917
1918//-----------------------------------------------------------------------------
1919// wxWindow
1920//-----------------------------------------------------------------------------
1921
1922IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
1923
1924void wxWindow::Init()
1925{
1926 // common init
1927 InitBase();
1928
1929 // GTK specific
1930 m_widget = (GtkWidget *) NULL;
1931 m_wxwindow = (GtkWidget *) NULL;
1932
1933 // position/size
1934 m_x = 0;
1935 m_y = 0;
1936 m_width = 0;
1937 m_height = 0;
1938
1939 m_sizeSet = FALSE;
1940 m_hasVMT = FALSE;
1941 m_needParent = TRUE;
1942 m_isBeingDeleted = FALSE;
1943
1944 m_noExpose = FALSE;
1945 m_nativeSizeEvent = FALSE;
1946
1947 m_hasScrolling = FALSE;
1948 m_isScrolling = FALSE;
1949
1950 m_hAdjust = (GtkAdjustment*) NULL;
1951 m_vAdjust = (GtkAdjustment*) NULL;
1952 m_oldHorizontalPos = 0.0;
1953 m_oldVerticalPos = 0.0;
1954
1955 m_resizing = FALSE;
1956 m_widgetStyle = (GtkStyle*) NULL;
1957
1958 m_insertCallback = (wxInsertChildFunction) NULL;
1959
1960 m_isStaticBox = FALSE;
1961 m_isRadioButton = FALSE;
1962 m_isFrame = FALSE;
1963 m_acceptsFocus = FALSE;
1964
1965 m_cursor = *wxSTANDARD_CURSOR;
1966
1967#ifdef HAVE_XIM
1968 m_ic = (GdkIC*) NULL;
1969 m_icattr = (GdkICAttr*) NULL;
1970#endif
1971}
1972
1973wxWindow::wxWindow()
1974{
1975 Init();
1976}
1977
1978wxWindow::wxWindow( wxWindow *parent, wxWindowID id,
1979 const wxPoint &pos, const wxSize &size,
1980 long style, const wxString &name )
1981{
1982 Init();
1983
1984 Create( parent, id, pos, size, style, name );
1985}
1986
1987bool wxWindow::Create( wxWindow *parent, wxWindowID id,
1988 const wxPoint &pos, const wxSize &size,
1989 long style, const wxString &name )
1990{
1991 if (!PreCreation( parent, pos, size ) ||
1992 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
1993 {
1994 wxFAIL_MSG( wxT("wxWindow creation failed") );
1995 return FALSE;
1996 }
1997
1998 m_insertCallback = wxInsertChildInWindow;
1999
2000 m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
2001 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
2002
2003#ifdef __WXDEBUG__
2004 debug_focus_in( m_widget, wxT("wxWindow::m_widget"), name );
2005#endif
2006
2007 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
2008
2009#ifdef __WXDEBUG__
2010 debug_focus_in( scrolledWindow->hscrollbar, wxT("wxWindow::hsrcollbar"), name );
2011 debug_focus_in( scrolledWindow->vscrollbar, wxT("wxWindow::vsrcollbar"), name );
2012#endif
2013
2014 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(m_widget)->klass );
2015 scroll_class->scrollbar_spacing = 0;
2016
2017 gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
2018
2019 m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->hscrollbar) );
2020 m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->vscrollbar) );
2021
2022 m_wxwindow = gtk_pizza_new();
2023
2024#ifdef __WXDEBUG__
2025 debug_focus_in( m_wxwindow, wxT("wxWindow::m_wxwindow"), name );
2026#endif
2027
2028 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
2029
2030#if (GTK_MINOR_VERSION > 0)
2031 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
2032
2033 if (HasFlag(wxRAISED_BORDER))
2034 {
2035 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_OUT );
2036 }
2037 else if (HasFlag(wxSUNKEN_BORDER))
2038 {
2039 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_IN );
2040 }
2041 else if (HasFlag(wxSIMPLE_BORDER))
2042 {
2043 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_THIN );
2044 }
2045 else
2046 {
2047 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_NONE );
2048 }
2049#else // GTK_MINOR_VERSION == 0
2050 GtkViewport *viewport = GTK_VIEWPORT(scrolledWindow->viewport);
2051
2052 if (HasFlag(wxRAISED_BORDER))
2053 {
2054 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_OUT );
2055 }
2056 else if (HasFlag(wxSUNKEN_BORDER))
2057 {
2058 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_IN );
2059 }
2060 else
2061 {
2062 gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_NONE );
2063 }
2064#endif // GTK_MINOR_VERSION
2065
2066 GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
2067 m_acceptsFocus = TRUE;
2068
2069#if (GTK_MINOR_VERSION == 0)
2070 // shut the viewport up
2071 gtk_viewport_set_hadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
2072 gtk_viewport_set_vadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
2073#endif // GTK_MINOR_VERSION == 0
2074
2075 // I _really_ don't want scrollbars in the beginning
2076 m_vAdjust->lower = 0.0;
2077 m_vAdjust->upper = 1.0;
2078 m_vAdjust->value = 0.0;
2079 m_vAdjust->step_increment = 1.0;
2080 m_vAdjust->page_increment = 1.0;
2081 m_vAdjust->page_size = 5.0;
2082 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
2083 m_hAdjust->lower = 0.0;
2084 m_hAdjust->upper = 1.0;
2085 m_hAdjust->value = 0.0;
2086 m_hAdjust->step_increment = 1.0;
2087 m_hAdjust->page_increment = 1.0;
2088 m_hAdjust->page_size = 5.0;
2089 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
2090
2091 // these handlers block mouse events to any window during scrolling such as
2092 // motion events and prevent GTK and wxWindows from fighting over where the
2093 // slider should be
2094
2095 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_press_event",
2096 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2097
2098 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_press_event",
2099 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2100
2101 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_release_event",
2102 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2103
2104 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_release_event",
2105 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2106
2107 // these handlers get notified when screen updates are required either when
2108 // scrolling or when the window size (and therefore scrollbar configuration)
2109 // has changed
2110
2111 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
2112 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
2113 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
2114 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
2115
2116 gtk_widget_show( m_wxwindow );
2117
2118 if (m_parent)
2119 m_parent->DoAddChild( this );
2120
2121 PostCreation();
2122
2123 Show( TRUE );
2124
2125 return TRUE;
2126}
2127
2128wxWindow::~wxWindow()
2129{
2130 m_isBeingDeleted = TRUE;
2131 m_hasVMT = FALSE;
2132
2133 if (m_widget)
2134 Show( FALSE );
2135
2136 DestroyChildren();
2137
2138 if (m_parent)
2139 m_parent->RemoveChild( this );
2140
2141#ifdef HAVE_XIM
2142 if (m_ic)
2143 gdk_ic_destroy (m_ic);
2144 if (m_icattr)
2145 gdk_ic_attr_destroy (m_icattr);
2146#endif
2147
2148 if (m_widgetStyle)
2149 {
2150 gtk_style_unref( m_widgetStyle );
2151 m_widgetStyle = (GtkStyle*) NULL;
2152 }
2153
2154 if (m_wxwindow)
2155 {
2156 gtk_widget_destroy( m_wxwindow );
2157 m_wxwindow = (GtkWidget*) NULL;
2158 }
2159
2160 if (m_widget)
2161 {
2162 gtk_widget_destroy( m_widget );
2163 m_widget = (GtkWidget*) NULL;
2164 }
2165}
2166
2167bool wxWindow::PreCreation( wxWindow *parent, const wxPoint &pos, const wxSize &size )
2168{
2169 wxCHECK_MSG( !m_needParent || parent, FALSE, wxT("Need complete parent.") );
2170
2171 /* this turns -1 into 20 so that a minimal window is
2172 visible even although -1,-1 has been given as the
2173 size of the window. the same trick is used in other
2174 ports and should make debugging easier */
2175 m_width = WidthDefault(size.x);
2176 m_height = HeightDefault(size.y);
2177
2178 m_x = (int)pos.x;
2179 m_y = (int)pos.y;
2180
2181 /* some reasonable defaults */
2182 if (!parent)
2183 {
2184 if (m_x == -1)
2185 {
2186 m_x = (gdk_screen_width () - m_width) / 2;
2187 if (m_x < 10) m_x = 10;
2188 }
2189 if (m_y == -1)
2190 {
2191 m_y = (gdk_screen_height () - m_height) / 2;
2192 if (m_y < 10) m_y = 10;
2193 }
2194 }
2195
2196 return TRUE;
2197}
2198
2199void wxWindow::PostCreation()
2200{
2201 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2202
2203 if (m_wxwindow)
2204 {
2205 if (!m_noExpose)
2206 {
2207 /* these get reported to wxWindows -> wxPaintEvent */
2208 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
2209 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
2210
2211 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
2212 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
2213 }
2214
2215#if (GTK_MINOR_VERSION > 0)
2216 /* these are called when the "sunken" or "raised" borders are drawn */
2217 gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
2218 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
2219
2220 gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
2221 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
2222#endif
2223 }
2224
2225 if (m_wxwindow && m_needParent)
2226 {
2227 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "focus_in_event",
2228 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
2229
2230 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "focus_out_event",
2231 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
2232 }
2233 else
2234 {
2235 // For dialogs and frames, we are interested mainly in
2236 // m_widget's focus.
2237
2238 gtk_signal_connect( GTK_OBJECT(m_widget), "focus_in_event",
2239 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
2240
2241 gtk_signal_connect( GTK_OBJECT(m_widget), "focus_out_event",
2242 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
2243 }
2244
2245 GtkWidget *connect_widget = GetConnectWidget();
2246
2247 ConnectWidget( connect_widget );
2248
2249 /* We cannot set colours, fonts and cursors before the widget has
2250 been realized, so we do this directly after realization */
2251 gtk_signal_connect( GTK_OBJECT(connect_widget), "realize",
2252 GTK_SIGNAL_FUNC(gtk_window_realized_callback), (gpointer) this );
2253
2254 if (m_wxwindow)
2255 {
2256 /* Catch native resize events. */
2257 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2258 GTK_SIGNAL_FUNC(gtk_window_size_callback), (gpointer)this );
2259
2260 /* Initialize XIM support. */
2261 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "realize",
2262 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback), (gpointer) this );
2263
2264 /* And resize XIM window. */
2265 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2266 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this );
2267 }
2268
2269 m_hasVMT = TRUE;
2270}
2271
2272void wxWindow::ConnectWidget( GtkWidget *widget )
2273{
2274 gtk_signal_connect( GTK_OBJECT(widget), "key_press_event",
2275 GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this );
2276
2277 gtk_signal_connect( GTK_OBJECT(widget), "key_release_event",
2278 GTK_SIGNAL_FUNC(gtk_window_key_release_callback), (gpointer)this );
2279
2280 gtk_signal_connect( GTK_OBJECT(widget), "button_press_event",
2281 GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
2282
2283 gtk_signal_connect( GTK_OBJECT(widget), "button_release_event",
2284 GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
2285
2286 gtk_signal_connect( GTK_OBJECT(widget), "motion_notify_event",
2287 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
2288
2289 gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event",
2290 GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
2291
2292 gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
2293 GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
2294}
2295
2296bool wxWindow::Destroy()
2297{
2298 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2299
2300 m_hasVMT = FALSE;
2301
2302 return wxWindowBase::Destroy();
2303}
2304
2305void wxWindow::DoMoveWindow(int x, int y, int width, int height)
2306{
2307 gtk_pizza_set_size( GTK_PIZZA(m_parent->m_wxwindow), m_widget, x, y, width, height );
2308}
2309
2310void wxWindow::DoSetSize( int x, int y, int width, int height, int sizeFlags )
2311{
2312 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2313 wxASSERT_MSG( (m_parent != NULL), wxT("wxWindow::SetSize requires parent.\n") );
2314
2315 if (m_resizing) return; /* I don't like recursions */
2316 m_resizing = TRUE;
2317
2318 if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
2319 {
2320 /* don't set the size for children of wxNotebook, just take the values. */
2321 m_x = x;
2322 m_y = y;
2323 m_width = width;
2324 m_height = height;
2325 }
2326 else
2327 {
2328 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
2329
2330 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
2331 {
2332 if (x != -1) m_x = x + pizza->xoffset;
2333 if (y != -1) m_y = y + pizza->yoffset;
2334 if (width != -1) m_width = width;
2335 if (height != -1) m_height = height;
2336 }
2337 else
2338 {
2339 m_x = x + pizza->xoffset;
2340 m_y = y + pizza->yoffset;
2341 m_width = width;
2342 m_height = height;
2343 }
2344
2345 if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
2346 {
2347 if (width == -1) m_width = 80;
2348 }
2349
2350 if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
2351 {
2352 if (height == -1) m_height = 26;
2353 }
2354
2355 if ((m_minWidth != -1) && (m_width < m_minWidth)) m_width = m_minWidth;
2356 if ((m_minHeight != -1) && (m_height < m_minHeight)) m_height = m_minHeight;
2357 if ((m_maxWidth != -1) && (m_width > m_maxWidth)) m_width = m_maxWidth;
2358 if ((m_maxHeight != -1) && (m_height > m_maxHeight)) m_height = m_maxHeight;
2359
2360 int border = 0;
2361 int bottom_border = 0;
2362
2363 if (GTK_WIDGET_CAN_DEFAULT(m_widget))
2364 {
2365 /* the default button has a border around it */
2366 border = 6;
2367 bottom_border = 5;
2368 }
2369
2370 DoMoveWindow( m_x-border,
2371 m_y-border,
2372 m_width+2*border,
2373 m_height+border+bottom_border );
2374 }
2375
2376 if (m_hasScrolling)
2377 {
2378 GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
2379 }
2380
2381/*
2382 wxPrintf( "OnSize sent from " );
2383 if (GetClassInfo() && GetClassInfo()->GetClassName())
2384 wxPrintf( GetClassInfo()->GetClassName() );
2385 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
2386*/
2387
2388 if (!m_nativeSizeEvent)
2389 {
2390 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
2391 event.SetEventObject( this );
2392 GetEventHandler()->ProcessEvent( event );
2393 }
2394
2395 m_resizing = FALSE;
2396}
2397
2398void wxWindow::OnInternalIdle()
2399{
2400 if ( g_sendActivateEvent != -1 )
2401 {
2402 bool activate = g_sendActivateEvent != 0;
2403
2404 // do it only once
2405 g_sendActivateEvent = -1;
2406
2407 wxActivateEvent event(wxEVT_ACTIVATE, activate, GetId());
2408 event.SetEventObject(this);
2409
2410 (void)GetEventHandler()->ProcessEvent(event);
2411 }
2412
2413 wxCursor cursor = m_cursor;
2414 if (g_globalCursor.Ok()) cursor = g_globalCursor;
2415
2416 if (cursor.Ok())
2417 {
2418 /* I now set the cursor anew in every OnInternalIdle call
2419 as setting the cursor in a parent window also effects the
2420 windows above so that checking for the current cursor is
2421 not possible. */
2422
2423 if (m_wxwindow)
2424 {
2425 GdkWindow *window = GTK_PIZZA(m_wxwindow)->bin_window;
2426 if (window)
2427 gdk_window_set_cursor( window, cursor.GetCursor() );
2428
2429 if (!g_globalCursor.Ok())
2430 cursor = *wxSTANDARD_CURSOR;
2431
2432 window = m_widget->window;
2433 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
2434 gdk_window_set_cursor( window, cursor.GetCursor() );
2435
2436 }
2437 else
2438 {
2439
2440 GdkWindow *window = m_widget->window;
2441 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
2442 gdk_window_set_cursor( window, cursor.GetCursor() );
2443
2444 }
2445 }
2446
2447 UpdateWindowUI();
2448}
2449
2450void wxWindow::DoGetSize( int *width, int *height ) const
2451{
2452 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2453
2454 if (width) (*width) = m_width;
2455 if (height) (*height) = m_height;
2456}
2457
2458void wxWindow::DoSetClientSize( int width, int height )
2459{
2460 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2461
2462 if (!m_wxwindow)
2463 {
2464 SetSize( width, height );
2465 }
2466 else
2467 {
2468 int dw = 0;
2469 int dh = 0;
2470
2471 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
2472 {
2473 /* when using GTK 1.2 we set the shadow border size to 2 */
2474 dw += 2 * 2;
2475 dh += 2 * 2;
2476 }
2477 if (HasFlag(wxSIMPLE_BORDER))
2478 {
2479 /* when using GTK 1.2 we set the simple border size to 1 */
2480 dw += 1 * 2;
2481 dh += 1 * 2;
2482 }
2483
2484 if (m_hasScrolling)
2485 {
2486 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2487
2488 GtkRequisition vscroll_req;
2489 vscroll_req.width = 2;
2490 vscroll_req.height = 2;
2491 (* GTK_WIDGET_CLASS( GTK_OBJECT(scroll_window->vscrollbar)->klass )->size_request )
2492 (scroll_window->vscrollbar, &vscroll_req );
2493
2494 GtkRequisition hscroll_req;
2495 hscroll_req.width = 2;
2496 hscroll_req.height = 2;
2497 (* GTK_WIDGET_CLASS( GTK_OBJECT(scroll_window->hscrollbar)->klass )->size_request )
2498 (scroll_window->hscrollbar, &hscroll_req );
2499
2500 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(m_widget)->klass );
2501
2502 if (scroll_window->vscrollbar_visible)
2503 {
2504 dw += vscroll_req.width;
2505 dw += scroll_class->scrollbar_spacing;
2506 }
2507
2508 if (scroll_window->hscrollbar_visible)
2509 {
2510 dh += hscroll_req.height;
2511 dh += scroll_class->scrollbar_spacing;
2512 }
2513 }
2514
2515 SetSize( width+dw, height+dh );
2516 }
2517}
2518
2519void wxWindow::DoGetClientSize( int *width, int *height ) const
2520{
2521 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2522
2523 if (!m_wxwindow)
2524 {
2525 if (width) (*width) = m_width;
2526 if (height) (*height) = m_height;
2527 }
2528 else
2529 {
2530 int dw = 0;
2531 int dh = 0;
2532
2533 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
2534 {
2535 /* when using GTK 1.2 we set the shadow border size to 2 */
2536 dw += 2 * 2;
2537 dh += 2 * 2;
2538 }
2539 if (HasFlag(wxSIMPLE_BORDER))
2540 {
2541 /* when using GTK 1.2 we set the simple border size to 1 */
2542 dw += 1 * 2;
2543 dh += 1 * 2;
2544 }
2545
2546 if (m_hasScrolling)
2547 {
2548 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
2549
2550 GtkRequisition vscroll_req;
2551 vscroll_req.width = 2;
2552 vscroll_req.height = 2;
2553 (* GTK_WIDGET_CLASS( GTK_OBJECT(scroll_window->vscrollbar)->klass )->size_request )
2554 (scroll_window->vscrollbar, &vscroll_req );
2555
2556 GtkRequisition hscroll_req;
2557 hscroll_req.width = 2;
2558 hscroll_req.height = 2;
2559 (* GTK_WIDGET_CLASS( GTK_OBJECT(scroll_window->hscrollbar)->klass )->size_request )
2560 (scroll_window->hscrollbar, &hscroll_req );
2561
2562 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(m_widget)->klass );
2563
2564 if (scroll_window->vscrollbar_visible)
2565 {
2566 dw += vscroll_req.width;
2567 dw += scroll_class->scrollbar_spacing;
2568 }
2569
2570 if (scroll_window->hscrollbar_visible)
2571 {
2572 dh += hscroll_req.height;
2573 dh += scroll_class->scrollbar_spacing;
2574 }
2575 }
2576
2577 if (width) (*width) = m_width - dw;
2578 if (height) (*height) = m_height - dh;
2579 }
2580}
2581
2582void wxWindow::DoGetPosition( int *x, int *y ) const
2583{
2584 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2585
2586 int dx = 0;
2587 int dy = 0;
2588 if (m_parent && m_parent->m_wxwindow)
2589 {
2590 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
2591 dx = pizza->xoffset;
2592 dy = pizza->yoffset;
2593 }
2594
2595 if (x) (*x) = m_x - dx;
2596 if (y) (*y) = m_y - dy;
2597}
2598
2599void wxWindow::DoClientToScreen( int *x, int *y ) const
2600{
2601 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2602
2603 if (!m_widget->window) return;
2604
2605 GdkWindow *source = (GdkWindow *) NULL;
2606 if (m_wxwindow)
2607 source = GTK_PIZZA(m_wxwindow)->bin_window;
2608 else
2609 source = m_widget->window;
2610
2611 int org_x = 0;
2612 int org_y = 0;
2613 gdk_window_get_origin( source, &org_x, &org_y );
2614
2615 if (!m_wxwindow)
2616 {
2617 if (GTK_WIDGET_NO_WINDOW (m_widget))
2618 {
2619 org_x += m_widget->allocation.x;
2620 org_y += m_widget->allocation.y;
2621 }
2622 }
2623
2624 if (x) *x += org_x;
2625 if (y) *y += org_y;
2626}
2627
2628void wxWindow::DoScreenToClient( int *x, int *y ) const
2629{
2630 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2631
2632 if (!m_widget->window) return;
2633
2634 GdkWindow *source = (GdkWindow *) NULL;
2635 if (m_wxwindow)
2636 source = GTK_PIZZA(m_wxwindow)->bin_window;
2637 else
2638 source = m_widget->window;
2639
2640 int org_x = 0;
2641 int org_y = 0;
2642 gdk_window_get_origin( source, &org_x, &org_y );
2643
2644 if (!m_wxwindow)
2645 {
2646 if (GTK_WIDGET_NO_WINDOW (m_widget))
2647 {
2648 org_x += m_widget->allocation.x;
2649 org_y += m_widget->allocation.y;
2650 }
2651 }
2652
2653 if (x) *x -= org_x;
2654 if (y) *y -= org_y;
2655}
2656
2657bool wxWindow::Show( bool show )
2658{
2659 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
2660
2661 if (!wxWindowBase::Show(show))
2662 {
2663 // nothing to do
2664 return FALSE;
2665 }
2666
2667 if (show)
2668 gtk_widget_show( m_widget );
2669 else
2670 gtk_widget_hide( m_widget );
2671
2672 return TRUE;
2673}
2674
2675bool wxWindow::Enable( bool enable )
2676{
2677 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
2678
2679 if (!wxWindowBase::Enable(enable))
2680 {
2681 // nothing to do
2682 return FALSE;
2683 }
2684
2685 gtk_widget_set_sensitive( m_widget, enable );
2686 if ( m_wxwindow )
2687 gtk_widget_set_sensitive( m_wxwindow, enable );
2688
2689 return TRUE;
2690}
2691
2692int wxWindow::GetCharHeight() const
2693{
2694 wxCHECK_MSG( (m_widget != NULL), 12, wxT("invalid window") );
2695
2696 wxCHECK_MSG( m_font.Ok(), 12, wxT("invalid font") );
2697
2698 GdkFont *font = m_font.GetInternalFont( 1.0 );
2699
2700 return font->ascent + font->descent;
2701}
2702
2703int wxWindow::GetCharWidth() const
2704{
2705 wxCHECK_MSG( (m_widget != NULL), 8, wxT("invalid window") );
2706
2707 wxCHECK_MSG( m_font.Ok(), 8, wxT("invalid font") );
2708
2709 GdkFont *font = m_font.GetInternalFont( 1.0 );
2710
2711 return gdk_string_width( font, "H" );
2712}
2713
2714void wxWindow::GetTextExtent( const wxString& string,
2715 int *x,
2716 int *y,
2717 int *descent,
2718 int *externalLeading,
2719 const wxFont *theFont ) const
2720{
2721 wxFont fontToUse = m_font;
2722 if (theFont) fontToUse = *theFont;
2723
2724 wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
2725
2726 GdkFont *font = fontToUse.GetInternalFont( 1.0 );
2727 if (x) (*x) = gdk_string_width( font, string.mbc_str() );
2728 if (y) (*y) = font->ascent + font->descent;
2729 if (descent) (*descent) = font->descent;
2730 if (externalLeading) (*externalLeading) = 0; // ??
2731}
2732
2733void wxWindow::SetFocus()
2734{
2735 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2736
2737 if (m_wxwindow)
2738 {
2739 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
2740 gtk_widget_grab_focus (m_wxwindow);
2741 return;
2742 }
2743
2744 if (m_widget)
2745 {
2746 if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
2747 {
2748 gtk_widget_grab_focus (m_widget);
2749 }
2750 else if (GTK_IS_CONTAINER(m_widget))
2751 {
2752 gtk_container_focus( GTK_CONTAINER(m_widget), GTK_DIR_TAB_FORWARD );
2753 }
2754 else
2755 {
2756 // ?
2757 }
2758 }
2759}
2760
2761bool wxWindow::AcceptsFocus() const
2762{
2763 return m_acceptsFocus && wxWindowBase::AcceptsFocus();
2764}
2765
2766bool wxWindow::Reparent( wxWindowBase *newParentBase )
2767{
2768 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
2769
2770 wxWindow *oldParent = m_parent,
2771 *newParent = (wxWindow *)newParentBase;
2772
2773 wxASSERT( GTK_IS_WIDGET(m_widget) );
2774
2775 if ( !wxWindowBase::Reparent(newParent) )
2776 return FALSE;
2777
2778 wxASSERT( GTK_IS_WIDGET(m_widget) );
2779
2780 /* prevent GTK from deleting the widget arbitrarily */
2781 gtk_widget_ref( m_widget );
2782
2783 if (oldParent)
2784 {
2785 gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget );
2786 }
2787
2788 wxASSERT( GTK_IS_WIDGET(m_widget) );
2789
2790 if (newParent)
2791 {
2792 /* insert GTK representation */
2793 (*(newParent->m_insertCallback))(newParent, this);
2794 }
2795
2796 /* reverse: prevent GTK from deleting the widget arbitrarily */
2797 gtk_widget_unref( m_widget );
2798
2799 return TRUE;
2800}
2801
2802void wxWindow::DoAddChild(wxWindow *child)
2803{
2804 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2805
2806 wxASSERT_MSG( (child != NULL), wxT("invalid child window") );
2807
2808 wxASSERT_MSG( (m_insertCallback != NULL), wxT("invalid child insertion function") );
2809
2810 /* add to list */
2811 AddChild( child );
2812
2813 /* insert GTK representation */
2814 (*m_insertCallback)(this, child);
2815}
2816
2817void wxWindow::Raise()
2818{
2819 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2820
2821 if (!m_widget->window) return;
2822
2823 gdk_window_raise( m_widget->window );
2824}
2825
2826void wxWindow::Lower()
2827{
2828 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2829
2830 if (!m_widget->window) return;
2831
2832 gdk_window_lower( m_widget->window );
2833}
2834
2835bool wxWindow::SetCursor( const wxCursor &cursor )
2836{
2837 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
2838
2839 return wxWindowBase::SetCursor( cursor );
2840}
2841
2842void wxWindow::WarpPointer( int x, int y )
2843{
2844 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
2845
2846 /* we provide this function ourselves as it is
2847 missing in GDK (top of this file) */
2848
2849 GdkWindow *window = (GdkWindow*) NULL;
2850 if (m_wxwindow)
2851 window = GTK_PIZZA(m_wxwindow)->bin_window;
2852 else
2853 window = GetConnectWidget()->window;
2854
2855 if (window)
2856 gdk_window_warp_pointer( window, x, y );
2857}
2858
2859void wxWindow::Refresh( bool eraseBackground, const wxRect *rect )
2860{
2861 if (!m_widget) return;
2862 if (!m_widget->window) return;
2863
2864 if (eraseBackground && m_wxwindow && m_wxwindow->window)
2865 {
2866 if (rect)
2867 {
2868 gdk_window_clear_area( GTK_PIZZA(m_wxwindow)->bin_window,
2869 rect->x, rect->y,
2870 rect->width, rect->height );
2871 }
2872 else
2873 {
2874 gdk_window_clear( GTK_PIZZA(m_wxwindow)->bin_window );
2875 }
2876 }
2877
2878 /* there is no GTK equivalent of "draw only, don't clear" so we
2879 invent our own in the GtkPizza widget */
2880
2881 if (!rect)
2882 {
2883 if (m_wxwindow)
2884 {
2885 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
2886 gboolean old_clear = pizza->clear_on_draw;
2887 gtk_pizza_set_clear( pizza, FALSE );
2888
2889 gtk_widget_draw( m_wxwindow, (GdkRectangle*) NULL );
2890
2891 gtk_pizza_set_clear( pizza, old_clear );
2892 }
2893 else
2894 gtk_widget_draw( m_widget, (GdkRectangle*) NULL );
2895 }
2896 else
2897 {
2898 GdkRectangle gdk_rect;
2899 gdk_rect.x = rect->x;
2900 gdk_rect.y = rect->y;
2901 gdk_rect.width = rect->width;
2902 gdk_rect.height = rect->height;
2903
2904 if (m_wxwindow)
2905 {
2906 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
2907 gboolean old_clear = pizza->clear_on_draw;
2908 gtk_pizza_set_clear( pizza, FALSE );
2909
2910 gtk_widget_draw( m_wxwindow, &gdk_rect );
2911
2912 gtk_pizza_set_clear( pizza, old_clear );
2913 }
2914 else
2915 gtk_widget_draw( m_widget, &gdk_rect );
2916 }
2917}
2918
2919void wxWindow::Clear()
2920{
2921 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
2922
2923 if (!m_widget->window) return;
2924
2925 if (m_wxwindow && m_wxwindow->window)
2926 {
2927 gdk_window_clear( m_wxwindow->window );
2928 }
2929}
2930
2931#if wxUSE_TOOLTIPS
2932void wxWindow::DoSetToolTip( wxToolTip *tip )
2933{
2934 wxWindowBase::DoSetToolTip(tip);
2935
2936 if (m_tooltip)
2937 m_tooltip->Apply( this );
2938}
2939
2940void wxWindow::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
2941{
2942 gtk_tooltips_set_tip( tips, GetConnectWidget(), wxConvCurrent->cWX2MB(tip), (gchar*) NULL );
2943}
2944#endif // wxUSE_TOOLTIPS
2945
2946bool wxWindow::SetBackgroundColour( const wxColour &colour )
2947{
2948 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
2949
2950 if (!wxWindowBase::SetBackgroundColour(colour))
2951 {
2952 // don't leave if the GTK widget has just
2953 // been realized
2954 if (!m_delayedBackgroundColour) return FALSE;
2955 }
2956
2957 GdkWindow *window = (GdkWindow*) NULL;
2958 if (m_wxwindow)
2959 window = GTK_PIZZA(m_wxwindow)->bin_window;
2960 else
2961 window = GetConnectWidget()->window;
2962
2963 if (!window)
2964 {
2965 // indicate that a new style has been set
2966 // but it couldn't get applied as the
2967 // widget hasn't been realized yet.
2968 m_delayedBackgroundColour = TRUE;
2969 }
2970
2971 if ((m_wxwindow) &&
2972 (m_wxwindow->window) &&
2973 (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE)))
2974 {
2975 /* wxMSW doesn't clear the window here. I don't do that either to
2976 provide compatibility. call Clear() to do the job. */
2977
2978 m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
2979 gdk_window_set_background( window, m_backgroundColour.GetColor() );
2980 }
2981
2982 ApplyWidgetStyle();
2983
2984 return TRUE;
2985}
2986
2987bool wxWindow::SetForegroundColour( const wxColour &colour )
2988{
2989 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
2990
2991 if (!wxWindowBase::SetForegroundColour(colour))
2992 {
2993 // don't leave if the GTK widget has just
2994 // been realized
2995 if (!m_delayedForegroundColour) return FALSE;
2996 }
2997
2998 GdkWindow *window = (GdkWindow*) NULL;
2999 if (m_wxwindow)
3000 window = GTK_PIZZA(m_wxwindow)->bin_window;
3001 else
3002 window = GetConnectWidget()->window;
3003
3004 if (!window)
3005 {
3006 // indicate that a new style has been set
3007 // but it couldn't get applied as the
3008 // widget hasn't been realized yet.
3009 m_delayedForegroundColour = TRUE;
3010 }
3011
3012 ApplyWidgetStyle();
3013
3014 return TRUE;
3015}
3016
3017GtkStyle *wxWindow::GetWidgetStyle()
3018{
3019 if (m_widgetStyle)
3020 {
3021 GtkStyle *remake = gtk_style_copy( m_widgetStyle );
3022 remake->klass = m_widgetStyle->klass;
3023
3024 gtk_style_unref( m_widgetStyle );
3025 m_widgetStyle = remake;
3026 }
3027 else
3028 {
3029 GtkStyle *def = gtk_rc_get_style( m_widget );
3030
3031 if (!def)
3032 def = gtk_widget_get_default_style();
3033
3034 m_widgetStyle = gtk_style_copy( def );
3035 m_widgetStyle->klass = def->klass;
3036 }
3037
3038 return m_widgetStyle;
3039}
3040
3041void wxWindow::SetWidgetStyle()
3042{
3043 if (m_widget->style->engine_data)
3044 {
3045 static bool s_warningPrinted = FALSE;
3046 if (!s_warningPrinted)
3047 {
3048 printf( "wxWindows warning: Widget styles disabled due to buggy GTK theme.\n" );
3049 s_warningPrinted = TRUE;
3050 }
3051 m_widgetStyle = m_widget->style;
3052 return;
3053 }
3054
3055 GtkStyle *style = GetWidgetStyle();
3056
3057 if (m_font != wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT ))
3058 {
3059 gdk_font_unref( style->font );
3060 style->font = gdk_font_ref( m_font.GetInternalFont( 1.0 ) );
3061 }
3062
3063 if (m_foregroundColour.Ok())
3064 {
3065 m_foregroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
3066 if (m_foregroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNTEXT))
3067 {
3068 style->fg[GTK_STATE_NORMAL] = *m_foregroundColour.GetColor();
3069 style->fg[GTK_STATE_PRELIGHT] = *m_foregroundColour.GetColor();
3070 style->fg[GTK_STATE_ACTIVE] = *m_foregroundColour.GetColor();
3071 }
3072 }
3073
3074 if (m_backgroundColour.Ok())
3075 {
3076 m_backgroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
3077 if (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE))
3078 {
3079 style->bg[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
3080 style->base[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
3081 style->bg[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
3082 style->base[GTK_STATE_PRELIGHT] = *m_backgroundColour.GetColor();
3083 style->bg[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
3084 style->base[GTK_STATE_ACTIVE] = *m_backgroundColour.GetColor();
3085 style->bg[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
3086 style->base[GTK_STATE_INSENSITIVE] = *m_backgroundColour.GetColor();
3087 }
3088 }
3089}
3090
3091void wxWindow::ApplyWidgetStyle()
3092{
3093}
3094
3095//-----------------------------------------------------------------------------
3096// Pop-up menu stuff
3097//-----------------------------------------------------------------------------
3098
3099static void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting )
3100{
3101 *is_waiting = FALSE;
3102}
3103
3104static void SetInvokingWindow( wxMenu *menu, wxWindow *win )
3105{
3106 menu->SetInvokingWindow( win );
3107 wxMenuItemList::Node *node = menu->GetMenuItems().GetFirst();
3108 while (node)
3109 {
3110 wxMenuItem *menuitem = node->GetData();
3111 if (menuitem->IsSubMenu())
3112 {
3113 SetInvokingWindow( menuitem->GetSubMenu(), win );
3114 }
3115
3116 node = node->GetNext();
3117 }
3118}
3119
3120static gint gs_pop_x = 0;
3121static gint gs_pop_y = 0;
3122
3123static void pop_pos_callback( GtkMenu * WXUNUSED(menu),
3124 gint *x, gint *y,
3125 wxWindow *win )
3126{
3127 win->ClientToScreen( &gs_pop_x, &gs_pop_y );
3128 *x = gs_pop_x;
3129 *y = gs_pop_y;
3130}
3131
3132bool wxWindow::DoPopupMenu( wxMenu *menu, int x, int y )
3133{
3134 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3135
3136 wxCHECK_MSG( menu != NULL, FALSE, wxT("invalid popup-menu") );
3137
3138 SetInvokingWindow( menu, this );
3139
3140 menu->UpdateUI();
3141
3142 gs_pop_x = x;
3143 gs_pop_y = y;
3144
3145 bool is_waiting = TRUE;
3146
3147 gtk_signal_connect( GTK_OBJECT(menu->m_menu), "hide",
3148 GTK_SIGNAL_FUNC(gtk_pop_hide_callback), (gpointer)&is_waiting );
3149
3150 gtk_menu_popup(
3151 GTK_MENU(menu->m_menu),
3152 (GtkWidget *) NULL, // parent menu shell
3153 (GtkWidget *) NULL, // parent menu item
3154 (GtkMenuPositionFunc) pop_pos_callback,
3155 (gpointer) this, // client data
3156 0, // button used to activate it
3157 gs_timeLastClick // the time of activation
3158 );
3159
3160 while (is_waiting)
3161 {
3162 while (gtk_events_pending())
3163 gtk_main_iteration();
3164 }
3165
3166 return TRUE;
3167}
3168
3169#if wxUSE_DRAG_AND_DROP
3170
3171void wxWindow::SetDropTarget( wxDropTarget *dropTarget )
3172{
3173 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3174
3175 GtkWidget *dnd_widget = GetConnectWidget();
3176
3177 if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
3178
3179 if (m_dropTarget) delete m_dropTarget;
3180 m_dropTarget = dropTarget;
3181
3182 if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
3183}
3184
3185#endif // wxUSE_DRAG_AND_DROP
3186
3187GtkWidget* wxWindow::GetConnectWidget()
3188{
3189 GtkWidget *connect_widget = m_widget;
3190 if (m_wxwindow) connect_widget = m_wxwindow;
3191
3192 return connect_widget;
3193}
3194
3195bool wxWindow::IsOwnGtkWindow( GdkWindow *window )
3196{
3197 if (m_wxwindow)
3198 return (window == GTK_PIZZA(m_wxwindow)->bin_window);
3199
3200 return (window == m_widget->window);
3201}
3202
3203bool wxWindow::SetFont( const wxFont &font )
3204{
3205 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
3206
3207 if (!wxWindowBase::SetFont(font))
3208 {
3209 return FALSE;
3210 }
3211
3212 wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
3213 if ( sysbg == m_backgroundColour )
3214 {
3215 m_backgroundColour = wxNullColour;
3216 ApplyWidgetStyle();
3217 m_backgroundColour = sysbg;
3218 }
3219 else
3220 {
3221 ApplyWidgetStyle();
3222 }
3223
3224 return TRUE;
3225}
3226
3227void wxWindow::CaptureMouse()
3228{
3229 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3230
3231 wxCHECK_RET( g_captureWindow == NULL, wxT("CaptureMouse called twice") );
3232
3233 GdkWindow *window = (GdkWindow*) NULL;
3234 if (m_wxwindow)
3235 window = GTK_PIZZA(m_wxwindow)->bin_window;
3236 else
3237 window = GetConnectWidget()->window;
3238
3239 if (!window) return;
3240
3241 gdk_pointer_grab( window, FALSE,
3242 (GdkEventMask)
3243 (GDK_BUTTON_PRESS_MASK |
3244 GDK_BUTTON_RELEASE_MASK |
3245 GDK_POINTER_MOTION_HINT_MASK |
3246 GDK_POINTER_MOTION_MASK),
3247 (GdkWindow *) NULL,
3248 m_cursor.GetCursor(),
3249 (guint32)GDK_CURRENT_TIME );
3250 g_captureWindow = this;
3251}
3252
3253void wxWindow::ReleaseMouse()
3254{
3255 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3256
3257 wxCHECK_RET( g_captureWindow, wxT("ReleaseMouse called twice") );
3258
3259 GdkWindow *window = (GdkWindow*) NULL;
3260 if (m_wxwindow)
3261 window = GTK_PIZZA(m_wxwindow)->bin_window;
3262 else
3263 window = GetConnectWidget()->window;
3264
3265 if (!window)
3266 return;
3267
3268 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
3269 g_captureWindow = (wxWindow*) NULL;
3270}
3271
3272bool wxWindow::IsRetained() const
3273{
3274 return FALSE;
3275}
3276
3277void wxWindow::SetScrollbar( int orient, int pos, int thumbVisible,
3278 int range, bool refresh )
3279{
3280 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3281
3282 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
3283
3284 m_hasScrolling = TRUE;
3285
3286 if (orient == wxHORIZONTAL)
3287 {
3288 float fpos = (float)pos;
3289 float frange = (float)range;
3290 float fthumb = (float)thumbVisible;
3291 if (fpos > frange-fthumb) fpos = frange-fthumb;
3292 if (fpos < 0.0) fpos = 0.0;
3293
3294 if ((fabs(frange-m_hAdjust->upper) < 0.2) &&
3295 (fabs(fthumb-m_hAdjust->page_size) < 0.2))
3296 {
3297 SetScrollPos( orient, pos, refresh );
3298 return;
3299 }
3300
3301 m_oldHorizontalPos = fpos;
3302
3303 m_hAdjust->lower = 0.0;
3304 m_hAdjust->upper = frange;
3305 m_hAdjust->value = fpos;
3306 m_hAdjust->step_increment = 1.0;
3307 m_hAdjust->page_increment = (float)(wxMax(fthumb,0));
3308 m_hAdjust->page_size = fthumb;
3309 }
3310 else
3311 {
3312 float fpos = (float)pos;
3313 float frange = (float)range;
3314 float fthumb = (float)thumbVisible;
3315 if (fpos > frange-fthumb) fpos = frange-fthumb;
3316 if (fpos < 0.0) fpos = 0.0;
3317
3318 if ((fabs(frange-m_vAdjust->upper) < 0.2) &&
3319 (fabs(fthumb-m_vAdjust->page_size) < 0.2))
3320 {
3321 SetScrollPos( orient, pos, refresh );
3322 return;
3323 }
3324
3325 m_oldVerticalPos = fpos;
3326
3327 m_vAdjust->lower = 0.0;
3328 m_vAdjust->upper = frange;
3329 m_vAdjust->value = fpos;
3330 m_vAdjust->step_increment = 1.0;
3331 m_vAdjust->page_increment = (float)(wxMax(fthumb,0));
3332 m_vAdjust->page_size = fthumb;
3333 }
3334
3335 if (orient == wxHORIZONTAL)
3336 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
3337 else
3338 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
3339}
3340
3341void wxWindow::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
3342{
3343 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3344
3345 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
3346
3347 if (orient == wxHORIZONTAL)
3348 {
3349 float fpos = (float)pos;
3350 if (fpos > m_hAdjust->upper - m_hAdjust->page_size) fpos = m_hAdjust->upper - m_hAdjust->page_size;
3351 if (fpos < 0.0) fpos = 0.0;
3352 m_oldHorizontalPos = fpos;
3353
3354 if (fabs(fpos-m_hAdjust->value) < 0.2) return;
3355 m_hAdjust->value = fpos;
3356 }
3357 else
3358 {
3359 float fpos = (float)pos;
3360 if (fpos > m_vAdjust->upper - m_vAdjust->page_size) fpos = m_vAdjust->upper - m_vAdjust->page_size;
3361 if (fpos < 0.0) fpos = 0.0;
3362 m_oldVerticalPos = fpos;
3363
3364 if (fabs(fpos-m_vAdjust->value) < 0.2) return;
3365 m_vAdjust->value = fpos;
3366 }
3367
3368 if (m_wxwindow->window)
3369 {
3370 if (orient == wxHORIZONTAL)
3371 {
3372 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust),
3373 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
3374
3375 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
3376
3377 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
3378 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
3379 }
3380 else
3381 {
3382 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust),
3383 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
3384
3385 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
3386
3387 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
3388 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
3389 }
3390 }
3391}
3392
3393int wxWindow::GetScrollThumb( int orient ) const
3394{
3395 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
3396
3397 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
3398
3399 if (orient == wxHORIZONTAL)
3400 return (int)(m_hAdjust->page_size+0.5);
3401 else
3402 return (int)(m_vAdjust->page_size+0.5);
3403}
3404
3405int wxWindow::GetScrollPos( int orient ) const
3406{
3407 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
3408
3409 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
3410
3411 if (orient == wxHORIZONTAL)
3412 return (int)(m_hAdjust->value+0.5);
3413 else
3414 return (int)(m_vAdjust->value+0.5);
3415}
3416
3417int wxWindow::GetScrollRange( int orient ) const
3418{
3419 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
3420
3421 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
3422
3423 if (orient == wxHORIZONTAL)
3424 return (int)(m_hAdjust->upper+0.5);
3425 else
3426 return (int)(m_vAdjust->upper+0.5);
3427}
3428
3429void wxWindow::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
3430{
3431 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3432
3433 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
3434
3435/*
3436 printf( "ScrollWindow: %d %d\n", dx, dy );
3437*/
3438
3439 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
3440
3441/*
3442 if (!m_scrollGC)
3443 {
3444 m_scrollGC = gdk_gc_new( m_wxwindow->window );
3445 gdk_gc_set_exposures( m_scrollGC, TRUE );
3446 }
3447
3448 wxNode *node = m_children.First();
3449 while (node)
3450 {
3451 wxWindow *child = (wxWindow*) node->Data();
3452 int sx = 0;
3453 int sy = 0;
3454 child->GetSize( &sx, &sy );
3455 child->SetSize( child->m_x + dx, child->m_y + dy, sx, sy, wxSIZE_ALLOW_MINUS_ONE );
3456 node = node->Next();
3457 }
3458
3459 int cw = 0;
3460 int ch = 0;
3461 GetClientSize( &cw, &ch );
3462 int w = cw - abs(dx);
3463 int h = ch - abs(dy);
3464
3465 if ((h < 0) || (w < 0))
3466 {
3467 Refresh();
3468 }
3469 else
3470 {
3471 int s_x = 0;
3472 int s_y = 0;
3473 if (dx < 0) s_x = -dx;
3474 if (dy < 0) s_y = -dy;
3475 int d_x = 0;
3476 int d_y = 0;
3477 if (dx > 0) d_x = dx;
3478 if (dy > 0) d_y = dy;
3479
3480 gdk_window_copy_area( m_wxwindow->window, m_scrollGC, d_x, d_y,
3481 m_wxwindow->window, s_x, s_y, w, h );
3482
3483 wxRect rect;
3484 if (dx < 0) rect.x = cw+dx; else rect.x = 0;
3485 if (dy < 0) rect.y = ch+dy; else rect.y = 0;
3486 if (dy != 0) rect.width = cw; else rect.width = abs(dx);
3487 if (dx != 0) rect.height = ch; else rect.height = abs(dy);
3488
3489 Refresh( TRUE, &rect );
3490 }
3491*/
3492}