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