Trying to get default button placement and size right.
[wxWidgets.git] / src / gtk1 / window.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10
11 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
12 #pragma implementation "window.h"
13 #endif
14
15 // For compilers that support precompilation, includes "wx.h".
16 #include "wx/wxprec.h"
17
18 #ifdef __VMS
19 #define XWarpPointer XWARPPOINTER
20 #endif
21
22 #include "wx/window.h"
23 #include "wx/dcclient.h"
24 #include "wx/frame.h"
25 #include "wx/app.h"
26 #include "wx/layout.h"
27 #include "wx/utils.h"
28 #include "wx/dialog.h"
29 #include "wx/msgdlg.h"
30 #include "wx/module.h"
31 #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 wxGetMousePosition( &x, &y );
1004 win->ScreenToClient( &x, &y );
1005 event.m_x = x;
1006 event.m_y = y;
1007 event.SetEventObject( win );
1008 }
1009
1010
1011 static bool
1012 wxTranslateGTKKeyEventToWx(wxKeyEvent& event,
1013 wxWindowGTK *win,
1014 GdkEventKey *gdk_event)
1015 {
1016 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
1017 // but only event->keyval which is quite useless to us, so remember
1018 // the last character from GDK_KEY_PRESS and reuse it as last resort
1019 //
1020 // NB: should be MT-safe as we're always called from the main thread only
1021 static struct
1022 {
1023 KeySym keysym;
1024 long keycode;
1025 } s_lastKeyPress = { 0, 0 };
1026
1027 KeySym keysym = gdk_event->keyval;
1028
1029 wxLogTrace(TRACE_KEYS, _T("Key %s event: keysym = %ld"),
1030 event.GetEventType() == wxEVT_KEY_UP ? _T("release")
1031 : _T("press"),
1032 keysym);
1033
1034 long key_code = wxTranslateKeySymToWXKey(keysym, FALSE /* !isChar */);
1035
1036 if ( !key_code )
1037 {
1038 // do we have the translation or is it a plain ASCII character?
1039 if ( (gdk_event->length == 1) || wxIsAsciiKeysym(keysym) )
1040 {
1041 // we should use keysym if it is ASCII as X does some translations
1042 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
1043 // which we don't want here (but which we do use for OnChar())
1044 if ( !wxIsAsciiKeysym(keysym) )
1045 {
1046 keysym = (KeySym)gdk_event->string[0];
1047 }
1048
1049 // we want to always get the same key code when the same key is
1050 // pressed regardless of the state of the modifies, i.e. on a
1051 // standard US keyboard pressing '5' or '%' ('5' key with
1052 // Shift) should result in the same key code in OnKeyDown():
1053 // '5' (although OnChar() will get either '5' or '%').
1054 //
1055 // to do it we first translate keysym to keycode (== scan code)
1056 // and then back but always using the lower register
1057 Display *dpy = (Display *)wxGetDisplay();
1058 KeyCode keycode = XKeysymToKeycode(dpy, keysym);
1059
1060 wxLogTrace(TRACE_KEYS, _T("\t-> keycode %d"), keycode);
1061
1062 KeySym keysymNormalized = XKeycodeToKeysym(dpy, keycode, 0);
1063
1064 // use the normalized, i.e. lower register, keysym if we've
1065 // got one
1066 key_code = keysymNormalized ? keysymNormalized : keysym;
1067
1068 // as explained above, we want to have lower register key codes
1069 // normally but for the letter keys we want to have the upper ones
1070 //
1071 // NB: don't use XConvertCase() here, we want to do it for letters
1072 // only
1073 key_code = toupper(key_code);
1074 }
1075 else // non ASCII key, what to do?
1076 {
1077 // by default, ignore it
1078 key_code = 0;
1079
1080 // but if we have cached information from the last KEY_PRESS
1081 if ( gdk_event->type == GDK_KEY_RELEASE )
1082 {
1083 // then reuse it
1084 if ( keysym == s_lastKeyPress.keysym )
1085 {
1086 key_code = s_lastKeyPress.keycode;
1087 }
1088 }
1089 }
1090
1091 if ( gdk_event->type == GDK_KEY_PRESS )
1092 {
1093 // remember it to be reused for KEY_UP event later
1094 s_lastKeyPress.keysym = keysym;
1095 s_lastKeyPress.keycode = key_code;
1096 }
1097 }
1098
1099 wxLogTrace(TRACE_KEYS, _T("\t-> wxKeyCode %ld"), key_code);
1100
1101 // sending unknown key events doesn't really make sense
1102 if ( !key_code )
1103 return FALSE;
1104
1105 // now fill all the other fields
1106 wxFillOtherKeyEventFields(event, win, gdk_event);
1107
1108 event.m_keyCode = key_code;
1109
1110 return TRUE;
1111 }
1112
1113
1114 #ifdef __WXGTK20__
1115 struct wxGtkIMData
1116 {
1117 GtkIMContext *context;
1118 GdkEventKey *lastKeyEvent;
1119
1120 wxGtkIMData()
1121 {
1122 context = gtk_im_multicontext_new();
1123 lastKeyEvent = NULL;
1124 }
1125 ~wxGtkIMData()
1126 {
1127 g_object_unref(context);
1128 }
1129 };
1130 #endif
1131
1132 static gint gtk_window_key_press_callback( GtkWidget *widget,
1133 GdkEventKey *gdk_event,
1134 wxWindow *win )
1135 {
1136 DEBUG_MAIN_THREAD
1137
1138 if (g_isIdle)
1139 wxapp_install_idle_handler();
1140
1141 if (!win->m_hasVMT)
1142 return FALSE;
1143 if (g_blockEventsOnDrag)
1144 return FALSE;
1145
1146
1147 wxKeyEvent event( wxEVT_KEY_DOWN );
1148 bool ret = false;
1149 bool return_after_IM = false;
1150
1151 if( wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
1152 {
1153 // Emit KEY_DOWN event
1154 ret = win->GetEventHandler()->ProcessEvent( event );
1155 }
1156 else
1157 {
1158 // Return after IM processing as we cannot do
1159 // anything with it anyhow.
1160 return_after_IM = true;
1161 }
1162
1163 #ifdef __WXGTK20__
1164 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
1165 // When we get a key_press event here, it could be originate
1166 // from the current widget or its child widgets. However, only the widget
1167 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
1168 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
1169 // originated from its child widgets and shouldn't be passed to IM context.
1170 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
1171 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
1172 // widgets has both IM context and input focus, the event should be filtered
1173 // by gtk_im_context_filter_keypress().
1174 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
1175 if ((!ret) && (win->m_imData != NULL) && ( wxWindow::FindFocus() == win ))
1176 {
1177 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1178 // docs, if IM filter returns true, no further processing should be done.
1179 // we should send the key_down event anyway.
1180 bool intercepted_by_IM = gtk_im_context_filter_keypress(win->m_imData->context, gdk_event);
1181 win->m_imData->lastKeyEvent = NULL;
1182 if (intercepted_by_IM)
1183 {
1184 wxLogTrace(TRACE_KEYS, _T("Key event intercepted by IM"));
1185 return true;
1186 }
1187 }
1188 #endif
1189 if (return_after_IM)
1190 return true;
1191
1192 #ifndef __WXGTK20__
1193 // This is for GTK+ 1.2 only. The char event generatation for GTK+ 2.0 is done
1194 // in the "commit" handler.
1195
1196 // 2005.02.02 modified by Hong Jen Yee (hzysoft@sina.com.tw).
1197 // In GTK+ 1.2, strings sent by IMs are also regarded as key_press events whose
1198 // keyCodes cannot be recognized by wxWidgets. These MBCS strings, however, are
1199 // composed of more than one character, which means gdk_event->length will always
1200 // greater than one. When gtk_event->length == 1, this may be an ASCII character
1201 // and can be translated by wx. However, when MBCS characters are sent by IM,
1202 // gdk_event->length will >= 2. So neither should we pass it to accelerator table,
1203 // nor should we pass it to controls. The following explanation was excerpted
1204 // from GDK documentation.
1205 // gint length : the length of string.
1206 // gchar *string : a null-terminated multi-byte string containing the composed
1207 // characters resulting from the key press. When text is being input, in a GtkEntry
1208 // for example, it is these characters which should be added to the input buffer.
1209 // When using Input Methods to support internationalized text input, the composed
1210 // characters appear here after the pre-editing has been completed.
1211
1212 if ( (!ret) && (gdk_event->length > 1) ) // If this event contains a pre-edited string from IM.
1213 {
1214 // We should translate this key event into wxEVT_CHAR not wxEVT_KEY_DOWN.
1215 #if wxUSE_UNICODE // GTK+ 1.2 is not UTF-8 based.
1216 const wxWCharBuffer string = wxConvLocal.cMB2WC( gdk_event->string );
1217 if( !string )
1218 return false;
1219 #else
1220 const char* string = gdk_event->string;
1221 #endif
1222
1223 // Implement OnCharHook by checking ancesteror top level windows
1224 wxWindow *parent = win;
1225 while (parent && !parent->IsTopLevel())
1226 parent = parent->GetParent();
1227
1228 for( const wxChar* pstr = string; *pstr; pstr++ )
1229 {
1230 #if wxUSE_UNICODE
1231 event.m_uniChar = *pstr;
1232 // Backward compatible for ISO-8859-1
1233 event.m_keyCode = *pstr < 256 ? event.m_uniChar : 0;
1234 #else
1235 event.m_keyCode = *pstr;
1236 #endif
1237 if (parent)
1238 {
1239 event.SetEventType( wxEVT_CHAR_HOOK );
1240 ret = parent->GetEventHandler()->ProcessEvent( event );
1241 }
1242 if (!ret)
1243 {
1244 event.SetEventType(wxEVT_CHAR);
1245 win->GetEventHandler()->ProcessEvent( event );
1246 }
1247 }
1248 return true;
1249 }
1250
1251 #endif // #ifndef __WXGTK20__
1252
1253 #if wxUSE_ACCEL
1254 if (!ret)
1255 {
1256 wxWindowGTK *ancestor = win;
1257 while (ancestor)
1258 {
1259 int command = ancestor->GetAcceleratorTable()->GetCommand( event );
1260 if (command != -1)
1261 {
1262 wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
1263 ret = ancestor->GetEventHandler()->ProcessEvent( command_event );
1264 break;
1265 }
1266 if (ancestor->IsTopLevel())
1267 break;
1268 ancestor = ancestor->GetParent();
1269 }
1270 }
1271 #endif // wxUSE_ACCEL
1272
1273 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1274 // will only be sent if it is not in an accelerator table.
1275 if (!ret)
1276 {
1277 long key_code;
1278 KeySym keysym = gdk_event->keyval;
1279 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1280 key_code = wxTranslateKeySymToWXKey(keysym, TRUE /* isChar */);
1281 if ( !key_code )
1282 {
1283 if ( wxIsAsciiKeysym(keysym) )
1284 {
1285 // ASCII key
1286 key_code = (unsigned char)keysym;
1287 }
1288 // gdk_event->string is actually deprecated
1289 else if ( gdk_event->length == 1 )
1290 {
1291 key_code = (unsigned char)gdk_event->string[0];
1292 }
1293 }
1294
1295 if ( key_code )
1296 {
1297 wxLogTrace(TRACE_KEYS, _T("Char event: %ld"), key_code);
1298
1299 event.m_keyCode = key_code;
1300
1301 // Implement OnCharHook by checking ancesteror top level windows
1302 wxWindow *parent = win;
1303 while (parent && !parent->IsTopLevel())
1304 parent = parent->GetParent();
1305 if (parent)
1306 {
1307 event.SetEventType( wxEVT_CHAR_HOOK );
1308 ret = parent->GetEventHandler()->ProcessEvent( event );
1309 }
1310
1311 if (!ret)
1312 {
1313 event.SetEventType(wxEVT_CHAR);
1314 ret = win->GetEventHandler()->ProcessEvent( event );
1315 }
1316 }
1317 }
1318
1319
1320
1321
1322
1323 // win is a control: tab can be propagated up
1324 if ( !ret &&
1325 ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) &&
1326 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1327 // have this style, yet choose not to process this particular TAB in which
1328 // case TAB must still work as a navigational character
1329 // JS: enabling again to make consistent with other platforms
1330 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1331 // navigation behaviour)
1332 #if wxUSE_TEXTCTRL
1333 (! (win->HasFlag(wxTE_PROCESS_TAB) && win->IsKindOf(CLASSINFO(wxTextCtrl)) )) &&
1334 #endif
1335 win->GetParent() && (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) )
1336 {
1337 wxNavigationKeyEvent new_event;
1338 new_event.SetEventObject( win->GetParent() );
1339 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1340 new_event.SetDirection( (gdk_event->keyval == GDK_Tab) );
1341 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1342 new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) );
1343 new_event.SetCurrentFocus( win );
1344 ret = win->GetParent()->GetEventHandler()->ProcessEvent( new_event );
1345 }
1346
1347 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1348 if ( !ret &&
1349 (gdk_event->keyval == GDK_Escape) )
1350 {
1351 // however only do it if we have a Cancel button in the dialog,
1352 // otherwise the user code may get confused by the events from a
1353 // non-existing button and, worse, a wxButton might get button event
1354 // from another button which is not really expected
1355 wxWindow *winForCancel = win,
1356 *btnCancel = NULL;
1357 while ( winForCancel )
1358 {
1359 btnCancel = winForCancel->FindWindow(wxID_CANCEL);
1360 if ( btnCancel )
1361 {
1362 // found a cancel button
1363 break;
1364 }
1365
1366 if ( winForCancel->IsTopLevel() )
1367 {
1368 // no need to look further
1369 break;
1370 }
1371
1372 // maybe our parent has a cancel button?
1373 winForCancel = winForCancel->GetParent();
1374 }
1375
1376 if ( btnCancel )
1377 {
1378 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL);
1379 event.SetEventObject(btnCancel);
1380 ret = btnCancel->GetEventHandler()->ProcessEvent(event);
1381 }
1382 }
1383
1384 if (ret)
1385 {
1386 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
1387 return TRUE;
1388 }
1389
1390 return FALSE;
1391 }
1392
1393 #ifdef __WXGTK20__
1394 static void gtk_wxwindow_commit_cb (GtkIMContext *context,
1395 const gchar *str,
1396 wxWindow *window)
1397 {
1398 wxKeyEvent event( wxEVT_KEY_DOWN );
1399
1400 // take modifiers, cursor position, timestamp etc. from the last
1401 // key_press_event that was fed into Input Method:
1402 if (window->m_imData->lastKeyEvent)
1403 {
1404 wxFillOtherKeyEventFields(event,
1405 window, window->m_imData->lastKeyEvent);
1406 }
1407
1408 #if wxUSE_UNICODE
1409 const wxWCharBuffer data = wxConvUTF8.cMB2WC( (char*)str );
1410 #else
1411 const wxWCharBuffer wdata = wxConvUTF8.cMB2WC( (char*)str );
1412 const wxCharBuffer data = wxConvLocal.cWC2MB( wdata );
1413 #endif // wxUSE_UNICODE
1414 if( !(const wxChar*)data )
1415 return;
1416
1417 bool ret = false;
1418
1419 // Implement OnCharHook by checking ancestor top level windows
1420 wxWindow *parent = window;
1421 while (parent && !parent->IsTopLevel())
1422 parent = parent->GetParent();
1423
1424 for( const wxChar* pstr = data; *pstr; pstr++ )
1425 {
1426 #if wxUSE_UNICODE
1427 event.m_uniChar = *pstr;
1428 // Backward compatible for ISO-8859-1
1429 event.m_keyCode = *pstr < 256 ? event.m_uniChar : 0;
1430 wxLogTrace(TRACE_KEYS, _T("IM sent character '%c'"), event.m_uniChar);
1431 #else
1432 event.m_keyCode = *pstr;
1433 #endif // wxUSE_UNICODE
1434 if (parent)
1435 {
1436 event.SetEventType( wxEVT_CHAR_HOOK );
1437 ret = parent->GetEventHandler()->ProcessEvent( event );
1438 }
1439
1440 if (!ret)
1441 {
1442 event.SetEventType(wxEVT_CHAR);
1443 ret = window->GetEventHandler()->ProcessEvent( event );
1444 }
1445 }
1446 }
1447 #endif
1448
1449
1450 //-----------------------------------------------------------------------------
1451 // "key_release_event" from any window
1452 //-----------------------------------------------------------------------------
1453
1454 static gint gtk_window_key_release_callback( GtkWidget *widget,
1455 GdkEventKey *gdk_event,
1456 wxWindowGTK *win )
1457 {
1458 DEBUG_MAIN_THREAD
1459
1460 if (g_isIdle)
1461 wxapp_install_idle_handler();
1462
1463 if (!win->m_hasVMT)
1464 return FALSE;
1465
1466 if (g_blockEventsOnDrag)
1467 return FALSE;
1468
1469 wxKeyEvent event( wxEVT_KEY_UP );
1470 if ( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
1471 {
1472 // unknown key pressed, ignore (the event would be useless anyhow
1473 return FALSE;
1474 }
1475
1476 if ( !win->GetEventHandler()->ProcessEvent( event ) )
1477 return FALSE;
1478
1479 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_release_event" );
1480 return TRUE;
1481 }
1482
1483 // ============================================================================
1484 // the mouse events
1485 // ============================================================================
1486
1487 // ----------------------------------------------------------------------------
1488 // mouse event processing helpers
1489 // ----------------------------------------------------------------------------
1490
1491 // init wxMouseEvent with the info from GdkEventXXX struct
1492 template<typename T> void InitMouseEvent(wxWindowGTK *win,
1493 wxMouseEvent& event,
1494 T *gdk_event)
1495 {
1496 event.SetTimestamp( gdk_event->time );
1497 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1498 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1499 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1500 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1501 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1502 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1503 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1504 if (event.GetEventType() == wxEVT_MOUSEWHEEL)
1505 {
1506 event.m_linesPerAction = 3;
1507 event.m_wheelDelta = 120;
1508 if (((GdkEventButton*)gdk_event)->button == 4)
1509 event.m_wheelRotation = 120;
1510 else if (((GdkEventButton*)gdk_event)->button == 5)
1511 event.m_wheelRotation = -120;
1512 }
1513
1514 wxPoint pt = win->GetClientAreaOrigin();
1515 event.m_x = (wxCoord)gdk_event->x - pt.x;
1516 event.m_y = (wxCoord)gdk_event->y - pt.y;
1517
1518 event.SetEventObject( win );
1519 event.SetId( win->GetId() );
1520 event.SetTimestamp( gdk_event->time );
1521 }
1522
1523 static void AdjustEventButtonState(wxMouseEvent& event)
1524 {
1525 // GDK reports the old state of the button for a button press event, but
1526 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1527 // for a LEFT_DOWN event, not FALSE, so we will invert
1528 // left/right/middleDown for the corresponding click events
1529
1530 if ((event.GetEventType() == wxEVT_LEFT_DOWN) ||
1531 (event.GetEventType() == wxEVT_LEFT_DCLICK) ||
1532 (event.GetEventType() == wxEVT_LEFT_UP))
1533 {
1534 event.m_leftDown = !event.m_leftDown;
1535 return;
1536 }
1537
1538 if ((event.GetEventType() == wxEVT_MIDDLE_DOWN) ||
1539 (event.GetEventType() == wxEVT_MIDDLE_DCLICK) ||
1540 (event.GetEventType() == wxEVT_MIDDLE_UP))
1541 {
1542 event.m_middleDown = !event.m_middleDown;
1543 return;
1544 }
1545
1546 if ((event.GetEventType() == wxEVT_RIGHT_DOWN) ||
1547 (event.GetEventType() == wxEVT_RIGHT_DCLICK) ||
1548 (event.GetEventType() == wxEVT_RIGHT_UP))
1549 {
1550 event.m_rightDown = !event.m_rightDown;
1551 return;
1552 }
1553 }
1554
1555 // find the window to send the mouse event too
1556 static
1557 wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y)
1558 {
1559 wxCoord xx = x;
1560 wxCoord yy = y;
1561
1562 if (win->m_wxwindow)
1563 {
1564 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1565 xx += pizza->xoffset;
1566 yy += pizza->yoffset;
1567 }
1568
1569 wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
1570 while (node)
1571 {
1572 wxWindowGTK *child = node->GetData();
1573
1574 node = node->GetNext();
1575 if (!child->IsShown())
1576 continue;
1577
1578 if (child->IsTransparentForMouse())
1579 {
1580 // wxStaticBox is transparent in the box itself
1581 int xx1 = child->m_x;
1582 int yy1 = child->m_y;
1583 int xx2 = child->m_x + child->m_width;
1584 int yy2 = child->m_y + child->m_height;
1585
1586 // left
1587 if (((xx >= xx1) && (xx <= xx1+10) && (yy >= yy1) && (yy <= yy2)) ||
1588 // right
1589 ((xx >= xx2-10) && (xx <= xx2) && (yy >= yy1) && (yy <= yy2)) ||
1590 // top
1591 ((xx >= xx1) && (xx <= xx2) && (yy >= yy1) && (yy <= yy1+10)) ||
1592 // bottom
1593 ((xx >= xx1) && (xx <= xx2) && (yy >= yy2-1) && (yy <= yy2)))
1594 {
1595 win = child;
1596 x -= child->m_x;
1597 y -= child->m_y;
1598 break;
1599 }
1600
1601 }
1602 else
1603 {
1604 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1605 (child->m_x <= xx) &&
1606 (child->m_y <= yy) &&
1607 (child->m_x+child->m_width >= xx) &&
1608 (child->m_y+child->m_height >= yy))
1609 {
1610 win = child;
1611 x -= child->m_x;
1612 y -= child->m_y;
1613 break;
1614 }
1615 }
1616 }
1617
1618 return win;
1619 }
1620
1621 //-----------------------------------------------------------------------------
1622 // "button_press_event"
1623 //-----------------------------------------------------------------------------
1624
1625 static gint gtk_window_button_press_callback( GtkWidget *widget,
1626 GdkEventButton *gdk_event,
1627 wxWindowGTK *win )
1628 {
1629 DEBUG_MAIN_THREAD
1630
1631 if (g_isIdle)
1632 wxapp_install_idle_handler();
1633
1634 /*
1635 wxPrintf( wxT("1) OnButtonPress from ") );
1636 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1637 wxPrintf( win->GetClassInfo()->GetClassName() );
1638 wxPrintf( wxT(".\n") );
1639 */
1640 if (!win->m_hasVMT) return FALSE;
1641 if (g_blockEventsOnDrag) return TRUE;
1642 if (g_blockEventsOnScroll) return TRUE;
1643
1644 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1645
1646 if (win->m_wxwindow && (g_focusWindow != win) && win->AcceptsFocus())
1647 {
1648 gtk_widget_grab_focus( win->m_wxwindow );
1649 /*
1650 wxPrintf( wxT("GrabFocus from ") );
1651 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1652 wxPrintf( win->GetClassInfo()->GetClassName() );
1653 wxPrintf( wxT(".\n") );
1654 */
1655 }
1656
1657 // GDK sends surplus button down event
1658 // before a double click event. We
1659 // need to filter these out.
1660 if (gdk_event->type == GDK_BUTTON_PRESS)
1661 {
1662 GdkEvent *peek_event = gdk_event_peek();
1663 if (peek_event)
1664 {
1665 if ((peek_event->type == GDK_2BUTTON_PRESS) ||
1666 (peek_event->type == GDK_3BUTTON_PRESS))
1667 {
1668 gdk_event_free( peek_event );
1669 return TRUE;
1670 }
1671 else
1672 {
1673 gdk_event_free( peek_event );
1674 }
1675 }
1676 }
1677
1678 wxEventType event_type = wxEVT_NULL;
1679
1680 // GdkDisplay is a GTK+ 2.2.0 thing
1681 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1682 if ( gdk_event->type == GDK_2BUTTON_PRESS &&
1683 gdk_event->button >= 1 && gdk_event->button <= 3 )
1684 {
1685 // Reset GDK internal timestamp variables in order to disable GDK
1686 // triple click events. GDK will then next time believe no button has
1687 // been clicked just before, and send a normal button click event.
1688 GdkDisplay* display = gtk_widget_get_display (widget);
1689 display->button_click_time[1] = 0;
1690 display->button_click_time[0] = 0;
1691 }
1692 #endif // GTK 2+
1693
1694 if (gdk_event->button == 1)
1695 {
1696 // note that GDK generates triple click events which are not supported
1697 // by wxWidgets but still have to be passed to the app as otherwise
1698 // clicks would simply go missing
1699 switch (gdk_event->type)
1700 {
1701 // we shouldn't get triple clicks at all for GTK2 because we
1702 // suppress them artificially using the code above but we still
1703 // should map them to something for GTK1 and not just ignore them
1704 // as this would lose clicks
1705 case GDK_3BUTTON_PRESS: // we could also map this to DCLICK...
1706 case GDK_BUTTON_PRESS:
1707 event_type = wxEVT_LEFT_DOWN;
1708 break;
1709
1710 case GDK_2BUTTON_PRESS:
1711 event_type = wxEVT_LEFT_DCLICK;
1712 break;
1713
1714 default:
1715 // just to silence gcc warnings
1716 ;
1717 }
1718 }
1719 else if (gdk_event->button == 2)
1720 {
1721 switch (gdk_event->type)
1722 {
1723 case GDK_3BUTTON_PRESS:
1724 case GDK_BUTTON_PRESS:
1725 event_type = wxEVT_MIDDLE_DOWN;
1726 break;
1727
1728 case GDK_2BUTTON_PRESS:
1729 event_type = wxEVT_MIDDLE_DCLICK;
1730 break;
1731
1732 default:
1733 ;
1734 }
1735 }
1736 else if (gdk_event->button == 3)
1737 {
1738 switch (gdk_event->type)
1739 {
1740 case GDK_3BUTTON_PRESS:
1741 case GDK_BUTTON_PRESS:
1742 event_type = wxEVT_RIGHT_DOWN;
1743 break;
1744
1745 case GDK_2BUTTON_PRESS:
1746 event_type = wxEVT_RIGHT_DCLICK;
1747 break;
1748
1749 default:
1750 ;
1751 }
1752 }
1753 else if (gdk_event->button == 4 || gdk_event->button == 5)
1754 {
1755 if (gdk_event->type == GDK_BUTTON_PRESS )
1756 {
1757 event_type = wxEVT_MOUSEWHEEL;
1758 }
1759 }
1760
1761 if ( event_type == wxEVT_NULL )
1762 {
1763 // unknown mouse button or click type
1764 return FALSE;
1765 }
1766
1767 wxMouseEvent event( event_type );
1768 InitMouseEvent( win, event, gdk_event );
1769
1770 AdjustEventButtonState(event);
1771
1772 // wxListBox actually get mouse events from the item, so we need to give it
1773 // a chance to correct this
1774 win->FixUpMouseEvent(widget, event.m_x, event.m_y);
1775
1776 // find the correct window to send the event too: it may be a different one
1777 // from the one which got it at GTK+ level because some control don't have
1778 // their own X window and thus cannot get any events.
1779 if ( !g_captureWindow )
1780 win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
1781
1782 gs_timeLastClick = gdk_event->time;
1783
1784 #ifndef __WXGTK20__
1785 if (event_type == wxEVT_LEFT_DCLICK)
1786 {
1787 // GTK 1.2 crashes when intercepting double
1788 // click events from both wxSpinButton and
1789 // wxSpinCtrl
1790 if (GTK_IS_SPIN_BUTTON(win->m_widget))
1791 {
1792 // Just disable this event for now.
1793 return FALSE;
1794 }
1795 }
1796 #endif
1797
1798 if (win->GetEventHandler()->ProcessEvent( event ))
1799 {
1800 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_press_event" );
1801 return TRUE;
1802 }
1803
1804 if (event_type == wxEVT_RIGHT_DOWN)
1805 {
1806 // generate a "context menu" event: this is similar to right mouse
1807 // click under many GUIs except that it is generated differently
1808 // (right up under MSW, ctrl-click under Mac, right down here) and
1809 //
1810 // (a) it's a command event and so is propagated to the parent
1811 // (b) under some ports it can be generated from kbd too
1812 // (c) it uses screen coords (because of (a))
1813 wxContextMenuEvent evtCtx(
1814 wxEVT_CONTEXT_MENU,
1815 win->GetId(),
1816 win->ClientToScreen(event.GetPosition()));
1817 evtCtx.SetEventObject(win);
1818 return win->GetEventHandler()->ProcessEvent(evtCtx);
1819 }
1820
1821 return FALSE;
1822 }
1823
1824 //-----------------------------------------------------------------------------
1825 // "button_release_event"
1826 //-----------------------------------------------------------------------------
1827
1828 static gint gtk_window_button_release_callback( GtkWidget *widget,
1829 GdkEventButton *gdk_event,
1830 wxWindowGTK *win )
1831 {
1832 DEBUG_MAIN_THREAD
1833
1834 if (g_isIdle)
1835 wxapp_install_idle_handler();
1836
1837 if (!win->m_hasVMT) return FALSE;
1838 if (g_blockEventsOnDrag) return FALSE;
1839 if (g_blockEventsOnScroll) return FALSE;
1840
1841 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1842
1843 wxEventType event_type = wxEVT_NULL;
1844
1845 switch (gdk_event->button)
1846 {
1847 case 1:
1848 event_type = wxEVT_LEFT_UP;
1849 break;
1850
1851 case 2:
1852 event_type = wxEVT_MIDDLE_UP;
1853 break;
1854
1855 case 3:
1856 event_type = wxEVT_RIGHT_UP;
1857 break;
1858
1859 default:
1860 // unknwon button, don't process
1861 return FALSE;
1862 }
1863
1864 wxMouseEvent event( event_type );
1865 InitMouseEvent( win, event, gdk_event );
1866
1867 AdjustEventButtonState(event);
1868
1869 // same wxListBox hack as above
1870 win->FixUpMouseEvent(widget, event.m_x, event.m_y);
1871
1872 if ( !g_captureWindow )
1873 win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
1874
1875 if (win->GetEventHandler()->ProcessEvent( event ))
1876 {
1877 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_release_event" );
1878 return TRUE;
1879 }
1880
1881 return FALSE;
1882 }
1883
1884 //-----------------------------------------------------------------------------
1885 // "motion_notify_event"
1886 //-----------------------------------------------------------------------------
1887
1888 static gint gtk_window_motion_notify_callback( GtkWidget *widget,
1889 GdkEventMotion *gdk_event,
1890 wxWindowGTK *win )
1891 {
1892 DEBUG_MAIN_THREAD
1893
1894 if (g_isIdle)
1895 wxapp_install_idle_handler();
1896
1897 if (!win->m_hasVMT) return FALSE;
1898 if (g_blockEventsOnDrag) return FALSE;
1899 if (g_blockEventsOnScroll) return FALSE;
1900
1901 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1902
1903 if (gdk_event->is_hint)
1904 {
1905 int x = 0;
1906 int y = 0;
1907 GdkModifierType state;
1908 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
1909 gdk_event->x = x;
1910 gdk_event->y = y;
1911 }
1912
1913 /*
1914 printf( "OnMotion from " );
1915 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1916 printf( win->GetClassInfo()->GetClassName() );
1917 printf( ".\n" );
1918 */
1919
1920 wxMouseEvent event( wxEVT_MOTION );
1921 InitMouseEvent(win, event, gdk_event);
1922
1923 if ( g_captureWindow )
1924 {
1925 // synthetize a mouse enter or leave event if needed
1926 GdkWindow *winUnderMouse = gdk_window_at_pointer(NULL, NULL);
1927 // This seems to be necessary and actually been added to
1928 // GDK itself in version 2.0.X
1929 gdk_flush();
1930
1931 bool hasMouse = winUnderMouse == gdk_event->window;
1932 if ( hasMouse != g_captureWindowHasMouse )
1933 {
1934 // the mouse changed window
1935 g_captureWindowHasMouse = hasMouse;
1936
1937 wxMouseEvent event(g_captureWindowHasMouse ? wxEVT_ENTER_WINDOW
1938 : wxEVT_LEAVE_WINDOW);
1939 InitMouseEvent(win, event, gdk_event);
1940 event.SetEventObject(win);
1941 win->GetEventHandler()->ProcessEvent(event);
1942 }
1943 }
1944 else // no capture
1945 {
1946 win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
1947 }
1948
1949 if (win->GetEventHandler()->ProcessEvent( event ))
1950 {
1951 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "motion_notify_event" );
1952 return TRUE;
1953 }
1954
1955 return FALSE;
1956 }
1957
1958 #ifdef __WXGTK20__
1959 //-----------------------------------------------------------------------------
1960 // "mouse_wheel_event"
1961 //-----------------------------------------------------------------------------
1962
1963 static gint gtk_window_wheel_callback (GtkWidget * widget,
1964 GdkEventScroll * gdk_event,
1965 wxWindowGTK * win)
1966 {
1967 DEBUG_MAIN_THREAD
1968
1969 if (g_isIdle)
1970 wxapp_install_idle_handler();
1971
1972 wxEventType event_type = wxEVT_NULL;
1973 if (gdk_event->direction == GDK_SCROLL_UP)
1974 event_type = wxEVT_MOUSEWHEEL;
1975 else if (gdk_event->direction == GDK_SCROLL_DOWN)
1976 event_type = wxEVT_MOUSEWHEEL;
1977 else
1978 return FALSE;
1979
1980 wxMouseEvent event( event_type );
1981 // Can't use InitMouse macro because scroll events don't have button
1982 event.SetTimestamp( gdk_event->time );
1983 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1984 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1985 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1986 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1987 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1988 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1989 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1990 event.m_linesPerAction = 3;
1991 event.m_wheelDelta = 120;
1992 if (gdk_event->direction == GDK_SCROLL_UP)
1993 event.m_wheelRotation = 120;
1994 else
1995 event.m_wheelRotation = -120;
1996
1997 wxPoint pt = win->GetClientAreaOrigin();
1998 event.m_x = (wxCoord)gdk_event->x - pt.x;
1999 event.m_y = (wxCoord)gdk_event->y - pt.y;
2000
2001 event.SetEventObject( win );
2002 event.SetId( win->GetId() );
2003 event.SetTimestamp( gdk_event->time );
2004
2005 if (win->GetEventHandler()->ProcessEvent( event ))
2006 {
2007 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "scroll_event" );
2008 return TRUE;
2009 }
2010
2011 return FALSE;
2012 }
2013
2014 //-----------------------------------------------------------------------------
2015 // "popup-menu"
2016 //-----------------------------------------------------------------------------
2017 static gboolean wxgtk_window_popup_menu_callback(GtkWidget*, wxWindowGTK* win)
2018 {
2019 wxContextMenuEvent event(
2020 wxEVT_CONTEXT_MENU,
2021 win->GetId(),
2022 wxPoint(-1, -1));
2023 event.SetEventObject(win);
2024 return win->GetEventHandler()->ProcessEvent(event);
2025 }
2026 #endif // __WXGTK20__
2027
2028 //-----------------------------------------------------------------------------
2029 // "focus_in_event"
2030 //-----------------------------------------------------------------------------
2031
2032 // send the wxChildFocusEvent and wxFocusEvent, common code of
2033 // gtk_window_focus_in_callback() and SetFocus()
2034 static bool DoSendFocusEvents(wxWindow *win)
2035 {
2036 // Notify the parent keeping track of focus for the kbd navigation
2037 // purposes that we got it.
2038 wxChildFocusEvent eventChildFocus(win);
2039 (void)win->GetEventHandler()->ProcessEvent(eventChildFocus);
2040
2041 wxFocusEvent eventFocus(wxEVT_SET_FOCUS, win->GetId());
2042 eventFocus.SetEventObject(win);
2043
2044 return win->GetEventHandler()->ProcessEvent(eventFocus);
2045 }
2046
2047 static gint gtk_window_focus_in_callback( GtkWidget *widget,
2048 GdkEvent *WXUNUSED(event),
2049 wxWindow *win )
2050 {
2051 DEBUG_MAIN_THREAD
2052
2053 if (g_isIdle)
2054 wxapp_install_idle_handler();
2055
2056 #ifdef __WXGTK20__
2057 if (win->m_imData)
2058 gtk_im_context_focus_in(win->m_imData->context);
2059 #endif
2060
2061 g_focusWindowLast =
2062 g_focusWindow = win;
2063
2064 wxLogTrace(TRACE_FOCUS,
2065 _T("%s: focus in"), win->GetName().c_str());
2066
2067 #ifdef HAVE_XIM
2068 if (win->m_ic)
2069 gdk_im_begin(win->m_ic, win->m_wxwindow->window);
2070 #endif
2071
2072 #if wxUSE_CARET
2073 // caret needs to be informed about focus change
2074 wxCaret *caret = win->GetCaret();
2075 if ( caret )
2076 {
2077 caret->OnSetFocus();
2078 }
2079 #endif // wxUSE_CARET
2080
2081 // does the window itself think that it has the focus?
2082 if ( !win->m_hasFocus )
2083 {
2084 // not yet, notify it
2085 win->m_hasFocus = TRUE;
2086
2087 if ( DoSendFocusEvents(win) )
2088 {
2089 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
2090 return TRUE;
2091 }
2092 }
2093
2094 return FALSE;
2095 }
2096
2097 //-----------------------------------------------------------------------------
2098 // "focus_out_event"
2099 //-----------------------------------------------------------------------------
2100
2101 static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEventFocus *gdk_event, wxWindowGTK *win )
2102 {
2103 DEBUG_MAIN_THREAD
2104
2105 if (g_isIdle)
2106 wxapp_install_idle_handler();
2107
2108 #ifdef __WXGTK20__
2109 if (win->m_imData)
2110 gtk_im_context_focus_out(win->m_imData->context);
2111 #endif
2112
2113 wxLogTrace( TRACE_FOCUS,
2114 _T("%s: focus out"), win->GetName().c_str() );
2115
2116
2117 wxWindowGTK *winFocus = wxFindFocusedChild(win);
2118 if ( winFocus )
2119 win = winFocus;
2120
2121 g_focusWindow = (wxWindowGTK *)NULL;
2122
2123 #ifdef HAVE_XIM
2124 if (win->m_ic)
2125 gdk_im_end();
2126 #endif
2127
2128 #if wxUSE_CARET
2129 // caret needs to be informed about focus change
2130 wxCaret *caret = win->GetCaret();
2131 if ( caret )
2132 {
2133 caret->OnKillFocus();
2134 }
2135 #endif // wxUSE_CARET
2136
2137 // don't send the window a kill focus event if it thinks that it doesn't
2138 // have focus already
2139 if ( win->m_hasFocus )
2140 {
2141 win->m_hasFocus = FALSE;
2142
2143 wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
2144 event.SetEventObject( win );
2145
2146 // even if we did process the event in wx code, still let GTK itself
2147 // process it too as otherwise bad things happen, especially in GTK2
2148 // where the text control simply aborts the program if it doesn't get
2149 // the matching focus out event
2150 (void)win->GetEventHandler()->ProcessEvent( event );
2151 }
2152
2153 return FALSE;
2154 }
2155
2156 //-----------------------------------------------------------------------------
2157 // "enter_notify_event"
2158 //-----------------------------------------------------------------------------
2159
2160 static
2161 gint gtk_window_enter_callback( GtkWidget *widget,
2162 GdkEventCrossing *gdk_event,
2163 wxWindowGTK *win )
2164 {
2165 DEBUG_MAIN_THREAD
2166
2167 if (g_isIdle)
2168 wxapp_install_idle_handler();
2169
2170 if (!win->m_hasVMT) return FALSE;
2171 if (g_blockEventsOnDrag) return FALSE;
2172
2173 // Event was emitted after a grab
2174 if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
2175
2176 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
2177
2178 int x = 0;
2179 int y = 0;
2180 GdkModifierType state = (GdkModifierType)0;
2181
2182 gdk_window_get_pointer( widget->window, &x, &y, &state );
2183
2184 wxMouseEvent event( wxEVT_ENTER_WINDOW );
2185 InitMouseEvent(win, event, gdk_event);
2186 wxPoint pt = win->GetClientAreaOrigin();
2187 event.m_x = x + pt.x;
2188 event.m_y = y + pt.y;
2189
2190 if (win->GetEventHandler()->ProcessEvent( event ))
2191 {
2192 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "enter_notify_event" );
2193 return TRUE;
2194 }
2195
2196 return FALSE;
2197 }
2198
2199 //-----------------------------------------------------------------------------
2200 // "leave_notify_event"
2201 //-----------------------------------------------------------------------------
2202
2203 static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win )
2204 {
2205 DEBUG_MAIN_THREAD
2206
2207 if (g_isIdle)
2208 wxapp_install_idle_handler();
2209
2210 if (!win->m_hasVMT) return FALSE;
2211 if (g_blockEventsOnDrag) return FALSE;
2212
2213 // Event was emitted after an ungrab
2214 if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
2215
2216 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
2217
2218 wxMouseEvent event( wxEVT_LEAVE_WINDOW );
2219 event.SetTimestamp( gdk_event->time );
2220 event.SetEventObject( win );
2221
2222 int x = 0;
2223 int y = 0;
2224 GdkModifierType state = (GdkModifierType)0;
2225
2226 gdk_window_get_pointer( widget->window, &x, &y, &state );
2227
2228 event.m_shiftDown = (state & GDK_SHIFT_MASK) != 0;
2229 event.m_controlDown = (state & GDK_CONTROL_MASK) != 0;
2230 event.m_altDown = (state & GDK_MOD1_MASK) != 0;
2231 event.m_metaDown = (state & GDK_MOD2_MASK) != 0;
2232 event.m_leftDown = (state & GDK_BUTTON1_MASK) != 0;
2233 event.m_middleDown = (state & GDK_BUTTON2_MASK) != 0;
2234 event.m_rightDown = (state & GDK_BUTTON3_MASK) != 0;
2235
2236 wxPoint pt = win->GetClientAreaOrigin();
2237 event.m_x = x + pt.x;
2238 event.m_y = y + pt.y;
2239
2240 if (win->GetEventHandler()->ProcessEvent( event ))
2241 {
2242 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "leave_notify_event" );
2243 return TRUE;
2244 }
2245
2246 return FALSE;
2247 }
2248
2249 //-----------------------------------------------------------------------------
2250 // "value_changed" from m_vAdjust
2251 //-----------------------------------------------------------------------------
2252
2253 static void gtk_window_vscroll_callback( GtkAdjustment *adjust,
2254 SCROLLBAR_CBACK_ARG
2255 wxWindowGTK *win )
2256 {
2257 DEBUG_MAIN_THREAD
2258
2259 if (g_isIdle)
2260 wxapp_install_idle_handler();
2261
2262 if (g_blockEventsOnDrag) return;
2263
2264 if (!win->m_hasVMT) return;
2265
2266 float diff = adjust->value - win->m_oldVerticalPos;
2267 if (fabs(diff) < 0.2) return;
2268
2269 win->m_oldVerticalPos = adjust->value;
2270
2271 #ifndef __WXGTK20__
2272 GtkScrolledWindow *sw = GTK_SCROLLED_WINDOW(win->m_widget);
2273 #endif
2274 wxEventType command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw->vscrollbar));
2275
2276 int value = (int)(adjust->value+0.5);
2277
2278 wxScrollWinEvent event( command, value, wxVERTICAL );
2279 event.SetEventObject( win );
2280 win->GetEventHandler()->ProcessEvent( event );
2281 }
2282
2283 //-----------------------------------------------------------------------------
2284 // "value_changed" from m_hAdjust
2285 //-----------------------------------------------------------------------------
2286
2287 static void gtk_window_hscroll_callback( GtkAdjustment *adjust,
2288 SCROLLBAR_CBACK_ARG
2289 wxWindowGTK *win )
2290 {
2291 DEBUG_MAIN_THREAD
2292
2293 if (g_isIdle)
2294 wxapp_install_idle_handler();
2295
2296 if (g_blockEventsOnDrag) return;
2297 if (!win->m_hasVMT) return;
2298
2299 float diff = adjust->value - win->m_oldHorizontalPos;
2300 if (fabs(diff) < 0.2) return;
2301
2302 #ifndef __WXGTK20__
2303 GtkScrolledWindow *sw = GTK_SCROLLED_WINDOW(win->m_widget);
2304 #endif
2305 wxEventType command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw->hscrollbar));
2306
2307 win->m_oldHorizontalPos = adjust->value;
2308
2309 int value = (int)(adjust->value+0.5);
2310
2311 wxScrollWinEvent event( command, value, wxHORIZONTAL );
2312 event.SetEventObject( win );
2313 win->GetEventHandler()->ProcessEvent( event );
2314 }
2315
2316 //-----------------------------------------------------------------------------
2317 // "button_press_event" from scrollbar
2318 //-----------------------------------------------------------------------------
2319
2320 static gint gtk_scrollbar_button_press_callback( GtkRange *widget,
2321 GdkEventButton *gdk_event,
2322 wxWindowGTK *win)
2323 {
2324 DEBUG_MAIN_THREAD
2325
2326 if (g_isIdle)
2327 wxapp_install_idle_handler();
2328
2329
2330 g_blockEventsOnScroll = TRUE;
2331
2332 // FIXME: there is no 'slider' field in GTK+ 2.0 any more
2333 #ifndef __WXGTK20__
2334 win->m_isScrolling = (gdk_event->window == widget->slider);
2335 #endif
2336
2337 return FALSE;
2338 }
2339
2340 //-----------------------------------------------------------------------------
2341 // "button_release_event" from scrollbar
2342 //-----------------------------------------------------------------------------
2343
2344 static gint gtk_scrollbar_button_release_callback( GtkRange *widget,
2345 GdkEventButton *WXUNUSED(gdk_event),
2346 wxWindowGTK *win)
2347 {
2348 DEBUG_MAIN_THREAD
2349
2350 // don't test here as we can release the mouse while being over
2351 // a different window than the slider
2352 //
2353 // if (gdk_event->window != widget->slider) return FALSE;
2354
2355 g_blockEventsOnScroll = FALSE;
2356
2357 if (win->m_isScrolling)
2358 {
2359 wxEventType command = wxEVT_SCROLLWIN_THUMBRELEASE;
2360 int value = -1;
2361 int dir = -1;
2362
2363 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
2364 if (widget == GTK_RANGE(scrolledWindow->hscrollbar))
2365 {
2366 value = (int)(win->m_hAdjust->value+0.5);
2367 dir = wxHORIZONTAL;
2368 }
2369 if (widget == GTK_RANGE(scrolledWindow->vscrollbar))
2370 {
2371 value = (int)(win->m_vAdjust->value+0.5);
2372 dir = wxVERTICAL;
2373 }
2374
2375 wxScrollWinEvent event( command, value, dir );
2376 event.SetEventObject( win );
2377 win->GetEventHandler()->ProcessEvent( event );
2378 }
2379
2380 win->m_isScrolling = FALSE;
2381
2382 return FALSE;
2383 }
2384
2385 // ----------------------------------------------------------------------------
2386 // this wxWindowBase function is implemented here (in platform-specific file)
2387 // because it is static and so couldn't be made virtual
2388 // ----------------------------------------------------------------------------
2389
2390 wxWindow *wxWindowBase::DoFindFocus()
2391 {
2392 // the cast is necessary when we compile in wxUniversal mode
2393 return (wxWindow *)g_focusWindow;
2394 }
2395
2396
2397 //-----------------------------------------------------------------------------
2398 // "realize" from m_widget
2399 //-----------------------------------------------------------------------------
2400
2401 /* We cannot set colours and fonts before the widget has
2402 been realized, so we do this directly after realization. */
2403
2404 static gint
2405 gtk_window_realized_callback( GtkWidget *m_widget, wxWindow *win )
2406 {
2407 DEBUG_MAIN_THREAD
2408
2409 if (g_isIdle)
2410 wxapp_install_idle_handler();
2411
2412 #ifdef __WXGTK20__
2413 if (win->m_imData)
2414 {
2415 GtkPizza *pizza = GTK_PIZZA( m_widget );
2416 gtk_im_context_set_client_window( win->m_imData->context,
2417 pizza->bin_window );
2418 }
2419 #endif
2420
2421 wxWindowCreateEvent event( win );
2422 event.SetEventObject( win );
2423 win->GetEventHandler()->ProcessEvent( event );
2424
2425 return FALSE;
2426 }
2427
2428 //-----------------------------------------------------------------------------
2429 // "size_allocate"
2430 //-----------------------------------------------------------------------------
2431
2432 static
2433 void gtk_window_size_callback( GtkWidget *WXUNUSED(widget),
2434 GtkAllocation *WXUNUSED(alloc),
2435 wxWindow *win )
2436 {
2437 if (g_isIdle)
2438 wxapp_install_idle_handler();
2439
2440 if (!win->m_hasScrolling) return;
2441
2442 int client_width = 0;
2443 int client_height = 0;
2444 win->GetClientSize( &client_width, &client_height );
2445 if ((client_width == win->m_oldClientWidth) && (client_height == win->m_oldClientHeight))
2446 return;
2447
2448 win->m_oldClientWidth = client_width;
2449 win->m_oldClientHeight = client_height;
2450
2451 if (!win->m_nativeSizeEvent)
2452 {
2453 wxSizeEvent event( win->GetSize(), win->GetId() );
2454 event.SetEventObject( win );
2455 win->GetEventHandler()->ProcessEvent( event );
2456 }
2457 }
2458
2459
2460 #ifdef HAVE_XIM
2461 #define WXUNUSED_UNLESS_XIM(param) param
2462 #else
2463 #define WXUNUSED_UNLESS_XIM(param) WXUNUSED(param)
2464 #endif
2465
2466 /* Resize XIM window */
2467
2468 static
2469 void gtk_wxwindow_size_callback( GtkWidget* WXUNUSED_UNLESS_XIM(widget),
2470 GtkAllocation* WXUNUSED_UNLESS_XIM(alloc),
2471 wxWindowGTK* WXUNUSED_UNLESS_XIM(win) )
2472 {
2473 if (g_isIdle)
2474 wxapp_install_idle_handler();
2475
2476 #ifdef HAVE_XIM
2477 if (!win->m_ic)
2478 return;
2479
2480 if (gdk_ic_get_style (win->m_ic) & GDK_IM_PREEDIT_POSITION)
2481 {
2482 gint width, height;
2483
2484 gdk_window_get_size (widget->window, &width, &height);
2485 win->m_icattr->preedit_area.width = width;
2486 win->m_icattr->preedit_area.height = height;
2487 gdk_ic_set_attr (win->m_ic, win->m_icattr, GDK_IC_PREEDIT_AREA);
2488 }
2489 #endif // HAVE_XIM
2490 }
2491
2492 //-----------------------------------------------------------------------------
2493 // "realize" from m_wxwindow
2494 //-----------------------------------------------------------------------------
2495
2496 /* Initialize XIM support */
2497
2498 static gint
2499 gtk_wxwindow_realized_callback( GtkWidget * WXUNUSED_UNLESS_XIM(widget),
2500 wxWindowGTK * WXUNUSED_UNLESS_XIM(win) )
2501 {
2502 if (g_isIdle)
2503 wxapp_install_idle_handler();
2504
2505 #ifdef HAVE_XIM
2506 if (win->m_ic) return FALSE;
2507 if (!widget) return FALSE;
2508 if (!gdk_im_ready()) return FALSE;
2509
2510 win->m_icattr = gdk_ic_attr_new();
2511 if (!win->m_icattr) return FALSE;
2512
2513 gint width, height;
2514 GdkEventMask mask;
2515 GdkColormap *colormap;
2516 GdkICAttr *attr = win->m_icattr;
2517 unsigned attrmask = GDK_IC_ALL_REQ;
2518 GdkIMStyle style;
2519 GdkIMStyle supported_style = (GdkIMStyle)
2520 (GDK_IM_PREEDIT_NONE |
2521 GDK_IM_PREEDIT_NOTHING |
2522 GDK_IM_PREEDIT_POSITION |
2523 GDK_IM_STATUS_NONE |
2524 GDK_IM_STATUS_NOTHING);
2525
2526 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
2527 supported_style = (GdkIMStyle)(supported_style & ~GDK_IM_PREEDIT_POSITION);
2528
2529 attr->style = style = gdk_im_decide_style (supported_style);
2530 attr->client_window = widget->window;
2531
2532 if ((colormap = gtk_widget_get_colormap (widget)) !=
2533 gtk_widget_get_default_colormap ())
2534 {
2535 attrmask |= GDK_IC_PREEDIT_COLORMAP;
2536 attr->preedit_colormap = colormap;
2537 }
2538
2539 attrmask |= GDK_IC_PREEDIT_FOREGROUND;
2540 attrmask |= GDK_IC_PREEDIT_BACKGROUND;
2541 attr->preedit_foreground = widget->style->fg[GTK_STATE_NORMAL];
2542 attr->preedit_background = widget->style->base[GTK_STATE_NORMAL];
2543
2544 switch (style & GDK_IM_PREEDIT_MASK)
2545 {
2546 case GDK_IM_PREEDIT_POSITION:
2547 if (widget->style && widget->style->font->type != GDK_FONT_FONTSET)
2548 {
2549 g_warning ("over-the-spot style requires fontset");
2550 break;
2551 }
2552
2553 gdk_window_get_size (widget->window, &width, &height);
2554
2555 attrmask |= GDK_IC_PREEDIT_POSITION_REQ;
2556 attr->spot_location.x = 0;
2557 attr->spot_location.y = height;
2558 attr->preedit_area.x = 0;
2559 attr->preedit_area.y = 0;
2560 attr->preedit_area.width = width;
2561 attr->preedit_area.height = height;
2562 attr->preedit_fontset = widget->style->font;
2563
2564 break;
2565 }
2566
2567 win->m_ic = gdk_ic_new (attr, (GdkICAttributesType)attrmask);
2568
2569 if (win->m_ic == NULL)
2570 g_warning ("Can't create input context.");
2571 else
2572 {
2573 mask = gdk_window_get_events (widget->window);
2574 mask = (GdkEventMask)(mask | gdk_ic_get_events (win->m_ic));
2575 gdk_window_set_events (widget->window, mask);
2576
2577 if (GTK_WIDGET_HAS_FOCUS(widget))
2578 gdk_im_begin (win->m_ic, widget->window);
2579 }
2580 #endif // HAVE_XIM
2581
2582 return FALSE;
2583 }
2584
2585 //-----------------------------------------------------------------------------
2586 // InsertChild for wxWindowGTK.
2587 //-----------------------------------------------------------------------------
2588
2589 /* Callback for wxWindowGTK. This very strange beast has to be used because
2590 * C++ has no virtual methods in a constructor. We have to emulate a
2591 * virtual function here as wxNotebook requires a different way to insert
2592 * a child in it. I had opted for creating a wxNotebookPage window class
2593 * which would have made this superfluous (such in the MDI window system),
2594 * but no-one was listening to me... */
2595
2596 static void wxInsertChildInWindow( wxWindowGTK* parent, wxWindowGTK* child )
2597 {
2598 /* the window might have been scrolled already, do we
2599 have to adapt the position */
2600 GtkPizza *pizza = GTK_PIZZA(parent->m_wxwindow);
2601 child->m_x += pizza->xoffset;
2602 child->m_y += pizza->yoffset;
2603
2604 gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
2605 GTK_WIDGET(child->m_widget),
2606 child->m_x,
2607 child->m_y,
2608 child->m_width,
2609 child->m_height );
2610 }
2611
2612 //-----------------------------------------------------------------------------
2613 // global functions
2614 //-----------------------------------------------------------------------------
2615
2616 wxWindow *wxGetActiveWindow()
2617 {
2618 return wxWindow::FindFocus();
2619 }
2620
2621 //-----------------------------------------------------------------------------
2622 // wxWindowGTK
2623 //-----------------------------------------------------------------------------
2624
2625 // in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
2626 // method
2627 #ifdef __WXUNIVERSAL__
2628 IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK, wxWindowBase)
2629 #else // __WXGTK__
2630 IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
2631 #endif // __WXUNIVERSAL__/__WXGTK__
2632
2633 void wxWindowGTK::Init()
2634 {
2635 // GTK specific
2636 m_widget = (GtkWidget *) NULL;
2637 m_wxwindow = (GtkWidget *) NULL;
2638 m_focusWidget = (GtkWidget *) NULL;
2639
2640 // position/size
2641 m_x = 0;
2642 m_y = 0;
2643 m_width = 0;
2644 m_height = 0;
2645
2646 m_sizeSet = FALSE;
2647 m_hasVMT = FALSE;
2648 m_needParent = TRUE;
2649 m_isBeingDeleted = FALSE;
2650
2651 m_noExpose = FALSE;
2652 m_nativeSizeEvent = FALSE;
2653
2654 m_hasScrolling = FALSE;
2655 m_isScrolling = FALSE;
2656
2657 m_hAdjust = (GtkAdjustment*) NULL;
2658 m_vAdjust = (GtkAdjustment*) NULL;
2659 m_oldHorizontalPos =
2660 m_oldVerticalPos = 0.0;
2661 m_oldClientWidth =
2662 m_oldClientHeight = 0;
2663
2664 m_resizing = FALSE;
2665
2666 m_insertCallback = (wxInsertChildFunction) NULL;
2667
2668 m_acceptsFocus = FALSE;
2669 m_hasFocus = FALSE;
2670
2671 m_clipPaintRegion = FALSE;
2672
2673 m_needsStyleChange = false;
2674
2675 m_cursor = *wxSTANDARD_CURSOR;
2676
2677 #ifdef __WXGTK20__
2678 m_imData = NULL;
2679 m_x11Context = NULL;
2680 m_dirtyTabOrder = false;
2681 #else
2682 #ifdef HAVE_XIM
2683 m_ic = (GdkIC*) NULL;
2684 m_icattr = (GdkICAttr*) NULL;
2685 #endif
2686 #endif
2687 }
2688
2689 wxWindowGTK::wxWindowGTK()
2690 {
2691 Init();
2692 }
2693
2694 wxWindowGTK::wxWindowGTK( wxWindow *parent,
2695 wxWindowID id,
2696 const wxPoint &pos,
2697 const wxSize &size,
2698 long style,
2699 const wxString &name )
2700 {
2701 Init();
2702
2703 Create( parent, id, pos, size, style, name );
2704 }
2705
2706 bool wxWindowGTK::Create( wxWindow *parent,
2707 wxWindowID id,
2708 const wxPoint &pos,
2709 const wxSize &size,
2710 long style,
2711 const wxString &name )
2712 {
2713 if (!PreCreation( parent, pos, size ) ||
2714 !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
2715 {
2716 wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
2717 return FALSE;
2718 }
2719
2720 m_insertCallback = wxInsertChildInWindow;
2721
2722 m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
2723 GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
2724
2725 GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
2726
2727 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
2728 scroll_class->scrollbar_spacing = 0;
2729
2730 gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
2731
2732 m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->hscrollbar) );
2733 m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(scrolledWindow->vscrollbar) );
2734
2735 m_wxwindow = gtk_pizza_new();
2736
2737 #ifndef __WXUNIVERSAL__
2738 GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
2739
2740 if (HasFlag(wxRAISED_BORDER))
2741 {
2742 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_OUT );
2743 }
2744 else if (HasFlag(wxSUNKEN_BORDER))
2745 {
2746 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_IN );
2747 }
2748 else if (HasFlag(wxSIMPLE_BORDER))
2749 {
2750 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_THIN );
2751 }
2752 else
2753 {
2754 gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_NONE );
2755 }
2756 #endif // __WXUNIVERSAL__
2757
2758 gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
2759
2760 GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
2761 m_acceptsFocus = TRUE;
2762
2763 // I _really_ don't want scrollbars in the beginning
2764 m_vAdjust->lower = 0.0;
2765 m_vAdjust->upper = 1.0;
2766 m_vAdjust->value = 0.0;
2767 m_vAdjust->step_increment = 1.0;
2768 m_vAdjust->page_increment = 1.0;
2769 m_vAdjust->page_size = 5.0;
2770 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
2771 m_hAdjust->lower = 0.0;
2772 m_hAdjust->upper = 1.0;
2773 m_hAdjust->value = 0.0;
2774 m_hAdjust->step_increment = 1.0;
2775 m_hAdjust->page_increment = 1.0;
2776 m_hAdjust->page_size = 5.0;
2777 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
2778
2779 // these handlers block mouse events to any window during scrolling such as
2780 // motion events and prevent GTK and wxWidgets from fighting over where the
2781 // slider should be
2782
2783 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_press_event",
2784 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2785
2786 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_press_event",
2787 (GtkSignalFunc)gtk_scrollbar_button_press_callback, (gpointer) this );
2788
2789 gtk_signal_connect( GTK_OBJECT(scrolledWindow->vscrollbar), "button_release_event",
2790 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2791
2792 gtk_signal_connect( GTK_OBJECT(scrolledWindow->hscrollbar), "button_release_event",
2793 (GtkSignalFunc)gtk_scrollbar_button_release_callback, (gpointer) this );
2794
2795 // these handlers get notified when screen updates are required either when
2796 // scrolling or when the window size (and therefore scrollbar configuration)
2797 // has changed
2798
2799 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
2800 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
2801 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
2802 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
2803
2804 gtk_widget_show( m_wxwindow );
2805
2806 if (m_parent)
2807 m_parent->DoAddChild( this );
2808
2809 m_focusWidget = m_wxwindow;
2810
2811 PostCreation();
2812
2813 return TRUE;
2814 }
2815
2816 wxWindowGTK::~wxWindowGTK()
2817 {
2818 SendDestroyEvent();
2819
2820 if (g_focusWindow == this)
2821 g_focusWindow = NULL;
2822
2823 if ( g_delayedFocus == this )
2824 g_delayedFocus = NULL;
2825
2826 m_isBeingDeleted = TRUE;
2827 m_hasVMT = FALSE;
2828
2829 if (m_widget)
2830 Show( FALSE );
2831
2832 DestroyChildren();
2833
2834 #ifdef HAVE_XIM
2835 if (m_ic)
2836 gdk_ic_destroy (m_ic);
2837 if (m_icattr)
2838 gdk_ic_attr_destroy (m_icattr);
2839 #endif
2840
2841 if (m_wxwindow)
2842 {
2843 gtk_widget_destroy( m_wxwindow );
2844 m_wxwindow = (GtkWidget*) NULL;
2845 }
2846
2847 if (m_widget)
2848 {
2849 gtk_widget_destroy( m_widget );
2850 m_widget = (GtkWidget*) NULL;
2851 }
2852
2853 #ifdef __WXGTK20__
2854 delete m_imData;
2855 #endif
2856 }
2857
2858 bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos, const wxSize &size )
2859 {
2860 wxCHECK_MSG( !m_needParent || parent, FALSE, wxT("Need complete parent.") );
2861
2862 // Use either the given size, or the default if -1 is given.
2863 // See wxWindowBase for these functions.
2864 m_width = WidthDefault(size.x) ;
2865 m_height = HeightDefault(size.y);
2866
2867 m_x = (int)pos.x;
2868 m_y = (int)pos.y;
2869
2870 return TRUE;
2871 }
2872
2873 void wxWindowGTK::PostCreation()
2874 {
2875 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2876
2877 if (m_wxwindow)
2878 {
2879 if (!m_noExpose)
2880 {
2881 // these get reported to wxWidgets -> wxPaintEvent
2882
2883 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow), TRUE );
2884
2885 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
2886 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
2887
2888 #ifndef __WXGTK20__
2889 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
2890 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
2891
2892 if (!HasFlag(wxFULL_REPAINT_ON_RESIZE))
2893 {
2894 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "event",
2895 GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this );
2896 }
2897 #else
2898 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2899 #endif
2900 }
2901
2902 #ifdef __WXGTK20__
2903 // Create input method handler
2904 m_imData = new wxGtkIMData;
2905
2906 // Cannot handle drawing preedited text yet
2907 gtk_im_context_set_use_preedit( m_imData->context, FALSE );
2908
2909 g_signal_connect (G_OBJECT (m_imData->context), "commit",
2910 G_CALLBACK (gtk_wxwindow_commit_cb), this);
2911 #endif
2912
2913 // these are called when the "sunken" or "raised" borders are drawn
2914 gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
2915 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
2916
2917 #ifndef __WXGTK20__
2918 gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
2919 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
2920 #endif
2921 }
2922
2923 // focus handling
2924
2925 if (!GTK_IS_WINDOW(m_widget))
2926 {
2927 if (m_focusWidget == NULL)
2928 m_focusWidget = m_widget;
2929
2930 gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_in_event",
2931 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
2932
2933 gtk_signal_connect_after( GTK_OBJECT(m_focusWidget), "focus_out_event",
2934 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
2935 }
2936
2937 // connect to the various key and mouse handlers
2938
2939 GtkWidget *connect_widget = GetConnectWidget();
2940
2941 ConnectWidget( connect_widget );
2942
2943 /* We cannot set colours, fonts and cursors before the widget has
2944 been realized, so we do this directly after realization */
2945 gtk_signal_connect( GTK_OBJECT(connect_widget), "realize",
2946 GTK_SIGNAL_FUNC(gtk_window_realized_callback), (gpointer) this );
2947
2948 if (m_wxwindow)
2949 {
2950 // Catch native resize events
2951 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2952 GTK_SIGNAL_FUNC(gtk_window_size_callback), (gpointer)this );
2953
2954 // Initialize XIM support
2955 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "realize",
2956 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback), (gpointer) this );
2957
2958 // And resize XIM window
2959 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
2960 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this );
2961 }
2962
2963 if (GTK_IS_COMBO(m_widget))
2964 {
2965 GtkCombo *gcombo = GTK_COMBO(m_widget);
2966
2967 gtk_signal_connect( GTK_OBJECT(gcombo->entry), "size_request",
2968 GTK_SIGNAL_FUNC(wxgtk_combo_size_request_callback),
2969 (gpointer) this );
2970 }
2971 else
2972 {
2973 // This is needed if we want to add our windows into native
2974 // GTK controls, such as the toolbar. With this callback, the
2975 // toolbar gets to know the correct size (the one set by the
2976 // programmer). Sadly, it misbehaves for wxComboBox.
2977 gtk_signal_connect( GTK_OBJECT(m_widget), "size_request",
2978 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback),
2979 (gpointer) this );
2980 }
2981
2982 InheritAttributes();
2983
2984 m_hasVMT = TRUE;
2985
2986 // unless the window was created initially hidden (i.e. Hide() had been
2987 // called before Create()), we should show it at GTK+ level as well
2988 if ( IsShown() )
2989 gtk_widget_show( m_widget );
2990 }
2991
2992 void wxWindowGTK::ConnectWidget( GtkWidget *widget )
2993 {
2994 gtk_signal_connect( GTK_OBJECT(widget), "key_press_event",
2995 GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this );
2996
2997 gtk_signal_connect( GTK_OBJECT(widget), "key_release_event",
2998 GTK_SIGNAL_FUNC(gtk_window_key_release_callback), (gpointer)this );
2999
3000 gtk_signal_connect( GTK_OBJECT(widget), "button_press_event",
3001 GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
3002
3003 gtk_signal_connect( GTK_OBJECT(widget), "button_release_event",
3004 GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
3005
3006 gtk_signal_connect( GTK_OBJECT(widget), "motion_notify_event",
3007 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
3008
3009 #ifdef __WXGTK20__
3010 gtk_signal_connect( GTK_OBJECT(widget), "scroll_event",
3011 GTK_SIGNAL_FUNC(gtk_window_wheel_callback), (gpointer)this );
3012 g_signal_connect(widget, "popup_menu",
3013 G_CALLBACK(wxgtk_window_popup_menu_callback), this);
3014 #endif
3015
3016 gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event",
3017 GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
3018
3019 gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
3020 GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
3021 }
3022
3023 bool wxWindowGTK::Destroy()
3024 {
3025 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
3026
3027 m_hasVMT = FALSE;
3028
3029 return wxWindowBase::Destroy();
3030 }
3031
3032 void wxWindowGTK::DoMoveWindow(int x, int y, int width, int height)
3033 {
3034 gtk_pizza_set_size( GTK_PIZZA(m_parent->m_wxwindow), m_widget, x, y, width, height );
3035 }
3036
3037 void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
3038 {
3039 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
3040 wxASSERT_MSG( (m_parent != NULL), wxT("wxWindowGTK::SetSize requires parent.\n") );
3041
3042 /*
3043 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
3044 */
3045
3046 if (m_resizing) return; /* I don't like recursions */
3047 m_resizing = TRUE;
3048
3049 int currentX, currentY;
3050 GetPosition(&currentX, &currentY);
3051 if (x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
3052 x = currentX;
3053 if (y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
3054 y = currentY;
3055 AdjustForParentClientOrigin(x, y, sizeFlags);
3056
3057 if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
3058 {
3059 /* don't set the size for children of wxNotebook, just take the values. */
3060 m_x = x;
3061 m_y = y;
3062 m_width = width;
3063 m_height = height;
3064 }
3065 else
3066 {
3067 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
3068 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
3069 {
3070 if (x != -1) m_x = x + pizza->xoffset;
3071 if (y != -1) m_y = y + pizza->yoffset;
3072 }
3073 else
3074 {
3075 m_x = x + pizza->xoffset;
3076 m_y = y + pizza->yoffset;
3077 }
3078
3079 // calculate the best size if we should auto size the window
3080 if ( ((sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1) ||
3081 ((sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1) )
3082 {
3083 const wxSize sizeBest = GetBestSize();
3084 if ( (sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1 )
3085 width = sizeBest.x;
3086 if ( (sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1 )
3087 height = sizeBest.y;
3088 }
3089
3090 if (width != -1)
3091 m_width = width;
3092 if (height != -1)
3093 m_height = height;
3094
3095 int minWidth = GetMinWidth(),
3096 minHeight = GetMinHeight(),
3097 maxWidth = GetMaxWidth(),
3098 maxHeight = GetMaxHeight();
3099
3100 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
3101 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
3102 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
3103 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
3104
3105 int left_border = 0;
3106 int right_border = 0;
3107 int top_border = 0;
3108 int bottom_border = 0;
3109
3110 /* the default button has a border around it */
3111 if (GTK_WIDGET_CAN_DEFAULT(m_widget))
3112 {
3113 #ifdef __WXGTK20__
3114 #if 0
3115 GtkBorder *default_border;
3116 gtk_widget_style_get( m_widget, "default_border", &default_border, NULL );
3117 if (default_border)
3118 {
3119 left_border += default_border->left;
3120 right_border += default_border->right;
3121 top_border += default_border->top;
3122 bottom_border += default_border->bottom;
3123 g_free( default_border );
3124
3125 }
3126 #endif
3127 GtkBorder *default_outside_border;
3128 {
3129 gtk_widget_style_get( m_widget, "default_outside_border", &default_outside_border, NULL );
3130 left_border += default_outside_border->left;
3131 right_border += default_outside_border->right;
3132 top_border += default_outside_border->top;
3133 bottom_border += default_outside_border->bottom;
3134 g_free( default_outside_border );
3135 }
3136 #else
3137 left_border = 6;
3138 right_border = 6;
3139 top_border = 6;
3140 bottom_border = 5;
3141 #endif
3142 }
3143
3144 DoMoveWindow( m_x-top_border,
3145 m_y-left_border,
3146 m_width+left_border+right_border,
3147 m_height+top_border+bottom_border );
3148 }
3149
3150 if (m_hasScrolling)
3151 {
3152 /* Sometimes the client area changes size without the
3153 whole windows's size changing, but if the whole
3154 windows's size doesn't change, no wxSizeEvent will
3155 normally be sent. Here we add an extra test if
3156 the client test has been changed and this will
3157 be used then. */
3158 GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
3159 }
3160
3161 /*
3162 wxPrintf( "OnSize sent from " );
3163 if (GetClassInfo() && GetClassInfo()->GetClassName())
3164 wxPrintf( GetClassInfo()->GetClassName() );
3165 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3166 */
3167
3168 if (!m_nativeSizeEvent)
3169 {
3170 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
3171 event.SetEventObject( this );
3172 GetEventHandler()->ProcessEvent( event );
3173 }
3174
3175 m_resizing = FALSE;
3176 }
3177
3178 void wxWindowGTK::OnInternalIdle()
3179 {
3180 #ifdef __WXGTK20__
3181 if ( m_dirtyTabOrder )
3182 RealizeTabOrder();
3183 #endif
3184 // Update style if the window was not yet realized
3185 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
3186 if (m_needsStyleChange)
3187 {
3188 SetBackgroundStyle(GetBackgroundStyle());
3189 m_needsStyleChange = false;
3190 }
3191
3192 // Update invalidated regions.
3193 GtkUpdate();
3194
3195 wxCursor cursor = m_cursor;
3196 if (g_globalCursor.Ok()) cursor = g_globalCursor;
3197
3198 if (cursor.Ok())
3199 {
3200 /* I now set the cursor anew in every OnInternalIdle call
3201 as setting the cursor in a parent window also effects the
3202 windows above so that checking for the current cursor is
3203 not possible. */
3204
3205 if (m_wxwindow)
3206 {
3207 GdkWindow *window = GTK_PIZZA(m_wxwindow)->bin_window;
3208 if (window)
3209 gdk_window_set_cursor( window, cursor.GetCursor() );
3210
3211 if (!g_globalCursor.Ok())
3212 cursor = *wxSTANDARD_CURSOR;
3213
3214 window = m_widget->window;
3215 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
3216 gdk_window_set_cursor( window, cursor.GetCursor() );
3217
3218 }
3219 else
3220 {
3221
3222 GdkWindow *window = m_widget->window;
3223 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
3224 gdk_window_set_cursor( window, cursor.GetCursor() );
3225
3226 }
3227 }
3228
3229 if (wxUpdateUIEvent::CanUpdate(this))
3230 UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
3231 }
3232
3233 void wxWindowGTK::DoGetSize( int *width, int *height ) const
3234 {
3235 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3236
3237 if (width) (*width) = m_width;
3238 if (height) (*height) = m_height;
3239 }
3240
3241 void wxWindowGTK::DoSetClientSize( int width, int height )
3242 {
3243 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3244
3245 if (!m_wxwindow)
3246 {
3247 SetSize( width, height );
3248 }
3249 else
3250 {
3251 int dw = 0;
3252 int dh = 0;
3253
3254 #ifndef __WXUNIVERSAL__
3255 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
3256 {
3257 /* when using GTK 1.2 we set the shadow border size to 2 */
3258 dw += 2 * 2;
3259 dh += 2 * 2;
3260 }
3261 if (HasFlag(wxSIMPLE_BORDER))
3262 {
3263 /* when using GTK 1.2 we set the simple border size to 1 */
3264 dw += 1 * 2;
3265 dh += 1 * 2;
3266 }
3267 #endif // __WXUNIVERSAL__
3268
3269 if (m_hasScrolling)
3270 {
3271 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
3272
3273 GtkRequisition vscroll_req;
3274 vscroll_req.width = 2;
3275 vscroll_req.height = 2;
3276 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
3277 (scroll_window->vscrollbar, &vscroll_req );
3278
3279 GtkRequisition hscroll_req;
3280 hscroll_req.width = 2;
3281 hscroll_req.height = 2;
3282 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
3283 (scroll_window->hscrollbar, &hscroll_req );
3284
3285 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
3286
3287 if (scroll_window->vscrollbar_visible)
3288 {
3289 dw += vscroll_req.width;
3290 dw += scroll_class->scrollbar_spacing;
3291 }
3292
3293 if (scroll_window->hscrollbar_visible)
3294 {
3295 dh += hscroll_req.height;
3296 dh += scroll_class->scrollbar_spacing;
3297 }
3298 }
3299
3300 SetSize( width+dw, height+dh );
3301 }
3302 }
3303
3304 void wxWindowGTK::DoGetClientSize( int *width, int *height ) const
3305 {
3306 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3307
3308 if (!m_wxwindow)
3309 {
3310 if (width) (*width) = m_width;
3311 if (height) (*height) = m_height;
3312 }
3313 else
3314 {
3315 int dw = 0;
3316 int dh = 0;
3317
3318 #ifndef __WXUNIVERSAL__
3319 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
3320 {
3321 /* when using GTK 1.2 we set the shadow border size to 2 */
3322 dw += 2 * 2;
3323 dh += 2 * 2;
3324 }
3325 if (HasFlag(wxSIMPLE_BORDER))
3326 {
3327 /* when using GTK 1.2 we set the simple border size to 1 */
3328 dw += 1 * 2;
3329 dh += 1 * 2;
3330 }
3331 #endif // __WXUNIVERSAL__
3332
3333 if (m_hasScrolling)
3334 {
3335 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
3336
3337 GtkRequisition vscroll_req;
3338 vscroll_req.width = 2;
3339 vscroll_req.height = 2;
3340 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
3341 (scroll_window->vscrollbar, &vscroll_req );
3342
3343 GtkRequisition hscroll_req;
3344 hscroll_req.width = 2;
3345 hscroll_req.height = 2;
3346 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
3347 (scroll_window->hscrollbar, &hscroll_req );
3348
3349 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
3350
3351 if (scroll_window->vscrollbar_visible)
3352 {
3353 dw += vscroll_req.width;
3354 dw += scroll_class->scrollbar_spacing;
3355 }
3356
3357 if (scroll_window->hscrollbar_visible)
3358 {
3359 dh += hscroll_req.height;
3360 dh += scroll_class->scrollbar_spacing;
3361 }
3362 }
3363
3364 if (width) (*width) = m_width - dw;
3365 if (height) (*height) = m_height - dh;
3366 }
3367
3368 /*
3369 printf( "GetClientSize, name %s ", GetName().c_str() );
3370 if (width) printf( " width = %d", (*width) );
3371 if (height) printf( " height = %d", (*height) );
3372 printf( "\n" );
3373 */
3374 }
3375
3376 void wxWindowGTK::DoGetPosition( int *x, int *y ) const
3377 {
3378 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3379
3380 int dx = 0;
3381 int dy = 0;
3382 if (m_parent && m_parent->m_wxwindow)
3383 {
3384 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
3385 dx = pizza->xoffset;
3386 dy = pizza->yoffset;
3387 }
3388
3389 if (x) (*x) = m_x - dx;
3390 if (y) (*y) = m_y - dy;
3391 }
3392
3393 void wxWindowGTK::DoClientToScreen( 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 void wxWindowGTK::DoScreenToClient( int *x, int *y ) const
3423 {
3424 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3425
3426 if (!m_widget->window) return;
3427
3428 GdkWindow *source = (GdkWindow *) NULL;
3429 if (m_wxwindow)
3430 source = GTK_PIZZA(m_wxwindow)->bin_window;
3431 else
3432 source = m_widget->window;
3433
3434 int org_x = 0;
3435 int org_y = 0;
3436 gdk_window_get_origin( source, &org_x, &org_y );
3437
3438 if (!m_wxwindow)
3439 {
3440 if (GTK_WIDGET_NO_WINDOW (m_widget))
3441 {
3442 org_x += m_widget->allocation.x;
3443 org_y += m_widget->allocation.y;
3444 }
3445 }
3446
3447 if (x) *x -= org_x;
3448 if (y) *y -= org_y;
3449 }
3450
3451 bool wxWindowGTK::Show( bool show )
3452 {
3453 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3454
3455 if (!wxWindowBase::Show(show))
3456 {
3457 // nothing to do
3458 return FALSE;
3459 }
3460
3461 if (show)
3462 gtk_widget_show( m_widget );
3463 else
3464 gtk_widget_hide( m_widget );
3465
3466 wxShowEvent eventShow(GetId(), show);
3467 eventShow.SetEventObject(this);
3468
3469 GetEventHandler()->ProcessEvent(eventShow);
3470
3471 return TRUE;
3472 }
3473
3474 static void wxWindowNotifyEnable(wxWindowGTK* win, bool enable)
3475 {
3476 win->OnParentEnable(enable);
3477
3478 // Recurse, so that children have the opportunity to Do The Right Thing
3479 // and reset colours that have been messed up by a parent's (really ancestor's)
3480 // Enable call
3481 for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
3482 node;
3483 node = node->GetNext() )
3484 {
3485 wxWindow *child = node->GetData();
3486 if (!child->IsKindOf(CLASSINFO(wxDialog)) && !child->IsKindOf(CLASSINFO(wxFrame)))
3487 wxWindowNotifyEnable(child, enable);
3488 }
3489 }
3490
3491 bool wxWindowGTK::Enable( bool enable )
3492 {
3493 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3494
3495 if (!wxWindowBase::Enable(enable))
3496 {
3497 // nothing to do
3498 return FALSE;
3499 }
3500
3501 gtk_widget_set_sensitive( m_widget, enable );
3502 if ( m_wxwindow )
3503 gtk_widget_set_sensitive( m_wxwindow, enable );
3504
3505 wxWindowNotifyEnable(this, enable);
3506
3507 return TRUE;
3508 }
3509
3510 int wxWindowGTK::GetCharHeight() const
3511 {
3512 wxCHECK_MSG( (m_widget != NULL), 12, wxT("invalid window") );
3513
3514 wxFont font = GetFont();
3515 wxCHECK_MSG( font.Ok(), 12, wxT("invalid font") );
3516
3517 #ifdef __WXGTK20__
3518 PangoContext *context = NULL;
3519 if (m_widget)
3520 context = gtk_widget_get_pango_context( m_widget );
3521
3522 if (!context)
3523 return 0;
3524
3525 PangoFontDescription *desc = font.GetNativeFontInfo()->description;
3526 PangoLayout *layout = pango_layout_new(context);
3527 pango_layout_set_font_description(layout, desc);
3528 pango_layout_set_text(layout, "H", 1);
3529 PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
3530
3531 PangoRectangle rect;
3532 pango_layout_line_get_extents(line, NULL, &rect);
3533
3534 g_object_unref( G_OBJECT( layout ) );
3535
3536 return (int) PANGO_PIXELS(rect.height);
3537 #else
3538 GdkFont *gfont = font.GetInternalFont( 1.0 );
3539
3540 return gfont->ascent + gfont->descent;
3541 #endif
3542 }
3543
3544 int wxWindowGTK::GetCharWidth() const
3545 {
3546 wxCHECK_MSG( (m_widget != NULL), 8, wxT("invalid window") );
3547
3548 wxFont font = GetFont();
3549 wxCHECK_MSG( font.Ok(), 8, wxT("invalid font") );
3550
3551 #ifdef __WXGTK20__
3552 PangoContext *context = NULL;
3553 if (m_widget)
3554 context = gtk_widget_get_pango_context( m_widget );
3555
3556 if (!context)
3557 return 0;
3558
3559 PangoFontDescription *desc = font.GetNativeFontInfo()->description;
3560 PangoLayout *layout = pango_layout_new(context);
3561 pango_layout_set_font_description(layout, desc);
3562 pango_layout_set_text(layout, "g", 1);
3563 PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
3564
3565 PangoRectangle rect;
3566 pango_layout_line_get_extents(line, NULL, &rect);
3567
3568 g_object_unref( G_OBJECT( layout ) );
3569
3570 return (int) PANGO_PIXELS(rect.width);
3571 #else
3572 GdkFont *gfont = font.GetInternalFont( 1.0 );
3573
3574 return gdk_string_width( gfont, "g" );
3575 #endif
3576 }
3577
3578 void wxWindowGTK::GetTextExtent( const wxString& string,
3579 int *x,
3580 int *y,
3581 int *descent,
3582 int *externalLeading,
3583 const wxFont *theFont ) const
3584 {
3585 wxFont fontToUse = theFont ? *theFont : GetFont();
3586
3587 wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
3588
3589 if (string.IsEmpty())
3590 {
3591 if (x) (*x) = 0;
3592 if (y) (*y) = 0;
3593 return;
3594 }
3595
3596 #ifdef __WXGTK20__
3597 PangoContext *context = NULL;
3598 if (m_widget)
3599 context = gtk_widget_get_pango_context( m_widget );
3600
3601 if (!context)
3602 {
3603 if (x) (*x) = 0;
3604 if (y) (*y) = 0;
3605 return;
3606 }
3607
3608 PangoFontDescription *desc = fontToUse.GetNativeFontInfo()->description;
3609 PangoLayout *layout = pango_layout_new(context);
3610 pango_layout_set_font_description(layout, desc);
3611 {
3612 #if wxUSE_UNICODE
3613 const wxCharBuffer data = wxConvUTF8.cWC2MB( string );
3614 pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data ));
3615 #else
3616 const wxWCharBuffer wdata = wxConvLocal.cMB2WC( string );
3617 const wxCharBuffer data = wxConvUTF8.cWC2MB( wdata );
3618 pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data ));
3619 #endif
3620 }
3621
3622 PangoRectangle rect;
3623 pango_layout_get_extents(layout, NULL, &rect);
3624
3625 if (x) (*x) = (wxCoord) PANGO_PIXELS(rect.width);
3626 if (y) (*y) = (wxCoord) PANGO_PIXELS(rect.height);
3627 if (descent)
3628 {
3629 PangoLayoutIter *iter = pango_layout_get_iter(layout);
3630 int baseline = pango_layout_iter_get_baseline(iter);
3631 pango_layout_iter_free(iter);
3632 *descent = *y - PANGO_PIXELS(baseline);
3633 }
3634 if (externalLeading) (*externalLeading) = 0; // ??
3635
3636 g_object_unref( G_OBJECT( layout ) );
3637 #else
3638 GdkFont *font = fontToUse.GetInternalFont( 1.0 );
3639 if (x) (*x) = gdk_string_width( font, wxGTK_CONV( string ) );
3640 if (y) (*y) = font->ascent + font->descent;
3641 if (descent) (*descent) = font->descent;
3642 if (externalLeading) (*externalLeading) = 0; // ??
3643 #endif
3644 }
3645
3646 void wxWindowGTK::SetFocus()
3647 {
3648 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3649 if ( m_hasFocus )
3650 {
3651 // don't do anything if we already have focus
3652 return;
3653 }
3654
3655 if (m_wxwindow)
3656 {
3657 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
3658 {
3659 gtk_widget_grab_focus (m_wxwindow);
3660 }
3661 }
3662 else if (m_widget)
3663 {
3664 #ifdef __WXGTK20__
3665 if (GTK_IS_CONTAINER(m_widget))
3666 {
3667 gtk_widget_child_focus( m_widget, GTK_DIR_TAB_FORWARD );
3668 }
3669 else
3670 #endif
3671 if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
3672 {
3673
3674 if (!GTK_WIDGET_REALIZED(m_widget))
3675 {
3676 // we can't set the focus to the widget now so we remember that
3677 // it should be focused and will do it later, during the idle
3678 // time, as soon as we can
3679 wxLogTrace(TRACE_FOCUS,
3680 _T("Delaying setting focus to %s(%s)"),
3681 GetClassInfo()->GetClassName(), GetLabel().c_str());
3682
3683 g_delayedFocus = this;
3684 }
3685 else
3686 {
3687 wxLogTrace(TRACE_FOCUS,
3688 _T("Setting focus to %s(%s)"),
3689 GetClassInfo()->GetClassName(), GetLabel().c_str());
3690
3691 gtk_widget_grab_focus (m_widget);
3692 }
3693 }
3694 else
3695 #ifndef __WXGTK20__
3696 if (GTK_IS_CONTAINER(m_widget))
3697 {
3698 gtk_container_focus( GTK_CONTAINER(m_widget), GTK_DIR_TAB_FORWARD );
3699 }
3700 else
3701 #endif
3702 {
3703 wxLogTrace(TRACE_FOCUS,
3704 _T("Can't set focus to %s(%s)"),
3705 GetClassInfo()->GetClassName(), GetLabel().c_str());
3706 }
3707 }
3708 }
3709
3710 bool wxWindowGTK::AcceptsFocus() const
3711 {
3712 return m_acceptsFocus && wxWindowBase::AcceptsFocus();
3713 }
3714
3715 bool wxWindowGTK::Reparent( wxWindowBase *newParentBase )
3716 {
3717 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3718
3719 wxWindowGTK *oldParent = m_parent,
3720 *newParent = (wxWindowGTK *)newParentBase;
3721
3722 wxASSERT( GTK_IS_WIDGET(m_widget) );
3723
3724 if ( !wxWindowBase::Reparent(newParent) )
3725 return FALSE;
3726
3727 wxASSERT( GTK_IS_WIDGET(m_widget) );
3728
3729 /* prevent GTK from deleting the widget arbitrarily */
3730 gtk_widget_ref( m_widget );
3731
3732 if (oldParent)
3733 {
3734 gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget );
3735 }
3736
3737 wxASSERT( GTK_IS_WIDGET(m_widget) );
3738
3739 if (newParent)
3740 {
3741 /* insert GTK representation */
3742 (*(newParent->m_insertCallback))(newParent, this);
3743 }
3744
3745 /* reverse: prevent GTK from deleting the widget arbitrarily */
3746 gtk_widget_unref( m_widget );
3747
3748 return TRUE;
3749 }
3750
3751 void wxWindowGTK::DoAddChild(wxWindowGTK *child)
3752 {
3753 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
3754
3755 wxASSERT_MSG( (child != NULL), wxT("invalid child window") );
3756
3757 wxASSERT_MSG( (m_insertCallback != NULL), wxT("invalid child insertion function") );
3758
3759 /* add to list */
3760 AddChild( child );
3761
3762 /* insert GTK representation */
3763 (*m_insertCallback)(this, child);
3764 }
3765
3766 #ifdef __WXGTK20__
3767
3768 void wxWindowGTK::AddChild(wxWindowBase *child)
3769 {
3770 wxWindowBase::AddChild(child);
3771 m_dirtyTabOrder = true;
3772 if (g_isIdle)
3773 wxapp_install_idle_handler();
3774 }
3775
3776 void wxWindowGTK::RemoveChild(wxWindowBase *child)
3777 {
3778 wxWindowBase::RemoveChild(child);
3779 m_dirtyTabOrder = true;
3780 if (g_isIdle)
3781 wxapp_install_idle_handler();
3782 }
3783
3784 void wxWindowGTK::DoMoveInTabOrder(wxWindow *win, MoveKind move)
3785 {
3786 wxWindowBase::DoMoveInTabOrder(win, move);
3787 m_dirtyTabOrder = true;
3788 if (g_isIdle)
3789 wxapp_install_idle_handler();
3790 }
3791
3792 void wxWindowGTK::RealizeTabOrder()
3793 {
3794 if (m_wxwindow)
3795 {
3796 if (m_children.size() > 0)
3797 {
3798 GList *chain = NULL;
3799
3800 for (wxWindowList::const_iterator i = m_children.begin();
3801 i != m_children.end(); ++i)
3802 {
3803 chain = g_list_prepend(chain, (*i)->m_widget);
3804 }
3805
3806 chain = g_list_reverse(chain);
3807
3808 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow), chain);
3809 g_list_free(chain);
3810 }
3811 else
3812 {
3813 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow));
3814 }
3815 }
3816
3817 m_dirtyTabOrder = false;
3818 }
3819
3820 #endif // __WXGTK20__
3821
3822 void wxWindowGTK::Raise()
3823 {
3824 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3825
3826 if (m_wxwindow && m_wxwindow->window)
3827 {
3828 gdk_window_raise( m_wxwindow->window );
3829 }
3830 else if (m_widget->window)
3831 {
3832 gdk_window_raise( m_widget->window );
3833 }
3834 }
3835
3836 void wxWindowGTK::Lower()
3837 {
3838 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3839
3840 if (m_wxwindow && m_wxwindow->window)
3841 {
3842 gdk_window_lower( m_wxwindow->window );
3843 }
3844 else if (m_widget->window)
3845 {
3846 gdk_window_lower( m_widget->window );
3847 }
3848 }
3849
3850 bool wxWindowGTK::SetCursor( const wxCursor &cursor )
3851 {
3852 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3853
3854 if (cursor == m_cursor)
3855 return FALSE;
3856
3857 if (g_isIdle)
3858 wxapp_install_idle_handler();
3859
3860 if (cursor == wxNullCursor)
3861 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR );
3862 else
3863 return wxWindowBase::SetCursor( cursor );
3864 }
3865
3866 void wxWindowGTK::WarpPointer( int x, int y )
3867 {
3868 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3869
3870 // We provide this function ourselves as it is
3871 // missing in GDK (top of this file).
3872
3873 GdkWindow *window = (GdkWindow*) NULL;
3874 if (m_wxwindow)
3875 window = GTK_PIZZA(m_wxwindow)->bin_window;
3876 else
3877 window = GetConnectWidget()->window;
3878
3879 if (window)
3880 gdk_window_warp_pointer( window, x, y );
3881 }
3882
3883
3884 void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
3885 {
3886 if (!m_widget) return;
3887 if (!m_widget->window) return;
3888
3889 #ifndef __WXGTK20__
3890 if (g_isIdle)
3891 wxapp_install_idle_handler();
3892
3893 wxRect myRect(0,0,0,0);
3894 if (m_wxwindow && rect)
3895 {
3896 myRect.SetSize(wxSize( m_wxwindow->allocation.width,
3897 m_wxwindow->allocation.height));
3898 myRect.Intersect(*rect);
3899 if (!myRect.width || !myRect.height)
3900 // nothing to do, rectangle is empty
3901 return;
3902 rect = &myRect;
3903 }
3904
3905 if (eraseBackground && m_wxwindow && m_wxwindow->window)
3906 {
3907 if (rect)
3908 {
3909 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3910 m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height );
3911 }
3912 else
3913 {
3914 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3915 m_clearRegion.Clear();
3916 m_clearRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
3917 }
3918 }
3919
3920 if (rect)
3921 {
3922 if (m_wxwindow)
3923 {
3924 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3925 m_updateRegion.Union( rect->x, rect->y, rect->width, rect->height );
3926 }
3927 else
3928 {
3929 GdkRectangle gdk_rect;
3930 gdk_rect.x = rect->x;
3931 gdk_rect.y = rect->y;
3932 gdk_rect.width = rect->width;
3933 gdk_rect.height = rect->height;
3934 gtk_widget_draw( m_widget, &gdk_rect );
3935 }
3936 }
3937 else
3938 {
3939 if (m_wxwindow)
3940 {
3941 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3942 m_updateRegion.Clear();
3943 m_updateRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
3944 }
3945 else
3946 {
3947 gtk_widget_draw( m_widget, (GdkRectangle*) NULL );
3948 }
3949 }
3950 #else
3951 if (m_wxwindow)
3952 {
3953 if (rect)
3954 {
3955 GdkRectangle gdk_rect;
3956 gdk_rect.x = rect->x;
3957 gdk_rect.y = rect->y;
3958 gdk_rect.width = rect->width;
3959 gdk_rect.height = rect->height;
3960 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow)->bin_window, &gdk_rect, TRUE );
3961 }
3962 else
3963 {
3964 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow)->bin_window, NULL, TRUE );
3965 }
3966 }
3967 #endif
3968 }
3969
3970 void wxWindowGTK::Update()
3971 {
3972 GtkUpdate();
3973
3974 // when we call Update() we really want to update the window immediately on
3975 // screen, even if itmeans flushing the entire queue and hence slowing down
3976 // everything -- but it should still be done, it's just that Update() should
3977 // be called very rarely
3978 gdk_flush();
3979 }
3980
3981 void wxWindowGTK::GtkUpdate()
3982 {
3983 #ifdef __WXGTK20__
3984 if (m_wxwindow && GTK_PIZZA(m_wxwindow)->bin_window)
3985 gdk_window_process_updates( GTK_PIZZA(m_wxwindow)->bin_window, FALSE );
3986 #else
3987 if (!m_updateRegion.IsEmpty())
3988 GtkSendPaintEvents();
3989 #endif
3990 }
3991
3992 void wxWindowGTK::GtkSendPaintEvents()
3993 {
3994 if (!m_wxwindow)
3995 {
3996 #ifndef __WXGTK20__
3997 m_clearRegion.Clear();
3998 #endif
3999 m_updateRegion.Clear();
4000 return;
4001 }
4002
4003 // Clip to paint region in wxClientDC
4004 m_clipPaintRegion = TRUE;
4005
4006 // widget to draw on
4007 GtkPizza *pizza = GTK_PIZZA (m_wxwindow);
4008
4009 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM))
4010 {
4011 // find ancestor from which to steal background
4012 wxWindow *parent = wxGetTopLevelParent((wxWindow *)this);
4013 if (!parent)
4014 parent = (wxWindow*)this;
4015
4016 if (GTK_WIDGET_MAPPED(parent->m_widget))
4017 {
4018 wxRegionIterator upd( m_updateRegion );
4019 while (upd)
4020 {
4021 GdkRectangle rect;
4022 rect.x = upd.GetX();
4023 rect.y = upd.GetY();
4024 rect.width = upd.GetWidth();
4025 rect.height = upd.GetHeight();
4026
4027 gtk_paint_flat_box( parent->m_widget->style,
4028 pizza->bin_window,
4029 (GtkStateType)GTK_WIDGET_STATE(m_wxwindow),
4030 GTK_SHADOW_NONE,
4031 &rect,
4032 parent->m_widget,
4033 (char *)"base",
4034 0, 0, -1, -1 );
4035
4036 upd ++;
4037 }
4038 }
4039 }
4040 else
4041
4042 #ifdef __WXGTK20__
4043 {
4044 wxWindowDC dc( (wxWindow*)this );
4045 dc.SetClippingRegion( m_updateRegion );
4046
4047 wxEraseEvent erase_event( GetId(), &dc );
4048 erase_event.SetEventObject( this );
4049
4050 GetEventHandler()->ProcessEvent(erase_event);
4051 }
4052 #else
4053 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
4054 {
4055 wxWindowDC dc( (wxWindow*)this );
4056 if (m_clearRegion.IsEmpty())
4057 dc.SetClippingRegion( m_updateRegion );
4058 else
4059 dc.SetClippingRegion( m_clearRegion );
4060
4061 wxEraseEvent erase_event( GetId(), &dc );
4062 erase_event.SetEventObject( this );
4063
4064 if (!GetEventHandler()->ProcessEvent(erase_event) && GetBackgroundStyle() != wxBG_STYLE_CUSTOM)
4065 {
4066 if (!g_eraseGC)
4067 {
4068 g_eraseGC = gdk_gc_new( pizza->bin_window );
4069 gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4070 }
4071 gdk_gc_set_foreground( g_eraseGC, GetBackgroundColour().GetColor() );
4072
4073 wxRegionIterator upd( m_clearRegion );
4074 while (upd)
4075 {
4076 gdk_draw_rectangle( pizza->bin_window, g_eraseGC, 1,
4077 upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
4078 upd ++;
4079 }
4080 }
4081 m_clearRegion.Clear();
4082 }
4083 #endif
4084
4085 wxNcPaintEvent nc_paint_event( GetId() );
4086 nc_paint_event.SetEventObject( this );
4087 GetEventHandler()->ProcessEvent( nc_paint_event );
4088
4089 wxPaintEvent paint_event( GetId() );
4090 paint_event.SetEventObject( this );
4091 GetEventHandler()->ProcessEvent( paint_event );
4092
4093 m_clipPaintRegion = FALSE;
4094
4095 #ifndef __WXUNIVERSAL__
4096 #ifndef __WXGTK20__
4097 // The following code will result in all window-less widgets
4098 // being redrawn because the wxWidgets class is allowed to
4099 // paint over the window-less widgets.
4100
4101 GList *children = pizza->children;
4102 while (children)
4103 {
4104 GtkPizzaChild *child = (GtkPizzaChild*) children->data;
4105 children = children->next;
4106
4107 if (GTK_WIDGET_NO_WINDOW (child->widget) &&
4108 GTK_WIDGET_DRAWABLE (child->widget))
4109 {
4110 // Get intersection of widget area and update region
4111 wxRegion region( m_updateRegion );
4112
4113 GdkEventExpose gdk_event;
4114 gdk_event.type = GDK_EXPOSE;
4115 gdk_event.window = pizza->bin_window;
4116 gdk_event.count = 0;
4117
4118 wxRegionIterator upd( m_updateRegion );
4119 while (upd)
4120 {
4121 GdkRectangle rect;
4122 rect.x = upd.GetX();
4123 rect.y = upd.GetY();
4124 rect.width = upd.GetWidth();
4125 rect.height = upd.GetHeight();
4126
4127 if (gtk_widget_intersect (child->widget, &rect, &gdk_event.area))
4128 {
4129 gtk_widget_event (child->widget, (GdkEvent*) &gdk_event);
4130 }
4131
4132 upd ++;
4133 }
4134 }
4135 }
4136 #endif
4137 #endif
4138
4139 m_updateRegion.Clear();
4140 }
4141
4142 void wxWindowGTK::ClearBackground()
4143 {
4144 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4145
4146 #ifndef __WXGTK20__
4147 if (m_wxwindow && m_wxwindow->window)
4148 {
4149 m_clearRegion.Clear();
4150 wxSize size( GetClientSize() );
4151 m_clearRegion.Union( 0,0,size.x,size.y );
4152
4153 // Better do this in idle?
4154 GtkUpdate();
4155 }
4156 #endif
4157 }
4158
4159 #if wxUSE_TOOLTIPS
4160 void wxWindowGTK::DoSetToolTip( wxToolTip *tip )
4161 {
4162 wxWindowBase::DoSetToolTip(tip);
4163
4164 if (m_tooltip)
4165 m_tooltip->Apply( (wxWindow *)this );
4166 }
4167
4168 void wxWindowGTK::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
4169 {
4170 wxString tmp( tip );
4171 gtk_tooltips_set_tip( tips, GetConnectWidget(), wxGTK_CONV(tmp), (gchar*) NULL );
4172 }
4173 #endif // wxUSE_TOOLTIPS
4174
4175 bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
4176 {
4177 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
4178
4179 if (!wxWindowBase::SetBackgroundColour(colour))
4180 return false;
4181
4182 if (colour.Ok())
4183 {
4184 // We need the pixel value e.g. for background clearing.
4185 m_backgroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
4186 }
4187
4188 // apply style change (forceStyle=true so that new style is applied
4189 // even if the bg colour changed from valid to wxNullColour)
4190 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM)
4191 ApplyWidgetStyle(true);
4192
4193 return true;
4194 }
4195
4196 bool wxWindowGTK::SetForegroundColour( const wxColour &colour )
4197 {
4198 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
4199
4200 if (!wxWindowBase::SetForegroundColour(colour))
4201 {
4202 return false;
4203 }
4204
4205 if (colour.Ok())
4206 {
4207 // We need the pixel value e.g. for background clearing.
4208 m_foregroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
4209 }
4210
4211 // apply style change (forceStyle=true so that new style is applied
4212 // even if the bg colour changed from valid to wxNullColour):
4213 ApplyWidgetStyle(true);
4214
4215 return true;
4216 }
4217
4218 #ifdef __WXGTK20__
4219 PangoContext *wxWindowGTK::GtkGetPangoDefaultContext()
4220 {
4221 return gtk_widget_get_pango_context( m_widget );
4222 }
4223
4224 PangoContext *wxWindowGTK::GtkGetPangoX11Context()
4225 {
4226 if (!m_x11Context)
4227 m_x11Context = pango_x_get_context( gdk_display );
4228
4229 return m_x11Context;
4230 }
4231 #endif
4232
4233 GtkRcStyle *wxWindowGTK::CreateWidgetStyle(bool forceStyle)
4234 {
4235 // do we need to apply any changes at all?
4236 if ( !forceStyle &&
4237 !m_font.Ok() &&
4238 !m_foregroundColour.Ok() && !m_backgroundColour.Ok() )
4239 {
4240 return NULL;
4241 }
4242
4243 GtkRcStyle *style = gtk_rc_style_new();
4244
4245 if ( m_font.Ok() )
4246 {
4247 #ifdef __WXGTK20__
4248 style->font_desc =
4249 pango_font_description_copy( m_font.GetNativeFontInfo()->description );
4250 #else
4251 wxString xfontname = m_font.GetNativeFontInfo()->GetXFontName();
4252 style->fontset_name = g_strdup(xfontname.c_str());
4253 #endif
4254 }
4255
4256 if ( m_foregroundColour.Ok() )
4257 {
4258 GdkColor *fg = m_foregroundColour.GetColor();
4259
4260 style->fg[GTK_STATE_NORMAL] = *fg;
4261 style->color_flags[GTK_STATE_NORMAL] = GTK_RC_FG;
4262
4263 style->fg[GTK_STATE_PRELIGHT] = *fg;
4264 style->color_flags[GTK_STATE_PRELIGHT] = GTK_RC_FG;
4265
4266 style->fg[GTK_STATE_ACTIVE] = *fg;
4267 style->color_flags[GTK_STATE_ACTIVE] = GTK_RC_FG;
4268 }
4269
4270 if ( m_backgroundColour.Ok() )
4271 {
4272 GdkColor *bg = m_backgroundColour.GetColor();
4273
4274 style->bg[GTK_STATE_NORMAL] = *bg;
4275 style->base[GTK_STATE_NORMAL] = *bg;
4276 style->color_flags[GTK_STATE_NORMAL] = (GtkRcFlags)
4277 (style->color_flags[GTK_STATE_NORMAL] | GTK_RC_BG | GTK_RC_BASE);
4278
4279 style->bg[GTK_STATE_PRELIGHT] = *bg;
4280 style->base[GTK_STATE_PRELIGHT] = *bg;
4281 style->color_flags[GTK_STATE_PRELIGHT] = (GtkRcFlags)
4282 (style->color_flags[GTK_STATE_PRELIGHT] | GTK_RC_BG | GTK_RC_BASE);
4283
4284 style->bg[GTK_STATE_ACTIVE] = *bg;
4285 style->base[GTK_STATE_ACTIVE] = *bg;
4286 style->color_flags[GTK_STATE_ACTIVE] = (GtkRcFlags)
4287 (style->color_flags[GTK_STATE_ACTIVE] | GTK_RC_BG | GTK_RC_BASE);
4288
4289 style->bg[GTK_STATE_INSENSITIVE] = *bg;
4290 style->base[GTK_STATE_INSENSITIVE] = *bg;
4291 style->color_flags[GTK_STATE_INSENSITIVE] = (GtkRcFlags)
4292 (style->color_flags[GTK_STATE_INSENSITIVE] | GTK_RC_BG | GTK_RC_BASE);
4293 }
4294
4295 return style;
4296 }
4297
4298 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle)
4299 {
4300 GtkRcStyle *style = CreateWidgetStyle(forceStyle);
4301 if ( style )
4302 {
4303 DoApplyWidgetStyle(style);
4304 gtk_rc_style_unref(style);
4305 }
4306
4307 // Style change may affect GTK+'s size calculation:
4308 InvalidateBestSize();
4309 }
4310
4311 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle *style)
4312 {
4313 if (m_wxwindow)
4314 gtk_widget_modify_style(m_wxwindow, style);
4315 gtk_widget_modify_style(m_widget, style);
4316 }
4317
4318 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style)
4319 {
4320 wxWindowBase::SetBackgroundStyle(style);
4321
4322 if (style == wxBG_STYLE_CUSTOM)
4323 {
4324 GdkWindow *window = (GdkWindow*) NULL;
4325 if (m_wxwindow)
4326 window = GTK_PIZZA(m_wxwindow)->bin_window;
4327 else
4328 window = GetConnectWidget()->window;
4329
4330 if (window)
4331 {
4332 // Make sure GDK/X11 doesn't refresh the window
4333 // automatically.
4334 gdk_window_set_back_pixmap( window, None, False );
4335 #ifdef __X__
4336 Display* display = GDK_WINDOW_DISPLAY(window);
4337 XFlush(display);
4338 #endif
4339 m_needsStyleChange = false;
4340 }
4341 else
4342 // Do in OnIdle, because the window is not yet available
4343 m_needsStyleChange = true;
4344
4345 // Don't apply widget style, or we get a grey background
4346 }
4347 else
4348 {
4349 // apply style change (forceStyle=true so that new style is applied
4350 // even if the bg colour changed from valid to wxNullColour):
4351 ApplyWidgetStyle(true);
4352 }
4353 return true;
4354 }
4355
4356 //-----------------------------------------------------------------------------
4357 // Pop-up menu stuff
4358 //-----------------------------------------------------------------------------
4359
4360 #if wxUSE_MENUS_NATIVE
4361
4362 extern "C"
4363 void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting )
4364 {
4365 *is_waiting = FALSE;
4366 }
4367
4368 void SetInvokingWindow( wxMenu *menu, wxWindow* win )
4369 {
4370 menu->SetInvokingWindow( win );
4371
4372 wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst();
4373 while (node)
4374 {
4375 wxMenuItem *menuitem = node->GetData();
4376 if (menuitem->IsSubMenu())
4377 {
4378 SetInvokingWindow( menuitem->GetSubMenu(), win );
4379 }
4380
4381 node = node->GetNext();
4382 }
4383 }
4384
4385 extern "C" void wxPopupMenuPositionCallback( GtkMenu *menu,
4386 gint *x, gint *y,
4387 #ifdef __WXGTK20__
4388 gboolean * WXUNUSED(whatever),
4389 #endif
4390 gpointer user_data )
4391 {
4392 // ensure that the menu appears entirely on screen
4393 GtkRequisition req;
4394 gtk_widget_get_child_requisition(GTK_WIDGET(menu), &req);
4395
4396 wxSize sizeScreen = wxGetDisplaySize();
4397 wxPoint *pos = (wxPoint*)user_data;
4398
4399 gint xmax = sizeScreen.x - req.width,
4400 ymax = sizeScreen.y - req.height;
4401
4402 *x = pos->x < xmax ? pos->x : xmax;
4403 *y = pos->y < ymax ? pos->y : ymax;
4404 }
4405
4406 bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
4407 {
4408 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
4409
4410 wxCHECK_MSG( menu != NULL, false, wxT("invalid popup-menu") );
4411
4412 // NOTE: if you change this code, you need to update
4413 // the same code in taskbar.cpp as well. This
4414 // is ugly code duplication, I know,
4415
4416 SetInvokingWindow( menu, this );
4417
4418 menu->UpdateUI();
4419
4420 bool is_waiting = true;
4421
4422 gulong handler = gtk_signal_connect( GTK_OBJECT(menu->m_menu),
4423 "hide",
4424 GTK_SIGNAL_FUNC(gtk_pop_hide_callback),
4425 (gpointer)&is_waiting );
4426
4427 wxPoint pos;
4428 gpointer userdata;
4429 GtkMenuPositionFunc posfunc;
4430 if ( x == -1 && y == -1 )
4431 {
4432 // use GTK's default positioning algorithm
4433 userdata = NULL;
4434 posfunc = NULL;
4435 }
4436 else
4437 {
4438 pos = ClientToScreen(wxPoint(x, y));
4439 userdata = &pos;
4440 posfunc = wxPopupMenuPositionCallback;
4441 }
4442
4443 gtk_menu_popup(
4444 GTK_MENU(menu->m_menu),
4445 (GtkWidget *) NULL, // parent menu shell
4446 (GtkWidget *) NULL, // parent menu item
4447 posfunc, // function to position it
4448 userdata, // client data
4449 0, // button used to activate it
4450 #ifdef __WXGTK20__
4451 gtk_get_current_event_time()
4452 #else
4453 gs_timeLastClick // the time of activation
4454 #endif
4455 );
4456
4457 while (is_waiting)
4458 {
4459 gtk_main_iteration();
4460 }
4461
4462 gtk_signal_disconnect(GTK_OBJECT(menu->m_menu), handler);
4463
4464 return true;
4465 }
4466
4467 #endif // wxUSE_MENUS_NATIVE
4468
4469 #if wxUSE_DRAG_AND_DROP
4470
4471 void wxWindowGTK::SetDropTarget( wxDropTarget *dropTarget )
4472 {
4473 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4474
4475 GtkWidget *dnd_widget = GetConnectWidget();
4476
4477 if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
4478
4479 if (m_dropTarget) delete m_dropTarget;
4480 m_dropTarget = dropTarget;
4481
4482 if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
4483 }
4484
4485 #endif // wxUSE_DRAG_AND_DROP
4486
4487 GtkWidget* wxWindowGTK::GetConnectWidget()
4488 {
4489 GtkWidget *connect_widget = m_widget;
4490 if (m_wxwindow) connect_widget = m_wxwindow;
4491
4492 return connect_widget;
4493 }
4494
4495 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow *window )
4496 {
4497 if (m_wxwindow)
4498 return (window == GTK_PIZZA(m_wxwindow)->bin_window);
4499
4500 return (window == m_widget->window);
4501 }
4502
4503 bool wxWindowGTK::SetFont( const wxFont &font )
4504 {
4505 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
4506
4507 if (!wxWindowBase::SetFont(font))
4508 return false;
4509
4510 // apply style change (forceStyle=true so that new style is applied
4511 // even if the font changed from valid to wxNullFont):
4512 ApplyWidgetStyle(true);
4513
4514 return true;
4515 }
4516
4517 void wxWindowGTK::DoCaptureMouse()
4518 {
4519 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4520
4521 GdkWindow *window = (GdkWindow*) NULL;
4522 if (m_wxwindow)
4523 window = GTK_PIZZA(m_wxwindow)->bin_window;
4524 else
4525 window = GetConnectWidget()->window;
4526
4527 wxCHECK_RET( window, _T("CaptureMouse() failed") );
4528
4529 wxCursor* cursor = & m_cursor;
4530 if (!cursor->Ok())
4531 cursor = wxSTANDARD_CURSOR;
4532
4533 gdk_pointer_grab( window, FALSE,
4534 (GdkEventMask)
4535 (GDK_BUTTON_PRESS_MASK |
4536 GDK_BUTTON_RELEASE_MASK |
4537 GDK_POINTER_MOTION_HINT_MASK |
4538 GDK_POINTER_MOTION_MASK),
4539 (GdkWindow *) NULL,
4540 cursor->GetCursor(),
4541 (guint32)GDK_CURRENT_TIME );
4542 g_captureWindow = this;
4543 g_captureWindowHasMouse = TRUE;
4544 }
4545
4546 void wxWindowGTK::DoReleaseMouse()
4547 {
4548 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4549
4550 wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") );
4551
4552 g_captureWindow = (wxWindowGTK*) NULL;
4553
4554 GdkWindow *window = (GdkWindow*) NULL;
4555 if (m_wxwindow)
4556 window = GTK_PIZZA(m_wxwindow)->bin_window;
4557 else
4558 window = GetConnectWidget()->window;
4559
4560 if (!window)
4561 return;
4562
4563 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
4564 }
4565
4566 /* static */
4567 wxWindow *wxWindowBase::GetCapture()
4568 {
4569 return (wxWindow *)g_captureWindow;
4570 }
4571
4572 bool wxWindowGTK::IsRetained() const
4573 {
4574 return FALSE;
4575 }
4576
4577 void wxWindowGTK::SetScrollbar( int orient, int pos, int thumbVisible,
4578 int range, bool refresh )
4579 {
4580 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4581
4582 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
4583
4584 m_hasScrolling = TRUE;
4585
4586 if (orient == wxHORIZONTAL)
4587 {
4588 float fpos = (float)pos;
4589 float frange = (float)range;
4590 float fthumb = (float)thumbVisible;
4591 if (fpos > frange-fthumb) fpos = frange-fthumb;
4592 if (fpos < 0.0) fpos = 0.0;
4593
4594 if ((fabs(frange-m_hAdjust->upper) < 0.2) &&
4595 (fabs(fthumb-m_hAdjust->page_size) < 0.2))
4596 {
4597 SetScrollPos( orient, pos, refresh );
4598 return;
4599 }
4600
4601 m_oldHorizontalPos = fpos;
4602
4603 m_hAdjust->lower = 0.0;
4604 m_hAdjust->upper = frange;
4605 m_hAdjust->value = fpos;
4606 m_hAdjust->step_increment = 1.0;
4607 m_hAdjust->page_increment = (float)(wxMax(fthumb,0));
4608 m_hAdjust->page_size = fthumb;
4609 }
4610 else
4611 {
4612 float fpos = (float)pos;
4613 float frange = (float)range;
4614 float fthumb = (float)thumbVisible;
4615 if (fpos > frange-fthumb) fpos = frange-fthumb;
4616 if (fpos < 0.0) fpos = 0.0;
4617
4618 if ((fabs(frange-m_vAdjust->upper) < 0.2) &&
4619 (fabs(fthumb-m_vAdjust->page_size) < 0.2))
4620 {
4621 SetScrollPos( orient, pos, refresh );
4622 return;
4623 }
4624
4625 m_oldVerticalPos = fpos;
4626
4627 m_vAdjust->lower = 0.0;
4628 m_vAdjust->upper = frange;
4629 m_vAdjust->value = fpos;
4630 m_vAdjust->step_increment = 1.0;
4631 m_vAdjust->page_increment = (float)(wxMax(fthumb,0));
4632 m_vAdjust->page_size = fthumb;
4633 }
4634
4635 if (orient == wxHORIZONTAL)
4636 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
4637 else
4638 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
4639 }
4640
4641 void wxWindowGTK::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
4642 {
4643 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4644
4645 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
4646
4647 if (orient == wxHORIZONTAL)
4648 {
4649 float fpos = (float)pos;
4650 if (fpos > m_hAdjust->upper - m_hAdjust->page_size) fpos = m_hAdjust->upper - m_hAdjust->page_size;
4651 if (fpos < 0.0) fpos = 0.0;
4652 m_oldHorizontalPos = fpos;
4653
4654 if (fabs(fpos-m_hAdjust->value) < 0.2) return;
4655 m_hAdjust->value = fpos;
4656 }
4657 else
4658 {
4659 float fpos = (float)pos;
4660 if (fpos > m_vAdjust->upper - m_vAdjust->page_size) fpos = m_vAdjust->upper - m_vAdjust->page_size;
4661 if (fpos < 0.0) fpos = 0.0;
4662 m_oldVerticalPos = fpos;
4663
4664 if (fabs(fpos-m_vAdjust->value) < 0.2) return;
4665 m_vAdjust->value = fpos;
4666 }
4667
4668 if (m_wxwindow->window)
4669 {
4670 if (orient == wxHORIZONTAL)
4671 {
4672 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust),
4673 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
4674
4675 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
4676
4677 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
4678 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
4679 }
4680 else
4681 {
4682 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust),
4683 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
4684
4685 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
4686
4687 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
4688 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
4689 }
4690 }
4691 }
4692
4693 int wxWindowGTK::GetScrollThumb( int orient ) const
4694 {
4695 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
4696
4697 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
4698
4699 if (orient == wxHORIZONTAL)
4700 return (int)(m_hAdjust->page_size+0.5);
4701 else
4702 return (int)(m_vAdjust->page_size+0.5);
4703 }
4704
4705 int wxWindowGTK::GetScrollPos( int orient ) const
4706 {
4707 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
4708
4709 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
4710
4711 if (orient == wxHORIZONTAL)
4712 return (int)(m_hAdjust->value+0.5);
4713 else
4714 return (int)(m_vAdjust->value+0.5);
4715 }
4716
4717 int wxWindowGTK::GetScrollRange( int orient ) const
4718 {
4719 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
4720
4721 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
4722
4723 if (orient == wxHORIZONTAL)
4724 return (int)(m_hAdjust->upper+0.5);
4725 else
4726 return (int)(m_vAdjust->upper+0.5);
4727 }
4728
4729 void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
4730 {
4731 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4732
4733 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
4734
4735 // No scrolling requested.
4736 if ((dx == 0) && (dy == 0)) return;
4737
4738 #ifndef __WXGTK20__
4739 if (!m_updateRegion.IsEmpty())
4740 {
4741 m_updateRegion.Offset( dx, dy );
4742
4743 int cw = 0;
4744 int ch = 0;
4745 GetClientSize( &cw, &ch );
4746 m_updateRegion.Intersect( 0, 0, cw, ch );
4747 }
4748
4749 if (!m_clearRegion.IsEmpty())
4750 {
4751 m_clearRegion.Offset( dx, dy );
4752
4753 int cw = 0;
4754 int ch = 0;
4755 GetClientSize( &cw, &ch );
4756 m_clearRegion.Intersect( 0, 0, cw, ch );
4757 }
4758 #endif
4759
4760 m_clipPaintRegion = TRUE;
4761
4762 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
4763
4764 m_clipPaintRegion = FALSE;
4765 }
4766
4767
4768 // Find the wxWindow at the current mouse position, also returning the mouse
4769 // position.
4770 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
4771 {
4772 pt = wxGetMousePosition();
4773 wxWindow* found = wxFindWindowAtPoint(pt);
4774 return found;
4775 }
4776
4777 // Get the current mouse position.
4778 wxPoint wxGetMousePosition()
4779 {
4780 /* This crashes when used within wxHelpContext,
4781 so we have to use the X-specific implementation below.
4782 gint x, y;
4783 GdkModifierType *mask;
4784 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4785
4786 return wxPoint(x, y);
4787 */
4788
4789 int x, y;
4790 GdkWindow* windowAtPtr = gdk_window_at_pointer(& x, & y);
4791
4792 Display *display = windowAtPtr ? GDK_WINDOW_XDISPLAY(windowAtPtr) : GDK_DISPLAY();
4793 Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
4794 Window rootReturn, childReturn;
4795 int rootX, rootY, winX, winY;
4796 unsigned int maskReturn;
4797
4798 XQueryPointer (display,
4799 rootWindow,
4800 &rootReturn,
4801 &childReturn,
4802 &rootX, &rootY, &winX, &winY, &maskReturn);
4803 return wxPoint(rootX, rootY);
4804
4805 }
4806
4807 // ----------------------------------------------------------------------------
4808 // wxDCModule
4809 // ----------------------------------------------------------------------------
4810
4811 class wxWinModule : public wxModule
4812 {
4813 public:
4814 bool OnInit();
4815 void OnExit();
4816
4817 private:
4818 DECLARE_DYNAMIC_CLASS(wxWinModule)
4819 };
4820
4821 IMPLEMENT_DYNAMIC_CLASS(wxWinModule, wxModule)
4822
4823 bool wxWinModule::OnInit()
4824 {
4825 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4826 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4827
4828 return TRUE;
4829 }
4830
4831 void wxWinModule::OnExit()
4832 {
4833 if (g_eraseGC)
4834 gdk_gc_unref( g_eraseGC );
4835 }
4836
4837 // vi:sts=4:sw=4:et