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