Committed Raise()Lower() fix.
[wxWidgets.git] / src / gtk1 / window.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10
11 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
12 #pragma implementation "window.h"
13 #endif
14
15 // For compilers that support precompilation, includes "wx.h".
16 #include "wx/wxprec.h"
17
18 #ifdef __VMS
19 #define XWarpPointer XWARPPOINTER
20 #endif
21
22 #include "wx/window.h"
23 #include "wx/dcclient.h"
24 #include "wx/frame.h"
25 #include "wx/app.h"
26 #include "wx/layout.h"
27 #include "wx/utils.h"
28 #include "wx/dialog.h"
29 #include "wx/msgdlg.h"
30 #include "wx/module.h"
31
32 #if wxUSE_DRAG_AND_DROP
33 #include "wx/dnd.h"
34 #endif
35
36 #if wxUSE_TOOLTIPS
37 #include "wx/tooltip.h"
38 #endif
39
40 #if wxUSE_CARET
41 #include "wx/caret.h"
42 #endif // wxUSE_CARET
43
44 #if wxUSE_TEXTCTRL
45 #include "wx/textctrl.h"
46 #endif
47
48 #include "wx/menu.h"
49 #include "wx/statusbr.h"
50 #include "wx/intl.h"
51 #include "wx/settings.h"
52 #include "wx/log.h"
53 #include "wx/fontutil.h"
54
55 #ifdef __WXDEBUG__
56 #include "wx/thread.h"
57 #endif
58
59 #include "wx/math.h"
60 #include <ctype.h>
61
62 #include "wx/gtk/private.h"
63 #include <gdk/gdkprivate.h>
64 #include <gdk/gdkkeysyms.h>
65 #include <gdk/gdkx.h>
66
67 #include <gtk/gtk.h>
68 #include <gtk/gtkprivate.h>
69
70 #include "wx/gtk/win_gtk.h"
71
72 #ifdef __WXGTK20__
73 #include <pango/pangox.h>
74 #endif
75
76
77 #ifdef __WXGTK20__
78 #ifdef HAVE_XIM
79 #undef HAVE_XIM
80 #endif
81 #endif
82
83 #ifdef __WXGTK20__
84 extern GtkContainerClass *pizza_parent_class;
85 #endif
86
87 //-----------------------------------------------------------------------------
88 // documentation on internals
89 //-----------------------------------------------------------------------------
90
91 /*
92 I have been asked several times about writing some documentation about
93 the GTK port of wxWidgets, especially its internal structures. Obviously,
94 you cannot understand wxGTK without knowing a little about the GTK, but
95 some more information about what the wxWindow, which is the base class
96 for all other window classes, does seems required as well.
97
98 I)
99
100 What does wxWindow do? It contains the common interface for the following
101 jobs of its descendants:
102
103 1) Define the rudimentary behaviour common to all window classes, such as
104 resizing, intercepting user input (so as to make it possible to use these
105 events for special purposes in a derived class), window names etc.
106
107 2) Provide the possibility to contain and manage children, if the derived
108 class is allowed to contain children, which holds true for those window
109 classes which do not display a native GTK widget. To name them, these
110 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
111 work classes are a special case and are handled a bit differently from
112 the rest. The same holds true for the wxNotebook class.
113
114 3) Provide the possibility to draw into a client area of a window. This,
115 too, only holds true for classes that do not display a native GTK widget
116 as above.
117
118 4) Provide the entire mechanism for scrolling widgets. This actual inter-
119 face for this is usually in wxScrolledWindow, but the GTK implementation
120 is in this class.
121
122 5) A multitude of helper or extra methods for special purposes, such as
123 Drag'n'Drop, managing validators etc.
124
125 6) Display a border (sunken, raised, simple or none).
126
127 Normally one might expect, that one wxWidgets window would always correspond
128 to one GTK widget. Under GTK, there is no such allround widget that has all
129 the functionality. Moreover, the GTK defines a client area as a different
130 widget from the actual widget you are handling. Last but not least some
131 special classes (e.g. wxFrame) handle different categories of widgets and
132 still have the possibility to draw something in the client area.
133 It was therefore required to write a special purpose GTK widget, that would
134 represent a client area in the sense of wxWidgets capable to do the jobs
135 2), 3) and 4). I have written this class and it resides in win_gtk.c of
136 this directory.
137
138 All windows must have a widget, with which they interact with other under-
139 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
140 thw wxWindow class has a member variable called m_widget which holds a
141 pointer to this widget. When the window class represents a GTK native widget,
142 this is (in most cases) the only GTK widget the class manages. E.g. the
143 wxStaticText class handles only a GtkLabel widget a pointer to which you
144 can find in m_widget (defined in wxWindow)
145
146 When the class has a client area for drawing into and for containing children
147 it has to handle the client area widget (of the type GtkPizza, defined in
148 win_gtk.c), but there could be any number of widgets, handled by a class
149 The common rule for all windows is only, that the widget that interacts with
150 the rest of GTK must be referenced in m_widget and all other widgets must be
151 children of this widget on the GTK level. The top-most widget, which also
152 represents the client area, must be in the m_wxwindow field and must be of
153 the type GtkPizza.
154
155 As I said, the window classes that display a GTK native widget only have
156 one widget, so in the case of e.g. the wxButton class m_widget holds a
157 pointer to a GtkButton widget. But windows with client areas (for drawing
158 and children) have a m_widget field that is a pointer to a GtkScrolled-
159 Window and a m_wxwindow field that is pointer to a GtkPizza and this
160 one is (in the GTK sense) a child of the GtkScrolledWindow.
161
162 If the m_wxwindow field is set, then all input to this widget is inter-
163 cepted and sent to the wxWidgets class. If not, all input to the widget
164 that gets pointed to by m_widget gets intercepted and sent to the class.
165
166 II)
167
168 The design of scrolling in wxWidgets is markedly different from that offered
169 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
170 clicking on a scrollbar belonging to scrolled window will inevitably move
171 the window. In wxWidgets, the scrollbar will only emit an event, send this
172 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
173 which actually moves the window and its subchildren. Note that GtkPizza
174 memorizes how much it has been scrolled but that wxWidgets forgets this
175 so that the two coordinates systems have to be kept in synch. This is done
176 in various places using the pizza->xoffset and pizza->yoffset values.
177
178 III)
179
180 Singularily the most broken code in GTK is the code that is supposes to
181 inform subwindows (child windows) about new positions. Very often, duplicate
182 events are sent without changes in size or position, equally often no
183 events are sent at all (All this is due to a bug in the GtkContainer code
184 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
185 GTK's own system and it simply waits for size events for toplevel windows
186 and then iterates down the respective size events to all window. This has
187 the disadvantage, that windows might get size events before the GTK widget
188 actually has the reported size. This doesn't normally pose any problem, but
189 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
190 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
191 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
192 window that is used for OpenGl output really has that size (as reported by
193 GTK).
194
195 IV)
196
197 If someone at some point of time feels the immense desire to have a look at,
198 change or attempt to optimse the Refresh() logic, this person will need an
199 intimate understanding of what a "draw" and what an "expose" events are and
200 what there are used for, in particular when used in connection with GTK's
201 own windowless widgets. Beware.
202
203 V)
204
205 Cursors, too, have been a constant source of pleasure. The main difficulty
206 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
207 for the parent. To prevent this from doing too much harm, I use idle time
208 to set the cursor over and over again, starting from the toplevel windows
209 and ending with the youngest generation (speaking of parent and child windows).
210 Also don't forget that cursors (like much else) are connected to GdkWindows,
211 not GtkWidgets and that the "window" field of a GtkWidget might very well
212 point to the GdkWindow of the parent widget (-> "window less widget") and
213 that the two obviously have very different meanings.
214
215 */
216
217 //-----------------------------------------------------------------------------
218 // data
219 //-----------------------------------------------------------------------------
220
221 extern wxList wxPendingDelete;
222 extern bool g_blockEventsOnDrag;
223 extern bool g_blockEventsOnScroll;
224 extern wxCursor g_globalCursor;
225
226 static GdkGC *g_eraseGC = NULL;
227
228 // mouse capture state: the window which has it and if the mouse is currently
229 // inside it
230 static wxWindowGTK *g_captureWindow = (wxWindowGTK*) NULL;
231 static bool g_captureWindowHasMouse = FALSE;
232
233 wxWindowGTK *g_focusWindow = (wxWindowGTK*) NULL;
234
235 // the last window which had the focus - this is normally never NULL (except
236 // if we never had focus at all) as even when g_focusWindow is NULL it still
237 // keeps its previous value
238 wxWindowGTK *g_focusWindowLast = (wxWindowGTK*) NULL;
239
240 // If a window get the focus set but has not been realized
241 // yet, defer setting the focus to idle time.
242 wxWindowGTK *g_delayedFocus = (wxWindowGTK*) NULL;
243
244 // hack: we need something to pass to gtk_menu_popup, so we store the time of
245 // the last click here
246 static guint32 gs_timeLastClick = 0;
247
248 extern bool g_mainThreadLocked;
249
250 //-----------------------------------------------------------------------------
251 // debug
252 //-----------------------------------------------------------------------------
253
254 #ifdef __WXDEBUG__
255
256 #if wxUSE_THREADS
257 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
258 #else
259 # define DEBUG_MAIN_THREAD
260 #endif
261 #else
262 #define DEBUG_MAIN_THREAD
263 #endif // Debug
264
265 // the trace mask used for the focus debugging messages
266 #define TRACE_FOCUS _T("focus")
267
268 //-----------------------------------------------------------------------------
269 // missing gdk functions
270 //-----------------------------------------------------------------------------
271
272 void
273 gdk_window_warp_pointer (GdkWindow *window,
274 gint x,
275 gint y)
276 {
277 #ifndef __WXGTK20__
278 GdkWindowPrivate *priv;
279 #endif
280
281 if (!window)
282 window = GDK_ROOT_PARENT();
283
284 #ifdef __WXGTK20__
285 if (!GDK_WINDOW_DESTROYED(window))
286 {
287 XWarpPointer (GDK_WINDOW_XDISPLAY(window),
288 None, /* not source window -> move from anywhere */
289 GDK_WINDOW_XID(window), /* dest window */
290 0, 0, 0, 0, /* not source window -> move from anywhere */
291 x, y );
292 }
293 #else
294 priv = (GdkWindowPrivate*) window;
295
296 if (!priv->destroyed)
297 {
298 XWarpPointer (priv->xdisplay,
299 None, /* not source window -> move from anywhere */
300 priv->xwindow, /* dest window */
301 0, 0, 0, 0, /* not source window -> move from anywhere */
302 x, y );
303 }
304 #endif
305 }
306
307 //-----------------------------------------------------------------------------
308 // idle system
309 //-----------------------------------------------------------------------------
310
311 extern void wxapp_install_idle_handler();
312 extern bool g_isIdle;
313
314 //-----------------------------------------------------------------------------
315 // local code (see below)
316 //-----------------------------------------------------------------------------
317
318 // returns the child of win which currently has focus or NULL if not found
319 //
320 // Note: can't be static, needed by textctrl.cpp.
321 wxWindow *wxFindFocusedChild(wxWindowGTK *win)
322 {
323 wxWindow *winFocus = wxWindowGTK::FindFocus();
324 if ( !winFocus )
325 return (wxWindow *)NULL;
326
327 if ( winFocus == win )
328 return (wxWindow *)win;
329
330 for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
331 node;
332 node = node->GetNext() )
333 {
334 wxWindow *child = wxFindFocusedChild(node->GetData());
335 if ( child )
336 return child;
337 }
338
339 return (wxWindow *)NULL;
340 }
341
342 static void draw_frame( GtkWidget *widget, wxWindowGTK *win )
343 {
344 // wxUniversal widgets draw the borders and scrollbars themselves
345 #ifndef __WXUNIVERSAL__
346 if (!win->m_hasVMT)
347 return;
348
349 int dw = 0;
350 int dh = 0;
351
352 if (win->m_hasScrolling)
353 {
354 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(widget);
355
356 GtkRequisition vscroll_req;
357 vscroll_req.width = 2;
358 vscroll_req.height = 2;
359 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
360 (scroll_window->vscrollbar, &vscroll_req );
361
362 GtkRequisition hscroll_req;
363 hscroll_req.width = 2;
364 hscroll_req.height = 2;
365 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
366 (scroll_window->hscrollbar, &hscroll_req );
367
368 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget) );
369
370 if (scroll_window->vscrollbar_visible)
371 {
372 dw += vscroll_req.width;
373 dw += scroll_class->scrollbar_spacing;
374 }
375
376 if (scroll_window->hscrollbar_visible)
377 {
378 dh += hscroll_req.height;
379 dh += scroll_class->scrollbar_spacing;
380 }
381 }
382
383 int dx = 0;
384 int dy = 0;
385 if (GTK_WIDGET_NO_WINDOW (widget))
386 {
387 dx += widget->allocation.x;
388 dy += widget->allocation.y;
389 }
390
391 if (win->HasFlag(wxRAISED_BORDER))
392 {
393 gtk_draw_shadow( widget->style,
394 widget->window,
395 GTK_STATE_NORMAL,
396 GTK_SHADOW_OUT,
397 dx, dy,
398 widget->allocation.width-dw, widget->allocation.height-dh );
399 return;
400 }
401
402 if (win->HasFlag(wxSUNKEN_BORDER))
403 {
404 gtk_draw_shadow( widget->style,
405 widget->window,
406 GTK_STATE_NORMAL,
407 GTK_SHADOW_IN,
408 dx, dy,
409 widget->allocation.width-dw, widget->allocation.height-dh );
410 return;
411 }
412
413 if (win->HasFlag(wxSIMPLE_BORDER))
414 {
415 GdkGC *gc;
416 gc = gdk_gc_new( widget->window );
417 gdk_gc_set_foreground( gc, &widget->style->black );
418 gdk_draw_rectangle( widget->window, gc, FALSE,
419 dx, dy,
420 widget->allocation.width-dw-1, widget->allocation.height-dh-1 );
421 gdk_gc_unref( gc );
422 return;
423 }
424 #endif // __WXUNIVERSAL__
425 }
426
427 //-----------------------------------------------------------------------------
428 // "expose_event" of m_widget
429 //-----------------------------------------------------------------------------
430
431 gint gtk_window_own_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindowGTK *win )
432 {
433 if (gdk_event->count > 0) return FALSE;
434
435 draw_frame( widget, win );
436
437 #ifdef __WXGTK20__
438
439 (* GTK_WIDGET_CLASS (pizza_parent_class)->expose_event) (widget, gdk_event);
440
441 #endif
442 return TRUE;
443 }
444
445 //-----------------------------------------------------------------------------
446 // "draw" of m_widget
447 //-----------------------------------------------------------------------------
448
449 #ifndef __WXGTK20__
450
451 static void gtk_window_own_draw_callback( GtkWidget *widget, GdkRectangle *WXUNUSED(rect), wxWindowGTK *win )
452 {
453 draw_frame( widget, win );
454 }
455
456 #endif // GTK+ < 2.0
457
458 //-----------------------------------------------------------------------------
459 // "size_request" of m_widget
460 //-----------------------------------------------------------------------------
461
462 // make it extern because wxStatitText needs to disconnect this one
463 extern "C"
464 void wxgtk_window_size_request_callback(GtkWidget *widget,
465 GtkRequisition *requisition,
466 wxWindow *win)
467 {
468 int w, h;
469 win->GetSize( &w, &h );
470 if (w < 2)
471 w = 2;
472 if (h < 2)
473 h = 2;
474
475 requisition->height = h;
476 requisition->width = w;
477 }
478
479 //-----------------------------------------------------------------------------
480 // "expose_event" of m_wxwindow
481 //-----------------------------------------------------------------------------
482
483 static int gtk_window_expose_callback( GtkWidget *widget,
484 GdkEventExpose *gdk_event,
485 wxWindow *win )
486 {
487 DEBUG_MAIN_THREAD
488
489 if (g_isIdle)
490 wxapp_install_idle_handler();
491
492 #ifdef __WXGTK20__
493 // This callback gets called in drawing-idle time under
494 // GTK 2.0, so we don't need to defer anything to idle
495 // time anymore.
496
497 GtkPizza *pizza = GTK_PIZZA( widget );
498 if (gdk_event->window != pizza->bin_window) return FALSE;
499
500 #if 0
501 if (win->GetName())
502 {
503 wxPrintf( wxT("OnExpose from ") );
504 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
505 wxPrintf( win->GetClassInfo()->GetClassName() );
506 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event->area.x,
507 (int)gdk_event->area.y,
508 (int)gdk_event->area.width,
509 (int)gdk_event->area.height );
510 }
511
512 gtk_paint_box
513 (
514 win->m_wxwindow->style,
515 pizza->bin_window,
516 GTK_STATE_NORMAL,
517 GTK_SHADOW_OUT,
518 (GdkRectangle*) NULL,
519 win->m_wxwindow,
520 (char *)"button", // const_cast
521 20,20,24,24
522 );
523 #endif
524
525 win->GetUpdateRegion() = wxRegion( gdk_event->region );
526
527 win->GtkSendPaintEvents();
528
529
530 // Let parent window draw window less widgets
531 (* GTK_WIDGET_CLASS (pizza_parent_class)->expose_event) (widget, gdk_event);
532 #else
533 // This gets called immediately after an expose event
534 // under GTK 1.2 so we collect the calls and wait for
535 // the idle handler to pick things up.
536
537 win->GetUpdateRegion().Union( gdk_event->area.x,
538 gdk_event->area.y,
539 gdk_event->area.width,
540 gdk_event->area.height );
541 win->m_clearRegion.Union( gdk_event->area.x,
542 gdk_event->area.y,
543 gdk_event->area.width,
544 gdk_event->area.height );
545
546 // Actual redrawing takes place in idle time.
547 // win->GtkUpdate();
548 #endif
549
550 return FALSE;
551 }
552
553 //-----------------------------------------------------------------------------
554 // "event" of m_wxwindow
555 //-----------------------------------------------------------------------------
556
557 // GTK thinks it is clever and filters out a certain amount of "unneeded"
558 // expose events. We need them, of course, so we override the main event
559 // procedure in GtkWidget by giving our own handler for all system events.
560 // There, we look for expose events ourselves whereas all other events are
561 // handled normally.
562
563 gint gtk_window_event_event_callback( GtkWidget *widget,
564 GdkEventExpose *event,
565 wxWindow *win )
566 {
567 if (event->type == GDK_EXPOSE)
568 {
569 gint ret = gtk_window_expose_callback( widget, event, win );
570 return ret;
571 }
572
573 return FALSE;
574 }
575
576 //-----------------------------------------------------------------------------
577 // "draw" of m_wxwindow
578 //-----------------------------------------------------------------------------
579
580 #ifndef __WXGTK20__
581
582 // This callback is a complete replacement of the gtk_pizza_draw() function,
583 // which is disabled.
584
585 static void gtk_window_draw_callback( GtkWidget *widget,
586 GdkRectangle *rect,
587 wxWindow *win )
588 {
589 DEBUG_MAIN_THREAD
590
591 if (g_isIdle)
592 wxapp_install_idle_handler();
593
594 // if there are any children we must refresh everything
595 //
596 // VZ: why?
597 if ( !win->HasFlag(wxFULL_REPAINT_ON_RESIZE) &&
598 win->GetChildren().IsEmpty() )
599 {
600 return;
601 }
602
603 #if 0
604 if (win->GetName())
605 {
606 wxPrintf( wxT("OnDraw from ") );
607 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
608 wxPrintf( win->GetClassInfo()->GetClassName() );
609 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect->x,
610 (int)rect->y,
611 (int)rect->width,
612 (int)rect->height );
613 }
614 #endif
615
616 #ifndef __WXUNIVERSAL__
617 GtkPizza *pizza = GTK_PIZZA (widget);
618
619 if (win->GetThemeEnabled() && win->GetBackgroundStyle() == wxBG_STYLE_SYSTEM)
620 {
621 wxWindow *parent = win->GetParent();
622 while (parent && !parent->IsTopLevel())
623 parent = parent->GetParent();
624 if (!parent)
625 parent = win;
626
627 gtk_paint_flat_box (parent->m_widget->style,
628 pizza->bin_window,
629 GTK_STATE_NORMAL,
630 GTK_SHADOW_NONE,
631 rect,
632 parent->m_widget,
633 (char *)"base",
634 0, 0, -1, -1);
635 }
636 #endif
637
638 win->m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height );
639 win->GetUpdateRegion().Union( rect->x, rect->y, rect->width, rect->height );
640
641 // Update immediately, not in idle time.
642 win->GtkUpdate();
643
644 #ifndef __WXUNIVERSAL__
645 // Redraw child widgets
646 GList *children = pizza->children;
647 while (children)
648 {
649 GtkPizzaChild *child = (GtkPizzaChild*) children->data;
650 children = children->next;
651
652 GdkRectangle child_area;
653 if (gtk_widget_intersect (child->widget, rect, &child_area))
654 {
655 gtk_widget_draw (child->widget, &child_area /* (GdkRectangle*) NULL*/ );
656 }
657 }
658 #endif
659 }
660
661 #endif
662
663 //-----------------------------------------------------------------------------
664 // "key_press_event" from any window
665 //-----------------------------------------------------------------------------
666
667 // set WXTRACE to this to see the key event codes on the console
668 #define TRACE_KEYS _T("keyevent")
669
670 // translates an X key symbol to WXK_XXX value
671 //
672 // if isChar is true it means that the value returned will be used for EVT_CHAR
673 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
674 // for example, while if it is false it means that the value is going to be
675 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
676 // WXK_NUMPAD_DIVIDE
677 static long wxTranslateKeySymToWXKey(KeySym keysym, bool isChar)
678 {
679 long key_code;
680
681 switch ( keysym )
682 {
683 // Shift, Control and Alt don't generate the CHAR events at all
684 case GDK_Shift_L:
685 case GDK_Shift_R:
686 key_code = isChar ? 0 : WXK_SHIFT;
687 break;
688 case GDK_Control_L:
689 case GDK_Control_R:
690 key_code = isChar ? 0 : WXK_CONTROL;
691 break;
692 case GDK_Meta_L:
693 case GDK_Meta_R:
694 case GDK_Alt_L:
695 case GDK_Alt_R:
696 case GDK_Super_L:
697 case GDK_Super_R:
698 key_code = isChar ? 0 : WXK_ALT;
699 break;
700
701 // neither do the toggle modifies
702 case GDK_Scroll_Lock:
703 key_code = isChar ? 0 : WXK_SCROLL;
704 break;
705
706 case GDK_Caps_Lock:
707 key_code = isChar ? 0 : WXK_CAPITAL;
708 break;
709
710 case GDK_Num_Lock:
711 key_code = isChar ? 0 : WXK_NUMLOCK;
712 break;
713
714
715 // various other special keys
716 case GDK_Menu:
717 key_code = WXK_MENU;
718 break;
719
720 case GDK_Help:
721 key_code = WXK_HELP;
722 break;
723
724 case GDK_BackSpace:
725 key_code = WXK_BACK;
726 break;
727
728 case GDK_ISO_Left_Tab:
729 case GDK_Tab:
730 key_code = WXK_TAB;
731 break;
732
733 case GDK_Linefeed:
734 case GDK_Return:
735 key_code = WXK_RETURN;
736 break;
737
738 case GDK_Clear:
739 key_code = WXK_CLEAR;
740 break;
741
742 case GDK_Pause:
743 key_code = WXK_PAUSE;
744 break;
745
746 case GDK_Select:
747 key_code = WXK_SELECT;
748 break;
749
750 case GDK_Print:
751 key_code = WXK_PRINT;
752 break;
753
754 case GDK_Execute:
755 key_code = WXK_EXECUTE;
756 break;
757
758 case GDK_Escape:
759 key_code = WXK_ESCAPE;
760 break;
761
762 // cursor and other extended keyboard keys
763 case GDK_Delete:
764 key_code = WXK_DELETE;
765 break;
766
767 case GDK_Home:
768 key_code = WXK_HOME;
769 break;
770
771 case GDK_Left:
772 key_code = WXK_LEFT;
773 break;
774
775 case GDK_Up:
776 key_code = WXK_UP;
777 break;
778
779 case GDK_Right:
780 key_code = WXK_RIGHT;
781 break;
782
783 case GDK_Down:
784 key_code = WXK_DOWN;
785 break;
786
787 case GDK_Prior: // == GDK_Page_Up
788 key_code = WXK_PRIOR;
789 break;
790
791 case GDK_Next: // == GDK_Page_Down
792 key_code = WXK_NEXT;
793 break;
794
795 case GDK_End:
796 key_code = WXK_END;
797 break;
798
799 case GDK_Begin:
800 key_code = WXK_HOME;
801 break;
802
803 case GDK_Insert:
804 key_code = WXK_INSERT;
805 break;
806
807
808 // numpad keys
809 case GDK_KP_0:
810 case GDK_KP_1:
811 case GDK_KP_2:
812 case GDK_KP_3:
813 case GDK_KP_4:
814 case GDK_KP_5:
815 case GDK_KP_6:
816 case GDK_KP_7:
817 case GDK_KP_8:
818 case GDK_KP_9:
819 key_code = (isChar ? '0' : WXK_NUMPAD0) + keysym - GDK_KP_0;
820 break;
821
822 case GDK_KP_Space:
823 key_code = isChar ? ' ' : WXK_NUMPAD_SPACE;
824 break;
825
826 case GDK_KP_Tab:
827 key_code = isChar ? WXK_TAB : WXK_NUMPAD_TAB;
828 break;
829
830 case GDK_KP_Enter:
831 key_code = isChar ? WXK_RETURN : WXK_NUMPAD_ENTER;
832 break;
833
834 case GDK_KP_F1:
835 key_code = isChar ? WXK_F1 : WXK_NUMPAD_F1;
836 break;
837
838 case GDK_KP_F2:
839 key_code = isChar ? WXK_F2 : WXK_NUMPAD_F2;
840 break;
841
842 case GDK_KP_F3:
843 key_code = isChar ? WXK_F3 : WXK_NUMPAD_F3;
844 break;
845
846 case GDK_KP_F4:
847 key_code = isChar ? WXK_F4 : WXK_NUMPAD_F4;
848 break;
849
850 case GDK_KP_Home:
851 key_code = isChar ? WXK_HOME : WXK_NUMPAD_HOME;
852 break;
853
854 case GDK_KP_Left:
855 key_code = isChar ? WXK_LEFT : WXK_NUMPAD_LEFT;
856 break;
857
858 case GDK_KP_Up:
859 key_code = isChar ? WXK_UP : WXK_NUMPAD_UP;
860 break;
861
862 case GDK_KP_Right:
863 key_code = isChar ? WXK_RIGHT : WXK_NUMPAD_RIGHT;
864 break;
865
866 case GDK_KP_Down:
867 key_code = isChar ? WXK_DOWN : WXK_NUMPAD_DOWN;
868 break;
869
870 case GDK_KP_Prior: // == GDK_KP_Page_Up
871 key_code = isChar ? WXK_PRIOR : WXK_NUMPAD_PRIOR;
872 break;
873
874 case GDK_KP_Next: // == GDK_KP_Page_Down
875 key_code = isChar ? WXK_NEXT : WXK_NUMPAD_NEXT;
876 break;
877
878 case GDK_KP_End:
879 key_code = isChar ? WXK_END : WXK_NUMPAD_END;
880 break;
881
882 case GDK_KP_Begin:
883 key_code = isChar ? WXK_HOME : WXK_NUMPAD_BEGIN;
884 break;
885
886 case GDK_KP_Insert:
887 key_code = isChar ? WXK_INSERT : WXK_NUMPAD_INSERT;
888 break;
889
890 case GDK_KP_Delete:
891 key_code = isChar ? WXK_DELETE : WXK_NUMPAD_DELETE;
892 break;
893
894 case GDK_KP_Equal:
895 key_code = isChar ? '=' : WXK_NUMPAD_EQUAL;
896 break;
897
898 case GDK_KP_Multiply:
899 key_code = isChar ? '*' : WXK_NUMPAD_MULTIPLY;
900 break;
901
902 case GDK_KP_Add:
903 key_code = isChar ? '+' : WXK_NUMPAD_ADD;
904 break;
905
906 case GDK_KP_Separator:
907 // FIXME: what is this?
908 key_code = isChar ? '.' : WXK_NUMPAD_SEPARATOR;
909 break;
910
911 case GDK_KP_Subtract:
912 key_code = isChar ? '-' : WXK_NUMPAD_SUBTRACT;
913 break;
914
915 case GDK_KP_Decimal:
916 key_code = isChar ? '.' : WXK_NUMPAD_DECIMAL;
917 break;
918
919 case GDK_KP_Divide:
920 key_code = isChar ? '/' : WXK_NUMPAD_DIVIDE;
921 break;
922
923
924 // function keys
925 case GDK_F1:
926 case GDK_F2:
927 case GDK_F3:
928 case GDK_F4:
929 case GDK_F5:
930 case GDK_F6:
931 case GDK_F7:
932 case GDK_F8:
933 case GDK_F9:
934 case GDK_F10:
935 case GDK_F11:
936 case GDK_F12:
937 key_code = WXK_F1 + keysym - GDK_F1;
938 break;
939
940 default:
941 key_code = 0;
942 }
943
944 return key_code;
945 }
946
947 static inline bool wxIsAsciiKeysym(KeySym ks)
948 {
949 return ks < 256;
950 }
951
952 static void wxFillOtherKeyEventFields(wxKeyEvent& event,
953 wxWindowGTK *win,
954 GdkEventKey *gdk_event)
955 {
956 int x = 0;
957 int y = 0;
958 GdkModifierType state;
959 if (gdk_event->window)
960 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
961
962 event.SetTimestamp( gdk_event->time );
963 event.SetId(win->GetId());
964 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK) != 0;
965 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK) != 0;
966 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK) != 0;
967 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK) != 0;
968 event.m_scanCode = gdk_event->keyval;
969 event.m_rawCode = (wxUint32) gdk_event->keyval;
970 event.m_rawFlags = 0;
971 #if wxUSE_UNICODE
972 event.m_uniChar = gdk_keyval_to_unicode(gdk_event->keyval);
973 #endif
974 event.m_x = x;
975 event.m_y = y;
976 event.SetEventObject( win );
977 }
978
979
980 static bool
981 wxTranslateGTKKeyEventToWx(wxKeyEvent& event,
982 wxWindowGTK *win,
983 GdkEventKey *gdk_event)
984 {
985 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
986 // but only event->keyval which is quite useless to us, so remember
987 // the last character from GDK_KEY_PRESS and reuse it as last resort
988 //
989 // NB: should be MT-safe as we're always called from the main thread only
990 static struct
991 {
992 KeySym keysym;
993 long keycode;
994 } s_lastKeyPress = { 0, 0 };
995
996 KeySym keysym = gdk_event->keyval;
997
998 wxLogTrace(TRACE_KEYS, _T("Key %s event: keysym = %ld"),
999 event.GetEventType() == wxEVT_KEY_UP ? _T("release")
1000 : _T("press"),
1001 keysym);
1002
1003 long key_code = wxTranslateKeySymToWXKey(keysym, FALSE /* !isChar */);
1004
1005 if ( !key_code )
1006 {
1007 // do we have the translation or is it a plain ASCII character?
1008 if ( (gdk_event->length == 1) || wxIsAsciiKeysym(keysym) )
1009 {
1010 // we should use keysym if it is ASCII as X does some translations
1011 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
1012 // which we don't want here (but which we do use for OnChar())
1013 if ( !wxIsAsciiKeysym(keysym) )
1014 {
1015 keysym = (KeySym)gdk_event->string[0];
1016 }
1017
1018 // we want to always get the same key code when the same key is
1019 // pressed regardless of the state of the modifies, i.e. on a
1020 // standard US keyboard pressing '5' or '%' ('5' key with
1021 // Shift) should result in the same key code in OnKeyDown():
1022 // '5' (although OnChar() will get either '5' or '%').
1023 //
1024 // to do it we first translate keysym to keycode (== scan code)
1025 // and then back but always using the lower register
1026 Display *dpy = (Display *)wxGetDisplay();
1027 KeyCode keycode = XKeysymToKeycode(dpy, keysym);
1028
1029 wxLogTrace(TRACE_KEYS, _T("\t-> keycode %d"), keycode);
1030
1031 KeySym keysymNormalized = XKeycodeToKeysym(dpy, keycode, 0);
1032
1033 // use the normalized, i.e. lower register, keysym if we've
1034 // got one
1035 key_code = keysymNormalized ? keysymNormalized : keysym;
1036
1037 // as explained above, we want to have lower register key codes
1038 // normally but for the letter keys we want to have the upper ones
1039 //
1040 // NB: don't use XConvertCase() here, we want to do it for letters
1041 // only
1042 key_code = toupper(key_code);
1043 }
1044 else // non ASCII key, what to do?
1045 {
1046 // by default, ignore it
1047 key_code = 0;
1048
1049 // but if we have cached information from the last KEY_PRESS
1050 if ( gdk_event->type == GDK_KEY_RELEASE )
1051 {
1052 // then reuse it
1053 if ( keysym == s_lastKeyPress.keysym )
1054 {
1055 key_code = s_lastKeyPress.keycode;
1056 }
1057 }
1058 }
1059
1060 if ( gdk_event->type == GDK_KEY_PRESS )
1061 {
1062 // remember it to be reused for KEY_UP event later
1063 s_lastKeyPress.keysym = keysym;
1064 s_lastKeyPress.keycode = key_code;
1065 }
1066 }
1067
1068 wxLogTrace(TRACE_KEYS, _T("\t-> wxKeyCode %ld"), key_code);
1069
1070 // sending unknown key events doesn't really make sense
1071 if ( !key_code )
1072 return FALSE;
1073
1074 // now fill all the other fields
1075 wxFillOtherKeyEventFields(event, win, gdk_event);
1076
1077 event.m_keyCode = key_code;
1078
1079 return TRUE;
1080 }
1081
1082
1083 #ifdef __WXGTK20__
1084 struct wxGtkIMData
1085 {
1086 GtkIMContext *context;
1087 GdkEventKey *lastKeyEvent;
1088
1089 wxGtkIMData()
1090 {
1091 context = gtk_im_multicontext_new();
1092 lastKeyEvent = NULL;
1093 }
1094 ~wxGtkIMData()
1095 {
1096 g_object_unref(context);
1097 }
1098 };
1099 #endif
1100
1101 static gint gtk_window_key_press_callback( GtkWidget *widget,
1102 GdkEventKey *gdk_event,
1103 wxWindow *win )
1104 {
1105 DEBUG_MAIN_THREAD
1106
1107 if (g_isIdle)
1108 wxapp_install_idle_handler();
1109
1110 if (!win->m_hasVMT)
1111 return FALSE;
1112 if (g_blockEventsOnDrag)
1113 return FALSE;
1114
1115 #ifdef __WXGTK20__
1116 #if 0
1117 // We have to pass key press events through GTK+'s Input Method context
1118 // object in order to get correct characters. By doing so, we lose the
1119 // ability to let other GTK+'s handlers (namely, widgets' default signal
1120 // handlers) handle the signal by returning false from this callback.
1121 // Because GTK+ sends the events to parent widgets as well, we can't
1122 // afford losing it, otherwise native widgets inserted into wxPanel
1123 // would break in subtle ways (e.g. spacebar would no longer toggle
1124 // wxCheckButton's state). Therefore, we only pass the event to IM if it
1125 // originated in this window's widget, which we detect by checking if we've
1126 // seen the same event before (no events from children are lost this way,
1127 // because gtk_window_key_press_callback is installed for native controls
1128 // as well and the wxKeyEvent it creates propagates upwards).
1129 static GdkEventKey s_lastEvent;
1130 bool useIM = (win->m_imData != NULL) &&
1131 memcmp(gdk_event, &s_lastEvent, sizeof(GdkEventKey)) != 0;
1132 s_lastEvent = *gdk_event;
1133 #else
1134 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
1135 // There is no need to store lastEvent. The original code makes GTK+ IM
1136 // dysfunction. When we get a key_press event here, it could be originate
1137 // from the current widget or its child widgets. However, only the widget
1138 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
1139 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
1140 // originated from its child widgets and shouldn't be passed to IM context.
1141 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
1142 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
1143 // widgets has both IM context and input focus, the event should be filtered
1144 // by gtk_im_context_filter_keypress().
1145 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
1146 bool useIM = (win->m_imData != NULL) && ( wxWindow::FindFocus() == win );
1147 #endif
1148
1149 #endif
1150
1151 #ifdef __WXGTK20__
1152 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
1153 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1154 // docs, if IM filter returns true, NO FURTHER PROCESSING SHOULD BE DONE for
1155 // this keystroke. Making wxWidgets unable to receive EVT_KEY_DOWN in this
1156 // situation is resonable. In reality, when IM is activated, wxWidgets should
1157 // receive EVT_CHAR instead.
1158 if (useIM)
1159 {
1160 // it may be useful for the input method, though:
1161 bool ret = gtk_im_context_filter_keypress(win->m_imData->context, gdk_event);
1162 win->m_imData->lastKeyEvent = NULL;
1163 if( ret )
1164 {
1165 wxLogTrace(TRACE_KEYS, _T("Key event intercepted by IM"));
1166 return ret;
1167 }
1168 }
1169 #endif
1170
1171 wxKeyEvent event( wxEVT_KEY_DOWN );
1172 bool ret = FALSE;
1173
1174 // 2005.02.02 modified by Hong Jen Yee (hzysoft@sina.com.tw).
1175 // In GTK+ 1.2, strings sent by IMs are also regarded as key_press events whose
1176 // keyCodes cannot be recognized by wxWidgets. These MBCS strings, however, are
1177 // composed of more than one character, which means gdk_event->length will always
1178 // greater than one. When gtk_event->length == 1, this may be an ASCII character
1179 // and can be translated by wx. However, when MBCS characters are sent by IM,
1180 // gdk_event->length will >= 2. So neither should we pass it to accelerator table,
1181 // nor should we pass it to controls. The following explanation was excerpted
1182 // from GDK documentation.
1183 // gint length : the length of string.
1184 // gchar *string : a null-terminated multi-byte string containing the composed
1185 // characters resulting from the key press. When text is being input, in a GtkEntry
1186 // for example, it is these characters which should be added to the input buffer.
1187 // When using Input Methods to support internationalized text input, the composed
1188 // characters appear here after the pre-editing has been completed.
1189
1190 #ifndef __WXGTK20__ // This is for GTK+ 1.2 only.
1191 if ( (gdk_event->length > 1) ) // If this event contains a pre-edited string from IM.
1192 {
1193 // We should translate this key event into wxEVT_CHAR not wxEVT_KEY_DOWN.
1194 #if wxUSE_UNICODE // GTK+ 1.2 is not UTF-8 based.
1195 const wxWCharBuffer string = wxConvLocal.cMB2WC( gdk_event->string );
1196 if( !string ) return FALSE;
1197 #else
1198 const char* string = gdk_event->string;
1199 #endif
1200
1201 // Implement OnCharHook by checking ancesteror top level windows
1202 wxWindow *parent = window;
1203 while (parent && !parent->IsTopLevel())
1204 parent = parent->GetParent();
1205
1206 for( wxChar* pstr = string; *pstr; pstr++ )
1207 {
1208 #if wxUSE_UNICODE
1209 event.m_uniChar = *pstr;
1210 // Backward compatible for ISO-8859-1
1211 event.m_keyCode = *pstr < 256 ? event.m_uniChar : 0;
1212 #else
1213 event.m_keyCode = *pstr;
1214 #endif
1215 if (parent)
1216 {
1217 event.SetEventType( wxEVT_CHAR_HOOK );
1218 ret = parent->GetEventHandler()->ProcessEvent( event );
1219 }
1220 if (!ret)
1221 {
1222 event.SetEventType(wxEVT_CHAR);
1223 window->GetEventHandler()->ProcessEvent( event );
1224 }
1225 }
1226 return TRUE;
1227 }
1228 // Only translate the key event when it's not sent with a pre-edited string.
1229 else
1230 #endif // #ifndef __WXGTK20__
1231 if( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
1232 {
1233 // unknown key pressed, ignore (the event would be useless anyhow)
1234 return FALSE;
1235 }
1236 else // This event doesn't contain a pre-edited string and is not an invalid key either.
1237 {
1238 // Emit KEY_DOWN event
1239 ret = win->GetEventHandler()->ProcessEvent( event );
1240 }
1241
1242 #if wxUSE_ACCEL
1243 if (!ret)
1244 {
1245 wxWindowGTK *ancestor = win;
1246 while (ancestor)
1247 {
1248 int command = ancestor->GetAcceleratorTable()->GetCommand( event );
1249 if (command != -1)
1250 {
1251 wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
1252 ret = ancestor->GetEventHandler()->ProcessEvent( command_event );
1253 break;
1254 }
1255 if (ancestor->IsTopLevel())
1256 break;
1257 ancestor = ancestor->GetParent();
1258 }
1259 }
1260 #endif // wxUSE_ACCEL
1261
1262 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1263 // will only be sent if it is not in an accelerator table.
1264 if (!ret)
1265 {
1266 long key_code;
1267 KeySym keysym = gdk_event->keyval;
1268 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1269 key_code = wxTranslateKeySymToWXKey(keysym, TRUE /* isChar */);
1270 if ( !key_code )
1271 {
1272 if ( wxIsAsciiKeysym(keysym) )
1273 {
1274 // ASCII key
1275 key_code = (unsigned char)keysym;
1276 }
1277 // gdk_event->string is actually deprecated
1278 else if ( gdk_event->length == 1 )
1279 {
1280 key_code = (unsigned char)gdk_event->string[0];
1281 }
1282 }
1283
1284 if ( key_code )
1285 {
1286 wxLogTrace(TRACE_KEYS, _T("Char event: %ld"), key_code);
1287
1288 event.m_keyCode = key_code;
1289
1290 // Implement OnCharHook by checking ancesteror top level windows
1291 wxWindow *parent = win;
1292 while (parent && !parent->IsTopLevel())
1293 parent = parent->GetParent();
1294 if (parent)
1295 {
1296 event.SetEventType( wxEVT_CHAR_HOOK );
1297 ret = parent->GetEventHandler()->ProcessEvent( event );
1298 }
1299
1300 if (!ret)
1301 {
1302 event.SetEventType(wxEVT_CHAR);
1303 ret = win->GetEventHandler()->ProcessEvent( event );
1304 }
1305 }
1306 }
1307
1308 // win is a control: tab can be propagated up
1309 if ( !ret &&
1310 ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) &&
1311 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1312 // have this style, yet choose not to process this particular TAB in which
1313 // case TAB must still work as a navigational character
1314 // JS: enabling again to make consistent with other platforms
1315 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1316 // navigation behaviour)
1317 #if wxUSE_TEXTCTRL
1318 (! (win->HasFlag(wxTE_PROCESS_TAB) && win->IsKindOf(CLASSINFO(wxTextCtrl)) )) &&
1319 #endif
1320 win->GetParent() && (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) )
1321 {
1322 wxNavigationKeyEvent new_event;
1323 new_event.SetEventObject( win->GetParent() );
1324 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1325 new_event.SetDirection( (gdk_event->keyval == GDK_Tab) );
1326 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1327 new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) );
1328 new_event.SetCurrentFocus( win );
1329 ret = win->GetParent()->GetEventHandler()->ProcessEvent( new_event );
1330 }
1331
1332 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1333 if ( !ret &&
1334 (gdk_event->keyval == GDK_Escape) )
1335 {
1336 // however only do it if we have a Cancel button in the dialog,
1337 // otherwise the user code may get confused by the events from a
1338 // non-existing button and, worse, a wxButton might get button event
1339 // from another button which is not really expected
1340 wxWindow *winForCancel = win,
1341 *btnCancel = NULL;
1342 while ( winForCancel )
1343 {
1344 btnCancel = winForCancel->FindWindow(wxID_CANCEL);
1345 if ( btnCancel )
1346 {
1347 // found a cancel button
1348 break;
1349 }
1350
1351 if ( winForCancel->IsTopLevel() )
1352 {
1353 // no need to look further
1354 break;
1355 }
1356
1357 // maybe our parent has a cancel button?
1358 winForCancel = winForCancel->GetParent();
1359 }
1360
1361 if ( btnCancel )
1362 {
1363 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL);
1364 event.SetEventObject(btnCancel);
1365 ret = btnCancel->GetEventHandler()->ProcessEvent(event);
1366 }
1367 }
1368
1369 if (ret)
1370 {
1371 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
1372 return TRUE;
1373 }
1374
1375 return FALSE;
1376 }
1377
1378 #ifdef __WXGTK20__
1379 static void gtk_wxwindow_commit_cb (GtkIMContext *context,
1380 const gchar *str,
1381 wxWindow *window)
1382 {
1383 wxKeyEvent event( wxEVT_KEY_DOWN );
1384
1385 // take modifiers, cursor position, timestamp etc. from the last
1386 // key_press_event that was fed into Input Method:
1387 if (window->m_imData->lastKeyEvent)
1388 {
1389 wxFillOtherKeyEventFields(event,
1390 window, window->m_imData->lastKeyEvent);
1391 }
1392
1393 #if wxUSE_UNICODE
1394 const wxWCharBuffer data = wxConvUTF8.cMB2WC( (char*)str );
1395 #else
1396 const wxWCharBuffer wdata = wxConvUTF8.cMB2WC( (char*)str );
1397 const wxCharBuffer data = wxConvLocal.cWC2MB( wdata );
1398 #endif // wxUSE_UNICODE
1399 if( !(const wxChar*)data )
1400 return;
1401
1402 bool ret = false;
1403
1404 // Implement OnCharHook by checking ancestor top level windows
1405 wxWindow *parent = window;
1406 while (parent && !parent->IsTopLevel())
1407 parent = parent->GetParent();
1408
1409 for( const wxChar* pstr = data; *pstr; pstr++ )
1410 {
1411 #if wxUSE_UNICODE
1412 event.m_uniChar = *pstr;
1413 // Backward compatible for ISO-8859-1
1414 event.m_keyCode = *pstr < 256 ? event.m_uniChar : 0;
1415 wxLogTrace(TRACE_KEYS, _T("IM sent character '%c'"), event.m_uniChar);
1416 #else
1417 event.m_keyCode = *pstr;
1418 #endif // wxUSE_UNICODE
1419 if (parent)
1420 {
1421 event.SetEventType( wxEVT_CHAR_HOOK );
1422 ret = parent->GetEventHandler()->ProcessEvent( event );
1423 }
1424
1425 if (!ret)
1426 {
1427 event.SetEventType(wxEVT_CHAR);
1428 ret = window->GetEventHandler()->ProcessEvent( event );
1429 }
1430 }
1431 }
1432 #endif
1433
1434
1435 //-----------------------------------------------------------------------------
1436 // "key_release_event" from any window
1437 //-----------------------------------------------------------------------------
1438
1439 static gint gtk_window_key_release_callback( GtkWidget *widget,
1440 GdkEventKey *gdk_event,
1441 wxWindowGTK *win )
1442 {
1443 DEBUG_MAIN_THREAD
1444
1445 if (g_isIdle)
1446 wxapp_install_idle_handler();
1447
1448 if (!win->m_hasVMT)
1449 return FALSE;
1450
1451 if (g_blockEventsOnDrag)
1452 return FALSE;
1453
1454 wxKeyEvent event( wxEVT_KEY_UP );
1455 if ( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
1456 {
1457 // unknown key pressed, ignore (the event would be useless anyhow
1458 return FALSE;
1459 }
1460
1461 if ( !win->GetEventHandler()->ProcessEvent( event ) )
1462 return FALSE;
1463
1464 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_release_event" );
1465 return TRUE;
1466 }
1467
1468 // ============================================================================
1469 // the mouse events
1470 // ============================================================================
1471
1472 // ----------------------------------------------------------------------------
1473 // mouse event processing helpers
1474 // ----------------------------------------------------------------------------
1475
1476 // init wxMouseEvent with the info from GdkEventXXX struct
1477 template<typename T> void InitMouseEvent(wxWindowGTK *win,
1478 wxMouseEvent& event,
1479 T *gdk_event)
1480 {
1481 event.SetTimestamp( gdk_event->time );
1482 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1483 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1484 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1485 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1486 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1487 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1488 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1489 if (event.GetEventType() == wxEVT_MOUSEWHEEL)
1490 {
1491 event.m_linesPerAction = 3;
1492 event.m_wheelDelta = 120;
1493 if (((GdkEventButton*)gdk_event)->button == 4)
1494 event.m_wheelRotation = 120;
1495 else if (((GdkEventButton*)gdk_event)->button == 5)
1496 event.m_wheelRotation = -120;
1497 }
1498
1499 wxPoint pt = win->GetClientAreaOrigin();
1500 event.m_x = (wxCoord)gdk_event->x - pt.x;
1501 event.m_y = (wxCoord)gdk_event->y - pt.y;
1502
1503 event.SetEventObject( win );
1504 event.SetId( win->GetId() );
1505 event.SetTimestamp( gdk_event->time );
1506 }
1507
1508 static void AdjustEventButtonState(wxMouseEvent& event)
1509 {
1510 // GDK reports the old state of the button for a button press event, but
1511 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1512 // for a LEFT_DOWN event, not FALSE, so we will invert
1513 // left/right/middleDown for the corresponding click events
1514
1515 if ((event.GetEventType() == wxEVT_LEFT_DOWN) ||
1516 (event.GetEventType() == wxEVT_LEFT_DCLICK) ||
1517 (event.GetEventType() == wxEVT_LEFT_UP))
1518 {
1519 event.m_leftDown = !event.m_leftDown;
1520 return;
1521 }
1522
1523 if ((event.GetEventType() == wxEVT_MIDDLE_DOWN) ||
1524 (event.GetEventType() == wxEVT_MIDDLE_DCLICK) ||
1525 (event.GetEventType() == wxEVT_MIDDLE_UP))
1526 {
1527 event.m_middleDown = !event.m_middleDown;
1528 return;
1529 }
1530
1531 if ((event.GetEventType() == wxEVT_RIGHT_DOWN) ||
1532 (event.GetEventType() == wxEVT_RIGHT_DCLICK) ||
1533 (event.GetEventType() == wxEVT_RIGHT_UP))
1534 {
1535 event.m_rightDown = !event.m_rightDown;
1536 return;
1537 }
1538 }
1539
1540 // find the window to send the mouse event too
1541 static
1542 wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y)
1543 {
1544 wxCoord xx = x;
1545 wxCoord yy = y;
1546
1547 if (win->m_wxwindow)
1548 {
1549 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1550 xx += pizza->xoffset;
1551 yy += pizza->yoffset;
1552 }
1553
1554 wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
1555 while (node)
1556 {
1557 wxWindowGTK *child = node->GetData();
1558
1559 node = node->GetNext();
1560 if (!child->IsShown())
1561 continue;
1562
1563 if (child->IsTransparentForMouse())
1564 {
1565 // wxStaticBox is transparent in the box itself
1566 int xx1 = child->m_x;
1567 int yy1 = child->m_y;
1568 int xx2 = child->m_x + child->m_width;
1569 int yy2 = child->m_y + child->m_height;
1570
1571 // left
1572 if (((xx >= xx1) && (xx <= xx1+10) && (yy >= yy1) && (yy <= yy2)) ||
1573 // right
1574 ((xx >= xx2-10) && (xx <= xx2) && (yy >= yy1) && (yy <= yy2)) ||
1575 // top
1576 ((xx >= xx1) && (xx <= xx2) && (yy >= yy1) && (yy <= yy1+10)) ||
1577 // bottom
1578 ((xx >= xx1) && (xx <= xx2) && (yy >= yy2-1) && (yy <= yy2)))
1579 {
1580 win = child;
1581 x -= child->m_x;
1582 y -= child->m_y;
1583 break;
1584 }
1585
1586 }
1587 else
1588 {
1589 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1590 (child->m_x <= xx) &&
1591 (child->m_y <= yy) &&
1592 (child->m_x+child->m_width >= xx) &&
1593 (child->m_y+child->m_height >= yy))
1594 {
1595 win = child;
1596 x -= child->m_x;
1597 y -= child->m_y;
1598 break;
1599 }
1600 }
1601 }
1602
1603 return win;
1604 }
1605
1606 //-----------------------------------------------------------------------------
1607 // "button_press_event"
1608 //-----------------------------------------------------------------------------
1609
1610 static gint gtk_window_button_press_callback( GtkWidget *widget,
1611 GdkEventButton *gdk_event,
1612 wxWindowGTK *win )
1613 {
1614 DEBUG_MAIN_THREAD
1615
1616 if (g_isIdle)
1617 wxapp_install_idle_handler();
1618
1619 /*
1620 wxPrintf( wxT("1) OnButtonPress from ") );
1621 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1622 wxPrintf( win->GetClassInfo()->GetClassName() );
1623 wxPrintf( wxT(".\n") );
1624 */
1625 if (!win->m_hasVMT) return FALSE;
1626 if (g_blockEventsOnDrag) return TRUE;
1627 if (g_blockEventsOnScroll) return TRUE;
1628
1629 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1630
1631 if (win->m_wxwindow && (g_focusWindow != win) && win->AcceptsFocus())
1632 {
1633 gtk_widget_grab_focus( win->m_wxwindow );
1634 /*
1635 wxPrintf( wxT("GrabFocus from ") );
1636 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1637 wxPrintf( win->GetClassInfo()->GetClassName() );
1638 wxPrintf( wxT(".\n") );
1639 */
1640 }
1641
1642 // GDK sends surplus button down event
1643 // before a double click event. We
1644 // need to filter these out.
1645 if (gdk_event->type == GDK_BUTTON_PRESS)
1646 {
1647 GdkEvent *peek_event = gdk_event_peek();
1648 if (peek_event)
1649 {
1650 if ((peek_event->type == GDK_2BUTTON_PRESS) ||
1651 (peek_event->type == GDK_3BUTTON_PRESS))
1652 {
1653 gdk_event_free( peek_event );
1654 return TRUE;
1655 }
1656 else
1657 {
1658 gdk_event_free( peek_event );
1659 }
1660 }
1661 }
1662
1663 wxEventType event_type = wxEVT_NULL;
1664
1665 // GdkDisplay is a GTK+ 2.2.0 thing
1666 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1667 if ( gdk_event->type == GDK_2BUTTON_PRESS &&
1668 gdk_event->button >= 1 && gdk_event->button <= 3 )
1669 {
1670 // Reset GDK internal timestamp variables in order to disable GDK
1671 // triple click events. GDK will then next time believe no button has
1672 // been clicked just before, and send a normal button click event.
1673 GdkDisplay* display = gtk_widget_get_display (widget);
1674 display->button_click_time[1] = 0;
1675 display->button_click_time[0] = 0;
1676 }
1677 #endif // GTK 2+
1678
1679 if (gdk_event->button == 1)
1680 {
1681 // note that GDK generates triple click events which are not supported
1682 // by wxWidgets but still have to be passed to the app as otherwise
1683 // clicks would simply go missing
1684 switch (gdk_event->type)
1685 {
1686 // we shouldn't get triple clicks at all for GTK2 because we
1687 // suppress them artificially using the code above but we still
1688 // should map them to something for GTK1 and not just ignore them
1689 // as this would lose clicks
1690 case GDK_3BUTTON_PRESS: // we could also map this to DCLICK...
1691 case GDK_BUTTON_PRESS:
1692 event_type = wxEVT_LEFT_DOWN;
1693 break;
1694
1695 case GDK_2BUTTON_PRESS:
1696 event_type = wxEVT_LEFT_DCLICK;
1697 break;
1698
1699 default:
1700 // just to silence gcc warnings
1701 ;
1702 }
1703 }
1704 else if (gdk_event->button == 2)
1705 {
1706 switch (gdk_event->type)
1707 {
1708 case GDK_3BUTTON_PRESS:
1709 case GDK_BUTTON_PRESS:
1710 event_type = wxEVT_MIDDLE_DOWN;
1711 break;
1712
1713 case GDK_2BUTTON_PRESS:
1714 event_type = wxEVT_MIDDLE_DCLICK;
1715 break;
1716
1717 default:
1718 ;
1719 }
1720 }
1721 else if (gdk_event->button == 3)
1722 {
1723 switch (gdk_event->type)
1724 {
1725 case GDK_3BUTTON_PRESS:
1726 case GDK_BUTTON_PRESS:
1727 event_type = wxEVT_RIGHT_DOWN;
1728 break;
1729
1730 case GDK_2BUTTON_PRESS:
1731 event_type = wxEVT_RIGHT_DCLICK;
1732 break;
1733
1734 default:
1735 ;
1736 }
1737 }
1738 else if (gdk_event->button == 4 || gdk_event->button == 5)
1739 {
1740 if (gdk_event->type == GDK_BUTTON_PRESS )
1741 {
1742 event_type = wxEVT_MOUSEWHEEL;
1743 }
1744 }
1745
1746 if ( event_type == wxEVT_NULL )
1747 {
1748 // unknown mouse button or click type
1749 return FALSE;
1750 }
1751
1752 wxMouseEvent event( event_type );
1753 InitMouseEvent( win, event, gdk_event );
1754
1755 AdjustEventButtonState(event);
1756
1757 // wxListBox actually get mouse events from the item, so we need to give it
1758 // a chance to correct this
1759 win->FixUpMouseEvent(widget, event.m_x, event.m_y);
1760
1761 // find the correct window to send the event too: it may be a different one
1762 // from the one which got it at GTK+ level because some control don't have
1763 // their own X window and thus cannot get any events.
1764 if ( !g_captureWindow )
1765 win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
1766
1767 gs_timeLastClick = gdk_event->time;
1768
1769 #ifndef __WXGTK20__
1770 if (event_type == wxEVT_LEFT_DCLICK)
1771 {
1772 // GTK 1.2 crashes when intercepting double
1773 // click events from both wxSpinButton and
1774 // wxSpinCtrl
1775 if (GTK_IS_SPIN_BUTTON(win->m_widget))
1776 {
1777 // Just disable this event for now.
1778 return FALSE;
1779 }
1780 }
1781 #endif
1782
1783 if (win->GetEventHandler()->ProcessEvent( event ))
1784 {
1785 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_press_event" );
1786 return TRUE;
1787 }
1788
1789 if (event_type == wxEVT_RIGHT_DOWN)
1790 {
1791 // generate a "context menu" event: this is similar to right mouse
1792 // click under many GUIs except that it is generated differently
1793 // (right up under MSW, ctrl-click under Mac, right down here) and
1794 //
1795 // (a) it's a command event and so is propagated to the parent
1796 // (b) under some ports it can be generated from kbd too
1797 // (c) it uses screen coords (because of (a))
1798 wxContextMenuEvent evtCtx(
1799 wxEVT_CONTEXT_MENU,
1800 win->GetId(),
1801 win->ClientToScreen(event.GetPosition()));
1802 evtCtx.SetEventObject(win);
1803 return win->GetEventHandler()->ProcessEvent(evtCtx);
1804 }
1805
1806 return FALSE;
1807 }
1808
1809 //-----------------------------------------------------------------------------
1810 // "button_release_event"
1811 //-----------------------------------------------------------------------------
1812
1813 static gint gtk_window_button_release_callback( GtkWidget *widget,
1814 GdkEventButton *gdk_event,
1815 wxWindowGTK *win )
1816 {
1817 DEBUG_MAIN_THREAD
1818
1819 if (g_isIdle)
1820 wxapp_install_idle_handler();
1821
1822 if (!win->m_hasVMT) return FALSE;
1823 if (g_blockEventsOnDrag) return FALSE;
1824 if (g_blockEventsOnScroll) return FALSE;
1825
1826 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1827
1828 wxEventType event_type = wxEVT_NULL;
1829
1830 switch (gdk_event->button)
1831 {
1832 case 1:
1833 event_type = wxEVT_LEFT_UP;
1834 break;
1835
1836 case 2:
1837 event_type = wxEVT_MIDDLE_UP;
1838 break;
1839
1840 case 3:
1841 event_type = wxEVT_RIGHT_UP;
1842 break;
1843
1844 default:
1845 // unknwon button, don't process
1846 return FALSE;
1847 }
1848
1849 wxMouseEvent event( event_type );
1850 InitMouseEvent( win, event, gdk_event );
1851
1852 AdjustEventButtonState(event);
1853
1854 // same wxListBox hack as above
1855 win->FixUpMouseEvent(widget, event.m_x, event.m_y);
1856
1857 if ( !g_captureWindow )
1858 win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
1859
1860 if (win->GetEventHandler()->ProcessEvent( event ))
1861 {
1862 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_release_event" );
1863 return TRUE;
1864 }
1865
1866 return FALSE;
1867 }
1868
1869 //-----------------------------------------------------------------------------
1870 // "motion_notify_event"
1871 //-----------------------------------------------------------------------------
1872
1873 static gint gtk_window_motion_notify_callback( GtkWidget *widget,
1874 GdkEventMotion *gdk_event,
1875 wxWindowGTK *win )
1876 {
1877 DEBUG_MAIN_THREAD
1878
1879 if (g_isIdle)
1880 wxapp_install_idle_handler();
1881
1882 if (!win->m_hasVMT) return FALSE;
1883 if (g_blockEventsOnDrag) return FALSE;
1884 if (g_blockEventsOnScroll) return FALSE;
1885
1886 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1887
1888 if (gdk_event->is_hint)
1889 {
1890 int x = 0;
1891 int y = 0;
1892 GdkModifierType state;
1893 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
1894 gdk_event->x = x;
1895 gdk_event->y = y;
1896 }
1897
1898 /*
1899 printf( "OnMotion from " );
1900 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1901 printf( win->GetClassInfo()->GetClassName() );
1902 printf( ".\n" );
1903 */
1904
1905 wxMouseEvent event( wxEVT_MOTION );
1906 InitMouseEvent(win, event, gdk_event);
1907
1908 if ( g_captureWindow )
1909 {
1910 // synthetize a mouse enter or leave event if needed
1911 GdkWindow *winUnderMouse = gdk_window_at_pointer(NULL, NULL);
1912 // This seems to be necessary and actually been added to
1913 // GDK itself in version 2.0.X
1914 gdk_flush();
1915
1916 bool hasMouse = winUnderMouse == gdk_event->window;
1917 if ( hasMouse != g_captureWindowHasMouse )
1918 {
1919 // the mouse changed window
1920 g_captureWindowHasMouse = hasMouse;
1921
1922 wxMouseEvent event(g_captureWindowHasMouse ? wxEVT_ENTER_WINDOW
1923 : wxEVT_LEAVE_WINDOW);
1924 InitMouseEvent(win, event, gdk_event);
1925 event.SetEventObject(win);
1926 win->GetEventHandler()->ProcessEvent(event);
1927 }
1928 }
1929 else // no capture
1930 {
1931 win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
1932 }
1933
1934 if (win->GetEventHandler()->ProcessEvent( event ))
1935 {
1936 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "motion_notify_event" );
1937 return TRUE;
1938 }
1939
1940 return FALSE;
1941 }
1942
1943 #ifdef __WXGTK20__
1944 //-----------------------------------------------------------------------------
1945 // "mouse_wheel_event"
1946 //-----------------------------------------------------------------------------
1947
1948 static gint gtk_window_wheel_callback (GtkWidget * widget,
1949 GdkEventScroll * gdk_event,
1950 wxWindowGTK * win)
1951 {
1952 DEBUG_MAIN_THREAD
1953
1954 if (g_isIdle)
1955 wxapp_install_idle_handler();
1956
1957 wxEventType event_type = wxEVT_NULL;
1958 if (gdk_event->direction == GDK_SCROLL_UP)
1959 event_type = wxEVT_MOUSEWHEEL;
1960 else if (gdk_event->direction == GDK_SCROLL_DOWN)
1961 event_type = wxEVT_MOUSEWHEEL;
1962 else
1963 return FALSE;
1964
1965 wxMouseEvent event( event_type );
1966 // Can't use InitMouse macro because scroll events don't have button
1967 event.SetTimestamp( gdk_event->time );
1968 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1969 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1970 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1971 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1972 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1973 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1974 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1975 event.m_linesPerAction = 3;
1976 event.m_wheelDelta = 120;
1977 if (gdk_event->direction == GDK_SCROLL_UP)
1978 event.m_wheelRotation = 120;
1979 else
1980 event.m_wheelRotation = -120;
1981
1982 wxPoint pt = win->GetClientAreaOrigin();
1983 event.m_x = (wxCoord)gdk_event->x - pt.x;
1984 event.m_y = (wxCoord)gdk_event->y - pt.y;
1985
1986 event.SetEventObject( win );
1987 event.SetId( win->GetId() );
1988 event.SetTimestamp( gdk_event->time );
1989
1990 if (win->GetEventHandler()->ProcessEvent( event ))
1991 {
1992 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "scroll_event" );
1993 return TRUE;
1994 }
1995
1996 return FALSE;
1997 }
1998
1999 //-----------------------------------------------------------------------------
2000 // "popup-menu"
2001 //-----------------------------------------------------------------------------
2002 static gboolean wxgtk_window_popup_menu_callback(GtkWidget*, wxWindowGTK* win)
2003 {
2004 wxContextMenuEvent event(
2005 wxEVT_CONTEXT_MENU,
2006 win->GetId(),
2007 wxPoint(-1, -1));
2008 event.SetEventObject(win);
2009 return win->GetEventHandler()->ProcessEvent(event);
2010 }
2011 #endif // __WXGTK20__
2012
2013 //-----------------------------------------------------------------------------
2014 // "focus_in_event"
2015 //-----------------------------------------------------------------------------
2016
2017 // send the wxChildFocusEvent and wxFocusEvent, common code of
2018 // gtk_window_focus_in_callback() and SetFocus()
2019 static bool DoSendFocusEvents(wxWindow *win)
2020 {
2021 // Notify the parent keeping track of focus for the kbd navigation
2022 // purposes that we got it.
2023 wxChildFocusEvent eventChildFocus(win);
2024 (void)win->GetEventHandler()->ProcessEvent(eventChildFocus);
2025
2026 wxFocusEvent eventFocus(wxEVT_SET_FOCUS, win->GetId());
2027 eventFocus.SetEventObject(win);
2028
2029 return win->GetEventHandler()->ProcessEvent(eventFocus);
2030 }
2031
2032 static gint gtk_window_focus_in_callback( GtkWidget *widget,
2033 GdkEvent *WXUNUSED(event),
2034 wxWindow *win )
2035 {
2036 DEBUG_MAIN_THREAD
2037
2038 if (g_isIdle)
2039 wxapp_install_idle_handler();
2040
2041 #ifdef __WXGTK20__
2042 if (win->m_imData)
2043 gtk_im_context_focus_in(win->m_imData->context);
2044 #endif
2045
2046 g_focusWindowLast =
2047 g_focusWindow = win;
2048
2049 wxLogTrace(TRACE_FOCUS,
2050 _T("%s: focus in"), win->GetName().c_str());
2051
2052 #ifdef HAVE_XIM
2053 if (win->m_ic)
2054 gdk_im_begin(win->m_ic, win->m_wxwindow->window);
2055 #endif
2056
2057 #if wxUSE_CARET
2058 // caret needs to be informed about focus change
2059 wxCaret *caret = win->GetCaret();
2060 if ( caret )
2061 {
2062 caret->OnSetFocus();
2063 }
2064 #endif // wxUSE_CARET
2065
2066 // does the window itself think that it has the focus?
2067 if ( !win->m_hasFocus )
2068 {
2069 // not yet, notify it
2070 win->m_hasFocus = TRUE;
2071
2072 if ( DoSendFocusEvents(win) )
2073 {
2074 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
2075 return TRUE;
2076 }
2077 }
2078
2079 return FALSE;
2080 }
2081
2082 //-----------------------------------------------------------------------------
2083 // "focus_out_event"
2084 //-----------------------------------------------------------------------------
2085
2086 static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEventFocus *gdk_event, wxWindowGTK *win )
2087 {
2088 DEBUG_MAIN_THREAD
2089
2090 if (g_isIdle)
2091 wxapp_install_idle_handler();
2092
2093 #ifdef __WXGTK20__
2094 if (win->m_imData)
2095 gtk_im_context_focus_out(win->m_imData->context);
2096 #endif
2097
2098 wxLogTrace( TRACE_FOCUS,
2099 _T("%s: focus out"), win->GetName().c_str() );
2100
2101
2102 wxWindowGTK *winFocus = wxFindFocusedChild(win);
2103 if ( winFocus )
2104 win = winFocus;
2105
2106 g_focusWindow = (wxWindowGTK *)NULL;
2107
2108 #ifdef HAVE_XIM
2109 if (win->m_ic)
2110 gdk_im_end();
2111 #endif
2112
2113 #if wxUSE_CARET
2114 // caret needs to be informed about focus change
2115 wxCaret *caret = win->GetCaret();
2116 if ( caret )
2117 {
2118 caret->OnKillFocus();
2119 }
2120 #endif // wxUSE_CARET
2121
2122 // don't send the window a kill focus event if it thinks that it doesn't
2123 // have focus already
2124 if ( win->m_hasFocus )
2125 {
2126 win->m_hasFocus = FALSE;
2127
2128 wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
2129 event.SetEventObject( win );
2130
2131 // even if we did process the event in wx code, still let GTK itself
2132 // process it too as otherwise bad things happen, especially in GTK2
2133 // where the text control simply aborts the program if it doesn't get
2134 // the matching focus out event
2135 (void)win->GetEventHandler()->ProcessEvent( event );
2136 }
2137
2138 return FALSE;
2139 }
2140
2141 //-----------------------------------------------------------------------------
2142 // "enter_notify_event"
2143 //-----------------------------------------------------------------------------
2144
2145 static
2146 gint gtk_window_enter_callback( GtkWidget *widget,
2147 GdkEventCrossing *gdk_event,
2148 wxWindowGTK *win )
2149 {
2150 DEBUG_MAIN_THREAD
2151
2152 if (g_isIdle)
2153 wxapp_install_idle_handler();
2154
2155 if (!win->m_hasVMT) return FALSE;
2156 if (g_blockEventsOnDrag) return FALSE;
2157
2158 // Event was emitted after a grab
2159 if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
2160
2161 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
2162
2163 int x = 0;
2164 int y = 0;
2165 GdkModifierType state = (GdkModifierType)0;
2166
2167 gdk_window_get_pointer( widget->window, &x, &y, &state );
2168
2169 wxMouseEvent event( wxEVT_ENTER_WINDOW );
2170 InitMouseEvent(win, event, gdk_event);
2171 wxPoint pt = win->GetClientAreaOrigin();
2172 event.m_x = x + pt.x;
2173 event.m_y = y + pt.y;
2174
2175 if (win->GetEventHandler()->ProcessEvent( event ))
2176 {
2177 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "enter_notify_event" );
2178 return TRUE;
2179 }
2180
2181 return FALSE;
2182 }
2183
2184 //-----------------------------------------------------------------------------
2185 // "leave_notify_event"
2186 //-----------------------------------------------------------------------------
2187
2188 static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win )
2189 {
2190 DEBUG_MAIN_THREAD
2191
2192 if (g_isIdle)
2193 wxapp_install_idle_handler();
2194
2195 if (!win->m_hasVMT) return FALSE;
2196 if (g_blockEventsOnDrag) return FALSE;
2197
2198 // Event was emitted after an ungrab
2199 if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
2200
2201 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
2202
2203 wxMouseEvent event( wxEVT_LEAVE_WINDOW );
2204 event.SetTimestamp( gdk_event->time );
2205 event.SetEventObject( win );
2206
2207 int x = 0;
2208 int y = 0;
2209 GdkModifierType state = (GdkModifierType)0;
2210
2211 gdk_window_get_pointer( widget->window, &x, &y, &state );
2212
2213 event.m_shiftDown = (state & GDK_SHIFT_MASK) != 0;
2214 event.m_controlDown = (state & GDK_CONTROL_MASK) != 0;
2215 event.m_altDown = (state & GDK_MOD1_MASK) != 0;
2216 event.m_metaDown = (state & GDK_MOD2_MASK) != 0;
2217 event.m_leftDown = (state & GDK_BUTTON1_MASK) != 0;
2218 event.m_middleDown = (state & GDK_BUTTON2_MASK) != 0;
2219 event.m_rightDown = (state & GDK_BUTTON3_MASK) != 0;
2220
2221 wxPoint pt = win->GetClientAreaOrigin();
2222 event.m_x = x + pt.x;
2223 event.m_y = y + pt.y;
2224
2225 if (win->GetEventHandler()->ProcessEvent( event ))
2226 {
2227 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "leave_notify_event" );
2228 return TRUE;
2229 }
2230
2231 return FALSE;
2232 }
2233
2234 //-----------------------------------------------------------------------------
2235 // "value_changed" from m_vAdjust
2236 //-----------------------------------------------------------------------------
2237
2238 static void gtk_window_vscroll_callback( GtkAdjustment *adjust,
2239 SCROLLBAR_CBACK_ARG
2240 wxWindowGTK *win )
2241 {
2242 DEBUG_MAIN_THREAD
2243
2244 if (g_isIdle)
2245 wxapp_install_idle_handler();
2246
2247 if (g_blockEventsOnDrag) return;
2248
2249 if (!win->m_hasVMT) return;
2250
2251 float diff = adjust->value - win->m_oldVerticalPos;
2252 if (fabs(diff) < 0.2) return;
2253
2254 win->m_oldVerticalPos = adjust->value;
2255
2256 #ifndef __WXGTK20__
2257 GtkScrolledWindow *sw = GTK_SCROLLED_WINDOW(win->m_widget);
2258 #endif
2259 wxEventType command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw->vscrollbar));
2260
2261 int value = (int)(adjust->value+0.5);
2262
2263 wxScrollWinEvent event( command, value, wxVERTICAL );
2264 event.SetEventObject( win );
2265 win->GetEventHandler()->ProcessEvent( event );
2266 }
2267
2268 //-----------------------------------------------------------------------------
2269 // "value_changed" from m_hAdjust
2270 //-----------------------------------------------------------------------------
2271
2272 static void gtk_window_hscroll_callback( GtkAdjustment *adjust,
2273 SCROLLBAR_CBACK_ARG
2274 wxWindowGTK *win )
2275 {
2276 DEBUG_MAIN_THREAD
2277
2278 if (g_isIdle)
2279 wxapp_install_idle_handler();
2280
2281 if (g_blockEventsOnDrag) return;
2282 if (!win->m_hasVMT) return;
2283
2284 float diff = adjust->value - win->m_oldHorizontalPos;
2285 if (fabs(diff) < 0.2) return;
2286
2287 #ifndef __WXGTK20__
2288 GtkScrolledWindow *sw = GTK_SCROLLED_WINDOW(win->m_widget);
2289 #endif
2290 wxEventType command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw->hscrollbar));
2291
2292 win->m_oldHorizontalPos = adjust->value;
2293
2294 int value = (int)(adjust->value+0.5);
2295
2296 wxScrollWinEvent event( command, value, wxHORIZONTAL );
2297 event.SetEventObject( win );
2298 win->GetEventHandler()->ProcessEvent( event );
2299 }
2300
2301 //-----------------------------------------------------------------------------
2302 // "button_press_event" from scrollbar
2303 //-----------------------------------------------------------------------------
2304
2305 static gint gtk_scrollbar_button_press_callback( GtkRange *widget,
2306 GdkEventButton *gdk_event,
2307 wxWindowGTK *win)
2308 {
2309 DEBUG_MAIN_THREAD
2310
2311 if (g_isIdle)
2312 wxapp_install_idle_handler();
2313
2314
2315 g_blockEventsOnScroll = TRUE;
2316
2317 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2318 #ifndef __WXGTK20__
2319 win->m_isScrolling = (gdk_event->window == widget->slider);
2320 #endif
2321
2322 return FALSE;
2323 }
2324
2325 //-----------------------------------------------------------------------------
2326 // "button_release_event" from scrollbar
2327 //-----------------------------------------------------------------------------
2328
2329 static gint gtk_scrollbar_button_release_callback( GtkRange *widget,
2330 GdkEventButton *WXUNUSED(gdk_event),
2331 wxWindowGTK *win)
2332 {
2333 DEBUG_MAIN_THREAD
2334
2335 // don't test here as we can release the mouse while being over
2336 // a different window than the slider
2337 //
2338 // if (gdk_event->window != widget->slider) return FALSE;
2339
2340 g_blockEventsOnScroll = FALSE;
2341
2342 if (win->m_isScrolling)
2343 {
2344 wxEventType command = wxEVT_SCROLLWIN_THUMBRELEASE;
2345 int value = -1;
2346 int dir = -1;
2347
2348 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
2349 if (widget == GTK_RANGE(scrolledWindow->hscrollbar))
2350 {
2351 value = (int)(win->m_hAdjust->value+0.5);
2352 dir = wxHORIZONTAL;
2353 }
2354 if (widget == GTK_RANGE(scrolledWindow->vscrollbar))
2355 {
2356 value = (int)(win->m_vAdjust->value+0.5);
2357 dir = wxVERTICAL;
2358 }
2359
2360 wxScrollWinEvent event( command, value, dir );
2361 event.SetEventObject( win );
2362 win->GetEventHandler()->ProcessEvent( event );
2363 }
2364
2365 win->m_isScrolling = FALSE;
2366
2367 return FALSE;
2368 }
2369
2370 // ----------------------------------------------------------------------------
2371 // this wxWindowBase function is implemented here (in platform-specific file)
2372 // because it is static and so couldn't be made virtual
2373 // ----------------------------------------------------------------------------
2374
2375 wxWindow *wxWindowBase::DoFindFocus()
2376 {
2377 // the cast is necessary when we compile in wxUniversal mode
2378 return (wxWindow *)g_focusWindow;
2379 }
2380
2381
2382 //-----------------------------------------------------------------------------
2383 // "realize" from m_widget
2384 //-----------------------------------------------------------------------------
2385
2386 /* We cannot set colours and fonts before the widget has
2387 been realized, so we do this directly after realization. */
2388
2389 static gint
2390 gtk_window_realized_callback( GtkWidget *m_widget, wxWindow *win )
2391 {
2392 DEBUG_MAIN_THREAD
2393
2394 if (g_isIdle)
2395 wxapp_install_idle_handler();
2396
2397 #ifdef __WXGTK20__
2398 if (win->m_imData)
2399 {
2400 GtkPizza *pizza = GTK_PIZZA( m_widget );
2401 gtk_im_context_set_client_window( win->m_imData->context,
2402 pizza->bin_window );
2403 }
2404 #endif
2405
2406 wxWindowCreateEvent event( win );
2407 event.SetEventObject( win );
2408 win->GetEventHandler()->ProcessEvent( event );
2409
2410 return FALSE;
2411 }
2412
2413 //-----------------------------------------------------------------------------
2414 // "size_allocate"
2415 //-----------------------------------------------------------------------------
2416
2417 static
2418 void gtk_window_size_callback( GtkWidget *WXUNUSED(widget),
2419 GtkAllocation *WXUNUSED(alloc),
2420 wxWindow *win )
2421 {
2422 if (g_isIdle)
2423 wxapp_install_idle_handler();
2424
2425 if (!win->m_hasScrolling) return;
2426
2427 int client_width = 0;
2428 int client_height = 0;
2429 win->GetClientSize( &client_width, &client_height );
2430 if ((client_width == win->m_oldClientWidth) && (client_height == win->m_oldClientHeight))
2431 return;
2432
2433 win->m_oldClientWidth = client_width;
2434 win->m_oldClientHeight = client_height;
2435
2436 if (!win->m_nativeSizeEvent)
2437 {
2438 wxSizeEvent event( win->GetSize(), win->GetId() );
2439 event.SetEventObject( win );
2440 win->GetEventHandler()->ProcessEvent( event );
2441 }
2442 }
2443
2444
2445 #ifdef HAVE_XIM
2446 #define WXUNUSED_UNLESS_XIM(param) param
2447 #else
2448 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2449 #endif
2450
2451 /* Resize XIM window */
2452
2453 static
2454 void gtk_wxwindow_size_callback( GtkWidget* WXUNUSED_UNLESS_XIM(widget),
2455 GtkAllocation* WXUNUSED_UNLESS_XIM(alloc),
2456 wxWindowGTK* WXUNUSED_UNLESS_XIM(win) )
2457 {
2458 if (g_isIdle)
2459 wxapp_install_idle_handler();
2460
2461 #ifdef HAVE_XIM
2462 if (!win->m_ic)
2463 return;
2464
2465 if (gdk_ic_get_style (win->m_ic) & GDK_IM_PREEDIT_POSITION)
2466 {
2467 gint width, height;
2468
2469 gdk_window_get_size (widget->window, &width, &height);
2470 win->m_icattr->preedit_area.width = width;
2471 win->m_icattr->preedit_area.height = height;
2472 gdk_ic_set_attr (win->m_ic, win->m_icattr, GDK_IC_PREEDIT_AREA);
2473 }
2474 #endif // HAVE_XIM
2475 }
2476
2477 //-----------------------------------------------------------------------------
2478 // "realize" from m_wxwindow
2479 //-----------------------------------------------------------------------------
2480
2481 /* Initialize XIM support */
2482
2483 static gint
2484 gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget),
2485 wxWindowGTK * WXUNUSED_UNLESS_XIM(win) )
2486 {
2487 if (g_isIdle)
2488 wxapp_install_idle_handler();
2489
2490 #ifdef HAVE_XIM
2491 if (win->m_ic) return FALSE;
2492 if (!widget) return FALSE;
2493 if (!gdk_im_ready()) return FALSE;
2494
2495 win->m_icattr = gdk_ic_attr_new();
2496 if (!win->m_icattr) return FALSE;
2497
2498 gint width, height;
2499 GdkEventMask mask;
2500 GdkColormap *colormap;
2501 GdkICAttr *attr = win->m_icattr;
2502 unsigned attrmask = GDK_IC_ALL_REQ;
2503 GdkIMStyle style;
2504 GdkIMStyle supported_style = (GdkIMStyle)
2505 (GDK_IM_PREEDIT_NONE |
2506 GDK_IM_PREEDIT_NOTHING |
2507 GDK_IM_PREEDIT_POSITION |
2508 GDK_IM_STATUS_NONE |
2509 GDK_IM_STATUS_NOTHING);
2510
2511 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
2512 supported_style = (GdkIMStyle)(supported_style & ~GDK_IM_PREEDIT_POSITION);
2513
2514 attr->style = style = gdk_im_decide_style (supported_style);
2515 attr->client_window = widget->window;
2516
2517 if ((colormap = gtk_widget_get_colormap (widget)) !=
2518 gtk_widget_get_default_colormap ())
2519 {
2520 attrmask |= GDK_IC_PREEDIT_COLORMAP;
2521 attr->preedit_colormap = colormap;
2522 }
2523
2524 attrmask |= GDK_IC_PREEDIT_FOREGROUND;
2525 attrmask |= GDK_IC_PREEDIT_BACKGROUND;
2526 attr->preedit_foreground = widget->style->fg[GTK_STATE_NORMAL];
2527 attr->preedit_background = widget->style->base[GTK_STATE_NORMAL];
2528
2529 switch (style & GDK_IM_PREEDIT_MASK)
2530 {
2531 case GDK_IM_PREEDIT_POSITION:
2532 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
2533 {
2534 g_warning ("over-the-spot style requires fontset");
2535 break;
2536 }
2537
2538 gdk_window_get_size (widget->window, &width, &height);
2539
2540 attrmask |= GDK_IC_PREEDIT_POSITION_REQ;
2541 attr->spot_location.x = 0;
2542 attr->spot_location.y = height;
2543 attr->preedit_area.x = 0;
2544 attr->preedit_area.y = 0;
2545 attr->preedit_area.width = width;
2546 attr->preedit_area.height = height;
2547 attr->preedit_fontset = widget->style->font;
2548
2549 break;
2550 }
2551
2552 win->m_ic = gdk_ic_new (attr, (GdkICAttributesType)attrmask);
2553
2554 if (win->m_ic == NULL)
2555 g_warning ("Can't create input context.");
2556 else
2557 {
2558 mask = gdk_window_get_events (widget->window);
2559 mask = (GdkEventMask)(mask | gdk_ic_get_events (win->m_ic));
2560 gdk_window_set_events (widget->window, mask);
2561
2562 if (GTK_WIDGET_HAS_FOCUS(widget))
2563 gdk_im_begin (win->m_ic, widget->window);
2564 }
2565 #endif // HAVE_XIM
2566
2567 return FALSE;
2568 }
2569
2570 //-----------------------------------------------------------------------------
2571 // InsertChild for wxWindowGTK.
2572 //-----------------------------------------------------------------------------
2573
2574 /* Callback for wxWindowGTK. This very strange beast has to be used because
2575 * C++ has no virtual methods in a constructor. We have to emulate a
2576 * virtual function here as wxNotebook requires a different way to insert
2577 * a child in it. I had opted for creating a wxNotebookPage window class
2578 * which would have made this superfluous (such in the MDI window system),
2579 * but no-one was listening to me... */
2580
2581 static void wxInsertChildInWindow( wxWindowGTK* parent, wxWindowGTK* child )
2582 {
2583 /* the window might have been scrolled already, do we
2584 have to adapt the position */
2585 GtkPizza *pizza = GTK_PIZZA(parent->m_wxwindow);
2586 child->m_x += pizza->xoffset;
2587 child->m_y += pizza->yoffset;
2588
2589 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
2590 GTK_WIDGET(child->m_widget),
2591 child->m_x,
2592 child->m_y,
2593 child->m_width,
2594 child->m_height );
2595 }
2596
2597 //-----------------------------------------------------------------------------
2598 // global functions
2599 //-----------------------------------------------------------------------------
2600
2601 wxWindow *wxGetActiveWindow()
2602 {
2603 return wxWindow::FindFocus();
2604 }
2605
2606 //-----------------------------------------------------------------------------
2607 // wxWindowGTK
2608 //-----------------------------------------------------------------------------
2609
2610 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2611 // method
2612 #ifdef __WXUNIVERSAL__
2613 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK, wxWindowBase)
2614 #else // __WXGTK__
2615 IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
2616 #endif // __WXUNIVERSAL__/__WXGTK__
2617
2618 void wxWindowGTK::Init()
2619 {
2620 // GTK specific
2621 m_widget = (GtkWidget *) NULL;
2622 m_wxwindow = (GtkWidget *) NULL;
2623 m_focusWidget = (GtkWidget *) NULL;
2624
2625 // position/size
2626 m_x = 0;
2627 m_y = 0;
2628 m_width = 0;
2629 m_height = 0;
2630
2631 m_sizeSet = FALSE;
2632 m_hasVMT = FALSE;
2633 m_needParent = TRUE;
2634 m_isBeingDeleted = FALSE;
2635
2636 m_noExpose = FALSE;
2637 m_nativeSizeEvent = FALSE;
2638
2639 m_hasScrolling = FALSE;
2640 m_isScrolling = FALSE;
2641
2642 m_hAdjust = (GtkAdjustment*) NULL;
2643 m_vAdjust = (GtkAdjustment*) NULL;
2644 m_oldHorizontalPos =
2645 m_oldVerticalPos = 0.0;
2646 m_oldClientWidth =
2647 m_oldClientHeight = 0;
2648
2649 m_resizing = FALSE;
2650
2651 m_insertCallback = (wxInsertChildFunction) NULL;
2652
2653 m_acceptsFocus = FALSE;
2654 m_hasFocus = FALSE;
2655
2656 m_clipPaintRegion = FALSE;
2657
2658 m_needsStyleChange = false;
2659
2660 m_cursor = *wxSTANDARD_CURSOR;
2661
2662 #ifdef __WXGTK20__
2663 m_imData = NULL;
2664 m_x11Context = NULL;
2665 m_dirtyTabOrder = false;
2666 #else
2667 #ifdef HAVE_XIM
2668 m_ic = (GdkIC*) NULL;
2669 m_icattr = (GdkICAttr*) NULL;
2670 #endif
2671 #endif
2672 }
2673
2674 wxWindowGTK::wxWindowGTK()
2675 {
2676 Init();
2677 }
2678
2679 wxWindowGTK::wxWindowGTK( wxWindow *parent,
2680 wxWindowID id,
2681 const wxPoint &pos,
2682 const wxSize &size,
2683 long style,
2684 const wxString &name )
2685 {
2686 Init();
2687
2688 Create( parent, id, pos, size, style, name );
2689 }
2690
2691 bool wxWindowGTK::Create( wxWindow *parent,
2692 wxWindowID id,
2693 const wxPoint &pos,
2694 const wxSize &size,
2695 long style,
2696 const wxString &name )
2697 {
2698 if (!PreCreation( parent, pos, size ) ||
2699 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
2700 {
2701 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2702 return FALSE;
2703 }
2704
2705 m_insertCallback = wxInsertChildInWindow;
2706
2707 m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
2708 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
2709
2710 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
2711
2712 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
2713 scroll_class->scrollbar_spacing = 0;
2714
2715 gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
2716
2717 m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->hscrollbar) );
2718 m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->vscrollbar) );
2719
2720 m_wxwindow = gtk_pizza_new();
2721
2722 #ifndef __WXUNIVERSAL__
2723 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
2724
2725 if (HasFlag(wxRAISED_BORDER))
2726 {
2727 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_OUT );
2728 }
2729 else if (HasFlag(wxSUNKEN_BORDER))
2730 {
2731 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_IN );
2732 }
2733 else if (HasFlag(wxSIMPLE_BORDER))
2734 {
2735 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_THIN );
2736 }
2737 else
2738 {
2739 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_NONE );
2740 }
2741 #endif // __WXUNIVERSAL__
2742
2743 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
2744
2745 GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
2746 m_acceptsFocus = TRUE;
2747
2748 // I _really_ don't want scrollbars in the beginning
2749 m_vAdjust->lower = 0.0;
2750 m_vAdjust->upper = 1.0;
2751 m_vAdjust->value = 0.0;
2752 m_vAdjust->step_increment = 1.0;
2753 m_vAdjust->page_increment = 1.0;
2754 m_vAdjust->page_size = 5.0;
2755 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
2756 m_hAdjust->lower = 0.0;
2757 m_hAdjust->upper = 1.0;
2758 m_hAdjust->value = 0.0;
2759 m_hAdjust->step_increment = 1.0;
2760 m_hAdjust->page_increment = 1.0;
2761 m_hAdjust->page_size = 5.0;
2762 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
2763
2764 // these handlers block mouse events to any window during scrolling such as
2765 // motion events and prevent GTK and wxWidgets from fighting over where the
2766 // slider should be
2767
2768 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_press_event",
2769 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2770
2771 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_press_event",
2772 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2773
2774 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_release_event",
2775 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2776
2777 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_release_event",
2778 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2779
2780 // these handlers get notified when screen updates are required either when
2781 // scrolling or when the window size (and therefore scrollbar configuration)
2782 // has changed
2783
2784 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
2785 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
2786 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
2787 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
2788
2789 gtk_widget_show( m_wxwindow );
2790
2791 if (m_parent)
2792 m_parent->DoAddChild( this );
2793
2794 m_focusWidget = m_wxwindow;
2795
2796 PostCreation();
2797
2798 return TRUE;
2799 }
2800
2801 wxWindowGTK::~wxWindowGTK()
2802 {
2803 SendDestroyEvent();
2804
2805 if (g_focusWindow == this)
2806 g_focusWindow = NULL;
2807
2808 if ( g_delayedFocus == this )
2809 g_delayedFocus = NULL;
2810
2811 m_isBeingDeleted = TRUE;
2812 m_hasVMT = FALSE;
2813
2814 if (m_widget)
2815 Show( FALSE );
2816
2817 DestroyChildren();
2818
2819 #ifdef HAVE_XIM
2820 if (m_ic)
2821 gdk_ic_destroy (m_ic);
2822 if (m_icattr)
2823 gdk_ic_attr_destroy (m_icattr);
2824 #endif
2825
2826 if (m_wxwindow)
2827 {
2828 gtk_widget_destroy( m_wxwindow );
2829 m_wxwindow = (GtkWidget*) NULL;
2830 }
2831
2832 if (m_widget)
2833 {
2834 gtk_widget_destroy( m_widget );
2835 m_widget = (GtkWidget*) NULL;
2836 }
2837
2838 #ifdef __WXGTK20__
2839 delete m_imData;
2840 #endif
2841 }
2842
2843 bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos, const wxSize &size )
2844 {
2845 wxCHECK_MSG( !m_needParent || parent, FALSE, wxT("Need complete parent.") );
2846
2847 // Use either the given size, or the default if -1 is given.
2848 // See wxWindowBase for these functions.
2849 m_width = WidthDefault(size.x) ;
2850 m_height = HeightDefault(size.y);
2851
2852 m_x = (int)pos.x;
2853 m_y = (int)pos.y;
2854
2855 return TRUE;
2856 }
2857
2858 void wxWindowGTK::PostCreation()
2859 {
2860 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2861
2862 if (m_wxwindow)
2863 {
2864 if (!m_noExpose)
2865 {
2866 // these get reported to wxWidgets -> wxPaintEvent
2867
2868 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow), TRUE );
2869
2870 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
2871 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
2872
2873 #ifndef __WXGTK20__
2874 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
2875 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
2876
2877 if (!HasFlag(wxFULL_REPAINT_ON_RESIZE))
2878 {
2879 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "event",
2880 GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this );
2881 }
2882 #else
2883 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2884 #endif
2885 }
2886
2887 #ifdef __WXGTK20__
2888 // Create input method handler
2889 m_imData = new wxGtkIMData;
2890
2891 // Cannot handle drawing preedited text yet
2892 gtk_im_context_set_use_preedit( m_imData->context, FALSE );
2893
2894 g_signal_connect (G_OBJECT (m_imData->context), "commit",
2895 G_CALLBACK (gtk_wxwindow_commit_cb), this);
2896 #endif
2897
2898 // these are called when the "sunken" or "raised" borders are drawn
2899 gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
2900 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
2901
2902 #ifndef __WXGTK20__
2903 gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
2904 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
2905 #endif
2906 }
2907
2908 // focus handling
2909
2910 if (!GTK_IS_WINDOW(m_widget))
2911 {
2912 if (m_focusWidget == NULL)
2913 m_focusWidget = m_widget;
2914
2915 gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_in_event",
2916 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
2917
2918 gtk_signal_connect_after( GTK_OBJECT(m_focusWidget), "focus_out_event",
2919 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
2920 }
2921
2922 // connect to the various key and mouse handlers
2923
2924 GtkWidget *connect_widget = GetConnectWidget();
2925
2926 ConnectWidget( connect_widget );
2927
2928 /* We cannot set colours, fonts and cursors before the widget has
2929 been realized, so we do this directly after realization */
2930 gtk_signal_connect( GTK_OBJECT(connect_widget), "realize",
2931 GTK_SIGNAL_FUNC(gtk_window_realized_callback), (gpointer) this );
2932
2933 if (m_wxwindow)
2934 {
2935 // Catch native resize events
2936 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2937 GTK_SIGNAL_FUNC(gtk_window_size_callback), (gpointer)this );
2938
2939 // Initialize XIM support
2940 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "realize",
2941 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback), (gpointer) this );
2942
2943 // And resize XIM window
2944 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2945 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this );
2946 }
2947
2948 if ( !GTK_IS_COMBO(m_widget))
2949 {
2950 // This is needed if we want to add our windows into native
2951 // GTK control, such as the toolbar. With this callback, the
2952 // toolbar gets to know the correct size (the one set by the
2953 // programmer). Sadly, it misbehaves for wxComboBox. FIXME
2954 // when moving to GTK 2.0.
2955 gtk_signal_connect( GTK_OBJECT(m_widget), "size_request",
2956 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback),
2957 (gpointer) this );
2958 }
2959
2960 InheritAttributes();
2961
2962 m_hasVMT = TRUE;
2963
2964 // unless the window was created initially hidden (i.e. Hide() had been
2965 // called before Create()), we should show it at GTK+ level as well
2966 if ( IsShown() )
2967 gtk_widget_show( m_widget );
2968 }
2969
2970 void wxWindowGTK::ConnectWidget( GtkWidget *widget )
2971 {
2972 gtk_signal_connect( GTK_OBJECT(widget), "key_press_event",
2973 GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this );
2974
2975 gtk_signal_connect( GTK_OBJECT(widget), "key_release_event",
2976 GTK_SIGNAL_FUNC(gtk_window_key_release_callback), (gpointer)this );
2977
2978 gtk_signal_connect( GTK_OBJECT(widget), "button_press_event",
2979 GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
2980
2981 gtk_signal_connect( GTK_OBJECT(widget), "button_release_event",
2982 GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
2983
2984 gtk_signal_connect( GTK_OBJECT(widget), "motion_notify_event",
2985 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
2986
2987 #ifdef __WXGTK20__
2988 gtk_signal_connect( GTK_OBJECT(widget), "scroll_event",
2989 GTK_SIGNAL_FUNC(gtk_window_wheel_callback), (gpointer)this );
2990 g_signal_connect(widget, "popup_menu",
2991 G_CALLBACK(wxgtk_window_popup_menu_callback), this);
2992 #endif
2993
2994 gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event",
2995 GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
2996
2997 gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
2998 GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
2999 }
3000
3001 bool wxWindowGTK::Destroy()
3002 {
3003 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
3004
3005 m_hasVMT = FALSE;
3006
3007 return wxWindowBase::Destroy();
3008 }
3009
3010 void wxWindowGTK::DoMoveWindow(int x, int y, int width, int height)
3011 {
3012 gtk_pizza_set_size( GTK_PIZZA(m_parent->m_wxwindow), m_widget, x, y, width, height );
3013 }
3014
3015 void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
3016 {
3017 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
3018 wxASSERT_MSG( (m_parent != NULL), wxT("wxWindowGTK::SetSize requires parent.\n") );
3019
3020 /*
3021 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
3022 */
3023
3024 if (m_resizing) return; /* I don't like recursions */
3025 m_resizing = TRUE;
3026
3027 int currentX, currentY;
3028 GetPosition(&currentX, &currentY);
3029 if (x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
3030 x = currentX;
3031 if (y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
3032 y = currentY;
3033 AdjustForParentClientOrigin(x, y, sizeFlags);
3034
3035 if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
3036 {
3037 /* don't set the size for children of wxNotebook, just take the values. */
3038 m_x = x;
3039 m_y = y;
3040 m_width = width;
3041 m_height = height;
3042 }
3043 else
3044 {
3045 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
3046 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
3047 {
3048 if (x != -1) m_x = x + pizza->xoffset;
3049 if (y != -1) m_y = y + pizza->yoffset;
3050 }
3051 else
3052 {
3053 m_x = x + pizza->xoffset;
3054 m_y = y + pizza->yoffset;
3055 }
3056
3057 // calculate the best size if we should auto size the window
3058 if ( ((sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1) ||
3059 ((sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1) )
3060 {
3061 const wxSize sizeBest = GetBestSize();
3062 if ( (sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1 )
3063 width = sizeBest.x;
3064 if ( (sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1 )
3065 height = sizeBest.y;
3066 }
3067
3068 if (width != -1)
3069 m_width = width;
3070 if (height != -1)
3071 m_height = height;
3072
3073 int minWidth = GetMinWidth(),
3074 minHeight = GetMinHeight(),
3075 maxWidth = GetMaxWidth(),
3076 maxHeight = GetMaxHeight();
3077
3078 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
3079 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
3080 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
3081 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
3082
3083 int border = 0;
3084 int bottom_border = 0;
3085
3086 #ifndef __WXGTK20__
3087 if (GTK_WIDGET_CAN_DEFAULT(m_widget))
3088 {
3089 /* the default button has a border around it */
3090 border = 6;
3091 bottom_border = 5;
3092 }
3093 #endif
3094
3095 DoMoveWindow( m_x-border,
3096 m_y-border,
3097 m_width+2*border,
3098 m_height+border+bottom_border );
3099 }
3100
3101 if (m_hasScrolling)
3102 {
3103 /* Sometimes the client area changes size without the
3104 whole windows's size changing, but if the whole
3105 windows's size doesn't change, no wxSizeEvent will
3106 normally be sent. Here we add an extra test if
3107 the client test has been changed and this will
3108 be used then. */
3109 GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
3110 }
3111
3112 /*
3113 wxPrintf( "OnSize sent from " );
3114 if (GetClassInfo() && GetClassInfo()->GetClassName())
3115 wxPrintf( GetClassInfo()->GetClassName() );
3116 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3117 */
3118
3119 if (!m_nativeSizeEvent)
3120 {
3121 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
3122 event.SetEventObject( this );
3123 GetEventHandler()->ProcessEvent( event );
3124 }
3125
3126 m_resizing = FALSE;
3127 }
3128
3129 void wxWindowGTK::OnInternalIdle()
3130 {
3131 #ifdef __WXGTK20__
3132 if ( m_dirtyTabOrder )
3133 RealizeTabOrder();
3134 #endif
3135 // Update style if the window was not yet realized
3136 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
3137 if (m_needsStyleChange)
3138 {
3139 SetBackgroundStyle(GetBackgroundStyle());
3140 m_needsStyleChange = false;
3141 }
3142
3143 // Update invalidated regions.
3144 GtkUpdate();
3145
3146 wxCursor cursor = m_cursor;
3147 if (g_globalCursor.Ok()) cursor = g_globalCursor;
3148
3149 if (cursor.Ok())
3150 {
3151 /* I now set the cursor anew in every OnInternalIdle call
3152 as setting the cursor in a parent window also effects the
3153 windows above so that checking for the current cursor is
3154 not possible. */
3155
3156 if (m_wxwindow)
3157 {
3158 GdkWindow *window = GTK_PIZZA(m_wxwindow)->bin_window;
3159 if (window)
3160 gdk_window_set_cursor( window, cursor.GetCursor() );
3161
3162 if (!g_globalCursor.Ok())
3163 cursor = *wxSTANDARD_CURSOR;
3164
3165 window = m_widget->window;
3166 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
3167 gdk_window_set_cursor( window, cursor.GetCursor() );
3168
3169 }
3170 else
3171 {
3172
3173 GdkWindow *window = m_widget->window;
3174 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
3175 gdk_window_set_cursor( window, cursor.GetCursor() );
3176
3177 }
3178 }
3179
3180 if (wxUpdateUIEvent::CanUpdate(this))
3181 UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
3182 }
3183
3184 void wxWindowGTK::DoGetSize( int *width, int *height ) const
3185 {
3186 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3187
3188 if (width) (*width) = m_width;
3189 if (height) (*height) = m_height;
3190 }
3191
3192 void wxWindowGTK::DoSetClientSize( int width, int height )
3193 {
3194 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3195
3196 if (!m_wxwindow)
3197 {
3198 SetSize( width, height );
3199 }
3200 else
3201 {
3202 int dw = 0;
3203 int dh = 0;
3204
3205 #ifndef __WXUNIVERSAL__
3206 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
3207 {
3208 /* when using GTK 1.2 we set the shadow border size to 2 */
3209 dw += 2 * 2;
3210 dh += 2 * 2;
3211 }
3212 if (HasFlag(wxSIMPLE_BORDER))
3213 {
3214 /* when using GTK 1.2 we set the simple border size to 1 */
3215 dw += 1 * 2;
3216 dh += 1 * 2;
3217 }
3218 #endif // __WXUNIVERSAL__
3219
3220 if (m_hasScrolling)
3221 {
3222 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
3223
3224 GtkRequisition vscroll_req;
3225 vscroll_req.width = 2;
3226 vscroll_req.height = 2;
3227 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
3228 (scroll_window->vscrollbar, &vscroll_req );
3229
3230 GtkRequisition hscroll_req;
3231 hscroll_req.width = 2;
3232 hscroll_req.height = 2;
3233 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
3234 (scroll_window->hscrollbar, &hscroll_req );
3235
3236 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
3237
3238 if (scroll_window->vscrollbar_visible)
3239 {
3240 dw += vscroll_req.width;
3241 dw += scroll_class->scrollbar_spacing;
3242 }
3243
3244 if (scroll_window->hscrollbar_visible)
3245 {
3246 dh += hscroll_req.height;
3247 dh += scroll_class->scrollbar_spacing;
3248 }
3249 }
3250
3251 SetSize( width+dw, height+dh );
3252 }
3253 }
3254
3255 void wxWindowGTK::DoGetClientSize( int *width, int *height ) const
3256 {
3257 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3258
3259 if (!m_wxwindow)
3260 {
3261 if (width) (*width) = m_width;
3262 if (height) (*height) = m_height;
3263 }
3264 else
3265 {
3266 int dw = 0;
3267 int dh = 0;
3268
3269 #ifndef __WXUNIVERSAL__
3270 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
3271 {
3272 /* when using GTK 1.2 we set the shadow border size to 2 */
3273 dw += 2 * 2;
3274 dh += 2 * 2;
3275 }
3276 if (HasFlag(wxSIMPLE_BORDER))
3277 {
3278 /* when using GTK 1.2 we set the simple border size to 1 */
3279 dw += 1 * 2;
3280 dh += 1 * 2;
3281 }
3282 #endif // __WXUNIVERSAL__
3283
3284 if (m_hasScrolling)
3285 {
3286 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
3287
3288 GtkRequisition vscroll_req;
3289 vscroll_req.width = 2;
3290 vscroll_req.height = 2;
3291 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
3292 (scroll_window->vscrollbar, &vscroll_req );
3293
3294 GtkRequisition hscroll_req;
3295 hscroll_req.width = 2;
3296 hscroll_req.height = 2;
3297 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
3298 (scroll_window->hscrollbar, &hscroll_req );
3299
3300 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
3301
3302 if (scroll_window->vscrollbar_visible)
3303 {
3304 dw += vscroll_req.width;
3305 dw += scroll_class->scrollbar_spacing;
3306 }
3307
3308 if (scroll_window->hscrollbar_visible)
3309 {
3310 dh += hscroll_req.height;
3311 dh += scroll_class->scrollbar_spacing;
3312 }
3313 }
3314
3315 if (width) (*width) = m_width - dw;
3316 if (height) (*height) = m_height - dh;
3317 }
3318
3319 /*
3320 printf( "GetClientSize, name %s ", GetName().c_str() );
3321 if (width) printf( " width = %d", (*width) );
3322 if (height) printf( " height = %d", (*height) );
3323 printf( "\n" );
3324 */
3325 }
3326
3327 void wxWindowGTK::DoGetPosition( int *x, int *y ) const
3328 {
3329 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3330
3331 int dx = 0;
3332 int dy = 0;
3333 if (m_parent && m_parent->m_wxwindow)
3334 {
3335 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
3336 dx = pizza->xoffset;
3337 dy = pizza->yoffset;
3338 }
3339
3340 if (x) (*x) = m_x - dx;
3341 if (y) (*y) = m_y - dy;
3342 }
3343
3344 void wxWindowGTK::DoClientToScreen( int *x, int *y ) const
3345 {
3346 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3347
3348 if (!m_widget->window) return;
3349
3350 GdkWindow *source = (GdkWindow *) NULL;
3351 if (m_wxwindow)
3352 source = GTK_PIZZA(m_wxwindow)->bin_window;
3353 else
3354 source = m_widget->window;
3355
3356 int org_x = 0;
3357 int org_y = 0;
3358 gdk_window_get_origin( source, &org_x, &org_y );
3359
3360 if (!m_wxwindow)
3361 {
3362 if (GTK_WIDGET_NO_WINDOW (m_widget))
3363 {
3364 org_x += m_widget->allocation.x;
3365 org_y += m_widget->allocation.y;
3366 }
3367 }
3368
3369 if (x) *x += org_x;
3370 if (y) *y += org_y;
3371 }
3372
3373 void wxWindowGTK::DoScreenToClient( int *x, int *y ) const
3374 {
3375 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3376
3377 if (!m_widget->window) return;
3378
3379 GdkWindow *source = (GdkWindow *) NULL;
3380 if (m_wxwindow)
3381 source = GTK_PIZZA(m_wxwindow)->bin_window;
3382 else
3383 source = m_widget->window;
3384
3385 int org_x = 0;
3386 int org_y = 0;
3387 gdk_window_get_origin( source, &org_x, &org_y );
3388
3389 if (!m_wxwindow)
3390 {
3391 if (GTK_WIDGET_NO_WINDOW (m_widget))
3392 {
3393 org_x += m_widget->allocation.x;
3394 org_y += m_widget->allocation.y;
3395 }
3396 }
3397
3398 if (x) *x -= org_x;
3399 if (y) *y -= org_y;
3400 }
3401
3402 bool wxWindowGTK::Show( bool show )
3403 {
3404 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3405
3406 if (!wxWindowBase::Show(show))
3407 {
3408 // nothing to do
3409 return FALSE;
3410 }
3411
3412 if (show)
3413 gtk_widget_show( m_widget );
3414 else
3415 gtk_widget_hide( m_widget );
3416
3417 wxShowEvent eventShow(GetId(), show);
3418 eventShow.SetEventObject(this);
3419
3420 GetEventHandler()->ProcessEvent(eventShow);
3421
3422 return TRUE;
3423 }
3424
3425 static void wxWindowNotifyEnable(wxWindowGTK* win, bool enable)
3426 {
3427 win->OnParentEnable(enable);
3428
3429 // Recurse, so that children have the opportunity to Do The Right Thing
3430 // and reset colours that have been messed up by a parent's (really ancestor's)
3431 // Enable call
3432 for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
3433 node;
3434 node = node->GetNext() )
3435 {
3436 wxWindow *child = node->GetData();
3437 if (!child->IsKindOf(CLASSINFO(wxDialog)) && !child->IsKindOf(CLASSINFO(wxFrame)))
3438 wxWindowNotifyEnable(child, enable);
3439 }
3440 }
3441
3442 bool wxWindowGTK::Enable( bool enable )
3443 {
3444 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3445
3446 if (!wxWindowBase::Enable(enable))
3447 {
3448 // nothing to do
3449 return FALSE;
3450 }
3451
3452 gtk_widget_set_sensitive( m_widget, enable );
3453 if ( m_wxwindow )
3454 gtk_widget_set_sensitive( m_wxwindow, enable );
3455
3456 wxWindowNotifyEnable(this, enable);
3457
3458 return TRUE;
3459 }
3460
3461 int wxWindowGTK::GetCharHeight() const
3462 {
3463 wxCHECK_MSG( (m_widget != NULL), 12, wxT("invalid window") );
3464
3465 wxFont font = GetFont();
3466 wxCHECK_MSG( font.Ok(), 12, wxT("invalid font") );
3467
3468 #ifdef __WXGTK20__
3469 PangoContext *context = NULL;
3470 if (m_widget)
3471 context = gtk_widget_get_pango_context( m_widget );
3472
3473 if (!context)
3474 return 0;
3475
3476 PangoFontDescription *desc = font.GetNativeFontInfo()->description;
3477 PangoLayout *layout = pango_layout_new(context);
3478 pango_layout_set_font_description(layout, desc);
3479 pango_layout_set_text(layout, "H", 1);
3480 PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
3481
3482 PangoRectangle rect;
3483 pango_layout_line_get_extents(line, NULL, &rect);
3484
3485 g_object_unref( G_OBJECT( layout ) );
3486
3487 return (int) PANGO_PIXELS(rect.height);
3488 #else
3489 GdkFont *gfont = font.GetInternalFont( 1.0 );
3490
3491 return gfont->ascent + gfont->descent;
3492 #endif
3493 }
3494
3495 int wxWindowGTK::GetCharWidth() const
3496 {
3497 wxCHECK_MSG( (m_widget != NULL), 8, wxT("invalid window") );
3498
3499 wxFont font = GetFont();
3500 wxCHECK_MSG( font.Ok(), 8, wxT("invalid font") );
3501
3502 #ifdef __WXGTK20__
3503 PangoContext *context = NULL;
3504 if (m_widget)
3505 context = gtk_widget_get_pango_context( m_widget );
3506
3507 if (!context)
3508 return 0;
3509
3510 PangoFontDescription *desc = font.GetNativeFontInfo()->description;
3511 PangoLayout *layout = pango_layout_new(context);
3512 pango_layout_set_font_description(layout, desc);
3513 pango_layout_set_text(layout, "g", 1);
3514 PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
3515
3516 PangoRectangle rect;
3517 pango_layout_line_get_extents(line, NULL, &rect);
3518
3519 g_object_unref( G_OBJECT( layout ) );
3520
3521 return (int) PANGO_PIXELS(rect.width);
3522 #else
3523 GdkFont *gfont = font.GetInternalFont( 1.0 );
3524
3525 return gdk_string_width( gfont, "g" );
3526 #endif
3527 }
3528
3529 void wxWindowGTK::GetTextExtent( const wxString& string,
3530 int *x,
3531 int *y,
3532 int *descent,
3533 int *externalLeading,
3534 const wxFont *theFont ) const
3535 {
3536 wxFont fontToUse = theFont ? *theFont : GetFont();
3537
3538 wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
3539
3540 if (string.IsEmpty())
3541 {
3542 if (x) (*x) = 0;
3543 if (y) (*y) = 0;
3544 return;
3545 }
3546
3547 #ifdef __WXGTK20__
3548 PangoContext *context = NULL;
3549 if (m_widget)
3550 context = gtk_widget_get_pango_context( m_widget );
3551
3552 if (!context)
3553 {
3554 if (x) (*x) = 0;
3555 if (y) (*y) = 0;
3556 return;
3557 }
3558
3559 PangoFontDescription *desc = fontToUse.GetNativeFontInfo()->description;
3560 PangoLayout *layout = pango_layout_new(context);
3561 pango_layout_set_font_description(layout, desc);
3562 {
3563 #if wxUSE_UNICODE
3564 const wxCharBuffer data = wxConvUTF8.cWC2MB( string );
3565 pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data ));
3566 #else
3567 const wxWCharBuffer wdata = wxConvLocal.cMB2WC( string );
3568 const wxCharBuffer data = wxConvUTF8.cWC2MB( wdata );
3569 pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data ));
3570 #endif
3571 }
3572
3573 PangoRectangle rect;
3574 pango_layout_get_extents(layout, NULL, &rect);
3575
3576 if (x) (*x) = (wxCoord) PANGO_PIXELS(rect.width);
3577 if (y) (*y) = (wxCoord) PANGO_PIXELS(rect.height);
3578 if (descent)
3579 {
3580 PangoLayoutIter *iter = pango_layout_get_iter(layout);
3581 int baseline = pango_layout_iter_get_baseline(iter);
3582 pango_layout_iter_free(iter);
3583 *descent = *y - PANGO_PIXELS(baseline);
3584 }
3585 if (externalLeading) (*externalLeading) = 0; // ??
3586
3587 g_object_unref( G_OBJECT( layout ) );
3588 #else
3589 GdkFont *font = fontToUse.GetInternalFont( 1.0 );
3590 if (x) (*x) = gdk_string_width( font, wxGTK_CONV( string ) );
3591 if (y) (*y) = font->ascent + font->descent;
3592 if (descent) (*descent) = font->descent;
3593 if (externalLeading) (*externalLeading) = 0; // ??
3594 #endif
3595 }
3596
3597 void wxWindowGTK::SetFocus()
3598 {
3599 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3600 if ( m_hasFocus )
3601 {
3602 // don't do anything if we already have focus
3603 return;
3604 }
3605
3606 if (m_wxwindow)
3607 {
3608 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
3609 {
3610 gtk_widget_grab_focus (m_wxwindow);
3611 }
3612 }
3613 else if (m_widget)
3614 {
3615 #ifdef __WXGTK20__
3616 if (GTK_IS_CONTAINER(m_widget))
3617 {
3618 gtk_widget_child_focus( m_widget, GTK_DIR_TAB_FORWARD );
3619 }
3620 else
3621 #endif
3622 if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
3623 {
3624
3625 if (!GTK_WIDGET_REALIZED(m_widget))
3626 {
3627 // we can't set the focus to the widget now so we remember that
3628 // it should be focused and will do it later, during the idle
3629 // time, as soon as we can
3630 wxLogTrace(TRACE_FOCUS,
3631 _T("Delaying setting focus to %s(%s)"),
3632 GetClassInfo()->GetClassName(), GetLabel().c_str());
3633
3634 g_delayedFocus = this;
3635 }
3636 else
3637 {
3638 wxLogTrace(TRACE_FOCUS,
3639 _T("Setting focus to %s(%s)"),
3640 GetClassInfo()->GetClassName(), GetLabel().c_str());
3641
3642 gtk_widget_grab_focus (m_widget);
3643 }
3644 }
3645 else
3646 #ifndef __WXGTK20__
3647 if (GTK_IS_CONTAINER(m_widget))
3648 {
3649 gtk_container_focus( GTK_CONTAINER(m_widget), GTK_DIR_TAB_FORWARD );
3650 }
3651 else
3652 #endif
3653 {
3654 wxLogTrace(TRACE_FOCUS,
3655 _T("Can't set focus to %s(%s)"),
3656 GetClassInfo()->GetClassName(), GetLabel().c_str());
3657 }
3658 }
3659 }
3660
3661 bool wxWindowGTK::AcceptsFocus() const
3662 {
3663 return m_acceptsFocus && wxWindowBase::AcceptsFocus();
3664 }
3665
3666 bool wxWindowGTK::Reparent( wxWindowBase *newParentBase )
3667 {
3668 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3669
3670 wxWindowGTK *oldParent = m_parent,
3671 *newParent = (wxWindowGTK *)newParentBase;
3672
3673 wxASSERT( GTK_IS_WIDGET(m_widget) );
3674
3675 if ( !wxWindowBase::Reparent(newParent) )
3676 return FALSE;
3677
3678 wxASSERT( GTK_IS_WIDGET(m_widget) );
3679
3680 /* prevent GTK from deleting the widget arbitrarily */
3681 gtk_widget_ref( m_widget );
3682
3683 if (oldParent)
3684 {
3685 gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget );
3686 }
3687
3688 wxASSERT( GTK_IS_WIDGET(m_widget) );
3689
3690 if (newParent)
3691 {
3692 /* insert GTK representation */
3693 (*(newParent->m_insertCallback))(newParent, this);
3694 }
3695
3696 /* reverse: prevent GTK from deleting the widget arbitrarily */
3697 gtk_widget_unref( m_widget );
3698
3699 return TRUE;
3700 }
3701
3702 void wxWindowGTK::DoAddChild(wxWindowGTK *child)
3703 {
3704 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
3705
3706 wxASSERT_MSG( (child != NULL), wxT("invalid child window") );
3707
3708 wxASSERT_MSG( (m_insertCallback != NULL), wxT("invalid child insertion function") );
3709
3710 /* add to list */
3711 AddChild( child );
3712
3713 /* insert GTK representation */
3714 (*m_insertCallback)(this, child);
3715 }
3716
3717 #ifdef __WXGTK20__
3718
3719 void wxWindowGTK::AddChild(wxWindowBase *child)
3720 {
3721 wxWindowBase::AddChild(child);
3722 m_dirtyTabOrder = true;
3723 if (g_isIdle)
3724 wxapp_install_idle_handler();
3725 }
3726
3727 void wxWindowGTK::RemoveChild(wxWindowBase *child)
3728 {
3729 wxWindowBase::RemoveChild(child);
3730 m_dirtyTabOrder = true;
3731 if (g_isIdle)
3732 wxapp_install_idle_handler();
3733 }
3734
3735 void wxWindowGTK::DoMoveInTabOrder(wxWindow *win, MoveKind move)
3736 {
3737 wxWindowBase::DoMoveInTabOrder(win, move);
3738 m_dirtyTabOrder = true;
3739 if (g_isIdle)
3740 wxapp_install_idle_handler();
3741 }
3742
3743 void wxWindowGTK::RealizeTabOrder()
3744 {
3745 if (m_wxwindow)
3746 {
3747 if (m_children.size() > 0)
3748 {
3749 GList *chain = NULL;
3750
3751 for (wxWindowList::const_iterator i = m_children.begin();
3752 i != m_children.end(); ++i)
3753 {
3754 chain = g_list_prepend(chain, (*i)->m_widget);
3755 }
3756
3757 chain = g_list_reverse(chain);
3758
3759 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow), chain);
3760 g_list_free(chain);
3761 }
3762 else
3763 {
3764 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow));
3765 }
3766 }
3767
3768 m_dirtyTabOrder = false;
3769 }
3770
3771 #endif // __WXGTK20__
3772
3773 void wxWindowGTK::Raise()
3774 {
3775 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3776
3777 if (m_wxwindow && m_wxwindow->window)
3778 {
3779 gdk_window_raise( m_wxwindow->window );
3780 }
3781 else if (m_widget->window)
3782 {
3783 gdk_window_raise( m_widget->window );
3784 }
3785 }
3786
3787 void wxWindowGTK::Lower()
3788 {
3789 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3790
3791 if (m_wxwindow && m_wxwindow->window)
3792 {
3793 gdk_window_lower( m_wxwindow->window );
3794 }
3795 else if (m_widget->window)
3796 {
3797 gdk_window_lower( m_widget->window );
3798 }
3799 }
3800
3801 bool wxWindowGTK::SetCursor( const wxCursor &cursor )
3802 {
3803 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3804
3805 if (cursor == m_cursor)
3806 return FALSE;
3807
3808 if (g_isIdle)
3809 wxapp_install_idle_handler();
3810
3811 if (cursor == wxNullCursor)
3812 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR );
3813 else
3814 return wxWindowBase::SetCursor( cursor );
3815 }
3816
3817 void wxWindowGTK::WarpPointer( int x, int y )
3818 {
3819 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3820
3821 // We provide this function ourselves as it is
3822 // missing in GDK (top of this file).
3823
3824 GdkWindow *window = (GdkWindow*) NULL;
3825 if (m_wxwindow)
3826 window = GTK_PIZZA(m_wxwindow)->bin_window;
3827 else
3828 window = GetConnectWidget()->window;
3829
3830 if (window)
3831 gdk_window_warp_pointer( window, x, y );
3832 }
3833
3834
3835 void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
3836 {
3837 if (!m_widget) return;
3838 if (!m_widget->window) return;
3839
3840 #ifndef __WXGTK20__
3841 if (g_isIdle)
3842 wxapp_install_idle_handler();
3843
3844 wxRect myRect(0,0,0,0);
3845 if (m_wxwindow && rect)
3846 {
3847 myRect.SetSize(wxSize( m_wxwindow->allocation.width,
3848 m_wxwindow->allocation.height));
3849 myRect.Intersect(*rect);
3850 if (!myRect.width || !myRect.height)
3851 // nothing to do, rectangle is empty
3852 return;
3853 rect = &myRect;
3854 }
3855
3856 if (eraseBackground && m_wxwindow && m_wxwindow->window)
3857 {
3858 if (rect)
3859 {
3860 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3861 m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height );
3862 }
3863 else
3864 {
3865 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3866 m_clearRegion.Clear();
3867 m_clearRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
3868 }
3869 }
3870
3871 if (rect)
3872 {
3873 if (m_wxwindow)
3874 {
3875 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3876 m_updateRegion.Union( rect->x, rect->y, rect->width, rect->height );
3877 }
3878 else
3879 {
3880 GdkRectangle gdk_rect;
3881 gdk_rect.x = rect->x;
3882 gdk_rect.y = rect->y;
3883 gdk_rect.width = rect->width;
3884 gdk_rect.height = rect->height;
3885 gtk_widget_draw( m_widget, &gdk_rect );
3886 }
3887 }
3888 else
3889 {
3890 if (m_wxwindow)
3891 {
3892 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3893 m_updateRegion.Clear();
3894 m_updateRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
3895 }
3896 else
3897 {
3898 gtk_widget_draw( m_widget, (GdkRectangle*) NULL );
3899 }
3900 }
3901 #else
3902 if (m_wxwindow)
3903 {
3904 if (rect)
3905 {
3906 GdkRectangle gdk_rect;
3907 gdk_rect.x = rect->x;
3908 gdk_rect.y = rect->y;
3909 gdk_rect.width = rect->width;
3910 gdk_rect.height = rect->height;
3911 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow)->bin_window, &gdk_rect, TRUE );
3912 }
3913 else
3914 {
3915 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow)->bin_window, NULL, TRUE );
3916 }
3917 }
3918 #endif
3919 }
3920
3921 void wxWindowGTK::Update()
3922 {
3923 GtkUpdate();
3924 }
3925
3926 void wxWindowGTK::GtkUpdate()
3927 {
3928 #ifdef __WXGTK20__
3929 if (m_wxwindow && GTK_PIZZA(m_wxwindow)->bin_window)
3930 gdk_window_process_updates( GTK_PIZZA(m_wxwindow)->bin_window, FALSE );
3931 #else
3932 if (!m_updateRegion.IsEmpty())
3933 GtkSendPaintEvents();
3934 #endif
3935 }
3936
3937 void wxWindowGTK::GtkSendPaintEvents()
3938 {
3939 if (!m_wxwindow)
3940 {
3941 #ifndef __WXGTK20__
3942 m_clearRegion.Clear();
3943 #endif
3944 m_updateRegion.Clear();
3945 return;
3946 }
3947
3948 // Clip to paint region in wxClientDC
3949 m_clipPaintRegion = TRUE;
3950
3951 // widget to draw on
3952 GtkPizza *pizza = GTK_PIZZA (m_wxwindow);
3953
3954 if (GetThemeEnabled() && GetBackgroundStyle() == wxBG_STYLE_SYSTEM)
3955 {
3956 // find ancestor from which to steal background
3957 wxWindow *parent = GetParent();
3958 while (parent && !parent->IsTopLevel())
3959 parent = parent->GetParent();
3960 if (!parent)
3961 parent = (wxWindow*)this;
3962
3963 if (GTK_WIDGET_MAPPED(parent->m_widget))
3964 {
3965 wxRegionIterator upd( m_updateRegion );
3966 while (upd)
3967 {
3968 GdkRectangle rect;
3969 rect.x = upd.GetX();
3970 rect.y = upd.GetY();
3971 rect.width = upd.GetWidth();
3972 rect.height = upd.GetHeight();
3973
3974 gtk_paint_flat_box( parent->m_widget->style,
3975 pizza->bin_window,
3976 (GtkStateType)GTK_WIDGET_STATE(m_wxwindow),
3977 GTK_SHADOW_NONE,
3978 &rect,
3979 parent->m_widget,
3980 (char *)"base",
3981 0, 0, -1, -1 );
3982
3983 upd ++;
3984 }
3985 }
3986 }
3987 else
3988
3989 #ifdef __WXGTK20__
3990 {
3991 wxWindowDC dc( (wxWindow*)this );
3992 dc.SetClippingRegion( m_updateRegion );
3993
3994 wxEraseEvent erase_event( GetId(), &dc );
3995 erase_event.SetEventObject( this );
3996
3997 GetEventHandler()->ProcessEvent(erase_event);
3998 }
3999 #else
4000 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
4001 {
4002 wxWindowDC dc( (wxWindow*)this );
4003 if (m_clearRegion.IsEmpty())
4004 dc.SetClippingRegion( m_updateRegion );
4005 else
4006 dc.SetClippingRegion( m_clearRegion );
4007
4008 wxEraseEvent erase_event( GetId(), &dc );
4009 erase_event.SetEventObject( this );
4010
4011 if (!GetEventHandler()->ProcessEvent(erase_event) && GetBackgroundStyle() != wxBG_STYLE_CUSTOM)
4012 {
4013 if (!g_eraseGC)
4014 {
4015 g_eraseGC = gdk_gc_new( pizza->bin_window );
4016 gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4017 }
4018 gdk_gc_set_foreground( g_eraseGC, GetBackgroundColour().GetColor() );
4019
4020 wxRegionIterator upd( m_clearRegion );
4021 while (upd)
4022 {
4023 gdk_draw_rectangle( pizza->bin_window, g_eraseGC, 1,
4024 upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
4025 upd ++;
4026 }
4027 }
4028 m_clearRegion.Clear();
4029 }
4030 #endif
4031
4032 wxNcPaintEvent nc_paint_event( GetId() );
4033 nc_paint_event.SetEventObject( this );
4034 GetEventHandler()->ProcessEvent( nc_paint_event );
4035
4036 wxPaintEvent paint_event( GetId() );
4037 paint_event.SetEventObject( this );
4038 GetEventHandler()->ProcessEvent( paint_event );
4039
4040 m_clipPaintRegion = FALSE;
4041
4042 #ifndef __WXUNIVERSAL__
4043 #ifndef __WXGTK20__
4044 // The following code will result in all window-less widgets
4045 // being redrawn because the wxWidgets class is allowed to
4046 // paint over the window-less widgets.
4047
4048 GList *children = pizza->children;
4049 while (children)
4050 {
4051 GtkPizzaChild *child = (GtkPizzaChild*) children->data;
4052 children = children->next;
4053
4054 if (GTK_WIDGET_NO_WINDOW (child->widget) &&
4055 GTK_WIDGET_DRAWABLE (child->widget))
4056 {
4057 // Get intersection of widget area and update region
4058 wxRegion region( m_updateRegion );
4059
4060 GdkEventExpose gdk_event;
4061 gdk_event.type = GDK_EXPOSE;
4062 gdk_event.window = pizza->bin_window;
4063 gdk_event.count = 0;
4064
4065 wxRegionIterator upd( m_updateRegion );
4066 while (upd)
4067 {
4068 GdkRectangle rect;
4069 rect.x = upd.GetX();
4070 rect.y = upd.GetY();
4071 rect.width = upd.GetWidth();
4072 rect.height = upd.GetHeight();
4073
4074 if (gtk_widget_intersect (child->widget, &rect, &gdk_event.area))
4075 {
4076 gtk_widget_event (child->widget, (GdkEvent*) &gdk_event);
4077 }
4078
4079 upd ++;
4080 }
4081 }
4082 }
4083 #endif
4084 #endif
4085
4086 m_updateRegion.Clear();
4087 }
4088
4089 void wxWindowGTK::ClearBackground()
4090 {
4091 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4092
4093 #ifndef __WXGTK20__
4094 if (m_wxwindow && m_wxwindow->window)
4095 {
4096 m_clearRegion.Clear();
4097 wxSize size( GetClientSize() );
4098 m_clearRegion.Union( 0,0,size.x,size.y );
4099
4100 // Better do this in idle?
4101 GtkUpdate();
4102 }
4103 #endif
4104 }
4105
4106 #if wxUSE_TOOLTIPS
4107 void wxWindowGTK::DoSetToolTip( wxToolTip *tip )
4108 {
4109 wxWindowBase::DoSetToolTip(tip);
4110
4111 if (m_tooltip)
4112 m_tooltip->Apply( (wxWindow *)this );
4113 }
4114
4115 void wxWindowGTK::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
4116 {
4117 wxString tmp( tip );
4118 gtk_tooltips_set_tip( tips, GetConnectWidget(), wxGTK_CONV(tmp), (gchar*) NULL );
4119 }
4120 #endif // wxUSE_TOOLTIPS
4121
4122 bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
4123 {
4124 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
4125
4126 if (!wxWindowBase::SetBackgroundColour(colour))
4127 return false;
4128
4129 if (colour.Ok())
4130 {
4131 // We need the pixel value e.g. for background clearing.
4132 m_backgroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
4133 }
4134
4135 // apply style change (forceStyle=true so that new style is applied
4136 // even if the bg colour changed from valid to wxNullColour)
4137 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM)
4138 ApplyWidgetStyle(true);
4139
4140 return true;
4141 }
4142
4143 bool wxWindowGTK::SetForegroundColour( const wxColour &colour )
4144 {
4145 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
4146
4147 if (!wxWindowBase::SetForegroundColour(colour))
4148 {
4149 return false;
4150 }
4151
4152 if (colour.Ok())
4153 {
4154 // We need the pixel value e.g. for background clearing.
4155 m_foregroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
4156 }
4157
4158 // apply style change (forceStyle=true so that new style is applied
4159 // even if the bg colour changed from valid to wxNullColour):
4160 ApplyWidgetStyle(true);
4161
4162 return true;
4163 }
4164
4165 #ifdef __WXGTK20__
4166 PangoContext *wxWindowGTK::GtkGetPangoDefaultContext()
4167 {
4168 return gtk_widget_get_pango_context( m_widget );
4169 }
4170
4171 PangoContext *wxWindowGTK::GtkGetPangoX11Context()
4172 {
4173 if (!m_x11Context)
4174 m_x11Context = pango_x_get_context( gdk_display );
4175
4176 return m_x11Context;
4177 }
4178 #endif
4179
4180 GtkRcStyle *wxWindowGTK::CreateWidgetStyle(bool forceStyle)
4181 {
4182 // do we need to apply any changes at all?
4183 if ( !forceStyle &&
4184 !m_font.Ok() &&
4185 !m_foregroundColour.Ok() && !m_backgroundColour.Ok() )
4186 {
4187 return NULL;
4188 }
4189
4190 GtkRcStyle *style = gtk_rc_style_new();
4191
4192 if ( m_font.Ok() )
4193 {
4194 #ifdef __WXGTK20__
4195 style->font_desc =
4196 pango_font_description_copy( m_font.GetNativeFontInfo()->description );
4197 #else
4198 wxString xfontname = m_font.GetNativeFontInfo()->GetXFontName();
4199 style->fontset_name = g_strdup(xfontname.c_str());
4200 #endif
4201 }
4202
4203 if ( m_foregroundColour.Ok() )
4204 {
4205 GdkColor *fg = m_foregroundColour.GetColor();
4206
4207 style->fg[GTK_STATE_NORMAL] = *fg;
4208 style->color_flags[GTK_STATE_NORMAL] = GTK_RC_FG;
4209
4210 style->fg[GTK_STATE_PRELIGHT] = *fg;
4211 style->color_flags[GTK_STATE_PRELIGHT] = GTK_RC_FG;
4212
4213 style->fg[GTK_STATE_ACTIVE] = *fg;
4214 style->color_flags[GTK_STATE_ACTIVE] = GTK_RC_FG;
4215 }
4216
4217 if ( m_backgroundColour.Ok() )
4218 {
4219 GdkColor *bg = m_backgroundColour.GetColor();
4220
4221 style->bg[GTK_STATE_NORMAL] = *bg;
4222 style->base[GTK_STATE_NORMAL] = *bg;
4223 style->color_flags[GTK_STATE_NORMAL] = (GtkRcFlags)
4224 (style->color_flags[GTK_STATE_NORMAL] | GTK_RC_BG | GTK_RC_BASE);
4225
4226 style->bg[GTK_STATE_PRELIGHT] = *bg;
4227 style->base[GTK_STATE_PRELIGHT] = *bg;
4228 style->color_flags[GTK_STATE_PRELIGHT] = (GtkRcFlags)
4229 (style->color_flags[GTK_STATE_PRELIGHT] | GTK_RC_BG | GTK_RC_BASE);
4230
4231 style->bg[GTK_STATE_ACTIVE] = *bg;
4232 style->base[GTK_STATE_ACTIVE] = *bg;
4233 style->color_flags[GTK_STATE_ACTIVE] = (GtkRcFlags)
4234 (style->color_flags[GTK_STATE_ACTIVE] | GTK_RC_BG | GTK_RC_BASE);
4235
4236 style->bg[GTK_STATE_INSENSITIVE] = *bg;
4237 style->base[GTK_STATE_INSENSITIVE] = *bg;
4238 style->color_flags[GTK_STATE_INSENSITIVE] = (GtkRcFlags)
4239 (style->color_flags[GTK_STATE_INSENSITIVE] | GTK_RC_BG | GTK_RC_BASE);
4240 }
4241
4242 return style;
4243 }
4244
4245 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle)
4246 {
4247 GtkRcStyle *style = CreateWidgetStyle(forceStyle);
4248 if ( style )
4249 {
4250 DoApplyWidgetStyle(style);
4251 gtk_rc_style_unref(style);
4252 }
4253
4254 // Style change may affect GTK+'s size calculation:
4255 InvalidateBestSize();
4256 }
4257
4258 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle *style)
4259 {
4260 if (m_wxwindow)
4261 gtk_widget_modify_style(m_wxwindow, style);
4262 gtk_widget_modify_style(m_widget, style);
4263 }
4264
4265 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style)
4266 {
4267 wxWindowBase::SetBackgroundStyle(style);
4268
4269 if (style == wxBG_STYLE_CUSTOM)
4270 {
4271 GdkWindow *window = (GdkWindow*) NULL;
4272 if (m_wxwindow)
4273 window = GTK_PIZZA(m_wxwindow)->bin_window;
4274 else
4275 window = GetConnectWidget()->window;
4276
4277 if (window)
4278 {
4279 // Make sure GDK/X11 doesn't refresh the window
4280 // automatically.
4281 gdk_window_set_back_pixmap( window, None, False );
4282 #ifdef __X__
4283 Display* display = GDK_WINDOW_DISPLAY(window);
4284 XFlush(display);
4285 #endif
4286 m_needsStyleChange = false;
4287 }
4288 else
4289 // Do in OnIdle, because the window is not yet available
4290 m_needsStyleChange = true;
4291
4292 // Don't apply widget style, or we get a grey background
4293 }
4294 else
4295 {
4296 // apply style change (forceStyle=true so that new style is applied
4297 // even if the bg colour changed from valid to wxNullColour):
4298 ApplyWidgetStyle(true);
4299 }
4300 return true;
4301 }
4302
4303 //-----------------------------------------------------------------------------
4304 // Pop-up menu stuff
4305 //-----------------------------------------------------------------------------
4306
4307 #if wxUSE_MENUS_NATIVE
4308
4309 extern "C"
4310 void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting )
4311 {
4312 *is_waiting = FALSE;
4313 }
4314
4315 void SetInvokingWindow( wxMenu *menu, wxWindow* win )
4316 {
4317 menu->SetInvokingWindow( win );
4318
4319 wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst();
4320 while (node)
4321 {
4322 wxMenuItem *menuitem = node->GetData();
4323 if (menuitem->IsSubMenu())
4324 {
4325 SetInvokingWindow( menuitem->GetSubMenu(), win );
4326 }
4327
4328 node = node->GetNext();
4329 }
4330 }
4331
4332 extern "C" void wxPopupMenuPositionCallback( GtkMenu *menu,
4333 gint *x, gint *y,
4334 #ifdef __WXGTK20__
4335 gboolean * WXUNUSED(whatever),
4336 #endif
4337 gpointer user_data )
4338 {
4339 // ensure that the menu appears entirely on screen
4340 GtkRequisition req;
4341 gtk_widget_get_child_requisition(GTK_WIDGET(menu), &req);
4342
4343 wxSize sizeScreen = wxGetDisplaySize();
4344 wxPoint *pos = (wxPoint*)user_data;
4345
4346 gint xmax = sizeScreen.x - req.width,
4347 ymax = sizeScreen.y - req.height;
4348
4349 *x = pos->x < xmax ? pos->x : xmax;
4350 *y = pos->y < ymax ? pos->y : ymax;
4351 }
4352
4353 bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
4354 {
4355 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
4356
4357 wxCHECK_MSG( menu != NULL, false, wxT("invalid popup-menu") );
4358
4359 // NOTE: if you change this code, you need to update
4360 // the same code in taskbar.cpp as well. This
4361 // is ugly code duplication, I know,
4362
4363 SetInvokingWindow( menu, this );
4364
4365 menu->UpdateUI();
4366
4367 bool is_waiting = true;
4368
4369 gulong handler = gtk_signal_connect( GTK_OBJECT(menu->m_menu),
4370 "hide",
4371 GTK_SIGNAL_FUNC(gtk_pop_hide_callback),
4372 (gpointer)&is_waiting );
4373
4374 wxPoint pos;
4375 gpointer userdata;
4376 GtkMenuPositionFunc posfunc;
4377 if ( x == -1 && y == -1 )
4378 {
4379 // use GTK's default positioning algorithm
4380 userdata = NULL;
4381 posfunc = NULL;
4382 }
4383 else
4384 {
4385 pos = ClientToScreen(wxPoint(x, y));
4386 userdata = &pos;
4387 posfunc = wxPopupMenuPositionCallback;
4388 }
4389
4390 gtk_menu_popup(
4391 GTK_MENU(menu->m_menu),
4392 (GtkWidget *) NULL, // parent menu shell
4393 (GtkWidget *) NULL, // parent menu item
4394 posfunc, // function to position it
4395 userdata, // client data
4396 0, // button used to activate it
4397 #ifdef __WXGTK20__
4398 gtk_get_current_event_time()
4399 #else
4400 gs_timeLastClick // the time of activation
4401 #endif
4402 );
4403
4404 while (is_waiting)
4405 {
4406 gtk_main_iteration();
4407 }
4408
4409 gtk_signal_disconnect(GTK_OBJECT(menu->m_menu), handler);
4410
4411 return true;
4412 }
4413
4414 #endif // wxUSE_MENUS_NATIVE
4415
4416 #if wxUSE_DRAG_AND_DROP
4417
4418 void wxWindowGTK::SetDropTarget( wxDropTarget *dropTarget )
4419 {
4420 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4421
4422 GtkWidget *dnd_widget = GetConnectWidget();
4423
4424 if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
4425
4426 if (m_dropTarget) delete m_dropTarget;
4427 m_dropTarget = dropTarget;
4428
4429 if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
4430 }
4431
4432 #endif // wxUSE_DRAG_AND_DROP
4433
4434 GtkWidget* wxWindowGTK::GetConnectWidget()
4435 {
4436 GtkWidget *connect_widget = m_widget;
4437 if (m_wxwindow) connect_widget = m_wxwindow;
4438
4439 return connect_widget;
4440 }
4441
4442 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow *window )
4443 {
4444 if (m_wxwindow)
4445 return (window == GTK_PIZZA(m_wxwindow)->bin_window);
4446
4447 return (window == m_widget->window);
4448 }
4449
4450 bool wxWindowGTK::SetFont( const wxFont &font )
4451 {
4452 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
4453
4454 if (!wxWindowBase::SetFont(font))
4455 return false;
4456
4457 // apply style change (forceStyle=true so that new style is applied
4458 // even if the font changed from valid to wxNullFont):
4459 ApplyWidgetStyle(true);
4460
4461 return true;
4462 }
4463
4464 void wxWindowGTK::DoCaptureMouse()
4465 {
4466 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4467
4468 GdkWindow *window = (GdkWindow*) NULL;
4469 if (m_wxwindow)
4470 window = GTK_PIZZA(m_wxwindow)->bin_window;
4471 else
4472 window = GetConnectWidget()->window;
4473
4474 wxCHECK_RET( window, _T("CaptureMouse() failed") );
4475
4476 wxCursor* cursor = & m_cursor;
4477 if (!cursor->Ok())
4478 cursor = wxSTANDARD_CURSOR;
4479
4480 gdk_pointer_grab( window, FALSE,
4481 (GdkEventMask)
4482 (GDK_BUTTON_PRESS_MASK |
4483 GDK_BUTTON_RELEASE_MASK |
4484 GDK_POINTER_MOTION_HINT_MASK |
4485 GDK_POINTER_MOTION_MASK),
4486 (GdkWindow *) NULL,
4487 cursor->GetCursor(),
4488 (guint32)GDK_CURRENT_TIME );
4489 g_captureWindow = this;
4490 g_captureWindowHasMouse = TRUE;
4491 }
4492
4493 void wxWindowGTK::DoReleaseMouse()
4494 {
4495 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4496
4497 wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") );
4498
4499 g_captureWindow = (wxWindowGTK*) NULL;
4500
4501 GdkWindow *window = (GdkWindow*) NULL;
4502 if (m_wxwindow)
4503 window = GTK_PIZZA(m_wxwindow)->bin_window;
4504 else
4505 window = GetConnectWidget()->window;
4506
4507 if (!window)
4508 return;
4509
4510 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
4511 }
4512
4513 /* static */
4514 wxWindow *wxWindowBase::GetCapture()
4515 {
4516 return (wxWindow *)g_captureWindow;
4517 }
4518
4519 bool wxWindowGTK::IsRetained() const
4520 {
4521 return FALSE;
4522 }
4523
4524 void wxWindowGTK::SetScrollbar( int orient, int pos, int thumbVisible,
4525 int range, bool refresh )
4526 {
4527 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4528
4529 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
4530
4531 m_hasScrolling = TRUE;
4532
4533 if (orient == wxHORIZONTAL)
4534 {
4535 float fpos = (float)pos;
4536 float frange = (float)range;
4537 float fthumb = (float)thumbVisible;
4538 if (fpos > frange-fthumb) fpos = frange-fthumb;
4539 if (fpos < 0.0) fpos = 0.0;
4540
4541 if ((fabs(frange-m_hAdjust->upper) < 0.2) &&
4542 (fabs(fthumb-m_hAdjust->page_size) < 0.2))
4543 {
4544 SetScrollPos( orient, pos, refresh );
4545 return;
4546 }
4547
4548 m_oldHorizontalPos = fpos;
4549
4550 m_hAdjust->lower = 0.0;
4551 m_hAdjust->upper = frange;
4552 m_hAdjust->value = fpos;
4553 m_hAdjust->step_increment = 1.0;
4554 m_hAdjust->page_increment = (float)(wxMax(fthumb,0));
4555 m_hAdjust->page_size = fthumb;
4556 }
4557 else
4558 {
4559 float fpos = (float)pos;
4560 float frange = (float)range;
4561 float fthumb = (float)thumbVisible;
4562 if (fpos > frange-fthumb) fpos = frange-fthumb;
4563 if (fpos < 0.0) fpos = 0.0;
4564
4565 if ((fabs(frange-m_vAdjust->upper) < 0.2) &&
4566 (fabs(fthumb-m_vAdjust->page_size) < 0.2))
4567 {
4568 SetScrollPos( orient, pos, refresh );
4569 return;
4570 }
4571
4572 m_oldVerticalPos = fpos;
4573
4574 m_vAdjust->lower = 0.0;
4575 m_vAdjust->upper = frange;
4576 m_vAdjust->value = fpos;
4577 m_vAdjust->step_increment = 1.0;
4578 m_vAdjust->page_increment = (float)(wxMax(fthumb,0));
4579 m_vAdjust->page_size = fthumb;
4580 }
4581
4582 if (orient == wxHORIZONTAL)
4583 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
4584 else
4585 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
4586 }
4587
4588 void wxWindowGTK::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
4589 {
4590 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4591
4592 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
4593
4594 if (orient == wxHORIZONTAL)
4595 {
4596 float fpos = (float)pos;
4597 if (fpos > m_hAdjust->upper - m_hAdjust->page_size) fpos = m_hAdjust->upper - m_hAdjust->page_size;
4598 if (fpos < 0.0) fpos = 0.0;
4599 m_oldHorizontalPos = fpos;
4600
4601 if (fabs(fpos-m_hAdjust->value) < 0.2) return;
4602 m_hAdjust->value = fpos;
4603 }
4604 else
4605 {
4606 float fpos = (float)pos;
4607 if (fpos > m_vAdjust->upper - m_vAdjust->page_size) fpos = m_vAdjust->upper - m_vAdjust->page_size;
4608 if (fpos < 0.0) fpos = 0.0;
4609 m_oldVerticalPos = fpos;
4610
4611 if (fabs(fpos-m_vAdjust->value) < 0.2) return;
4612 m_vAdjust->value = fpos;
4613 }
4614
4615 if (m_wxwindow->window)
4616 {
4617 if (orient == wxHORIZONTAL)
4618 {
4619 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust),
4620 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
4621
4622 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
4623
4624 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
4625 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
4626 }
4627 else
4628 {
4629 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust),
4630 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
4631
4632 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
4633
4634 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
4635 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
4636 }
4637 }
4638 }
4639
4640 int wxWindowGTK::GetScrollThumb( int orient ) const
4641 {
4642 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
4643
4644 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
4645
4646 if (orient == wxHORIZONTAL)
4647 return (int)(m_hAdjust->page_size+0.5);
4648 else
4649 return (int)(m_vAdjust->page_size+0.5);
4650 }
4651
4652 int wxWindowGTK::GetScrollPos( int orient ) const
4653 {
4654 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
4655
4656 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
4657
4658 if (orient == wxHORIZONTAL)
4659 return (int)(m_hAdjust->value+0.5);
4660 else
4661 return (int)(m_vAdjust->value+0.5);
4662 }
4663
4664 int wxWindowGTK::GetScrollRange( int orient ) const
4665 {
4666 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
4667
4668 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
4669
4670 if (orient == wxHORIZONTAL)
4671 return (int)(m_hAdjust->upper+0.5);
4672 else
4673 return (int)(m_vAdjust->upper+0.5);
4674 }
4675
4676 void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
4677 {
4678 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4679
4680 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
4681
4682 // No scrolling requested.
4683 if ((dx == 0) && (dy == 0)) return;
4684
4685 #ifndef __WXGTK20__
4686 if (!m_updateRegion.IsEmpty())
4687 {
4688 m_updateRegion.Offset( dx, dy );
4689
4690 int cw = 0;
4691 int ch = 0;
4692 GetClientSize( &cw, &ch );
4693 m_updateRegion.Intersect( 0, 0, cw, ch );
4694 }
4695
4696 if (!m_clearRegion.IsEmpty())
4697 {
4698 m_clearRegion.Offset( dx, dy );
4699
4700 int cw = 0;
4701 int ch = 0;
4702 GetClientSize( &cw, &ch );
4703 m_clearRegion.Intersect( 0, 0, cw, ch );
4704 }
4705 #endif
4706
4707 m_clipPaintRegion = TRUE;
4708
4709 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
4710
4711 m_clipPaintRegion = FALSE;
4712 }
4713
4714
4715 // Find the wxWindow at the current mouse position, also returning the mouse
4716 // position.
4717 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
4718 {
4719 pt = wxGetMousePosition();
4720 wxWindow* found = wxFindWindowAtPoint(pt);
4721 return found;
4722 }
4723
4724 // Get the current mouse position.
4725 wxPoint wxGetMousePosition()
4726 {
4727 /* This crashes when used within wxHelpContext,
4728 so we have to use the X-specific implementation below.
4729 gint x, y;
4730 GdkModifierType *mask;
4731 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4732
4733 return wxPoint(x, y);
4734 */
4735
4736 int x, y;
4737 GdkWindow* windowAtPtr = gdk_window_at_pointer(& x, & y);
4738
4739 Display *display = windowAtPtr ? GDK_WINDOW_XDISPLAY(windowAtPtr) : GDK_DISPLAY();
4740 Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
4741 Window rootReturn, childReturn;
4742 int rootX, rootY, winX, winY;
4743 unsigned int maskReturn;
4744
4745 XQueryPointer (display,
4746 rootWindow,
4747 &rootReturn,
4748 &childReturn,
4749 &rootX, &rootY, &winX, &winY, &maskReturn);
4750 return wxPoint(rootX, rootY);
4751
4752 }
4753
4754 // ----------------------------------------------------------------------------
4755 // wxDCModule
4756 // ----------------------------------------------------------------------------
4757
4758 class wxWinModule : public wxModule
4759 {
4760 public:
4761 bool OnInit();
4762 void OnExit();
4763
4764 private:
4765 DECLARE_DYNAMIC_CLASS(wxWinModule)
4766 };
4767
4768 IMPLEMENT_DYNAMIC_CLASS(wxWinModule, wxModule)
4769
4770 bool wxWinModule::OnInit()
4771 {
4772 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4773 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4774
4775 return TRUE;
4776 }
4777
4778 void wxWinModule::OnExit()
4779 {
4780 if (g_eraseGC)
4781 gdk_gc_unref( g_eraseGC );
4782 }
4783
4784 // vi:sts=4:sw=4:et