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