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