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