]> git.saurik.com Git - wxWidgets.git/blob - src/gtk/window.cpp
fix wxExecute() return code checks and removed not working code to open URLs in new...
[wxWidgets.git] / src / gtk / window.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 // 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 if (m_wxwindow)
2905 {
2906 gtk_widget_destroy( m_wxwindow );
2907 m_wxwindow = (GtkWidget*) NULL;
2908 }
2909
2910 if (m_widget)
2911 {
2912 gtk_widget_destroy( m_widget );
2913 m_widget = (GtkWidget*) NULL;
2914 }
2915
2916 #ifdef __WXGTK20__
2917 delete m_imData;
2918 #endif
2919 }
2920
2921 bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos, const wxSize &size )
2922 {
2923 wxCHECK_MSG( !m_needParent || parent, false, wxT("Need complete parent.") );
2924
2925 // Use either the given size, or the default if -1 is given.
2926 // See wxWindowBase for these functions.
2927 m_width = WidthDefault(size.x) ;
2928 m_height = HeightDefault(size.y);
2929
2930 m_x = (int)pos.x;
2931 m_y = (int)pos.y;
2932
2933 return true;
2934 }
2935
2936 void wxWindowGTK::PostCreation()
2937 {
2938 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2939
2940 if (m_wxwindow)
2941 {
2942 if (!m_noExpose)
2943 {
2944 // these get reported to wxWidgets -> wxPaintEvent
2945
2946 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow), TRUE );
2947
2948 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
2949 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
2950
2951 #ifndef __WXGTK20__
2952 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
2953 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
2954
2955 if (!HasFlag(wxFULL_REPAINT_ON_RESIZE))
2956 {
2957 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "event",
2958 GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this );
2959 }
2960 #else
2961 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2962 #endif
2963 }
2964
2965 #ifdef __WXGTK20__
2966 // Create input method handler
2967 m_imData = new wxGtkIMData;
2968
2969 // Cannot handle drawing preedited text yet
2970 gtk_im_context_set_use_preedit( m_imData->context, FALSE );
2971
2972 g_signal_connect (G_OBJECT (m_imData->context), "commit",
2973 G_CALLBACK (gtk_wxwindow_commit_cb), this);
2974 #endif
2975
2976 // these are called when the "sunken" or "raised" borders are drawn
2977 gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
2978 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
2979
2980 #ifndef __WXGTK20__
2981 gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
2982 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
2983 #endif
2984 }
2985
2986 // focus handling
2987
2988 if (!GTK_IS_WINDOW(m_widget))
2989 {
2990 if (m_focusWidget == NULL)
2991 m_focusWidget = m_widget;
2992
2993 gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_in_event",
2994 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
2995
2996 gtk_signal_connect_after( GTK_OBJECT(m_focusWidget), "focus_out_event",
2997 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
2998 }
2999
3000 // connect to the various key and mouse handlers
3001
3002 GtkWidget *connect_widget = GetConnectWidget();
3003
3004 ConnectWidget( connect_widget );
3005
3006 /* We cannot set colours, fonts and cursors before the widget has
3007 been realized, so we do this directly after realization */
3008 gtk_signal_connect( GTK_OBJECT(connect_widget), "realize",
3009 GTK_SIGNAL_FUNC(gtk_window_realized_callback), (gpointer) this );
3010
3011 if (m_wxwindow)
3012 {
3013 // Catch native resize events
3014 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
3015 GTK_SIGNAL_FUNC(gtk_window_size_callback), (gpointer)this );
3016
3017 // Initialize XIM support
3018 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "realize",
3019 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback), (gpointer) this );
3020
3021 // And resize XIM window
3022 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
3023 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this );
3024 }
3025
3026 if (GTK_IS_COMBO(m_widget))
3027 {
3028 GtkCombo *gcombo = GTK_COMBO(m_widget);
3029
3030 gtk_signal_connect( GTK_OBJECT(gcombo->entry), "size_request",
3031 GTK_SIGNAL_FUNC(wxgtk_combo_size_request_callback),
3032 (gpointer) this );
3033 }
3034 else
3035 {
3036 // This is needed if we want to add our windows into native
3037 // GTK controls, such as the toolbar. With this callback, the
3038 // toolbar gets to know the correct size (the one set by the
3039 // programmer). Sadly, it misbehaves for wxComboBox.
3040 gtk_signal_connect( GTK_OBJECT(m_widget), "size_request",
3041 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback),
3042 (gpointer) this );
3043 }
3044
3045 InheritAttributes();
3046
3047 m_hasVMT = true;
3048
3049 // unless the window was created initially hidden (i.e. Hide() had been
3050 // called before Create()), we should show it at GTK+ level as well
3051 if ( IsShown() )
3052 gtk_widget_show( m_widget );
3053 }
3054
3055 void wxWindowGTK::ConnectWidget( GtkWidget *widget )
3056 {
3057 gtk_signal_connect( GTK_OBJECT(widget), "key_press_event",
3058 GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this );
3059
3060 gtk_signal_connect( GTK_OBJECT(widget), "key_release_event",
3061 GTK_SIGNAL_FUNC(gtk_window_key_release_callback), (gpointer)this );
3062
3063 gtk_signal_connect( GTK_OBJECT(widget), "button_press_event",
3064 GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
3065
3066 gtk_signal_connect( GTK_OBJECT(widget), "button_release_event",
3067 GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
3068
3069 gtk_signal_connect( GTK_OBJECT(widget), "motion_notify_event",
3070 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
3071
3072 #ifdef __WXGTK20__
3073 gtk_signal_connect( GTK_OBJECT(widget), "scroll_event",
3074 GTK_SIGNAL_FUNC(gtk_window_wheel_callback), (gpointer)this );
3075 g_signal_connect(widget, "popup_menu",
3076 G_CALLBACK(wxgtk_window_popup_menu_callback), this);
3077 #endif
3078
3079 gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event",
3080 GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
3081
3082 gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
3083 GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
3084 }
3085
3086 bool wxWindowGTK::Destroy()
3087 {
3088 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
3089
3090 m_hasVMT = false;
3091
3092 return wxWindowBase::Destroy();
3093 }
3094
3095 void wxWindowGTK::DoMoveWindow(int x, int y, int width, int height)
3096 {
3097 gtk_pizza_set_size( GTK_PIZZA(m_parent->m_wxwindow), m_widget, x, y, width, height );
3098 }
3099
3100 void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
3101 {
3102 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
3103 wxASSERT_MSG( (m_parent != NULL), wxT("wxWindowGTK::SetSize requires parent.\n") );
3104
3105 /*
3106 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
3107 */
3108
3109 if (m_resizing) return; /* I don't like recursions */
3110 m_resizing = true;
3111
3112 int currentX, currentY;
3113 GetPosition(&currentX, &currentY);
3114 if (x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
3115 x = currentX;
3116 if (y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
3117 y = currentY;
3118 AdjustForParentClientOrigin(x, y, sizeFlags);
3119
3120 if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
3121 {
3122 /* don't set the size for children of wxNotebook, just take the values. */
3123 m_x = x;
3124 m_y = y;
3125 m_width = width;
3126 m_height = height;
3127 }
3128 else
3129 {
3130 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
3131 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
3132 {
3133 if (x != -1) m_x = x + pizza->xoffset;
3134 if (y != -1) m_y = y + pizza->yoffset;
3135 }
3136 else
3137 {
3138 m_x = x + pizza->xoffset;
3139 m_y = y + pizza->yoffset;
3140 }
3141
3142 // calculate the best size if we should auto size the window
3143 if ( ((sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1) ||
3144 ((sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1) )
3145 {
3146 const wxSize sizeBest = GetBestSize();
3147 if ( (sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1 )
3148 width = sizeBest.x;
3149 if ( (sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1 )
3150 height = sizeBest.y;
3151 }
3152
3153 if (width != -1)
3154 m_width = width;
3155 if (height != -1)
3156 m_height = height;
3157
3158 int minWidth = GetMinWidth(),
3159 minHeight = GetMinHeight(),
3160 maxWidth = GetMaxWidth(),
3161 maxHeight = GetMaxHeight();
3162
3163 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
3164 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
3165 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
3166 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
3167
3168 int left_border = 0;
3169 int right_border = 0;
3170 int top_border = 0;
3171 int bottom_border = 0;
3172
3173 /* the default button has a border around it */
3174 if (GTK_WIDGET_CAN_DEFAULT(m_widget))
3175 {
3176 #ifdef __WXGTK20__
3177 GtkBorder *default_border = NULL;
3178 gtk_widget_style_get( m_widget, "default_border", &default_border, NULL );
3179 if (default_border)
3180 {
3181 left_border += default_border->left;
3182 right_border += default_border->right;
3183 top_border += default_border->top;
3184 bottom_border += default_border->bottom;
3185 g_free( default_border );
3186 }
3187 #else
3188 left_border = 6;
3189 right_border = 6;
3190 top_border = 6;
3191 bottom_border = 5;
3192 #endif
3193 }
3194
3195 DoMoveWindow( m_x-top_border,
3196 m_y-left_border,
3197 m_width+left_border+right_border,
3198 m_height+top_border+bottom_border );
3199 }
3200
3201 if (m_hasScrolling)
3202 {
3203 /* Sometimes the client area changes size without the
3204 whole windows's size changing, but if the whole
3205 windows's size doesn't change, no wxSizeEvent will
3206 normally be sent. Here we add an extra test if
3207 the client test has been changed and this will
3208 be used then. */
3209 GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
3210 }
3211
3212 /*
3213 wxPrintf( "OnSize sent from " );
3214 if (GetClassInfo() && GetClassInfo()->GetClassName())
3215 wxPrintf( GetClassInfo()->GetClassName() );
3216 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3217 */
3218
3219 if (!m_nativeSizeEvent)
3220 {
3221 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
3222 event.SetEventObject( this );
3223 GetEventHandler()->ProcessEvent( event );
3224 }
3225
3226 m_resizing = false;
3227 }
3228
3229 void wxWindowGTK::OnInternalIdle()
3230 {
3231 #ifdef __WXGTK20__
3232 if ( m_dirtyTabOrder )
3233 RealizeTabOrder();
3234 #endif
3235 // Update style if the window was not yet realized
3236 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
3237 if (m_needsStyleChange)
3238 {
3239 SetBackgroundStyle(GetBackgroundStyle());
3240 m_needsStyleChange = false;
3241 }
3242
3243 // Update invalidated regions.
3244 GtkUpdate();
3245
3246 wxCursor cursor = m_cursor;
3247 if (g_globalCursor.Ok()) cursor = g_globalCursor;
3248
3249 if (cursor.Ok())
3250 {
3251 /* I now set the cursor anew in every OnInternalIdle call
3252 as setting the cursor in a parent window also effects the
3253 windows above so that checking for the current cursor is
3254 not possible. */
3255
3256 if (m_wxwindow)
3257 {
3258 GdkWindow *window = GTK_PIZZA(m_wxwindow)->bin_window;
3259 if (window)
3260 gdk_window_set_cursor( window, cursor.GetCursor() );
3261
3262 if (!g_globalCursor.Ok())
3263 cursor = *wxSTANDARD_CURSOR;
3264
3265 window = m_widget->window;
3266 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
3267 gdk_window_set_cursor( window, cursor.GetCursor() );
3268
3269 }
3270 else
3271 {
3272
3273 GdkWindow *window = m_widget->window;
3274 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
3275 gdk_window_set_cursor( window, cursor.GetCursor() );
3276
3277 }
3278 }
3279
3280 if (wxUpdateUIEvent::CanUpdate(this))
3281 UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
3282 }
3283
3284 void wxWindowGTK::DoGetSize( int *width, int *height ) const
3285 {
3286 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3287
3288 if (width) (*width) = m_width;
3289 if (height) (*height) = m_height;
3290 }
3291
3292 void wxWindowGTK::DoSetClientSize( int width, int height )
3293 {
3294 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3295
3296 if (!m_wxwindow)
3297 {
3298 SetSize( width, height );
3299 }
3300 else
3301 {
3302 int dw = 0;
3303 int dh = 0;
3304
3305 #ifndef __WXUNIVERSAL__
3306 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
3307 {
3308 /* when using GTK 1.2 we set the shadow border size to 2 */
3309 dw += 2 * 2;
3310 dh += 2 * 2;
3311 }
3312 if (HasFlag(wxSIMPLE_BORDER))
3313 {
3314 /* when using GTK 1.2 we set the simple border size to 1 */
3315 dw += 1 * 2;
3316 dh += 1 * 2;
3317 }
3318 #endif // __WXUNIVERSAL__
3319
3320 if (m_hasScrolling)
3321 {
3322 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
3323
3324 GtkRequisition vscroll_req;
3325 vscroll_req.width = 2;
3326 vscroll_req.height = 2;
3327 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
3328 (scroll_window->vscrollbar, &vscroll_req );
3329
3330 GtkRequisition hscroll_req;
3331 hscroll_req.width = 2;
3332 hscroll_req.height = 2;
3333 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
3334 (scroll_window->hscrollbar, &hscroll_req );
3335
3336 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
3337
3338 if (scroll_window->vscrollbar_visible)
3339 {
3340 dw += vscroll_req.width;
3341 dw += scroll_class->scrollbar_spacing;
3342 }
3343
3344 if (scroll_window->hscrollbar_visible)
3345 {
3346 dh += hscroll_req.height;
3347 dh += scroll_class->scrollbar_spacing;
3348 }
3349 }
3350
3351 SetSize( width+dw, height+dh );
3352 }
3353 }
3354
3355 void wxWindowGTK::DoGetClientSize( int *width, int *height ) const
3356 {
3357 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3358
3359 if (!m_wxwindow)
3360 {
3361 if (width) (*width) = m_width;
3362 if (height) (*height) = m_height;
3363 }
3364 else
3365 {
3366 int dw = 0;
3367 int dh = 0;
3368
3369 #ifndef __WXUNIVERSAL__
3370 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
3371 {
3372 /* when using GTK 1.2 we set the shadow border size to 2 */
3373 dw += 2 * 2;
3374 dh += 2 * 2;
3375 }
3376 if (HasFlag(wxSIMPLE_BORDER))
3377 {
3378 /* when using GTK 1.2 we set the simple border size to 1 */
3379 dw += 1 * 2;
3380 dh += 1 * 2;
3381 }
3382 #endif // __WXUNIVERSAL__
3383
3384 if (m_hasScrolling)
3385 {
3386 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
3387
3388 GtkRequisition vscroll_req;
3389 vscroll_req.width = 2;
3390 vscroll_req.height = 2;
3391 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
3392 (scroll_window->vscrollbar, &vscroll_req );
3393
3394 GtkRequisition hscroll_req;
3395 hscroll_req.width = 2;
3396 hscroll_req.height = 2;
3397 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
3398 (scroll_window->hscrollbar, &hscroll_req );
3399
3400 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
3401
3402 if (scroll_window->vscrollbar_visible)
3403 {
3404 dw += vscroll_req.width;
3405 dw += scroll_class->scrollbar_spacing;
3406 }
3407
3408 if (scroll_window->hscrollbar_visible)
3409 {
3410 dh += hscroll_req.height;
3411 dh += scroll_class->scrollbar_spacing;
3412 }
3413 }
3414
3415 if (width) (*width) = m_width - dw;
3416 if (height) (*height) = m_height - dh;
3417 }
3418
3419 /*
3420 printf( "GetClientSize, name %s ", GetName().c_str() );
3421 if (width) printf( " width = %d", (*width) );
3422 if (height) printf( " height = %d", (*height) );
3423 printf( "\n" );
3424 */
3425 }
3426
3427 void wxWindowGTK::DoGetPosition( int *x, int *y ) const
3428 {
3429 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3430
3431 int dx = 0;
3432 int dy = 0;
3433 if (m_parent && m_parent->m_wxwindow)
3434 {
3435 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
3436 dx = pizza->xoffset;
3437 dy = pizza->yoffset;
3438 }
3439
3440 if (x) (*x) = m_x - dx;
3441 if (y) (*y) = m_y - dy;
3442 }
3443
3444 void wxWindowGTK::DoClientToScreen( int *x, int *y ) const
3445 {
3446 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3447
3448 if (!m_widget->window) return;
3449
3450 GdkWindow *source = (GdkWindow *) NULL;
3451 if (m_wxwindow)
3452 source = GTK_PIZZA(m_wxwindow)->bin_window;
3453 else
3454 source = m_widget->window;
3455
3456 int org_x = 0;
3457 int org_y = 0;
3458 gdk_window_get_origin( source, &org_x, &org_y );
3459
3460 if (!m_wxwindow)
3461 {
3462 if (GTK_WIDGET_NO_WINDOW (m_widget))
3463 {
3464 org_x += m_widget->allocation.x;
3465 org_y += m_widget->allocation.y;
3466 }
3467 }
3468
3469 if (x) *x += org_x;
3470 if (y) *y += org_y;
3471 }
3472
3473 void wxWindowGTK::DoScreenToClient( int *x, int *y ) const
3474 {
3475 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3476
3477 if (!m_widget->window) return;
3478
3479 GdkWindow *source = (GdkWindow *) NULL;
3480 if (m_wxwindow)
3481 source = GTK_PIZZA(m_wxwindow)->bin_window;
3482 else
3483 source = m_widget->window;
3484
3485 int org_x = 0;
3486 int org_y = 0;
3487 gdk_window_get_origin( source, &org_x, &org_y );
3488
3489 if (!m_wxwindow)
3490 {
3491 if (GTK_WIDGET_NO_WINDOW (m_widget))
3492 {
3493 org_x += m_widget->allocation.x;
3494 org_y += m_widget->allocation.y;
3495 }
3496 }
3497
3498 if (x) *x -= org_x;
3499 if (y) *y -= org_y;
3500 }
3501
3502 bool wxWindowGTK::Show( bool show )
3503 {
3504 wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
3505
3506 if (!wxWindowBase::Show(show))
3507 {
3508 // nothing to do
3509 return false;
3510 }
3511
3512 if (show)
3513 gtk_widget_show( m_widget );
3514 else
3515 gtk_widget_hide( m_widget );
3516
3517 wxShowEvent eventShow(GetId(), show);
3518 eventShow.SetEventObject(this);
3519
3520 GetEventHandler()->ProcessEvent(eventShow);
3521
3522 return true;
3523 }
3524
3525 static void wxWindowNotifyEnable(wxWindowGTK* win, bool enable)
3526 {
3527 win->OnParentEnable(enable);
3528
3529 // Recurse, so that children have the opportunity to Do The Right Thing
3530 // and reset colours that have been messed up by a parent's (really ancestor's)
3531 // Enable call
3532 for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
3533 node;
3534 node = node->GetNext() )
3535 {
3536 wxWindow *child = node->GetData();
3537 if (!child->IsKindOf(CLASSINFO(wxDialog)) && !child->IsKindOf(CLASSINFO(wxFrame)))
3538 wxWindowNotifyEnable(child, enable);
3539 }
3540 }
3541
3542 bool wxWindowGTK::Enable( bool enable )
3543 {
3544 wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
3545
3546 if (!wxWindowBase::Enable(enable))
3547 {
3548 // nothing to do
3549 return false;
3550 }
3551
3552 gtk_widget_set_sensitive( m_widget, enable );
3553 if ( m_wxwindow )
3554 gtk_widget_set_sensitive( m_wxwindow, enable );
3555
3556 wxWindowNotifyEnable(this, enable);
3557
3558 return true;
3559 }
3560
3561 int wxWindowGTK::GetCharHeight() const
3562 {
3563 wxCHECK_MSG( (m_widget != NULL), 12, wxT("invalid window") );
3564
3565 wxFont font = GetFont();
3566 wxCHECK_MSG( font.Ok(), 12, wxT("invalid font") );
3567
3568 #ifdef __WXGTK20__
3569 PangoContext *context = NULL;
3570 if (m_widget)
3571 context = gtk_widget_get_pango_context( m_widget );
3572
3573 if (!context)
3574 return 0;
3575
3576 PangoFontDescription *desc = font.GetNativeFontInfo()->description;
3577 PangoLayout *layout = pango_layout_new(context);
3578 pango_layout_set_font_description(layout, desc);
3579 pango_layout_set_text(layout, "H", 1);
3580 PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
3581
3582 PangoRectangle rect;
3583 pango_layout_line_get_extents(line, NULL, &rect);
3584
3585 g_object_unref( G_OBJECT( layout ) );
3586
3587 return (int) PANGO_PIXELS(rect.height);
3588 #else
3589 GdkFont *gfont = font.GetInternalFont( 1.0 );
3590
3591 return gfont->ascent + gfont->descent;
3592 #endif
3593 }
3594
3595 int wxWindowGTK::GetCharWidth() const
3596 {
3597 wxCHECK_MSG( (m_widget != NULL), 8, wxT("invalid window") );
3598
3599 wxFont font = GetFont();
3600 wxCHECK_MSG( font.Ok(), 8, wxT("invalid font") );
3601
3602 #ifdef __WXGTK20__
3603 PangoContext *context = NULL;
3604 if (m_widget)
3605 context = gtk_widget_get_pango_context( m_widget );
3606
3607 if (!context)
3608 return 0;
3609
3610 PangoFontDescription *desc = font.GetNativeFontInfo()->description;
3611 PangoLayout *layout = pango_layout_new(context);
3612 pango_layout_set_font_description(layout, desc);
3613 pango_layout_set_text(layout, "g", 1);
3614 PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
3615
3616 PangoRectangle rect;
3617 pango_layout_line_get_extents(line, NULL, &rect);
3618
3619 g_object_unref( G_OBJECT( layout ) );
3620
3621 return (int) PANGO_PIXELS(rect.width);
3622 #else
3623 GdkFont *gfont = font.GetInternalFont( 1.0 );
3624
3625 return gdk_string_width( gfont, "g" );
3626 #endif
3627 }
3628
3629 void wxWindowGTK::GetTextExtent( const wxString& string,
3630 int *x,
3631 int *y,
3632 int *descent,
3633 int *externalLeading,
3634 const wxFont *theFont ) const
3635 {
3636 wxFont fontToUse = theFont ? *theFont : GetFont();
3637
3638 wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
3639
3640 if (string.empty())
3641 {
3642 if (x) (*x) = 0;
3643 if (y) (*y) = 0;
3644 return;
3645 }
3646
3647 #ifdef __WXGTK20__
3648 PangoContext *context = NULL;
3649 if (m_widget)
3650 context = gtk_widget_get_pango_context( m_widget );
3651
3652 if (!context)
3653 {
3654 if (x) (*x) = 0;
3655 if (y) (*y) = 0;
3656 return;
3657 }
3658
3659 PangoFontDescription *desc = fontToUse.GetNativeFontInfo()->description;
3660 PangoLayout *layout = pango_layout_new(context);
3661 pango_layout_set_font_description(layout, desc);
3662 {
3663 #if wxUSE_UNICODE
3664 const wxCharBuffer data = wxConvUTF8.cWC2MB( string );
3665 pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data ));
3666 #else
3667 const wxWCharBuffer wdata = wxConvLocal.cMB2WC( string );
3668 const wxCharBuffer data = wxConvUTF8.cWC2MB( wdata );
3669 pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data ));
3670 #endif
3671 }
3672
3673 PangoRectangle rect;
3674 pango_layout_get_extents(layout, NULL, &rect);
3675
3676 if (x) (*x) = (wxCoord) PANGO_PIXELS(rect.width);
3677 if (y) (*y) = (wxCoord) PANGO_PIXELS(rect.height);
3678 if (descent)
3679 {
3680 PangoLayoutIter *iter = pango_layout_get_iter(layout);
3681 int baseline = pango_layout_iter_get_baseline(iter);
3682 pango_layout_iter_free(iter);
3683 *descent = *y - PANGO_PIXELS(baseline);
3684 }
3685 if (externalLeading) (*externalLeading) = 0; // ??
3686
3687 g_object_unref( G_OBJECT( layout ) );
3688 #else
3689 GdkFont *font = fontToUse.GetInternalFont( 1.0 );
3690 if (x) (*x) = gdk_string_width( font, wxGTK_CONV( string ) );
3691 if (y) (*y) = font->ascent + font->descent;
3692 if (descent) (*descent) = font->descent;
3693 if (externalLeading) (*externalLeading) = 0; // ??
3694 #endif
3695 }
3696
3697 void wxWindowGTK::SetFocus()
3698 {
3699 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3700 if ( m_hasFocus )
3701 {
3702 // don't do anything if we already have focus
3703 return;
3704 }
3705
3706 if (m_wxwindow)
3707 {
3708 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
3709 {
3710 gtk_widget_grab_focus (m_wxwindow);
3711 }
3712 }
3713 else if (m_widget)
3714 {
3715 #ifdef __WXGTK20__
3716 if (GTK_IS_CONTAINER(m_widget))
3717 {
3718 gtk_widget_child_focus( m_widget, GTK_DIR_TAB_FORWARD );
3719 }
3720 else
3721 #endif
3722 if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
3723 {
3724
3725 if (!GTK_WIDGET_REALIZED(m_widget))
3726 {
3727 // we can't set the focus to the widget now so we remember that
3728 // it should be focused and will do it later, during the idle
3729 // time, as soon as we can
3730 wxLogTrace(TRACE_FOCUS,
3731 _T("Delaying setting focus to %s(%s)"),
3732 GetClassInfo()->GetClassName(), GetLabel().c_str());
3733
3734 g_delayedFocus = this;
3735 }
3736 else
3737 {
3738 wxLogTrace(TRACE_FOCUS,
3739 _T("Setting focus to %s(%s)"),
3740 GetClassInfo()->GetClassName(), GetLabel().c_str());
3741
3742 gtk_widget_grab_focus (m_widget);
3743 }
3744 }
3745 else
3746 #ifndef __WXGTK20__
3747 if (GTK_IS_CONTAINER(m_widget))
3748 {
3749 gtk_container_focus( GTK_CONTAINER(m_widget), GTK_DIR_TAB_FORWARD );
3750 }
3751 else
3752 #endif
3753 {
3754 wxLogTrace(TRACE_FOCUS,
3755 _T("Can't set focus to %s(%s)"),
3756 GetClassInfo()->GetClassName(), GetLabel().c_str());
3757 }
3758 }
3759 }
3760
3761 bool wxWindowGTK::AcceptsFocus() const
3762 {
3763 return m_acceptsFocus && wxWindowBase::AcceptsFocus();
3764 }
3765
3766 bool wxWindowGTK::Reparent( wxWindowBase *newParentBase )
3767 {
3768 wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
3769
3770 wxWindowGTK *oldParent = m_parent,
3771 *newParent = (wxWindowGTK *)newParentBase;
3772
3773 wxASSERT( GTK_IS_WIDGET(m_widget) );
3774
3775 if ( !wxWindowBase::Reparent(newParent) )
3776 return false;
3777
3778 wxASSERT( GTK_IS_WIDGET(m_widget) );
3779
3780 /* prevent GTK from deleting the widget arbitrarily */
3781 gtk_widget_ref( m_widget );
3782
3783 if (oldParent)
3784 {
3785 gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget );
3786 }
3787
3788 wxASSERT( GTK_IS_WIDGET(m_widget) );
3789
3790 if (newParent)
3791 {
3792 /* insert GTK representation */
3793 (*(newParent->m_insertCallback))(newParent, this);
3794 }
3795
3796 /* reverse: prevent GTK from deleting the widget arbitrarily */
3797 gtk_widget_unref( m_widget );
3798
3799 return true;
3800 }
3801
3802 void wxWindowGTK::DoAddChild(wxWindowGTK *child)
3803 {
3804 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
3805
3806 wxASSERT_MSG( (child != NULL), wxT("invalid child window") );
3807
3808 wxASSERT_MSG( (m_insertCallback != NULL), wxT("invalid child insertion function") );
3809
3810 /* add to list */
3811 AddChild( child );
3812
3813 /* insert GTK representation */
3814 (*m_insertCallback)(this, child);
3815 }
3816
3817 #ifdef __WXGTK20__
3818
3819 void wxWindowGTK::AddChild(wxWindowBase *child)
3820 {
3821 wxWindowBase::AddChild(child);
3822 m_dirtyTabOrder = true;
3823 if (g_isIdle)
3824 wxapp_install_idle_handler();
3825 }
3826
3827 void wxWindowGTK::RemoveChild(wxWindowBase *child)
3828 {
3829 wxWindowBase::RemoveChild(child);
3830 m_dirtyTabOrder = true;
3831 if (g_isIdle)
3832 wxapp_install_idle_handler();
3833 }
3834
3835 void wxWindowGTK::DoMoveInTabOrder(wxWindow *win, MoveKind move)
3836 {
3837 wxWindowBase::DoMoveInTabOrder(win, move);
3838 m_dirtyTabOrder = true;
3839 if (g_isIdle)
3840 wxapp_install_idle_handler();
3841 }
3842
3843 void wxWindowGTK::RealizeTabOrder()
3844 {
3845 if (m_wxwindow)
3846 {
3847 if (m_children.size() > 0)
3848 {
3849 GList *chain = NULL;
3850
3851 for (wxWindowList::const_iterator i = m_children.begin();
3852 i != m_children.end(); ++i)
3853 {
3854 chain = g_list_prepend(chain, (*i)->m_widget);
3855 }
3856
3857 chain = g_list_reverse(chain);
3858
3859 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow), chain);
3860 g_list_free(chain);
3861 }
3862 else
3863 {
3864 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow));
3865 }
3866 }
3867
3868 m_dirtyTabOrder = false;
3869 }
3870
3871 #endif // __WXGTK20__
3872
3873 void wxWindowGTK::Raise()
3874 {
3875 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3876
3877 if (m_wxwindow && m_wxwindow->window)
3878 {
3879 gdk_window_raise( m_wxwindow->window );
3880 }
3881 else if (m_widget->window)
3882 {
3883 gdk_window_raise( m_widget->window );
3884 }
3885 }
3886
3887 void wxWindowGTK::Lower()
3888 {
3889 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3890
3891 if (m_wxwindow && m_wxwindow->window)
3892 {
3893 gdk_window_lower( m_wxwindow->window );
3894 }
3895 else if (m_widget->window)
3896 {
3897 gdk_window_lower( m_widget->window );
3898 }
3899 }
3900
3901 bool wxWindowGTK::SetCursor( const wxCursor &cursor )
3902 {
3903 wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
3904
3905 if (cursor == m_cursor)
3906 return false;
3907
3908 if (g_isIdle)
3909 wxapp_install_idle_handler();
3910
3911 if (cursor == wxNullCursor)
3912 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR );
3913 else
3914 return wxWindowBase::SetCursor( cursor );
3915 }
3916
3917 void wxWindowGTK::WarpPointer( int x, int y )
3918 {
3919 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3920
3921 // We provide this function ourselves as it is
3922 // missing in GDK (top of this file).
3923
3924 GdkWindow *window = (GdkWindow*) NULL;
3925 if (m_wxwindow)
3926 window = GTK_PIZZA(m_wxwindow)->bin_window;
3927 else
3928 window = GetConnectWidget()->window;
3929
3930 if (window)
3931 gdk_window_warp_pointer( window, x, y );
3932 }
3933
3934
3935 void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
3936 {
3937 if (!m_widget)
3938 return;
3939 if (!m_widget->window)
3940 return;
3941
3942 #ifndef __WXGTK20__
3943 if (g_isIdle)
3944 wxapp_install_idle_handler();
3945
3946 wxRect myRect;
3947 if (m_wxwindow && rect)
3948 {
3949 myRect.SetSize(wxSize( m_wxwindow->allocation.width,
3950 m_wxwindow->allocation.height));
3951 if ( myRect.Intersect(*rect).IsEmpty() )
3952 {
3953 // nothing to do, rectangle is empty
3954 return;
3955 }
3956
3957 rect = &myRect;
3958 }
3959
3960 // schedule the area for later updating in GtkUpdate()
3961 if (eraseBackground && m_wxwindow && m_wxwindow->window)
3962 {
3963 if (rect)
3964 {
3965 m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height );
3966 }
3967 else
3968 {
3969 m_clearRegion.Clear();
3970 m_clearRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
3971 }
3972 }
3973
3974 if (rect)
3975 {
3976 if (m_wxwindow)
3977 {
3978 m_updateRegion.Union( rect->x, rect->y, rect->width, rect->height );
3979 }
3980 else
3981 {
3982 GdkRectangle gdk_rect;
3983 gdk_rect.x = rect->x;
3984 gdk_rect.y = rect->y;
3985 gdk_rect.width = rect->width;
3986 gdk_rect.height = rect->height;
3987 gtk_widget_draw( m_widget, &gdk_rect );
3988 }
3989 }
3990 else
3991 {
3992 if (m_wxwindow)
3993 {
3994 m_updateRegion.Clear();
3995 m_updateRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
3996 }
3997 else
3998 {
3999 gtk_widget_draw( m_widget, (GdkRectangle*) NULL );
4000 }
4001 }
4002 #else // GTK+ 2
4003 if (m_wxwindow)
4004 {
4005 GdkRectangle gdk_rect,
4006 *p;
4007 if (rect)
4008 {
4009 gdk_rect.x = rect->x;
4010 gdk_rect.y = rect->y;
4011 gdk_rect.width = rect->width;
4012 gdk_rect.height = rect->height;
4013 p = &gdk_rect;
4014 }
4015 else // invalidate everything
4016 {
4017 p = NULL;
4018 }
4019
4020 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow)->bin_window, p, TRUE );
4021 }
4022 #endif // GTK+ 1/2
4023 }
4024
4025 void wxWindowGTK::Update()
4026 {
4027 GtkUpdate();
4028
4029 // when we call Update() we really want to update the window immediately on
4030 // screen, even if itmeans flushing the entire queue and hence slowing down
4031 // everything -- but it should still be done, it's just that Update() should
4032 // be called very rarely
4033 gdk_flush();
4034 }
4035
4036 void wxWindowGTK::GtkUpdate()
4037 {
4038 #ifdef __WXGTK20__
4039 if (m_wxwindow && GTK_PIZZA(m_wxwindow)->bin_window)
4040 gdk_window_process_updates( GTK_PIZZA(m_wxwindow)->bin_window, FALSE );
4041 #else
4042 if (!m_updateRegion.IsEmpty())
4043 GtkSendPaintEvents();
4044 #endif
4045
4046 // for consistency with other platforms (and also because it's convenient
4047 // to be able to update an entire TLW by calling Update() only once), we
4048 // should also update all our children here
4049 for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
4050 node;
4051 node = node->GetNext() )
4052 {
4053 node->GetData()->GtkUpdate();
4054 }
4055 }
4056
4057 void wxWindowGTK::GtkSendPaintEvents()
4058 {
4059 if (!m_wxwindow)
4060 {
4061 #ifndef __WXGTK20__
4062 m_clearRegion.Clear();
4063 #endif
4064 m_updateRegion.Clear();
4065 return;
4066 }
4067
4068 // Clip to paint region in wxClientDC
4069 m_clipPaintRegion = true;
4070
4071 // widget to draw on
4072 GtkPizza *pizza = GTK_PIZZA (m_wxwindow);
4073
4074 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM))
4075 {
4076 // find ancestor from which to steal background
4077 wxWindow *parent = wxGetTopLevelParent((wxWindow *)this);
4078 if (!parent)
4079 parent = (wxWindow*)this;
4080
4081 if (GTK_WIDGET_MAPPED(parent->m_widget))
4082 {
4083 wxRegionIterator upd( m_updateRegion );
4084 while (upd)
4085 {
4086 GdkRectangle rect;
4087 rect.x = upd.GetX();
4088 rect.y = upd.GetY();
4089 rect.width = upd.GetWidth();
4090 rect.height = upd.GetHeight();
4091
4092 gtk_paint_flat_box( parent->m_widget->style,
4093 pizza->bin_window,
4094 (GtkStateType)GTK_WIDGET_STATE(m_wxwindow),
4095 GTK_SHADOW_NONE,
4096 &rect,
4097 parent->m_widget,
4098 (char *)"base",
4099 0, 0, -1, -1 );
4100
4101 ++upd;
4102 }
4103 }
4104 }
4105 else
4106
4107 #ifdef __WXGTK20__
4108 {
4109 wxWindowDC dc( (wxWindow*)this );
4110 dc.SetClippingRegion( m_updateRegion );
4111
4112 wxEraseEvent erase_event( GetId(), &dc );
4113 erase_event.SetEventObject( this );
4114
4115 GetEventHandler()->ProcessEvent(erase_event);
4116 }
4117 #else
4118 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
4119 {
4120 wxWindowDC dc( (wxWindow*)this );
4121 if (m_clearRegion.IsEmpty())
4122 dc.SetClippingRegion( m_updateRegion );
4123 else
4124 dc.SetClippingRegion( m_clearRegion );
4125
4126 wxEraseEvent erase_event( GetId(), &dc );
4127 erase_event.SetEventObject( this );
4128
4129 if (!GetEventHandler()->ProcessEvent(erase_event) && GetBackgroundStyle() != wxBG_STYLE_CUSTOM)
4130 {
4131 if (!g_eraseGC)
4132 {
4133 g_eraseGC = gdk_gc_new( pizza->bin_window );
4134 gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4135 }
4136 gdk_gc_set_foreground( g_eraseGC, GetBackgroundColour().GetColor() );
4137
4138 wxRegionIterator upd( m_clearRegion );
4139 while (upd)
4140 {
4141 gdk_draw_rectangle( pizza->bin_window, g_eraseGC, 1,
4142 upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
4143 upd ++;
4144 }
4145 }
4146 m_clearRegion.Clear();
4147 }
4148 #endif
4149
4150 wxNcPaintEvent nc_paint_event( GetId() );
4151 nc_paint_event.SetEventObject( this );
4152 GetEventHandler()->ProcessEvent( nc_paint_event );
4153
4154 wxPaintEvent paint_event( GetId() );
4155 paint_event.SetEventObject( this );
4156 GetEventHandler()->ProcessEvent( paint_event );
4157
4158 m_clipPaintRegion = false;
4159
4160 #if !defined(__WXUNIVERSAL__) && !defined(__WXGTK20__)
4161 // The following code will result in all window-less widgets
4162 // being redrawn because the wxWidgets class is allowed to
4163 // paint over the window-less widgets.
4164
4165 GList *children = pizza->children;
4166 while (children)
4167 {
4168 GtkPizzaChild *child = (GtkPizzaChild*) children->data;
4169 children = children->next;
4170
4171 if (GTK_WIDGET_NO_WINDOW (child->widget) &&
4172 GTK_WIDGET_DRAWABLE (child->widget))
4173 {
4174 // Get intersection of widget area and update region
4175 wxRegion region( m_updateRegion );
4176
4177 GdkEventExpose gdk_event;
4178 gdk_event.type = GDK_EXPOSE;
4179 gdk_event.window = pizza->bin_window;
4180 gdk_event.count = 0;
4181 gdk_event.send_event = TRUE;
4182
4183 wxRegionIterator upd( m_updateRegion );
4184 while (upd)
4185 {
4186 GdkRectangle rect;
4187 rect.x = upd.GetX();
4188 rect.y = upd.GetY();
4189 rect.width = upd.GetWidth();
4190 rect.height = upd.GetHeight();
4191
4192 if (gtk_widget_intersect (child->widget, &rect, &gdk_event.area))
4193 {
4194 gtk_widget_event (child->widget, (GdkEvent*) &gdk_event);
4195 }
4196
4197 upd ++;
4198 }
4199 }
4200 }
4201 #endif // native GTK 1
4202
4203 m_updateRegion.Clear();
4204 }
4205
4206 void wxWindowGTK::ClearBackground()
4207 {
4208 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4209
4210 #ifndef __WXGTK20__
4211 if (m_wxwindow && m_wxwindow->window)
4212 {
4213 m_clearRegion.Clear();
4214 wxSize size( GetClientSize() );
4215 m_clearRegion.Union( 0,0,size.x,size.y );
4216
4217 // Better do this in idle?
4218 GtkUpdate();
4219 }
4220 #endif
4221 }
4222
4223 #if wxUSE_TOOLTIPS
4224 void wxWindowGTK::DoSetToolTip( wxToolTip *tip )
4225 {
4226 wxWindowBase::DoSetToolTip(tip);
4227
4228 if (m_tooltip)
4229 m_tooltip->Apply( (wxWindow *)this );
4230 }
4231
4232 void wxWindowGTK::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
4233 {
4234 wxString tmp( tip );
4235 gtk_tooltips_set_tip( tips, GetConnectWidget(), wxGTK_CONV(tmp), (gchar*) NULL );
4236 }
4237 #endif // wxUSE_TOOLTIPS
4238
4239 bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
4240 {
4241 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
4242
4243 if (!wxWindowBase::SetBackgroundColour(colour))
4244 return false;
4245
4246 if (colour.Ok())
4247 {
4248 // We need the pixel value e.g. for background clearing.
4249 m_backgroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
4250 }
4251
4252 // apply style change (forceStyle=true so that new style is applied
4253 // even if the bg colour changed from valid to wxNullColour)
4254 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM)
4255 ApplyWidgetStyle(true);
4256
4257 return true;
4258 }
4259
4260 bool wxWindowGTK::SetForegroundColour( const wxColour &colour )
4261 {
4262 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
4263
4264 if (!wxWindowBase::SetForegroundColour(colour))
4265 {
4266 return false;
4267 }
4268
4269 if (colour.Ok())
4270 {
4271 // We need the pixel value e.g. for background clearing.
4272 m_foregroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
4273 }
4274
4275 // apply style change (forceStyle=true so that new style is applied
4276 // even if the bg colour changed from valid to wxNullColour):
4277 ApplyWidgetStyle(true);
4278
4279 return true;
4280 }
4281
4282 #ifdef __WXGTK20__
4283 PangoContext *wxWindowGTK::GtkGetPangoDefaultContext()
4284 {
4285 return gtk_widget_get_pango_context( m_widget );
4286 }
4287
4288 // MR: Returns the same as GtkGetPangoDefaultContext until the symbol can be removed in 2.7.x
4289 PangoContext *wxWindowGTK::GtkGetPangoX11Context()
4290 {
4291 return gtk_widget_get_pango_context( m_widget );
4292 }
4293 #endif
4294
4295 GtkRcStyle *wxWindowGTK::CreateWidgetStyle(bool forceStyle)
4296 {
4297 // do we need to apply any changes at all?
4298 if ( !forceStyle &&
4299 !m_font.Ok() &&
4300 !m_foregroundColour.Ok() && !m_backgroundColour.Ok() )
4301 {
4302 return NULL;
4303 }
4304
4305 GtkRcStyle *style = gtk_rc_style_new();
4306
4307 if ( m_font.Ok() )
4308 {
4309 #ifdef __WXGTK20__
4310 style->font_desc =
4311 pango_font_description_copy( m_font.GetNativeFontInfo()->description );
4312 #else
4313 wxString xfontname = m_font.GetNativeFontInfo()->GetXFontName();
4314 style->fontset_name = g_strdup(xfontname.c_str());
4315 #endif
4316 }
4317
4318 if ( m_foregroundColour.Ok() )
4319 {
4320 GdkColor *fg = m_foregroundColour.GetColor();
4321
4322 style->fg[GTK_STATE_NORMAL] = *fg;
4323 style->color_flags[GTK_STATE_NORMAL] = GTK_RC_FG;
4324
4325 style->fg[GTK_STATE_PRELIGHT] = *fg;
4326 style->color_flags[GTK_STATE_PRELIGHT] = GTK_RC_FG;
4327
4328 style->fg[GTK_STATE_ACTIVE] = *fg;
4329 style->color_flags[GTK_STATE_ACTIVE] = GTK_RC_FG;
4330 }
4331
4332 if ( m_backgroundColour.Ok() )
4333 {
4334 GdkColor *bg = m_backgroundColour.GetColor();
4335
4336 style->bg[GTK_STATE_NORMAL] = *bg;
4337 style->base[GTK_STATE_NORMAL] = *bg;
4338 style->color_flags[GTK_STATE_NORMAL] = (GtkRcFlags)
4339 (style->color_flags[GTK_STATE_NORMAL] | GTK_RC_BG | GTK_RC_BASE);
4340
4341 style->bg[GTK_STATE_PRELIGHT] = *bg;
4342 style->base[GTK_STATE_PRELIGHT] = *bg;
4343 style->color_flags[GTK_STATE_PRELIGHT] = (GtkRcFlags)
4344 (style->color_flags[GTK_STATE_PRELIGHT] | GTK_RC_BG | GTK_RC_BASE);
4345
4346 style->bg[GTK_STATE_ACTIVE] = *bg;
4347 style->base[GTK_STATE_ACTIVE] = *bg;
4348 style->color_flags[GTK_STATE_ACTIVE] = (GtkRcFlags)
4349 (style->color_flags[GTK_STATE_ACTIVE] | GTK_RC_BG | GTK_RC_BASE);
4350
4351 style->bg[GTK_STATE_INSENSITIVE] = *bg;
4352 style->base[GTK_STATE_INSENSITIVE] = *bg;
4353 style->color_flags[GTK_STATE_INSENSITIVE] = (GtkRcFlags)
4354 (style->color_flags[GTK_STATE_INSENSITIVE] | GTK_RC_BG | GTK_RC_BASE);
4355 }
4356
4357 return style;
4358 }
4359
4360 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle)
4361 {
4362 GtkRcStyle *style = CreateWidgetStyle(forceStyle);
4363 if ( style )
4364 {
4365 DoApplyWidgetStyle(style);
4366 gtk_rc_style_unref(style);
4367 }
4368
4369 // Style change may affect GTK+'s size calculation:
4370 InvalidateBestSize();
4371 }
4372
4373 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle *style)
4374 {
4375 if (m_wxwindow)
4376 gtk_widget_modify_style(m_wxwindow, style);
4377 else
4378 gtk_widget_modify_style(m_widget, style);
4379 }
4380
4381 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style)
4382 {
4383 wxWindowBase::SetBackgroundStyle(style);
4384
4385 if (style == wxBG_STYLE_CUSTOM)
4386 {
4387 GdkWindow *window = (GdkWindow*) NULL;
4388 if (m_wxwindow)
4389 window = GTK_PIZZA(m_wxwindow)->bin_window;
4390 else
4391 window = GetConnectWidget()->window;
4392
4393 if (window)
4394 {
4395 // Make sure GDK/X11 doesn't refresh the window
4396 // automatically.
4397 gdk_window_set_back_pixmap( window, None, False );
4398 #ifdef __X__
4399 Display* display = GDK_WINDOW_DISPLAY(window);
4400 XFlush(display);
4401 #endif
4402 m_needsStyleChange = false;
4403 }
4404 else
4405 // Do in OnIdle, because the window is not yet available
4406 m_needsStyleChange = true;
4407
4408 // Don't apply widget style, or we get a grey background
4409 }
4410 else
4411 {
4412 // apply style change (forceStyle=true so that new style is applied
4413 // even if the bg colour changed from valid to wxNullColour):
4414 ApplyWidgetStyle(true);
4415 }
4416 return true;
4417 }
4418
4419 //-----------------------------------------------------------------------------
4420 // Pop-up menu stuff
4421 //-----------------------------------------------------------------------------
4422
4423 #if wxUSE_MENUS_NATIVE
4424
4425 extern "C" WXDLLIMPEXP_CORE
4426 void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting )
4427 {
4428 *is_waiting = FALSE;
4429 }
4430
4431 WXDLLIMPEXP_CORE void SetInvokingWindow( wxMenu *menu, wxWindow* win )
4432 {
4433 menu->SetInvokingWindow( win );
4434
4435 wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst();
4436 while (node)
4437 {
4438 wxMenuItem *menuitem = node->GetData();
4439 if (menuitem->IsSubMenu())
4440 {
4441 SetInvokingWindow( menuitem->GetSubMenu(), win );
4442 }
4443
4444 node = node->GetNext();
4445 }
4446 }
4447
4448 extern "C" WXDLLIMPEXP_CORE
4449 void wxPopupMenuPositionCallback( GtkMenu *menu,
4450 gint *x, gint *y,
4451 #ifdef __WXGTK20__
4452 gboolean * WXUNUSED(whatever),
4453 #endif
4454 gpointer user_data )
4455 {
4456 // ensure that the menu appears entirely on screen
4457 GtkRequisition req;
4458 gtk_widget_get_child_requisition(GTK_WIDGET(menu), &req);
4459
4460 wxSize sizeScreen = wxGetDisplaySize();
4461 wxPoint *pos = (wxPoint*)user_data;
4462
4463 gint xmax = sizeScreen.x - req.width,
4464 ymax = sizeScreen.y - req.height;
4465
4466 *x = pos->x < xmax ? pos->x : xmax;
4467 *y = pos->y < ymax ? pos->y : ymax;
4468 }
4469
4470 bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
4471 {
4472 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
4473
4474 wxCHECK_MSG( menu != NULL, false, wxT("invalid popup-menu") );
4475
4476 // NOTE: if you change this code, you need to update
4477 // the same code in taskbar.cpp as well. This
4478 // is ugly code duplication, I know,
4479
4480 SetInvokingWindow( menu, this );
4481
4482 menu->UpdateUI();
4483
4484 bool is_waiting = true;
4485
4486 gulong handler = gtk_signal_connect( GTK_OBJECT(menu->m_menu),
4487 "hide",
4488 GTK_SIGNAL_FUNC(gtk_pop_hide_callback),
4489 (gpointer)&is_waiting );
4490
4491 wxPoint pos;
4492 gpointer userdata;
4493 GtkMenuPositionFunc posfunc;
4494 if ( x == -1 && y == -1 )
4495 {
4496 // use GTK's default positioning algorithm
4497 userdata = NULL;
4498 posfunc = NULL;
4499 }
4500 else
4501 {
4502 pos = ClientToScreen(wxPoint(x, y));
4503 userdata = &pos;
4504 posfunc = wxPopupMenuPositionCallback;
4505 }
4506
4507 gtk_menu_popup(
4508 GTK_MENU(menu->m_menu),
4509 (GtkWidget *) NULL, // parent menu shell
4510 (GtkWidget *) NULL, // parent menu item
4511 posfunc, // function to position it
4512 userdata, // client data
4513 0, // button used to activate it
4514 #ifdef __WXGTK20__
4515 gtk_get_current_event_time()
4516 #else
4517 gs_timeLastClick // the time of activation
4518 #endif
4519 );
4520
4521 while (is_waiting)
4522 {
4523 gtk_main_iteration();
4524 }
4525
4526 gtk_signal_disconnect(GTK_OBJECT(menu->m_menu), handler);
4527
4528 return true;
4529 }
4530
4531 #endif // wxUSE_MENUS_NATIVE
4532
4533 #if wxUSE_DRAG_AND_DROP
4534
4535 void wxWindowGTK::SetDropTarget( wxDropTarget *dropTarget )
4536 {
4537 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4538
4539 GtkWidget *dnd_widget = GetConnectWidget();
4540
4541 if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
4542
4543 if (m_dropTarget) delete m_dropTarget;
4544 m_dropTarget = dropTarget;
4545
4546 if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
4547 }
4548
4549 #endif // wxUSE_DRAG_AND_DROP
4550
4551 GtkWidget* wxWindowGTK::GetConnectWidget()
4552 {
4553 GtkWidget *connect_widget = m_widget;
4554 if (m_wxwindow) connect_widget = m_wxwindow;
4555
4556 return connect_widget;
4557 }
4558
4559 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow *window )
4560 {
4561 if (m_wxwindow)
4562 return (window == GTK_PIZZA(m_wxwindow)->bin_window);
4563
4564 return (window == m_widget->window);
4565 }
4566
4567 bool wxWindowGTK::SetFont( const wxFont &font )
4568 {
4569 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
4570
4571 if (!wxWindowBase::SetFont(font))
4572 return false;
4573
4574 // apply style change (forceStyle=true so that new style is applied
4575 // even if the font changed from valid to wxNullFont):
4576 ApplyWidgetStyle(true);
4577
4578 return true;
4579 }
4580
4581 void wxWindowGTK::DoCaptureMouse()
4582 {
4583 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4584
4585 GdkWindow *window = (GdkWindow*) NULL;
4586 if (m_wxwindow)
4587 window = GTK_PIZZA(m_wxwindow)->bin_window;
4588 else
4589 window = GetConnectWidget()->window;
4590
4591 wxCHECK_RET( window, _T("CaptureMouse() failed") );
4592
4593 wxCursor* cursor = & m_cursor;
4594 if (!cursor->Ok())
4595 cursor = wxSTANDARD_CURSOR;
4596
4597 gdk_pointer_grab( window, FALSE,
4598 (GdkEventMask)
4599 (GDK_BUTTON_PRESS_MASK |
4600 GDK_BUTTON_RELEASE_MASK |
4601 GDK_POINTER_MOTION_HINT_MASK |
4602 GDK_POINTER_MOTION_MASK),
4603 (GdkWindow *) NULL,
4604 cursor->GetCursor(),
4605 (guint32)GDK_CURRENT_TIME );
4606 g_captureWindow = this;
4607 g_captureWindowHasMouse = true;
4608 }
4609
4610 void wxWindowGTK::DoReleaseMouse()
4611 {
4612 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4613
4614 wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") );
4615
4616 g_captureWindow = (wxWindowGTK*) NULL;
4617
4618 GdkWindow *window = (GdkWindow*) NULL;
4619 if (m_wxwindow)
4620 window = GTK_PIZZA(m_wxwindow)->bin_window;
4621 else
4622 window = GetConnectWidget()->window;
4623
4624 if (!window)
4625 return;
4626
4627 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
4628 }
4629
4630 /* static */
4631 wxWindow *wxWindowBase::GetCapture()
4632 {
4633 return (wxWindow *)g_captureWindow;
4634 }
4635
4636 bool wxWindowGTK::IsRetained() const
4637 {
4638 return false;
4639 }
4640
4641 void wxWindowGTK::SetScrollbar( int orient, int pos, int thumbVisible,
4642 int range, bool refresh )
4643 {
4644 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4645
4646 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
4647
4648 m_hasScrolling = true;
4649
4650 if (orient == wxHORIZONTAL)
4651 {
4652 float fpos = (float)pos;
4653 float frange = (float)range;
4654 float fthumb = (float)thumbVisible;
4655 if (fpos > frange-fthumb) fpos = frange-fthumb;
4656 if (fpos < 0.0) fpos = 0.0;
4657
4658 if ((fabs(frange-m_hAdjust->upper) < 0.2) &&
4659 (fabs(fthumb-m_hAdjust->page_size) < 0.2))
4660 {
4661 SetScrollPos( orient, pos, refresh );
4662 return;
4663 }
4664
4665 m_oldHorizontalPos = fpos;
4666
4667 m_hAdjust->lower = 0.0;
4668 m_hAdjust->upper = frange;
4669 m_hAdjust->value = fpos;
4670 m_hAdjust->step_increment = 1.0;
4671 m_hAdjust->page_increment = (float)(wxMax(fthumb,0));
4672 m_hAdjust->page_size = fthumb;
4673 }
4674 else
4675 {
4676 float fpos = (float)pos;
4677 float frange = (float)range;
4678 float fthumb = (float)thumbVisible;
4679 if (fpos > frange-fthumb) fpos = frange-fthumb;
4680 if (fpos < 0.0) fpos = 0.0;
4681
4682 if ((fabs(frange-m_vAdjust->upper) < 0.2) &&
4683 (fabs(fthumb-m_vAdjust->page_size) < 0.2))
4684 {
4685 SetScrollPos( orient, pos, refresh );
4686 return;
4687 }
4688
4689 m_oldVerticalPos = fpos;
4690
4691 m_vAdjust->lower = 0.0;
4692 m_vAdjust->upper = frange;
4693 m_vAdjust->value = fpos;
4694 m_vAdjust->step_increment = 1.0;
4695 m_vAdjust->page_increment = (float)(wxMax(fthumb,0));
4696 m_vAdjust->page_size = fthumb;
4697 }
4698
4699 if (orient == wxHORIZONTAL)
4700 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
4701 else
4702 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
4703 }
4704
4705 void wxWindowGTK::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
4706 {
4707 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4708
4709 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
4710
4711 if (orient == wxHORIZONTAL)
4712 {
4713 float fpos = (float)pos;
4714 if (fpos > m_hAdjust->upper - m_hAdjust->page_size) fpos = m_hAdjust->upper - m_hAdjust->page_size;
4715 if (fpos < 0.0) fpos = 0.0;
4716 m_oldHorizontalPos = fpos;
4717
4718 if (fabs(fpos-m_hAdjust->value) < 0.2) return;
4719 m_hAdjust->value = fpos;
4720 }
4721 else
4722 {
4723 float fpos = (float)pos;
4724 if (fpos > m_vAdjust->upper - m_vAdjust->page_size) fpos = m_vAdjust->upper - m_vAdjust->page_size;
4725 if (fpos < 0.0) fpos = 0.0;
4726 m_oldVerticalPos = fpos;
4727
4728 if (fabs(fpos-m_vAdjust->value) < 0.2) return;
4729 m_vAdjust->value = fpos;
4730 }
4731
4732 if (m_wxwindow->window)
4733 {
4734 if (orient == wxHORIZONTAL)
4735 {
4736 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust),
4737 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
4738
4739 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
4740
4741 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
4742 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
4743 }
4744 else
4745 {
4746 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust),
4747 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
4748
4749 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
4750
4751 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
4752 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
4753 }
4754 }
4755 }
4756
4757 int wxWindowGTK::GetScrollThumb( int orient ) const
4758 {
4759 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
4760
4761 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
4762
4763 if (orient == wxHORIZONTAL)
4764 return (int)(m_hAdjust->page_size+0.5);
4765 else
4766 return (int)(m_vAdjust->page_size+0.5);
4767 }
4768
4769 int wxWindowGTK::GetScrollPos( int orient ) const
4770 {
4771 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
4772
4773 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
4774
4775 if (orient == wxHORIZONTAL)
4776 return (int)(m_hAdjust->value+0.5);
4777 else
4778 return (int)(m_vAdjust->value+0.5);
4779 }
4780
4781 int wxWindowGTK::GetScrollRange( int orient ) const
4782 {
4783 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
4784
4785 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
4786
4787 if (orient == wxHORIZONTAL)
4788 return (int)(m_hAdjust->upper+0.5);
4789 else
4790 return (int)(m_vAdjust->upper+0.5);
4791 }
4792
4793 void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
4794 {
4795 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4796
4797 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
4798
4799 // No scrolling requested.
4800 if ((dx == 0) && (dy == 0)) return;
4801
4802 #ifndef __WXGTK20__
4803 if (!m_updateRegion.IsEmpty())
4804 {
4805 m_updateRegion.Offset( dx, dy );
4806
4807 int cw = 0;
4808 int ch = 0;
4809 GetClientSize( &cw, &ch );
4810 m_updateRegion.Intersect( 0, 0, cw, ch );
4811 }
4812
4813 if (!m_clearRegion.IsEmpty())
4814 {
4815 m_clearRegion.Offset( dx, dy );
4816
4817 int cw = 0;
4818 int ch = 0;
4819 GetClientSize( &cw, &ch );
4820 m_clearRegion.Intersect( 0, 0, cw, ch );
4821 }
4822 #endif
4823
4824 m_clipPaintRegion = true;
4825
4826 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
4827
4828 m_clipPaintRegion = false;
4829 }
4830
4831
4832 // Find the wxWindow at the current mouse position, also returning the mouse
4833 // position.
4834 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
4835 {
4836 pt = wxGetMousePosition();
4837 wxWindow* found = wxFindWindowAtPoint(pt);
4838 return found;
4839 }
4840
4841 // Get the current mouse position.
4842 wxPoint wxGetMousePosition()
4843 {
4844 /* This crashes when used within wxHelpContext,
4845 so we have to use the X-specific implementation below.
4846 gint x, y;
4847 GdkModifierType *mask;
4848 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4849
4850 return wxPoint(x, y);
4851 */
4852
4853 int x, y;
4854 GdkWindow* windowAtPtr = gdk_window_at_pointer(& x, & y);
4855
4856 Display *display = windowAtPtr ? GDK_WINDOW_XDISPLAY(windowAtPtr) : GDK_DISPLAY();
4857 Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
4858 Window rootReturn, childReturn;
4859 int rootX, rootY, winX, winY;
4860 unsigned int maskReturn;
4861
4862 XQueryPointer (display,
4863 rootWindow,
4864 &rootReturn,
4865 &childReturn,
4866 &rootX, &rootY, &winX, &winY, &maskReturn);
4867 return wxPoint(rootX, rootY);
4868
4869 }
4870
4871 // ----------------------------------------------------------------------------
4872 // wxDCModule
4873 // ----------------------------------------------------------------------------
4874
4875 class wxWinModule : public wxModule
4876 {
4877 public:
4878 bool OnInit();
4879 void OnExit();
4880
4881 private:
4882 DECLARE_DYNAMIC_CLASS(wxWinModule)
4883 };
4884
4885 IMPLEMENT_DYNAMIC_CLASS(wxWinModule, wxModule)
4886
4887 bool wxWinModule::OnInit()
4888 {
4889 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4890 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4891
4892 return true;
4893 }
4894
4895 void wxWinModule::OnExit()
4896 {
4897 if (g_eraseGC)
4898 gdk_gc_unref( g_eraseGC );
4899 }
4900
4901 // vi:sts=4:sw=4:et