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