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