GTK+ callbacks must have C linkage (patch 1157384)
[wxWidgets.git] / src / gtk1 / window.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: gtk/window.cpp
3 // Purpose:
4 // Author: Robert Roebling
5 // Id: $Id$
6 // Copyright: (c) 1998 Robert Roebling, Julian Smart
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10
11 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
12 #pragma implementation "window.h"
13 #endif
14
15 // For compilers that support precompilation, includes "wx.h".
16 #include "wx/wxprec.h"
17
18 #ifdef __VMS
19 #define XWarpPointer XWARPPOINTER
20 #endif
21
22 #include "wx/window.h"
23 #include "wx/dcclient.h"
24 #include "wx/frame.h"
25 #include "wx/app.h"
26 #include "wx/layout.h"
27 #include "wx/utils.h"
28 #include "wx/dialog.h"
29 #include "wx/msgdlg.h"
30 #include "wx/module.h"
31 #include "wx/combobox.h"
32
33 #if wxUSE_DRAG_AND_DROP
34 #include "wx/dnd.h"
35 #endif
36
37 #if wxUSE_TOOLTIPS
38 #include "wx/tooltip.h"
39 #endif
40
41 #if wxUSE_CARET
42 #include "wx/caret.h"
43 #endif // wxUSE_CARET
44
45 #if wxUSE_TEXTCTRL
46 #include "wx/textctrl.h"
47 #endif
48
49 #include "wx/menu.h"
50 #include "wx/statusbr.h"
51 #include "wx/intl.h"
52 #include "wx/settings.h"
53 #include "wx/log.h"
54 #include "wx/fontutil.h"
55
56 #ifdef __WXDEBUG__
57 #include "wx/thread.h"
58 #endif
59
60 #include "wx/math.h"
61 #include <ctype.h>
62
63 #include "wx/gtk/private.h"
64 #include <gdk/gdkprivate.h>
65 #include <gdk/gdkkeysyms.h>
66 #include <gdk/gdkx.h>
67
68 #include <gtk/gtk.h>
69 #include <gtk/gtkprivate.h>
70
71 #include "wx/gtk/win_gtk.h"
72
73 #ifdef __WXGTK20__
74 #include <pango/pangox.h>
75 #endif
76
77
78 #ifdef __WXGTK20__
79 #ifdef HAVE_XIM
80 #undef HAVE_XIM
81 #endif
82 #endif
83
84 #ifdef __WXGTK20__
85 extern GtkContainerClass *pizza_parent_class;
86 #endif
87
88 //-----------------------------------------------------------------------------
89 // documentation on internals
90 //-----------------------------------------------------------------------------
91
92 /*
93 I have been asked several times about writing some documentation about
94 the GTK port of wxWidgets, especially its internal structures. Obviously,
95 you cannot understand wxGTK without knowing a little about the GTK, but
96 some more information about what the wxWindow, which is the base class
97 for all other window classes, does seems required as well.
98
99 I)
100
101 What does wxWindow do? It contains the common interface for the following
102 jobs of its descendants:
103
104 1) Define the rudimentary behaviour common to all window classes, such as
105 resizing, intercepting user input (so as to make it possible to use these
106 events for special purposes in a derived class), window names etc.
107
108 2) Provide the possibility to contain and manage children, if the derived
109 class is allowed to contain children, which holds true for those window
110 classes which do not display a native GTK widget. To name them, these
111 classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
112 work classes are a special case and are handled a bit differently from
113 the rest. The same holds true for the wxNotebook class.
114
115 3) Provide the possibility to draw into a client area of a window. This,
116 too, only holds true for classes that do not display a native GTK widget
117 as above.
118
119 4) Provide the entire mechanism for scrolling widgets. This actual inter-
120 face for this is usually in wxScrolledWindow, but the GTK implementation
121 is in this class.
122
123 5) A multitude of helper or extra methods for special purposes, such as
124 Drag'n'Drop, managing validators etc.
125
126 6) Display a border (sunken, raised, simple or none).
127
128 Normally one might expect, that one wxWidgets window would always correspond
129 to one GTK widget. Under GTK, there is no such allround widget that has all
130 the functionality. Moreover, the GTK defines a client area as a different
131 widget from the actual widget you are handling. Last but not least some
132 special classes (e.g. wxFrame) handle different categories of widgets and
133 still have the possibility to draw something in the client area.
134 It was therefore required to write a special purpose GTK widget, that would
135 represent a client area in the sense of wxWidgets capable to do the jobs
136 2), 3) and 4). I have written this class and it resides in win_gtk.c of
137 this directory.
138
139 All windows must have a widget, with which they interact with other under-
140 lying GTK widgets. It is this widget, e.g. that has to be resized etc and
141 thw wxWindow class has a member variable called m_widget which holds a
142 pointer to this widget. When the window class represents a GTK native widget,
143 this is (in most cases) the only GTK widget the class manages. E.g. the
144 wxStaticText class handles only a GtkLabel widget a pointer to which you
145 can find in m_widget (defined in wxWindow)
146
147 When the class has a client area for drawing into and for containing children
148 it has to handle the client area widget (of the type GtkPizza, defined in
149 win_gtk.c), but there could be any number of widgets, handled by a class
150 The common rule for all windows is only, that the widget that interacts with
151 the rest of GTK must be referenced in m_widget and all other widgets must be
152 children of this widget on the GTK level. The top-most widget, which also
153 represents the client area, must be in the m_wxwindow field and must be of
154 the type GtkPizza.
155
156 As I said, the window classes that display a GTK native widget only have
157 one widget, so in the case of e.g. the wxButton class m_widget holds a
158 pointer to a GtkButton widget. But windows with client areas (for drawing
159 and children) have a m_widget field that is a pointer to a GtkScrolled-
160 Window and a m_wxwindow field that is pointer to a GtkPizza and this
161 one is (in the GTK sense) a child of the GtkScrolledWindow.
162
163 If the m_wxwindow field is set, then all input to this widget is inter-
164 cepted and sent to the wxWidgets class. If not, all input to the widget
165 that gets pointed to by m_widget gets intercepted and sent to the class.
166
167 II)
168
169 The design of scrolling in wxWidgets is markedly different from that offered
170 by the GTK itself and therefore we cannot simply take it as it is. In GTK,
171 clicking on a scrollbar belonging to scrolled window will inevitably move
172 the window. In wxWidgets, the scrollbar will only emit an event, send this
173 to (normally) a wxScrolledWindow and that class will call ScrollWindow()
174 which actually moves the window and its subchildren. Note that GtkPizza
175 memorizes how much it has been scrolled but that wxWidgets forgets this
176 so that the two coordinates systems have to be kept in synch. This is done
177 in various places using the pizza->xoffset and pizza->yoffset values.
178
179 III)
180
181 Singularily the most broken code in GTK is the code that is supposes to
182 inform subwindows (child windows) about new positions. Very often, duplicate
183 events are sent without changes in size or position, equally often no
184 events are sent at all (All this is due to a bug in the GtkContainer code
185 which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
186 GTK's own system and it simply waits for size events for toplevel windows
187 and then iterates down the respective size events to all window. This has
188 the disadvantage, that windows might get size events before the GTK widget
189 actually has the reported size. This doesn't normally pose any problem, but
190 the OpenGl drawing routines rely on correct behaviour. Therefore, I have
191 added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
192 i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
193 window that is used for OpenGl output really has that size (as reported by
194 GTK).
195
196 IV)
197
198 If someone at some point of time feels the immense desire to have a look at,
199 change or attempt to optimse the Refresh() logic, this person will need an
200 intimate understanding of what a "draw" and what an "expose" events are and
201 what there are used for, in particular when used in connection with GTK's
202 own windowless widgets. Beware.
203
204 V)
205
206 Cursors, too, have been a constant source of pleasure. The main difficulty
207 is that a GdkWindow inherits a cursor if the programmer sets a new cursor
208 for the parent. To prevent this from doing too much harm, I use idle time
209 to set the cursor over and over again, starting from the toplevel windows
210 and ending with the youngest generation (speaking of parent and child windows).
211 Also don't forget that cursors (like much else) are connected to GdkWindows,
212 not GtkWidgets and that the "window" field of a GtkWidget might very well
213 point to the GdkWindow of the parent widget (-> "window less widget") and
214 that the two obviously have very different meanings.
215
216 */
217
218 //-----------------------------------------------------------------------------
219 // data
220 //-----------------------------------------------------------------------------
221
222 extern wxList wxPendingDelete;
223 extern bool g_blockEventsOnDrag;
224 extern bool g_blockEventsOnScroll;
225 extern wxCursor g_globalCursor;
226
227 static GdkGC *g_eraseGC = NULL;
228
229 // mouse capture state: the window which has it and if the mouse is currently
230 // inside it
231 static wxWindowGTK *g_captureWindow = (wxWindowGTK*) NULL;
232 static bool g_captureWindowHasMouse = FALSE;
233
234 wxWindowGTK *g_focusWindow = (wxWindowGTK*) NULL;
235
236 // the last window which had the focus - this is normally never NULL (except
237 // if we never had focus at all) as even when g_focusWindow is NULL it still
238 // keeps its previous value
239 wxWindowGTK *g_focusWindowLast = (wxWindowGTK*) NULL;
240
241 // If a window get the focus set but has not been realized
242 // yet, defer setting the focus to idle time.
243 wxWindowGTK *g_delayedFocus = (wxWindowGTK*) NULL;
244
245 // hack: we need something to pass to gtk_menu_popup, so we store the time of
246 // the last click here
247 static guint32 gs_timeLastClick = 0;
248
249 extern bool g_mainThreadLocked;
250
251 //-----------------------------------------------------------------------------
252 // debug
253 //-----------------------------------------------------------------------------
254
255 #ifdef __WXDEBUG__
256
257 #if wxUSE_THREADS
258 # define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
259 #else
260 # define DEBUG_MAIN_THREAD
261 #endif
262 #else
263 #define DEBUG_MAIN_THREAD
264 #endif // Debug
265
266 // the trace mask used for the focus debugging messages
267 #define TRACE_FOCUS _T("focus")
268
269 //-----------------------------------------------------------------------------
270 // missing gdk functions
271 //-----------------------------------------------------------------------------
272
273 void
274 gdk_window_warp_pointer (GdkWindow *window,
275 gint x,
276 gint y)
277 {
278 #ifndef __WXGTK20__
279 GdkWindowPrivate *priv;
280 #endif
281
282 if (!window)
283 window = GDK_ROOT_PARENT();
284
285 #ifdef __WXGTK20__
286 if (!GDK_WINDOW_DESTROYED(window))
287 {
288 XWarpPointer (GDK_WINDOW_XDISPLAY(window),
289 None, /* not source window -> move from anywhere */
290 GDK_WINDOW_XID(window), /* dest window */
291 0, 0, 0, 0, /* not source window -> move from anywhere */
292 x, y );
293 }
294 #else
295 priv = (GdkWindowPrivate*) window;
296
297 if (!priv->destroyed)
298 {
299 XWarpPointer (priv->xdisplay,
300 None, /* not source window -> move from anywhere */
301 priv->xwindow, /* dest window */
302 0, 0, 0, 0, /* not source window -> move from anywhere */
303 x, y );
304 }
305 #endif
306 }
307
308 //-----------------------------------------------------------------------------
309 // idle system
310 //-----------------------------------------------------------------------------
311
312 extern void wxapp_install_idle_handler();
313 extern bool g_isIdle;
314
315 //-----------------------------------------------------------------------------
316 // local code (see below)
317 //-----------------------------------------------------------------------------
318
319 // returns the child of win which currently has focus or NULL if not found
320 //
321 // Note: can't be static, needed by textctrl.cpp.
322 wxWindow *wxFindFocusedChild(wxWindowGTK *win)
323 {
324 wxWindow *winFocus = wxWindowGTK::FindFocus();
325 if ( !winFocus )
326 return (wxWindow *)NULL;
327
328 if ( winFocus == win )
329 return (wxWindow *)win;
330
331 for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
332 node;
333 node = node->GetNext() )
334 {
335 wxWindow *child = wxFindFocusedChild(node->GetData());
336 if ( child )
337 return child;
338 }
339
340 return (wxWindow *)NULL;
341 }
342
343 static void draw_frame( GtkWidget *widget, wxWindowGTK *win )
344 {
345 // wxUniversal widgets draw the borders and scrollbars themselves
346 #ifndef __WXUNIVERSAL__
347 if (!win->m_hasVMT)
348 return;
349
350 int dw = 0;
351 int dh = 0;
352
353 if (win->m_hasScrolling)
354 {
355 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(widget);
356
357 GtkRequisition vscroll_req;
358 vscroll_req.width = 2;
359 vscroll_req.height = 2;
360 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
361 (scroll_window->vscrollbar, &vscroll_req );
362
363 GtkRequisition hscroll_req;
364 hscroll_req.width = 2;
365 hscroll_req.height = 2;
366 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
367 (scroll_window->hscrollbar, &hscroll_req );
368
369 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget) );
370
371 if (scroll_window->vscrollbar_visible)
372 {
373 dw += vscroll_req.width;
374 dw += scroll_class->scrollbar_spacing;
375 }
376
377 if (scroll_window->hscrollbar_visible)
378 {
379 dh += hscroll_req.height;
380 dh += scroll_class->scrollbar_spacing;
381 }
382 }
383
384 int dx = 0;
385 int dy = 0;
386 if (GTK_WIDGET_NO_WINDOW (widget))
387 {
388 dx += widget->allocation.x;
389 dy += widget->allocation.y;
390 }
391
392 if (win->HasFlag(wxRAISED_BORDER))
393 {
394 gtk_draw_shadow( widget->style,
395 widget->window,
396 GTK_STATE_NORMAL,
397 GTK_SHADOW_OUT,
398 dx, dy,
399 widget->allocation.width-dw, widget->allocation.height-dh );
400 return;
401 }
402
403 if (win->HasFlag(wxSUNKEN_BORDER))
404 {
405 gtk_draw_shadow( widget->style,
406 widget->window,
407 GTK_STATE_NORMAL,
408 GTK_SHADOW_IN,
409 dx, dy,
410 widget->allocation.width-dw, widget->allocation.height-dh );
411 return;
412 }
413
414 if (win->HasFlag(wxSIMPLE_BORDER))
415 {
416 GdkGC *gc;
417 gc = gdk_gc_new( widget->window );
418 gdk_gc_set_foreground( gc, &widget->style->black );
419 gdk_draw_rectangle( widget->window, gc, FALSE,
420 dx, dy,
421 widget->allocation.width-dw-1, widget->allocation.height-dh-1 );
422 gdk_gc_unref( gc );
423 return;
424 }
425 #endif // __WXUNIVERSAL__
426 }
427
428 //-----------------------------------------------------------------------------
429 // "expose_event" of m_widget
430 //-----------------------------------------------------------------------------
431
432 extern "C" {
433 static gint gtk_window_own_expose_callback( GtkWidget *widget, GdkEventExpose *gdk_event, wxWindowGTK *win )
434 {
435 if (gdk_event->count > 0) return FALSE;
436
437 draw_frame( widget, win );
438
439 #ifdef __WXGTK20__
440
441 (* GTK_WIDGET_CLASS (pizza_parent_class)->expose_event) (widget, gdk_event);
442
443 #endif
444 return TRUE;
445 }
446 }
447
448 //-----------------------------------------------------------------------------
449 // "draw" of m_widget
450 //-----------------------------------------------------------------------------
451
452 #ifndef __WXGTK20__
453
454 extern "C" {
455 static void gtk_window_own_draw_callback( GtkWidget *widget, GdkRectangle *WXUNUSED(rect), wxWindowGTK *win )
456 {
457 draw_frame( widget, win );
458 }
459 }
460
461 #endif // GTK+ < 2.0
462
463 //-----------------------------------------------------------------------------
464 // "size_request" of m_widget
465 //-----------------------------------------------------------------------------
466
467 // make it extern because wxStaticText needs to disconnect this one
468 extern "C" {
469 void wxgtk_window_size_request_callback(GtkWidget *widget,
470 GtkRequisition *requisition,
471 wxWindow *win)
472 {
473 int w, h;
474 win->GetSize( &w, &h );
475 if (w < 2)
476 w = 2;
477 if (h < 2)
478 h = 2;
479
480 requisition->height = h;
481 requisition->width = w;
482 }
483 }
484
485 extern "C" {
486 static
487 void wxgtk_combo_size_request_callback(GtkWidget *widget,
488 GtkRequisition *requisition,
489 wxComboBox *win)
490 {
491 // This callback is actually hooked into the text entry
492 // of the combo box, not the GtkHBox.
493
494 int w, h;
495 win->GetSize( &w, &h );
496 if (w < 2)
497 w = 2;
498 if (h < 2)
499 h = 2;
500
501 GtkCombo *gcombo = GTK_COMBO(win->m_widget);
502
503 GtkRequisition entry_req;
504 entry_req.width = 2;
505 entry_req.height = 2;
506 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo->button) )->size_request )
507 (gcombo->button, &entry_req );
508
509 requisition->width = w - entry_req.width;
510 requisition->height = entry_req.height+4; // TODO: why +4?
511 }
512 }
513
514 //-----------------------------------------------------------------------------
515 // "expose_event" of m_wxwindow
516 //-----------------------------------------------------------------------------
517
518 extern "C" {
519 static int gtk_window_expose_callback( GtkWidget *widget,
520 GdkEventExpose *gdk_event,
521 wxWindow *win )
522 {
523 DEBUG_MAIN_THREAD
524
525 if (g_isIdle)
526 wxapp_install_idle_handler();
527
528 #ifdef __WXGTK20__
529 // This callback gets called in drawing-idle time under
530 // GTK 2.0, so we don't need to defer anything to idle
531 // time anymore.
532
533 GtkPizza *pizza = GTK_PIZZA( widget );
534 if (gdk_event->window != pizza->bin_window) return FALSE;
535
536 #if 0
537 if (win->GetName())
538 {
539 wxPrintf( wxT("OnExpose from ") );
540 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
541 wxPrintf( win->GetClassInfo()->GetClassName() );
542 wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event->area.x,
543 (int)gdk_event->area.y,
544 (int)gdk_event->area.width,
545 (int)gdk_event->area.height );
546 }
547
548 gtk_paint_box
549 (
550 win->m_wxwindow->style,
551 pizza->bin_window,
552 GTK_STATE_NORMAL,
553 GTK_SHADOW_OUT,
554 (GdkRectangle*) NULL,
555 win->m_wxwindow,
556 (char *)"button", // const_cast
557 20,20,24,24
558 );
559 #endif
560
561 win->GetUpdateRegion() = wxRegion( gdk_event->region );
562
563 win->GtkSendPaintEvents();
564
565
566 // Let parent window draw window less widgets
567 (* GTK_WIDGET_CLASS (pizza_parent_class)->expose_event) (widget, gdk_event);
568 #else
569 // This gets called immediately after an expose event
570 // under GTK 1.2 so we collect the calls and wait for
571 // the idle handler to pick things up.
572
573 win->GetUpdateRegion().Union( gdk_event->area.x,
574 gdk_event->area.y,
575 gdk_event->area.width,
576 gdk_event->area.height );
577 win->m_clearRegion.Union( gdk_event->area.x,
578 gdk_event->area.y,
579 gdk_event->area.width,
580 gdk_event->area.height );
581
582 // Actual redrawing takes place in idle time.
583 // win->GtkUpdate();
584 #endif
585
586 return FALSE;
587 }
588 }
589
590 //-----------------------------------------------------------------------------
591 // "event" of m_wxwindow
592 //-----------------------------------------------------------------------------
593
594 // GTK thinks it is clever and filters out a certain amount of "unneeded"
595 // expose events. We need them, of course, so we override the main event
596 // procedure in GtkWidget by giving our own handler for all system events.
597 // There, we look for expose events ourselves whereas all other events are
598 // handled normally.
599
600 extern "C" {
601 static
602 gint gtk_window_event_event_callback( GtkWidget *widget,
603 GdkEventExpose *event,
604 wxWindow *win )
605 {
606 if (event->type == GDK_EXPOSE)
607 {
608 gint ret = gtk_window_expose_callback( widget, event, win );
609 return ret;
610 }
611
612 return FALSE;
613 }
614 }
615
616 //-----------------------------------------------------------------------------
617 // "draw" of m_wxwindow
618 //-----------------------------------------------------------------------------
619
620 #ifndef __WXGTK20__
621
622 // This callback is a complete replacement of the gtk_pizza_draw() function,
623 // which is disabled.
624
625 extern "C" {
626 static void gtk_window_draw_callback( GtkWidget *widget,
627 GdkRectangle *rect,
628 wxWindow *win )
629 {
630 DEBUG_MAIN_THREAD
631
632 if (g_isIdle)
633 wxapp_install_idle_handler();
634
635 // if there are any children we must refresh everything
636 //
637 // VZ: why?
638 if ( !win->HasFlag(wxFULL_REPAINT_ON_RESIZE) &&
639 win->GetChildren().IsEmpty() )
640 {
641 return;
642 }
643
644 #if 0
645 if (win->GetName())
646 {
647 wxPrintf( wxT("OnDraw from ") );
648 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
649 wxPrintf( win->GetClassInfo()->GetClassName() );
650 wxPrintf( wxT(" %d %d %d %d\n"), (int)rect->x,
651 (int)rect->y,
652 (int)rect->width,
653 (int)rect->height );
654 }
655 #endif
656
657 #ifndef __WXUNIVERSAL__
658 GtkPizza *pizza = GTK_PIZZA (widget);
659
660 if (win->GetThemeEnabled() && win->GetBackgroundStyle() == wxBG_STYLE_SYSTEM)
661 {
662 wxWindow *parent = win->GetParent();
663 while (parent && !parent->IsTopLevel())
664 parent = parent->GetParent();
665 if (!parent)
666 parent = win;
667
668 gtk_paint_flat_box (parent->m_widget->style,
669 pizza->bin_window,
670 GTK_STATE_NORMAL,
671 GTK_SHADOW_NONE,
672 rect,
673 parent->m_widget,
674 (char *)"base",
675 0, 0, -1, -1);
676 }
677 #endif
678
679 win->m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height );
680 win->GetUpdateRegion().Union( rect->x, rect->y, rect->width, rect->height );
681
682 // Update immediately, not in idle time.
683 win->GtkUpdate();
684
685 #ifndef __WXUNIVERSAL__
686 // Redraw child widgets
687 GList *children = pizza->children;
688 while (children)
689 {
690 GtkPizzaChild *child = (GtkPizzaChild*) children->data;
691 children = children->next;
692
693 GdkRectangle child_area;
694 if (gtk_widget_intersect (child->widget, rect, &child_area))
695 {
696 gtk_widget_draw (child->widget, &child_area /* (GdkRectangle*) NULL*/ );
697 }
698 }
699 #endif
700 }
701 }
702
703 #endif
704
705 //-----------------------------------------------------------------------------
706 // "key_press_event" from any window
707 //-----------------------------------------------------------------------------
708
709 // set WXTRACE to this to see the key event codes on the console
710 #define TRACE_KEYS _T("keyevent")
711
712 // translates an X key symbol to WXK_XXX value
713 //
714 // if isChar is true it means that the value returned will be used for EVT_CHAR
715 // event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
716 // for example, while if it is false it means that the value is going to be
717 // used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
718 // WXK_NUMPAD_DIVIDE
719 static long wxTranslateKeySymToWXKey(KeySym keysym, bool isChar)
720 {
721 long key_code;
722
723 switch ( keysym )
724 {
725 // Shift, Control and Alt don't generate the CHAR events at all
726 case GDK_Shift_L:
727 case GDK_Shift_R:
728 key_code = isChar ? 0 : WXK_SHIFT;
729 break;
730 case GDK_Control_L:
731 case GDK_Control_R:
732 key_code = isChar ? 0 : WXK_CONTROL;
733 break;
734 case GDK_Meta_L:
735 case GDK_Meta_R:
736 case GDK_Alt_L:
737 case GDK_Alt_R:
738 case GDK_Super_L:
739 case GDK_Super_R:
740 key_code = isChar ? 0 : WXK_ALT;
741 break;
742
743 // neither do the toggle modifies
744 case GDK_Scroll_Lock:
745 key_code = isChar ? 0 : WXK_SCROLL;
746 break;
747
748 case GDK_Caps_Lock:
749 key_code = isChar ? 0 : WXK_CAPITAL;
750 break;
751
752 case GDK_Num_Lock:
753 key_code = isChar ? 0 : WXK_NUMLOCK;
754 break;
755
756
757 // various other special keys
758 case GDK_Menu:
759 key_code = WXK_MENU;
760 break;
761
762 case GDK_Help:
763 key_code = WXK_HELP;
764 break;
765
766 case GDK_BackSpace:
767 key_code = WXK_BACK;
768 break;
769
770 case GDK_ISO_Left_Tab:
771 case GDK_Tab:
772 key_code = WXK_TAB;
773 break;
774
775 case GDK_Linefeed:
776 case GDK_Return:
777 key_code = WXK_RETURN;
778 break;
779
780 case GDK_Clear:
781 key_code = WXK_CLEAR;
782 break;
783
784 case GDK_Pause:
785 key_code = WXK_PAUSE;
786 break;
787
788 case GDK_Select:
789 key_code = WXK_SELECT;
790 break;
791
792 case GDK_Print:
793 key_code = WXK_PRINT;
794 break;
795
796 case GDK_Execute:
797 key_code = WXK_EXECUTE;
798 break;
799
800 case GDK_Escape:
801 key_code = WXK_ESCAPE;
802 break;
803
804 // cursor and other extended keyboard keys
805 case GDK_Delete:
806 key_code = WXK_DELETE;
807 break;
808
809 case GDK_Home:
810 key_code = WXK_HOME;
811 break;
812
813 case GDK_Left:
814 key_code = WXK_LEFT;
815 break;
816
817 case GDK_Up:
818 key_code = WXK_UP;
819 break;
820
821 case GDK_Right:
822 key_code = WXK_RIGHT;
823 break;
824
825 case GDK_Down:
826 key_code = WXK_DOWN;
827 break;
828
829 case GDK_Prior: // == GDK_Page_Up
830 key_code = WXK_PRIOR;
831 break;
832
833 case GDK_Next: // == GDK_Page_Down
834 key_code = WXK_NEXT;
835 break;
836
837 case GDK_End:
838 key_code = WXK_END;
839 break;
840
841 case GDK_Begin:
842 key_code = WXK_HOME;
843 break;
844
845 case GDK_Insert:
846 key_code = WXK_INSERT;
847 break;
848
849
850 // numpad keys
851 case GDK_KP_0:
852 case GDK_KP_1:
853 case GDK_KP_2:
854 case GDK_KP_3:
855 case GDK_KP_4:
856 case GDK_KP_5:
857 case GDK_KP_6:
858 case GDK_KP_7:
859 case GDK_KP_8:
860 case GDK_KP_9:
861 key_code = (isChar ? '0' : WXK_NUMPAD0) + keysym - GDK_KP_0;
862 break;
863
864 case GDK_KP_Space:
865 key_code = isChar ? ' ' : WXK_NUMPAD_SPACE;
866 break;
867
868 case GDK_KP_Tab:
869 key_code = isChar ? WXK_TAB : WXK_NUMPAD_TAB;
870 break;
871
872 case GDK_KP_Enter:
873 key_code = isChar ? WXK_RETURN : WXK_NUMPAD_ENTER;
874 break;
875
876 case GDK_KP_F1:
877 key_code = isChar ? WXK_F1 : WXK_NUMPAD_F1;
878 break;
879
880 case GDK_KP_F2:
881 key_code = isChar ? WXK_F2 : WXK_NUMPAD_F2;
882 break;
883
884 case GDK_KP_F3:
885 key_code = isChar ? WXK_F3 : WXK_NUMPAD_F3;
886 break;
887
888 case GDK_KP_F4:
889 key_code = isChar ? WXK_F4 : WXK_NUMPAD_F4;
890 break;
891
892 case GDK_KP_Home:
893 key_code = isChar ? WXK_HOME : WXK_NUMPAD_HOME;
894 break;
895
896 case GDK_KP_Left:
897 key_code = isChar ? WXK_LEFT : WXK_NUMPAD_LEFT;
898 break;
899
900 case GDK_KP_Up:
901 key_code = isChar ? WXK_UP : WXK_NUMPAD_UP;
902 break;
903
904 case GDK_KP_Right:
905 key_code = isChar ? WXK_RIGHT : WXK_NUMPAD_RIGHT;
906 break;
907
908 case GDK_KP_Down:
909 key_code = isChar ? WXK_DOWN : WXK_NUMPAD_DOWN;
910 break;
911
912 case GDK_KP_Prior: // == GDK_KP_Page_Up
913 key_code = isChar ? WXK_PRIOR : WXK_NUMPAD_PRIOR;
914 break;
915
916 case GDK_KP_Next: // == GDK_KP_Page_Down
917 key_code = isChar ? WXK_NEXT : WXK_NUMPAD_NEXT;
918 break;
919
920 case GDK_KP_End:
921 key_code = isChar ? WXK_END : WXK_NUMPAD_END;
922 break;
923
924 case GDK_KP_Begin:
925 key_code = isChar ? WXK_HOME : WXK_NUMPAD_BEGIN;
926 break;
927
928 case GDK_KP_Insert:
929 key_code = isChar ? WXK_INSERT : WXK_NUMPAD_INSERT;
930 break;
931
932 case GDK_KP_Delete:
933 key_code = isChar ? WXK_DELETE : WXK_NUMPAD_DELETE;
934 break;
935
936 case GDK_KP_Equal:
937 key_code = isChar ? '=' : WXK_NUMPAD_EQUAL;
938 break;
939
940 case GDK_KP_Multiply:
941 key_code = isChar ? '*' : WXK_NUMPAD_MULTIPLY;
942 break;
943
944 case GDK_KP_Add:
945 key_code = isChar ? '+' : WXK_NUMPAD_ADD;
946 break;
947
948 case GDK_KP_Separator:
949 // FIXME: what is this?
950 key_code = isChar ? '.' : WXK_NUMPAD_SEPARATOR;
951 break;
952
953 case GDK_KP_Subtract:
954 key_code = isChar ? '-' : WXK_NUMPAD_SUBTRACT;
955 break;
956
957 case GDK_KP_Decimal:
958 key_code = isChar ? '.' : WXK_NUMPAD_DECIMAL;
959 break;
960
961 case GDK_KP_Divide:
962 key_code = isChar ? '/' : WXK_NUMPAD_DIVIDE;
963 break;
964
965
966 // function keys
967 case GDK_F1:
968 case GDK_F2:
969 case GDK_F3:
970 case GDK_F4:
971 case GDK_F5:
972 case GDK_F6:
973 case GDK_F7:
974 case GDK_F8:
975 case GDK_F9:
976 case GDK_F10:
977 case GDK_F11:
978 case GDK_F12:
979 key_code = WXK_F1 + keysym - GDK_F1;
980 break;
981
982 default:
983 key_code = 0;
984 }
985
986 return key_code;
987 }
988
989 static inline bool wxIsAsciiKeysym(KeySym ks)
990 {
991 return ks < 256;
992 }
993
994 static void wxFillOtherKeyEventFields(wxKeyEvent& event,
995 wxWindowGTK *win,
996 GdkEventKey *gdk_event)
997 {
998 int x = 0;
999 int y = 0;
1000 GdkModifierType state;
1001 if (gdk_event->window)
1002 gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
1003
1004 event.SetTimestamp( gdk_event->time );
1005 event.SetId(win->GetId());
1006 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK) != 0;
1007 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK) != 0;
1008 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK) != 0;
1009 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK) != 0;
1010 event.m_scanCode = gdk_event->keyval;
1011 event.m_rawCode = (wxUint32) gdk_event->keyval;
1012 event.m_rawFlags = 0;
1013 #if wxUSE_UNICODE
1014 event.m_uniChar = gdk_keyval_to_unicode(gdk_event->keyval);
1015 #endif
1016 wxGetMousePosition( &x, &y );
1017 win->ScreenToClient( &x, &y );
1018 event.m_x = x;
1019 event.m_y = y;
1020 event.SetEventObject( win );
1021 }
1022
1023
1024 static bool
1025 wxTranslateGTKKeyEventToWx(wxKeyEvent& event,
1026 wxWindowGTK *win,
1027 GdkEventKey *gdk_event)
1028 {
1029 // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
1030 // but only event->keyval which is quite useless to us, so remember
1031 // the last character from GDK_KEY_PRESS and reuse it as last resort
1032 //
1033 // NB: should be MT-safe as we're always called from the main thread only
1034 static struct
1035 {
1036 KeySym keysym;
1037 long keycode;
1038 } s_lastKeyPress = { 0, 0 };
1039
1040 KeySym keysym = gdk_event->keyval;
1041
1042 wxLogTrace(TRACE_KEYS, _T("Key %s event: keysym = %ld"),
1043 event.GetEventType() == wxEVT_KEY_UP ? _T("release")
1044 : _T("press"),
1045 keysym);
1046
1047 long key_code = wxTranslateKeySymToWXKey(keysym, FALSE /* !isChar */);
1048
1049 if ( !key_code )
1050 {
1051 // do we have the translation or is it a plain ASCII character?
1052 if ( (gdk_event->length == 1) || wxIsAsciiKeysym(keysym) )
1053 {
1054 // we should use keysym if it is ASCII as X does some translations
1055 // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
1056 // which we don't want here (but which we do use for OnChar())
1057 if ( !wxIsAsciiKeysym(keysym) )
1058 {
1059 keysym = (KeySym)gdk_event->string[0];
1060 }
1061
1062 // we want to always get the same key code when the same key is
1063 // pressed regardless of the state of the modifies, i.e. on a
1064 // standard US keyboard pressing '5' or '%' ('5' key with
1065 // Shift) should result in the same key code in OnKeyDown():
1066 // '5' (although OnChar() will get either '5' or '%').
1067 //
1068 // to do it we first translate keysym to keycode (== scan code)
1069 // and then back but always using the lower register
1070 Display *dpy = (Display *)wxGetDisplay();
1071 KeyCode keycode = XKeysymToKeycode(dpy, keysym);
1072
1073 wxLogTrace(TRACE_KEYS, _T("\t-> keycode %d"), keycode);
1074
1075 KeySym keysymNormalized = XKeycodeToKeysym(dpy, keycode, 0);
1076
1077 // use the normalized, i.e. lower register, keysym if we've
1078 // got one
1079 key_code = keysymNormalized ? keysymNormalized : keysym;
1080
1081 // as explained above, we want to have lower register key codes
1082 // normally but for the letter keys we want to have the upper ones
1083 //
1084 // NB: don't use XConvertCase() here, we want to do it for letters
1085 // only
1086 key_code = toupper(key_code);
1087 }
1088 else // non ASCII key, what to do?
1089 {
1090 // by default, ignore it
1091 key_code = 0;
1092
1093 // but if we have cached information from the last KEY_PRESS
1094 if ( gdk_event->type == GDK_KEY_RELEASE )
1095 {
1096 // then reuse it
1097 if ( keysym == s_lastKeyPress.keysym )
1098 {
1099 key_code = s_lastKeyPress.keycode;
1100 }
1101 }
1102 }
1103
1104 if ( gdk_event->type == GDK_KEY_PRESS )
1105 {
1106 // remember it to be reused for KEY_UP event later
1107 s_lastKeyPress.keysym = keysym;
1108 s_lastKeyPress.keycode = key_code;
1109 }
1110 }
1111
1112 wxLogTrace(TRACE_KEYS, _T("\t-> wxKeyCode %ld"), key_code);
1113
1114 // sending unknown key events doesn't really make sense
1115 if ( !key_code )
1116 return FALSE;
1117
1118 // now fill all the other fields
1119 wxFillOtherKeyEventFields(event, win, gdk_event);
1120
1121 event.m_keyCode = key_code;
1122
1123 return TRUE;
1124 }
1125
1126
1127 #ifdef __WXGTK20__
1128 struct wxGtkIMData
1129 {
1130 GtkIMContext *context;
1131 GdkEventKey *lastKeyEvent;
1132
1133 wxGtkIMData()
1134 {
1135 context = gtk_im_multicontext_new();
1136 lastKeyEvent = NULL;
1137 }
1138 ~wxGtkIMData()
1139 {
1140 g_object_unref(context);
1141 }
1142 };
1143 #endif
1144
1145 extern "C" {
1146 static gint gtk_window_key_press_callback( GtkWidget *widget,
1147 GdkEventKey *gdk_event,
1148 wxWindow *win )
1149 {
1150 DEBUG_MAIN_THREAD
1151
1152 if (g_isIdle)
1153 wxapp_install_idle_handler();
1154
1155 if (!win->m_hasVMT)
1156 return FALSE;
1157 if (g_blockEventsOnDrag)
1158 return FALSE;
1159
1160
1161 wxKeyEvent event( wxEVT_KEY_DOWN );
1162 bool ret = false;
1163 bool return_after_IM = false;
1164
1165 if( wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
1166 {
1167 // Emit KEY_DOWN event
1168 ret = win->GetEventHandler()->ProcessEvent( event );
1169 }
1170 else
1171 {
1172 // Return after IM processing as we cannot do
1173 // anything with it anyhow.
1174 return_after_IM = true;
1175 }
1176
1177 #ifdef __WXGTK20__
1178 // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
1179 // When we get a key_press event here, it could be originate
1180 // from the current widget or its child widgets. However, only the widget
1181 // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
1182 // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
1183 // originated from its child widgets and shouldn't be passed to IM context.
1184 // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
1185 // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
1186 // widgets has both IM context and input focus, the event should be filtered
1187 // by gtk_im_context_filter_keypress().
1188 // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
1189 if ((!ret) && (win->m_imData != NULL) && ( wxWindow::FindFocus() == win ))
1190 {
1191 // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
1192 // docs, if IM filter returns true, no further processing should be done.
1193 // we should send the key_down event anyway.
1194 bool intercepted_by_IM = gtk_im_context_filter_keypress(win->m_imData->context, gdk_event);
1195 win->m_imData->lastKeyEvent = NULL;
1196 if (intercepted_by_IM)
1197 {
1198 wxLogTrace(TRACE_KEYS, _T("Key event intercepted by IM"));
1199 return true;
1200 }
1201 }
1202 #endif
1203 if (return_after_IM)
1204 return false;
1205
1206 #ifndef __WXGTK20__
1207 // This is for GTK+ 1.2 only. The char event generatation for GTK+ 2.0 is done
1208 // in the "commit" handler.
1209
1210 // 2005.02.02 modified by Hong Jen Yee (hzysoft@sina.com.tw).
1211 // In GTK+ 1.2, strings sent by IMs are also regarded as key_press events whose
1212 // keyCodes cannot be recognized by wxWidgets. These MBCS strings, however, are
1213 // composed of more than one character, which means gdk_event->length will always
1214 // greater than one. When gtk_event->length == 1, this may be an ASCII character
1215 // and can be translated by wx. However, when MBCS characters are sent by IM,
1216 // gdk_event->length will >= 2. So neither should we pass it to accelerator table,
1217 // nor should we pass it to controls. The following explanation was excerpted
1218 // from GDK documentation.
1219 // gint length : the length of string.
1220 // gchar *string : a null-terminated multi-byte string containing the composed
1221 // characters resulting from the key press. When text is being input, in a GtkEntry
1222 // for example, it is these characters which should be added to the input buffer.
1223 // When using Input Methods to support internationalized text input, the composed
1224 // characters appear here after the pre-editing has been completed.
1225
1226 if ( (!ret) && (gdk_event->length > 1) ) // If this event contains a pre-edited string from IM.
1227 {
1228 // We should translate this key event into wxEVT_CHAR not wxEVT_KEY_DOWN.
1229 #if wxUSE_UNICODE // GTK+ 1.2 is not UTF-8 based.
1230 const wxWCharBuffer string = wxConvLocal.cMB2WC( gdk_event->string );
1231 if( !string )
1232 return false;
1233 #else
1234 const char* string = gdk_event->string;
1235 #endif
1236
1237 // Implement OnCharHook by checking ancesteror top level windows
1238 wxWindow *parent = win;
1239 while (parent && !parent->IsTopLevel())
1240 parent = parent->GetParent();
1241
1242 for( const wxChar* pstr = string; *pstr; pstr++ )
1243 {
1244 #if wxUSE_UNICODE
1245 event.m_uniChar = *pstr;
1246 // Backward compatible for ISO-8859-1
1247 event.m_keyCode = *pstr < 256 ? event.m_uniChar : 0;
1248 #else
1249 event.m_keyCode = *pstr;
1250 #endif
1251 if (parent)
1252 {
1253 event.SetEventType( wxEVT_CHAR_HOOK );
1254 ret = parent->GetEventHandler()->ProcessEvent( event );
1255 }
1256 if (!ret)
1257 {
1258 event.SetEventType(wxEVT_CHAR);
1259 win->GetEventHandler()->ProcessEvent( event );
1260 }
1261 }
1262 return true;
1263 }
1264
1265 #endif // #ifndef __WXGTK20__
1266
1267 #if wxUSE_ACCEL
1268 if (!ret)
1269 {
1270 wxWindowGTK *ancestor = win;
1271 while (ancestor)
1272 {
1273 int command = ancestor->GetAcceleratorTable()->GetCommand( event );
1274 if (command != -1)
1275 {
1276 wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
1277 ret = ancestor->GetEventHandler()->ProcessEvent( command_event );
1278 break;
1279 }
1280 if (ancestor->IsTopLevel())
1281 break;
1282 ancestor = ancestor->GetParent();
1283 }
1284 }
1285 #endif // wxUSE_ACCEL
1286
1287 // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
1288 // will only be sent if it is not in an accelerator table.
1289 if (!ret)
1290 {
1291 long key_code;
1292 KeySym keysym = gdk_event->keyval;
1293 // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
1294 key_code = wxTranslateKeySymToWXKey(keysym, TRUE /* isChar */);
1295 if ( !key_code )
1296 {
1297 if ( wxIsAsciiKeysym(keysym) )
1298 {
1299 // ASCII key
1300 key_code = (unsigned char)keysym;
1301 }
1302 // gdk_event->string is actually deprecated
1303 else if ( gdk_event->length == 1 )
1304 {
1305 key_code = (unsigned char)gdk_event->string[0];
1306 }
1307 }
1308
1309 if ( key_code )
1310 {
1311 wxLogTrace(TRACE_KEYS, _T("Char event: %ld"), key_code);
1312
1313 event.m_keyCode = key_code;
1314
1315 // Implement OnCharHook by checking ancesteror top level windows
1316 wxWindow *parent = win;
1317 while (parent && !parent->IsTopLevel())
1318 parent = parent->GetParent();
1319 if (parent)
1320 {
1321 event.SetEventType( wxEVT_CHAR_HOOK );
1322 ret = parent->GetEventHandler()->ProcessEvent( event );
1323 }
1324
1325 if (!ret)
1326 {
1327 event.SetEventType(wxEVT_CHAR);
1328 ret = win->GetEventHandler()->ProcessEvent( event );
1329 }
1330 }
1331 }
1332
1333
1334
1335
1336
1337 // win is a control: tab can be propagated up
1338 if ( !ret &&
1339 ((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) &&
1340 // VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
1341 // have this style, yet choose not to process this particular TAB in which
1342 // case TAB must still work as a navigational character
1343 // JS: enabling again to make consistent with other platforms
1344 // (with wxTE_PROCESS_TAB you have to call Navigate to get default
1345 // navigation behaviour)
1346 #if wxUSE_TEXTCTRL
1347 (! (win->HasFlag(wxTE_PROCESS_TAB) && win->IsKindOf(CLASSINFO(wxTextCtrl)) )) &&
1348 #endif
1349 win->GetParent() && (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) )
1350 {
1351 wxNavigationKeyEvent new_event;
1352 new_event.SetEventObject( win->GetParent() );
1353 // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
1354 new_event.SetDirection( (gdk_event->keyval == GDK_Tab) );
1355 // CTRL-TAB changes the (parent) window, i.e. switch notebook page
1356 new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) );
1357 new_event.SetCurrentFocus( win );
1358 ret = win->GetParent()->GetEventHandler()->ProcessEvent( new_event );
1359 }
1360
1361 // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
1362 if ( !ret &&
1363 (gdk_event->keyval == GDK_Escape) )
1364 {
1365 // however only do it if we have a Cancel button in the dialog,
1366 // otherwise the user code may get confused by the events from a
1367 // non-existing button and, worse, a wxButton might get button event
1368 // from another button which is not really expected
1369 wxWindow *winForCancel = win,
1370 *btnCancel = NULL;
1371 while ( winForCancel )
1372 {
1373 btnCancel = winForCancel->FindWindow(wxID_CANCEL);
1374 if ( btnCancel )
1375 {
1376 // found a cancel button
1377 break;
1378 }
1379
1380 if ( winForCancel->IsTopLevel() )
1381 {
1382 // no need to look further
1383 break;
1384 }
1385
1386 // maybe our parent has a cancel button?
1387 winForCancel = winForCancel->GetParent();
1388 }
1389
1390 if ( btnCancel )
1391 {
1392 wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL);
1393 event.SetEventObject(btnCancel);
1394 ret = btnCancel->GetEventHandler()->ProcessEvent(event);
1395 }
1396 }
1397
1398 if (ret)
1399 {
1400 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
1401 return TRUE;
1402 }
1403
1404 return FALSE;
1405 }
1406 }
1407
1408 #ifdef __WXGTK20__
1409 extern "C" {
1410 static void gtk_wxwindow_commit_cb (GtkIMContext *context,
1411 const gchar *str,
1412 wxWindow *window)
1413 {
1414 wxKeyEvent event( wxEVT_KEY_DOWN );
1415
1416 // take modifiers, cursor position, timestamp etc. from the last
1417 // key_press_event that was fed into Input Method:
1418 if (window->m_imData->lastKeyEvent)
1419 {
1420 wxFillOtherKeyEventFields(event,
1421 window, window->m_imData->lastKeyEvent);
1422 }
1423
1424 #if wxUSE_UNICODE
1425 const wxWCharBuffer data = wxConvUTF8.cMB2WC( (char*)str );
1426 #else
1427 const wxWCharBuffer wdata = wxConvUTF8.cMB2WC( (char*)str );
1428 const wxCharBuffer data = wxConvLocal.cWC2MB( wdata );
1429 #endif // wxUSE_UNICODE
1430 if( !(const wxChar*)data )
1431 return;
1432
1433 bool ret = false;
1434
1435 // Implement OnCharHook by checking ancestor top level windows
1436 wxWindow *parent = window;
1437 while (parent && !parent->IsTopLevel())
1438 parent = parent->GetParent();
1439
1440 for( const wxChar* pstr = data; *pstr; pstr++ )
1441 {
1442 #if wxUSE_UNICODE
1443 event.m_uniChar = *pstr;
1444 // Backward compatible for ISO-8859-1
1445 event.m_keyCode = *pstr < 256 ? event.m_uniChar : 0;
1446 wxLogTrace(TRACE_KEYS, _T("IM sent character '%c'"), event.m_uniChar);
1447 #else
1448 event.m_keyCode = *pstr;
1449 #endif // wxUSE_UNICODE
1450 if (parent)
1451 {
1452 event.SetEventType( wxEVT_CHAR_HOOK );
1453 ret = parent->GetEventHandler()->ProcessEvent( event );
1454 }
1455
1456 if (!ret)
1457 {
1458 event.SetEventType(wxEVT_CHAR);
1459 ret = window->GetEventHandler()->ProcessEvent( event );
1460 }
1461 }
1462 }
1463 }
1464 #endif
1465
1466
1467 //-----------------------------------------------------------------------------
1468 // "key_release_event" from any window
1469 //-----------------------------------------------------------------------------
1470
1471 extern "C" {
1472 static gint gtk_window_key_release_callback( GtkWidget *widget,
1473 GdkEventKey *gdk_event,
1474 wxWindowGTK *win )
1475 {
1476 DEBUG_MAIN_THREAD
1477
1478 if (g_isIdle)
1479 wxapp_install_idle_handler();
1480
1481 if (!win->m_hasVMT)
1482 return FALSE;
1483
1484 if (g_blockEventsOnDrag)
1485 return FALSE;
1486
1487 wxKeyEvent event( wxEVT_KEY_UP );
1488 if ( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
1489 {
1490 // unknown key pressed, ignore (the event would be useless anyhow
1491 return FALSE;
1492 }
1493
1494 if ( !win->GetEventHandler()->ProcessEvent( event ) )
1495 return FALSE;
1496
1497 gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_release_event" );
1498 return TRUE;
1499 }
1500 }
1501
1502 // ============================================================================
1503 // the mouse events
1504 // ============================================================================
1505
1506 // ----------------------------------------------------------------------------
1507 // mouse event processing helpers
1508 // ----------------------------------------------------------------------------
1509
1510 // init wxMouseEvent with the info from GdkEventXXX struct
1511 template<typename T> void InitMouseEvent(wxWindowGTK *win,
1512 wxMouseEvent& event,
1513 T *gdk_event)
1514 {
1515 event.SetTimestamp( gdk_event->time );
1516 event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
1517 event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
1518 event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
1519 event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
1520 event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
1521 event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
1522 event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
1523 if (event.GetEventType() == wxEVT_MOUSEWHEEL)
1524 {
1525 event.m_linesPerAction = 3;
1526 event.m_wheelDelta = 120;
1527 if (((GdkEventButton*)gdk_event)->button == 4)
1528 event.m_wheelRotation = 120;
1529 else if (((GdkEventButton*)gdk_event)->button == 5)
1530 event.m_wheelRotation = -120;
1531 }
1532
1533 wxPoint pt = win->GetClientAreaOrigin();
1534 event.m_x = (wxCoord)gdk_event->x - pt.x;
1535 event.m_y = (wxCoord)gdk_event->y - pt.y;
1536
1537 event.SetEventObject( win );
1538 event.SetId( win->GetId() );
1539 event.SetTimestamp( gdk_event->time );
1540 }
1541
1542 static void AdjustEventButtonState(wxMouseEvent& event)
1543 {
1544 // GDK reports the old state of the button for a button press event, but
1545 // for compatibility with MSW and common sense we want m_leftDown be TRUE
1546 // for a LEFT_DOWN event, not FALSE, so we will invert
1547 // left/right/middleDown for the corresponding click events
1548
1549 if ((event.GetEventType() == wxEVT_LEFT_DOWN) ||
1550 (event.GetEventType() == wxEVT_LEFT_DCLICK) ||
1551 (event.GetEventType() == wxEVT_LEFT_UP))
1552 {
1553 event.m_leftDown = !event.m_leftDown;
1554 return;
1555 }
1556
1557 if ((event.GetEventType() == wxEVT_MIDDLE_DOWN) ||
1558 (event.GetEventType() == wxEVT_MIDDLE_DCLICK) ||
1559 (event.GetEventType() == wxEVT_MIDDLE_UP))
1560 {
1561 event.m_middleDown = !event.m_middleDown;
1562 return;
1563 }
1564
1565 if ((event.GetEventType() == wxEVT_RIGHT_DOWN) ||
1566 (event.GetEventType() == wxEVT_RIGHT_DCLICK) ||
1567 (event.GetEventType() == wxEVT_RIGHT_UP))
1568 {
1569 event.m_rightDown = !event.m_rightDown;
1570 return;
1571 }
1572 }
1573
1574 // find the window to send the mouse event too
1575 static
1576 wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y)
1577 {
1578 wxCoord xx = x;
1579 wxCoord yy = y;
1580
1581 if (win->m_wxwindow)
1582 {
1583 GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
1584 xx += pizza->xoffset;
1585 yy += pizza->yoffset;
1586 }
1587
1588 wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
1589 while (node)
1590 {
1591 wxWindowGTK *child = node->GetData();
1592
1593 node = node->GetNext();
1594 if (!child->IsShown())
1595 continue;
1596
1597 if (child->IsTransparentForMouse())
1598 {
1599 // wxStaticBox is transparent in the box itself
1600 int xx1 = child->m_x;
1601 int yy1 = child->m_y;
1602 int xx2 = child->m_x + child->m_width;
1603 int yy2 = child->m_y + child->m_height;
1604
1605 // left
1606 if (((xx >= xx1) && (xx <= xx1+10) && (yy >= yy1) && (yy <= yy2)) ||
1607 // right
1608 ((xx >= xx2-10) && (xx <= xx2) && (yy >= yy1) && (yy <= yy2)) ||
1609 // top
1610 ((xx >= xx1) && (xx <= xx2) && (yy >= yy1) && (yy <= yy1+10)) ||
1611 // bottom
1612 ((xx >= xx1) && (xx <= xx2) && (yy >= yy2-1) && (yy <= yy2)))
1613 {
1614 win = child;
1615 x -= child->m_x;
1616 y -= child->m_y;
1617 break;
1618 }
1619
1620 }
1621 else
1622 {
1623 if ((child->m_wxwindow == (GtkWidget*) NULL) &&
1624 (child->m_x <= xx) &&
1625 (child->m_y <= yy) &&
1626 (child->m_x+child->m_width >= xx) &&
1627 (child->m_y+child->m_height >= yy))
1628 {
1629 win = child;
1630 x -= child->m_x;
1631 y -= child->m_y;
1632 break;
1633 }
1634 }
1635 }
1636
1637 return win;
1638 }
1639
1640 //-----------------------------------------------------------------------------
1641 // "button_press_event"
1642 //-----------------------------------------------------------------------------
1643
1644 extern "C" {
1645 static gint gtk_window_button_press_callback( GtkWidget *widget,
1646 GdkEventButton *gdk_event,
1647 wxWindowGTK *win )
1648 {
1649 DEBUG_MAIN_THREAD
1650
1651 if (g_isIdle)
1652 wxapp_install_idle_handler();
1653
1654 /*
1655 wxPrintf( wxT("1) OnButtonPress from ") );
1656 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1657 wxPrintf( win->GetClassInfo()->GetClassName() );
1658 wxPrintf( wxT(".\n") );
1659 */
1660 if (!win->m_hasVMT) return FALSE;
1661 if (g_blockEventsOnDrag) return TRUE;
1662 if (g_blockEventsOnScroll) return TRUE;
1663
1664 if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
1665
1666 if (win->m_wxwindow && (g_focusWindow != win) && win->AcceptsFocus())
1667 {
1668 gtk_widget_grab_focus( win->m_wxwindow );
1669 /*
1670 wxPrintf( wxT("GrabFocus from ") );
1671 if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
1672 wxPrintf( win->GetClassInfo()->GetClassName() );
1673 wxPrintf( wxT(".\n") );
1674 */
1675 }
1676
1677 // GDK sends surplus button down event
1678 // before a double click event. We
1679 // need to filter these out.
1680 if (gdk_event->type == GDK_BUTTON_PRESS)
1681 {
1682 GdkEvent *peek_event = gdk_event_peek();
1683 if (peek_event)
1684 {
1685 if ((peek_event->type == GDK_2BUTTON_PRESS) ||
1686 (peek_event->type == GDK_3BUTTON_PRESS))
1687 {
1688 gdk_event_free( peek_event );
1689 return TRUE;
1690 }
1691 else
1692 {
1693 gdk_event_free( peek_event );
1694 }
1695 }
1696 }
1697
1698 wxEventType event_type = wxEVT_NULL;
1699
1700 // GdkDisplay is a GTK+ 2.2.0 thing
1701 #if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
1702 if ( gdk_event->type == GDK_2BUTTON_PRESS &&
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 if (m_widget)
2882 Show( FALSE );
2883
2884 DestroyChildren();
2885
2886 #ifdef HAVE_XIM
2887 if (m_ic)
2888 gdk_ic_destroy (m_ic);
2889 if (m_icattr)
2890 gdk_ic_attr_destroy (m_icattr);
2891 #endif
2892
2893 if (m_wxwindow)
2894 {
2895 gtk_widget_destroy( m_wxwindow );
2896 m_wxwindow = (GtkWidget*) NULL;
2897 }
2898
2899 if (m_widget)
2900 {
2901 gtk_widget_destroy( m_widget );
2902 m_widget = (GtkWidget*) NULL;
2903 }
2904
2905 #ifdef __WXGTK20__
2906 delete m_imData;
2907 #endif
2908 }
2909
2910 bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos, const wxSize &size )
2911 {
2912 wxCHECK_MSG( !m_needParent || parent, FALSE, wxT("Need complete parent.") );
2913
2914 // Use either the given size, or the default if -1 is given.
2915 // See wxWindowBase for these functions.
2916 m_width = WidthDefault(size.x) ;
2917 m_height = HeightDefault(size.y);
2918
2919 m_x = (int)pos.x;
2920 m_y = (int)pos.y;
2921
2922 return TRUE;
2923 }
2924
2925 void wxWindowGTK::PostCreation()
2926 {
2927 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
2928
2929 if (m_wxwindow)
2930 {
2931 if (!m_noExpose)
2932 {
2933 // these get reported to wxWidgets -> wxPaintEvent
2934
2935 gtk_pizza_set_external( GTK_PIZZA(m_wxwindow), TRUE );
2936
2937 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
2938 GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
2939
2940 #ifndef __WXGTK20__
2941 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
2942 GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
2943
2944 if (!HasFlag(wxFULL_REPAINT_ON_RESIZE))
2945 {
2946 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "event",
2947 GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this );
2948 }
2949 #else
2950 // gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), !HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
2951 #endif
2952 }
2953
2954 #ifdef __WXGTK20__
2955 // Create input method handler
2956 m_imData = new wxGtkIMData;
2957
2958 // Cannot handle drawing preedited text yet
2959 gtk_im_context_set_use_preedit( m_imData->context, FALSE );
2960
2961 g_signal_connect (G_OBJECT (m_imData->context), "commit",
2962 G_CALLBACK (gtk_wxwindow_commit_cb), this);
2963 #endif
2964
2965 // these are called when the "sunken" or "raised" borders are drawn
2966 gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
2967 GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
2968
2969 #ifndef __WXGTK20__
2970 gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
2971 GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
2972 #endif
2973 }
2974
2975 // focus handling
2976
2977 if (!GTK_IS_WINDOW(m_widget))
2978 {
2979 if (m_focusWidget == NULL)
2980 m_focusWidget = m_widget;
2981
2982 gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_in_event",
2983 GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
2984
2985 gtk_signal_connect_after( GTK_OBJECT(m_focusWidget), "focus_out_event",
2986 GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
2987 }
2988
2989 // connect to the various key and mouse handlers
2990
2991 GtkWidget *connect_widget = GetConnectWidget();
2992
2993 ConnectWidget( connect_widget );
2994
2995 /* We cannot set colours, fonts and cursors before the widget has
2996 been realized, so we do this directly after realization */
2997 gtk_signal_connect( GTK_OBJECT(connect_widget), "realize",
2998 GTK_SIGNAL_FUNC(gtk_window_realized_callback), (gpointer) this );
2999
3000 if (m_wxwindow)
3001 {
3002 // Catch native resize events
3003 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
3004 GTK_SIGNAL_FUNC(gtk_window_size_callback), (gpointer)this );
3005
3006 // Initialize XIM support
3007 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "realize",
3008 GTK_SIGNAL_FUNC(gtk_wxwindow_realized_callback), (gpointer) this );
3009
3010 // And resize XIM window
3011 gtk_signal_connect( GTK_OBJECT(m_wxwindow), "size_allocate",
3012 GTK_SIGNAL_FUNC(gtk_wxwindow_size_callback), (gpointer)this );
3013 }
3014
3015 if (GTK_IS_COMBO(m_widget))
3016 {
3017 GtkCombo *gcombo = GTK_COMBO(m_widget);
3018
3019 gtk_signal_connect( GTK_OBJECT(gcombo->entry), "size_request",
3020 GTK_SIGNAL_FUNC(wxgtk_combo_size_request_callback),
3021 (gpointer) this );
3022 }
3023 else
3024 {
3025 // This is needed if we want to add our windows into native
3026 // GTK controls, such as the toolbar. With this callback, the
3027 // toolbar gets to know the correct size (the one set by the
3028 // programmer). Sadly, it misbehaves for wxComboBox.
3029 gtk_signal_connect( GTK_OBJECT(m_widget), "size_request",
3030 GTK_SIGNAL_FUNC(wxgtk_window_size_request_callback),
3031 (gpointer) this );
3032 }
3033
3034 InheritAttributes();
3035
3036 m_hasVMT = TRUE;
3037
3038 // unless the window was created initially hidden (i.e. Hide() had been
3039 // called before Create()), we should show it at GTK+ level as well
3040 if ( IsShown() )
3041 gtk_widget_show( m_widget );
3042 }
3043
3044 void wxWindowGTK::ConnectWidget( GtkWidget *widget )
3045 {
3046 gtk_signal_connect( GTK_OBJECT(widget), "key_press_event",
3047 GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this );
3048
3049 gtk_signal_connect( GTK_OBJECT(widget), "key_release_event",
3050 GTK_SIGNAL_FUNC(gtk_window_key_release_callback), (gpointer)this );
3051
3052 gtk_signal_connect( GTK_OBJECT(widget), "button_press_event",
3053 GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
3054
3055 gtk_signal_connect( GTK_OBJECT(widget), "button_release_event",
3056 GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
3057
3058 gtk_signal_connect( GTK_OBJECT(widget), "motion_notify_event",
3059 GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
3060
3061 #ifdef __WXGTK20__
3062 gtk_signal_connect( GTK_OBJECT(widget), "scroll_event",
3063 GTK_SIGNAL_FUNC(gtk_window_wheel_callback), (gpointer)this );
3064 g_signal_connect(widget, "popup_menu",
3065 G_CALLBACK(wxgtk_window_popup_menu_callback), this);
3066 #endif
3067
3068 gtk_signal_connect( GTK_OBJECT(widget), "enter_notify_event",
3069 GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
3070
3071 gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
3072 GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
3073 }
3074
3075 bool wxWindowGTK::Destroy()
3076 {
3077 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
3078
3079 m_hasVMT = FALSE;
3080
3081 return wxWindowBase::Destroy();
3082 }
3083
3084 void wxWindowGTK::DoMoveWindow(int x, int y, int width, int height)
3085 {
3086 gtk_pizza_set_size( GTK_PIZZA(m_parent->m_wxwindow), m_widget, x, y, width, height );
3087 }
3088
3089 void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
3090 {
3091 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
3092 wxASSERT_MSG( (m_parent != NULL), wxT("wxWindowGTK::SetSize requires parent.\n") );
3093
3094 /*
3095 printf( "DoSetSize: name %s, x,y,w,h: %d,%d,%d,%d \n", GetName().c_str(), x,y,width,height );
3096 */
3097
3098 if (m_resizing) return; /* I don't like recursions */
3099 m_resizing = TRUE;
3100
3101 int currentX, currentY;
3102 GetPosition(&currentX, &currentY);
3103 if (x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
3104 x = currentX;
3105 if (y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
3106 y = currentY;
3107 AdjustForParentClientOrigin(x, y, sizeFlags);
3108
3109 if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
3110 {
3111 /* don't set the size for children of wxNotebook, just take the values. */
3112 m_x = x;
3113 m_y = y;
3114 m_width = width;
3115 m_height = height;
3116 }
3117 else
3118 {
3119 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
3120 if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
3121 {
3122 if (x != -1) m_x = x + pizza->xoffset;
3123 if (y != -1) m_y = y + pizza->yoffset;
3124 }
3125 else
3126 {
3127 m_x = x + pizza->xoffset;
3128 m_y = y + pizza->yoffset;
3129 }
3130
3131 // calculate the best size if we should auto size the window
3132 if ( ((sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1) ||
3133 ((sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1) )
3134 {
3135 const wxSize sizeBest = GetBestSize();
3136 if ( (sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1 )
3137 width = sizeBest.x;
3138 if ( (sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1 )
3139 height = sizeBest.y;
3140 }
3141
3142 if (width != -1)
3143 m_width = width;
3144 if (height != -1)
3145 m_height = height;
3146
3147 int minWidth = GetMinWidth(),
3148 minHeight = GetMinHeight(),
3149 maxWidth = GetMaxWidth(),
3150 maxHeight = GetMaxHeight();
3151
3152 if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
3153 if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
3154 if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
3155 if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
3156
3157 int left_border = 0;
3158 int right_border = 0;
3159 int top_border = 0;
3160 int bottom_border = 0;
3161
3162 /* the default button has a border around it */
3163 if (GTK_WIDGET_CAN_DEFAULT(m_widget))
3164 {
3165 #ifdef __WXGTK20__
3166 GtkBorder *default_border = NULL;
3167 gtk_widget_style_get( m_widget, "default_border", &default_border, NULL );
3168 if (default_border)
3169 {
3170 left_border += default_border->left;
3171 right_border += default_border->right;
3172 top_border += default_border->top;
3173 bottom_border += default_border->bottom;
3174 g_free( default_border );
3175 }
3176 #else
3177 left_border = 6;
3178 right_border = 6;
3179 top_border = 6;
3180 bottom_border = 5;
3181 #endif
3182 }
3183
3184 DoMoveWindow( m_x-top_border,
3185 m_y-left_border,
3186 m_width+left_border+right_border,
3187 m_height+top_border+bottom_border );
3188 }
3189
3190 if (m_hasScrolling)
3191 {
3192 /* Sometimes the client area changes size without the
3193 whole windows's size changing, but if the whole
3194 windows's size doesn't change, no wxSizeEvent will
3195 normally be sent. Here we add an extra test if
3196 the client test has been changed and this will
3197 be used then. */
3198 GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
3199 }
3200
3201 /*
3202 wxPrintf( "OnSize sent from " );
3203 if (GetClassInfo() && GetClassInfo()->GetClassName())
3204 wxPrintf( GetClassInfo()->GetClassName() );
3205 wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
3206 */
3207
3208 if (!m_nativeSizeEvent)
3209 {
3210 wxSizeEvent event( wxSize(m_width,m_height), GetId() );
3211 event.SetEventObject( this );
3212 GetEventHandler()->ProcessEvent( event );
3213 }
3214
3215 m_resizing = FALSE;
3216 }
3217
3218 void wxWindowGTK::OnInternalIdle()
3219 {
3220 #ifdef __WXGTK20__
3221 if ( m_dirtyTabOrder )
3222 RealizeTabOrder();
3223 #endif
3224 // Update style if the window was not yet realized
3225 // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
3226 if (m_needsStyleChange)
3227 {
3228 SetBackgroundStyle(GetBackgroundStyle());
3229 m_needsStyleChange = false;
3230 }
3231
3232 // Update invalidated regions.
3233 GtkUpdate();
3234
3235 wxCursor cursor = m_cursor;
3236 if (g_globalCursor.Ok()) cursor = g_globalCursor;
3237
3238 if (cursor.Ok())
3239 {
3240 /* I now set the cursor anew in every OnInternalIdle call
3241 as setting the cursor in a parent window also effects the
3242 windows above so that checking for the current cursor is
3243 not possible. */
3244
3245 if (m_wxwindow)
3246 {
3247 GdkWindow *window = GTK_PIZZA(m_wxwindow)->bin_window;
3248 if (window)
3249 gdk_window_set_cursor( window, cursor.GetCursor() );
3250
3251 if (!g_globalCursor.Ok())
3252 cursor = *wxSTANDARD_CURSOR;
3253
3254 window = m_widget->window;
3255 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
3256 gdk_window_set_cursor( window, cursor.GetCursor() );
3257
3258 }
3259 else
3260 {
3261
3262 GdkWindow *window = m_widget->window;
3263 if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
3264 gdk_window_set_cursor( window, cursor.GetCursor() );
3265
3266 }
3267 }
3268
3269 if (wxUpdateUIEvent::CanUpdate(this))
3270 UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
3271 }
3272
3273 void wxWindowGTK::DoGetSize( int *width, int *height ) const
3274 {
3275 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3276
3277 if (width) (*width) = m_width;
3278 if (height) (*height) = m_height;
3279 }
3280
3281 void wxWindowGTK::DoSetClientSize( int width, int height )
3282 {
3283 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3284
3285 if (!m_wxwindow)
3286 {
3287 SetSize( width, height );
3288 }
3289 else
3290 {
3291 int dw = 0;
3292 int dh = 0;
3293
3294 #ifndef __WXUNIVERSAL__
3295 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
3296 {
3297 /* when using GTK 1.2 we set the shadow border size to 2 */
3298 dw += 2 * 2;
3299 dh += 2 * 2;
3300 }
3301 if (HasFlag(wxSIMPLE_BORDER))
3302 {
3303 /* when using GTK 1.2 we set the simple border size to 1 */
3304 dw += 1 * 2;
3305 dh += 1 * 2;
3306 }
3307 #endif // __WXUNIVERSAL__
3308
3309 if (m_hasScrolling)
3310 {
3311 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
3312
3313 GtkRequisition vscroll_req;
3314 vscroll_req.width = 2;
3315 vscroll_req.height = 2;
3316 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
3317 (scroll_window->vscrollbar, &vscroll_req );
3318
3319 GtkRequisition hscroll_req;
3320 hscroll_req.width = 2;
3321 hscroll_req.height = 2;
3322 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
3323 (scroll_window->hscrollbar, &hscroll_req );
3324
3325 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
3326
3327 if (scroll_window->vscrollbar_visible)
3328 {
3329 dw += vscroll_req.width;
3330 dw += scroll_class->scrollbar_spacing;
3331 }
3332
3333 if (scroll_window->hscrollbar_visible)
3334 {
3335 dh += hscroll_req.height;
3336 dh += scroll_class->scrollbar_spacing;
3337 }
3338 }
3339
3340 SetSize( width+dw, height+dh );
3341 }
3342 }
3343
3344 void wxWindowGTK::DoGetClientSize( int *width, int *height ) const
3345 {
3346 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3347
3348 if (!m_wxwindow)
3349 {
3350 if (width) (*width) = m_width;
3351 if (height) (*height) = m_height;
3352 }
3353 else
3354 {
3355 int dw = 0;
3356 int dh = 0;
3357
3358 #ifndef __WXUNIVERSAL__
3359 if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
3360 {
3361 /* when using GTK 1.2 we set the shadow border size to 2 */
3362 dw += 2 * 2;
3363 dh += 2 * 2;
3364 }
3365 if (HasFlag(wxSIMPLE_BORDER))
3366 {
3367 /* when using GTK 1.2 we set the simple border size to 1 */
3368 dw += 1 * 2;
3369 dh += 1 * 2;
3370 }
3371 #endif // __WXUNIVERSAL__
3372
3373 if (m_hasScrolling)
3374 {
3375 GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
3376
3377 GtkRequisition vscroll_req;
3378 vscroll_req.width = 2;
3379 vscroll_req.height = 2;
3380 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
3381 (scroll_window->vscrollbar, &vscroll_req );
3382
3383 GtkRequisition hscroll_req;
3384 hscroll_req.width = 2;
3385 hscroll_req.height = 2;
3386 (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
3387 (scroll_window->hscrollbar, &hscroll_req );
3388
3389 GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
3390
3391 if (scroll_window->vscrollbar_visible)
3392 {
3393 dw += vscroll_req.width;
3394 dw += scroll_class->scrollbar_spacing;
3395 }
3396
3397 if (scroll_window->hscrollbar_visible)
3398 {
3399 dh += hscroll_req.height;
3400 dh += scroll_class->scrollbar_spacing;
3401 }
3402 }
3403
3404 if (width) (*width) = m_width - dw;
3405 if (height) (*height) = m_height - dh;
3406 }
3407
3408 /*
3409 printf( "GetClientSize, name %s ", GetName().c_str() );
3410 if (width) printf( " width = %d", (*width) );
3411 if (height) printf( " height = %d", (*height) );
3412 printf( "\n" );
3413 */
3414 }
3415
3416 void wxWindowGTK::DoGetPosition( int *x, int *y ) const
3417 {
3418 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3419
3420 int dx = 0;
3421 int dy = 0;
3422 if (m_parent && m_parent->m_wxwindow)
3423 {
3424 GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
3425 dx = pizza->xoffset;
3426 dy = pizza->yoffset;
3427 }
3428
3429 if (x) (*x) = m_x - dx;
3430 if (y) (*y) = m_y - dy;
3431 }
3432
3433 void wxWindowGTK::DoClientToScreen( int *x, int *y ) const
3434 {
3435 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3436
3437 if (!m_widget->window) return;
3438
3439 GdkWindow *source = (GdkWindow *) NULL;
3440 if (m_wxwindow)
3441 source = GTK_PIZZA(m_wxwindow)->bin_window;
3442 else
3443 source = m_widget->window;
3444
3445 int org_x = 0;
3446 int org_y = 0;
3447 gdk_window_get_origin( source, &org_x, &org_y );
3448
3449 if (!m_wxwindow)
3450 {
3451 if (GTK_WIDGET_NO_WINDOW (m_widget))
3452 {
3453 org_x += m_widget->allocation.x;
3454 org_y += m_widget->allocation.y;
3455 }
3456 }
3457
3458 if (x) *x += org_x;
3459 if (y) *y += org_y;
3460 }
3461
3462 void wxWindowGTK::DoScreenToClient( int *x, int *y ) const
3463 {
3464 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3465
3466 if (!m_widget->window) return;
3467
3468 GdkWindow *source = (GdkWindow *) NULL;
3469 if (m_wxwindow)
3470 source = GTK_PIZZA(m_wxwindow)->bin_window;
3471 else
3472 source = m_widget->window;
3473
3474 int org_x = 0;
3475 int org_y = 0;
3476 gdk_window_get_origin( source, &org_x, &org_y );
3477
3478 if (!m_wxwindow)
3479 {
3480 if (GTK_WIDGET_NO_WINDOW (m_widget))
3481 {
3482 org_x += m_widget->allocation.x;
3483 org_y += m_widget->allocation.y;
3484 }
3485 }
3486
3487 if (x) *x -= org_x;
3488 if (y) *y -= org_y;
3489 }
3490
3491 bool wxWindowGTK::Show( bool show )
3492 {
3493 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3494
3495 if (!wxWindowBase::Show(show))
3496 {
3497 // nothing to do
3498 return FALSE;
3499 }
3500
3501 if (show)
3502 gtk_widget_show( m_widget );
3503 else
3504 gtk_widget_hide( m_widget );
3505
3506 wxShowEvent eventShow(GetId(), show);
3507 eventShow.SetEventObject(this);
3508
3509 GetEventHandler()->ProcessEvent(eventShow);
3510
3511 return TRUE;
3512 }
3513
3514 static void wxWindowNotifyEnable(wxWindowGTK* win, bool enable)
3515 {
3516 win->OnParentEnable(enable);
3517
3518 // Recurse, so that children have the opportunity to Do The Right Thing
3519 // and reset colours that have been messed up by a parent's (really ancestor's)
3520 // Enable call
3521 for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
3522 node;
3523 node = node->GetNext() )
3524 {
3525 wxWindow *child = node->GetData();
3526 if (!child->IsKindOf(CLASSINFO(wxDialog)) && !child->IsKindOf(CLASSINFO(wxFrame)))
3527 wxWindowNotifyEnable(child, enable);
3528 }
3529 }
3530
3531 bool wxWindowGTK::Enable( bool enable )
3532 {
3533 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3534
3535 if (!wxWindowBase::Enable(enable))
3536 {
3537 // nothing to do
3538 return FALSE;
3539 }
3540
3541 gtk_widget_set_sensitive( m_widget, enable );
3542 if ( m_wxwindow )
3543 gtk_widget_set_sensitive( m_wxwindow, enable );
3544
3545 wxWindowNotifyEnable(this, enable);
3546
3547 return TRUE;
3548 }
3549
3550 int wxWindowGTK::GetCharHeight() const
3551 {
3552 wxCHECK_MSG( (m_widget != NULL), 12, wxT("invalid window") );
3553
3554 wxFont font = GetFont();
3555 wxCHECK_MSG( font.Ok(), 12, wxT("invalid font") );
3556
3557 #ifdef __WXGTK20__
3558 PangoContext *context = NULL;
3559 if (m_widget)
3560 context = gtk_widget_get_pango_context( m_widget );
3561
3562 if (!context)
3563 return 0;
3564
3565 PangoFontDescription *desc = font.GetNativeFontInfo()->description;
3566 PangoLayout *layout = pango_layout_new(context);
3567 pango_layout_set_font_description(layout, desc);
3568 pango_layout_set_text(layout, "H", 1);
3569 PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
3570
3571 PangoRectangle rect;
3572 pango_layout_line_get_extents(line, NULL, &rect);
3573
3574 g_object_unref( G_OBJECT( layout ) );
3575
3576 return (int) PANGO_PIXELS(rect.height);
3577 #else
3578 GdkFont *gfont = font.GetInternalFont( 1.0 );
3579
3580 return gfont->ascent + gfont->descent;
3581 #endif
3582 }
3583
3584 int wxWindowGTK::GetCharWidth() const
3585 {
3586 wxCHECK_MSG( (m_widget != NULL), 8, wxT("invalid window") );
3587
3588 wxFont font = GetFont();
3589 wxCHECK_MSG( font.Ok(), 8, wxT("invalid font") );
3590
3591 #ifdef __WXGTK20__
3592 PangoContext *context = NULL;
3593 if (m_widget)
3594 context = gtk_widget_get_pango_context( m_widget );
3595
3596 if (!context)
3597 return 0;
3598
3599 PangoFontDescription *desc = font.GetNativeFontInfo()->description;
3600 PangoLayout *layout = pango_layout_new(context);
3601 pango_layout_set_font_description(layout, desc);
3602 pango_layout_set_text(layout, "g", 1);
3603 PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
3604
3605 PangoRectangle rect;
3606 pango_layout_line_get_extents(line, NULL, &rect);
3607
3608 g_object_unref( G_OBJECT( layout ) );
3609
3610 return (int) PANGO_PIXELS(rect.width);
3611 #else
3612 GdkFont *gfont = font.GetInternalFont( 1.0 );
3613
3614 return gdk_string_width( gfont, "g" );
3615 #endif
3616 }
3617
3618 void wxWindowGTK::GetTextExtent( const wxString& string,
3619 int *x,
3620 int *y,
3621 int *descent,
3622 int *externalLeading,
3623 const wxFont *theFont ) const
3624 {
3625 wxFont fontToUse = theFont ? *theFont : GetFont();
3626
3627 wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
3628
3629 if (string.IsEmpty())
3630 {
3631 if (x) (*x) = 0;
3632 if (y) (*y) = 0;
3633 return;
3634 }
3635
3636 #ifdef __WXGTK20__
3637 PangoContext *context = NULL;
3638 if (m_widget)
3639 context = gtk_widget_get_pango_context( m_widget );
3640
3641 if (!context)
3642 {
3643 if (x) (*x) = 0;
3644 if (y) (*y) = 0;
3645 return;
3646 }
3647
3648 PangoFontDescription *desc = fontToUse.GetNativeFontInfo()->description;
3649 PangoLayout *layout = pango_layout_new(context);
3650 pango_layout_set_font_description(layout, desc);
3651 {
3652 #if wxUSE_UNICODE
3653 const wxCharBuffer data = wxConvUTF8.cWC2MB( string );
3654 pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data ));
3655 #else
3656 const wxWCharBuffer wdata = wxConvLocal.cMB2WC( string );
3657 const wxCharBuffer data = wxConvUTF8.cWC2MB( wdata );
3658 pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data ));
3659 #endif
3660 }
3661
3662 PangoRectangle rect;
3663 pango_layout_get_extents(layout, NULL, &rect);
3664
3665 if (x) (*x) = (wxCoord) PANGO_PIXELS(rect.width);
3666 if (y) (*y) = (wxCoord) PANGO_PIXELS(rect.height);
3667 if (descent)
3668 {
3669 PangoLayoutIter *iter = pango_layout_get_iter(layout);
3670 int baseline = pango_layout_iter_get_baseline(iter);
3671 pango_layout_iter_free(iter);
3672 *descent = *y - PANGO_PIXELS(baseline);
3673 }
3674 if (externalLeading) (*externalLeading) = 0; // ??
3675
3676 g_object_unref( G_OBJECT( layout ) );
3677 #else
3678 GdkFont *font = fontToUse.GetInternalFont( 1.0 );
3679 if (x) (*x) = gdk_string_width( font, wxGTK_CONV( string ) );
3680 if (y) (*y) = font->ascent + font->descent;
3681 if (descent) (*descent) = font->descent;
3682 if (externalLeading) (*externalLeading) = 0; // ??
3683 #endif
3684 }
3685
3686 void wxWindowGTK::SetFocus()
3687 {
3688 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
3689 if ( m_hasFocus )
3690 {
3691 // don't do anything if we already have focus
3692 return;
3693 }
3694
3695 if (m_wxwindow)
3696 {
3697 if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
3698 {
3699 gtk_widget_grab_focus (m_wxwindow);
3700 }
3701 }
3702 else if (m_widget)
3703 {
3704 #ifdef __WXGTK20__
3705 if (GTK_IS_CONTAINER(m_widget))
3706 {
3707 gtk_widget_child_focus( m_widget, GTK_DIR_TAB_FORWARD );
3708 }
3709 else
3710 #endif
3711 if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
3712 {
3713
3714 if (!GTK_WIDGET_REALIZED(m_widget))
3715 {
3716 // we can't set the focus to the widget now so we remember that
3717 // it should be focused and will do it later, during the idle
3718 // time, as soon as we can
3719 wxLogTrace(TRACE_FOCUS,
3720 _T("Delaying setting focus to %s(%s)"),
3721 GetClassInfo()->GetClassName(), GetLabel().c_str());
3722
3723 g_delayedFocus = this;
3724 }
3725 else
3726 {
3727 wxLogTrace(TRACE_FOCUS,
3728 _T("Setting focus to %s(%s)"),
3729 GetClassInfo()->GetClassName(), GetLabel().c_str());
3730
3731 gtk_widget_grab_focus (m_widget);
3732 }
3733 }
3734 else
3735 #ifndef __WXGTK20__
3736 if (GTK_IS_CONTAINER(m_widget))
3737 {
3738 gtk_container_focus( GTK_CONTAINER(m_widget), GTK_DIR_TAB_FORWARD );
3739 }
3740 else
3741 #endif
3742 {
3743 wxLogTrace(TRACE_FOCUS,
3744 _T("Can't set focus to %s(%s)"),
3745 GetClassInfo()->GetClassName(), GetLabel().c_str());
3746 }
3747 }
3748 }
3749
3750 bool wxWindowGTK::AcceptsFocus() const
3751 {
3752 return m_acceptsFocus && wxWindowBase::AcceptsFocus();
3753 }
3754
3755 bool wxWindowGTK::Reparent( wxWindowBase *newParentBase )
3756 {
3757 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3758
3759 wxWindowGTK *oldParent = m_parent,
3760 *newParent = (wxWindowGTK *)newParentBase;
3761
3762 wxASSERT( GTK_IS_WIDGET(m_widget) );
3763
3764 if ( !wxWindowBase::Reparent(newParent) )
3765 return FALSE;
3766
3767 wxASSERT( GTK_IS_WIDGET(m_widget) );
3768
3769 /* prevent GTK from deleting the widget arbitrarily */
3770 gtk_widget_ref( m_widget );
3771
3772 if (oldParent)
3773 {
3774 gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget );
3775 }
3776
3777 wxASSERT( GTK_IS_WIDGET(m_widget) );
3778
3779 if (newParent)
3780 {
3781 /* insert GTK representation */
3782 (*(newParent->m_insertCallback))(newParent, this);
3783 }
3784
3785 /* reverse: prevent GTK from deleting the widget arbitrarily */
3786 gtk_widget_unref( m_widget );
3787
3788 return TRUE;
3789 }
3790
3791 void wxWindowGTK::DoAddChild(wxWindowGTK *child)
3792 {
3793 wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
3794
3795 wxASSERT_MSG( (child != NULL), wxT("invalid child window") );
3796
3797 wxASSERT_MSG( (m_insertCallback != NULL), wxT("invalid child insertion function") );
3798
3799 /* add to list */
3800 AddChild( child );
3801
3802 /* insert GTK representation */
3803 (*m_insertCallback)(this, child);
3804 }
3805
3806 #ifdef __WXGTK20__
3807
3808 void wxWindowGTK::AddChild(wxWindowBase *child)
3809 {
3810 wxWindowBase::AddChild(child);
3811 m_dirtyTabOrder = true;
3812 if (g_isIdle)
3813 wxapp_install_idle_handler();
3814 }
3815
3816 void wxWindowGTK::RemoveChild(wxWindowBase *child)
3817 {
3818 wxWindowBase::RemoveChild(child);
3819 m_dirtyTabOrder = true;
3820 if (g_isIdle)
3821 wxapp_install_idle_handler();
3822 }
3823
3824 void wxWindowGTK::DoMoveInTabOrder(wxWindow *win, MoveKind move)
3825 {
3826 wxWindowBase::DoMoveInTabOrder(win, move);
3827 m_dirtyTabOrder = true;
3828 if (g_isIdle)
3829 wxapp_install_idle_handler();
3830 }
3831
3832 void wxWindowGTK::RealizeTabOrder()
3833 {
3834 if (m_wxwindow)
3835 {
3836 if (m_children.size() > 0)
3837 {
3838 GList *chain = NULL;
3839
3840 for (wxWindowList::const_iterator i = m_children.begin();
3841 i != m_children.end(); ++i)
3842 {
3843 chain = g_list_prepend(chain, (*i)->m_widget);
3844 }
3845
3846 chain = g_list_reverse(chain);
3847
3848 gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow), chain);
3849 g_list_free(chain);
3850 }
3851 else
3852 {
3853 gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow));
3854 }
3855 }
3856
3857 m_dirtyTabOrder = false;
3858 }
3859
3860 #endif // __WXGTK20__
3861
3862 void wxWindowGTK::Raise()
3863 {
3864 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3865
3866 if (m_wxwindow && m_wxwindow->window)
3867 {
3868 gdk_window_raise( m_wxwindow->window );
3869 }
3870 else if (m_widget->window)
3871 {
3872 gdk_window_raise( m_widget->window );
3873 }
3874 }
3875
3876 void wxWindowGTK::Lower()
3877 {
3878 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3879
3880 if (m_wxwindow && m_wxwindow->window)
3881 {
3882 gdk_window_lower( m_wxwindow->window );
3883 }
3884 else if (m_widget->window)
3885 {
3886 gdk_window_lower( m_widget->window );
3887 }
3888 }
3889
3890 bool wxWindowGTK::SetCursor( const wxCursor &cursor )
3891 {
3892 wxCHECK_MSG( (m_widget != NULL), FALSE, wxT("invalid window") );
3893
3894 if (cursor == m_cursor)
3895 return FALSE;
3896
3897 if (g_isIdle)
3898 wxapp_install_idle_handler();
3899
3900 if (cursor == wxNullCursor)
3901 return wxWindowBase::SetCursor( *wxSTANDARD_CURSOR );
3902 else
3903 return wxWindowBase::SetCursor( cursor );
3904 }
3905
3906 void wxWindowGTK::WarpPointer( int x, int y )
3907 {
3908 wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
3909
3910 // We provide this function ourselves as it is
3911 // missing in GDK (top of this file).
3912
3913 GdkWindow *window = (GdkWindow*) NULL;
3914 if (m_wxwindow)
3915 window = GTK_PIZZA(m_wxwindow)->bin_window;
3916 else
3917 window = GetConnectWidget()->window;
3918
3919 if (window)
3920 gdk_window_warp_pointer( window, x, y );
3921 }
3922
3923
3924 void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
3925 {
3926 if (!m_widget) return;
3927 if (!m_widget->window) return;
3928
3929 #ifndef __WXGTK20__
3930 if (g_isIdle)
3931 wxapp_install_idle_handler();
3932
3933 wxRect myRect(0,0,0,0);
3934 if (m_wxwindow && rect)
3935 {
3936 myRect.SetSize(wxSize( m_wxwindow->allocation.width,
3937 m_wxwindow->allocation.height));
3938 myRect.Intersect(*rect);
3939 if (!myRect.width || !myRect.height)
3940 // nothing to do, rectangle is empty
3941 return;
3942 rect = &myRect;
3943 }
3944
3945 if (eraseBackground && m_wxwindow && m_wxwindow->window)
3946 {
3947 if (rect)
3948 {
3949 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3950 m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height );
3951 }
3952 else
3953 {
3954 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3955 m_clearRegion.Clear();
3956 m_clearRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
3957 }
3958 }
3959
3960 if (rect)
3961 {
3962 if (m_wxwindow)
3963 {
3964 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3965 m_updateRegion.Union( rect->x, rect->y, rect->width, rect->height );
3966 }
3967 else
3968 {
3969 GdkRectangle gdk_rect;
3970 gdk_rect.x = rect->x;
3971 gdk_rect.y = rect->y;
3972 gdk_rect.width = rect->width;
3973 gdk_rect.height = rect->height;
3974 gtk_widget_draw( m_widget, &gdk_rect );
3975 }
3976 }
3977 else
3978 {
3979 if (m_wxwindow)
3980 {
3981 // Schedule for later Updating in ::Update() or ::OnInternalIdle().
3982 m_updateRegion.Clear();
3983 m_updateRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
3984 }
3985 else
3986 {
3987 gtk_widget_draw( m_widget, (GdkRectangle*) NULL );
3988 }
3989 }
3990 #else
3991 if (m_wxwindow)
3992 {
3993 if (rect)
3994 {
3995 GdkRectangle gdk_rect;
3996 gdk_rect.x = rect->x;
3997 gdk_rect.y = rect->y;
3998 gdk_rect.width = rect->width;
3999 gdk_rect.height = rect->height;
4000 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow)->bin_window, &gdk_rect, TRUE );
4001 }
4002 else
4003 {
4004 gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow)->bin_window, NULL, TRUE );
4005 }
4006 }
4007 #endif
4008 }
4009
4010 void wxWindowGTK::Update()
4011 {
4012 GtkUpdate();
4013
4014 // when we call Update() we really want to update the window immediately on
4015 // screen, even if itmeans flushing the entire queue and hence slowing down
4016 // everything -- but it should still be done, it's just that Update() should
4017 // be called very rarely
4018 gdk_flush();
4019 }
4020
4021 void wxWindowGTK::GtkUpdate()
4022 {
4023 #ifdef __WXGTK20__
4024 if (m_wxwindow && GTK_PIZZA(m_wxwindow)->bin_window)
4025 gdk_window_process_updates( GTK_PIZZA(m_wxwindow)->bin_window, FALSE );
4026 #else
4027 if (!m_updateRegion.IsEmpty())
4028 GtkSendPaintEvents();
4029 #endif
4030 }
4031
4032 void wxWindowGTK::GtkSendPaintEvents()
4033 {
4034 if (!m_wxwindow)
4035 {
4036 #ifndef __WXGTK20__
4037 m_clearRegion.Clear();
4038 #endif
4039 m_updateRegion.Clear();
4040 return;
4041 }
4042
4043 // Clip to paint region in wxClientDC
4044 m_clipPaintRegion = TRUE;
4045
4046 // widget to draw on
4047 GtkPizza *pizza = GTK_PIZZA (m_wxwindow);
4048
4049 if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM))
4050 {
4051 // find ancestor from which to steal background
4052 wxWindow *parent = wxGetTopLevelParent((wxWindow *)this);
4053 if (!parent)
4054 parent = (wxWindow*)this;
4055
4056 if (GTK_WIDGET_MAPPED(parent->m_widget))
4057 {
4058 wxRegionIterator upd( m_updateRegion );
4059 while (upd)
4060 {
4061 GdkRectangle rect;
4062 rect.x = upd.GetX();
4063 rect.y = upd.GetY();
4064 rect.width = upd.GetWidth();
4065 rect.height = upd.GetHeight();
4066
4067 gtk_paint_flat_box( parent->m_widget->style,
4068 pizza->bin_window,
4069 (GtkStateType)GTK_WIDGET_STATE(m_wxwindow),
4070 GTK_SHADOW_NONE,
4071 &rect,
4072 parent->m_widget,
4073 (char *)"base",
4074 0, 0, -1, -1 );
4075
4076 ++upd;
4077 }
4078 }
4079 }
4080 else
4081
4082 #ifdef __WXGTK20__
4083 {
4084 wxWindowDC dc( (wxWindow*)this );
4085 dc.SetClippingRegion( m_updateRegion );
4086
4087 wxEraseEvent erase_event( GetId(), &dc );
4088 erase_event.SetEventObject( this );
4089
4090 GetEventHandler()->ProcessEvent(erase_event);
4091 }
4092 #else
4093 // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
4094 {
4095 wxWindowDC dc( (wxWindow*)this );
4096 if (m_clearRegion.IsEmpty())
4097 dc.SetClippingRegion( m_updateRegion );
4098 else
4099 dc.SetClippingRegion( m_clearRegion );
4100
4101 wxEraseEvent erase_event( GetId(), &dc );
4102 erase_event.SetEventObject( this );
4103
4104 if (!GetEventHandler()->ProcessEvent(erase_event) && GetBackgroundStyle() != wxBG_STYLE_CUSTOM)
4105 {
4106 if (!g_eraseGC)
4107 {
4108 g_eraseGC = gdk_gc_new( pizza->bin_window );
4109 gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4110 }
4111 gdk_gc_set_foreground( g_eraseGC, GetBackgroundColour().GetColor() );
4112
4113 wxRegionIterator upd( m_clearRegion );
4114 while (upd)
4115 {
4116 gdk_draw_rectangle( pizza->bin_window, g_eraseGC, 1,
4117 upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
4118 upd ++;
4119 }
4120 }
4121 m_clearRegion.Clear();
4122 }
4123 #endif
4124
4125 wxNcPaintEvent nc_paint_event( GetId() );
4126 nc_paint_event.SetEventObject( this );
4127 GetEventHandler()->ProcessEvent( nc_paint_event );
4128
4129 wxPaintEvent paint_event( GetId() );
4130 paint_event.SetEventObject( this );
4131 GetEventHandler()->ProcessEvent( paint_event );
4132
4133 m_clipPaintRegion = FALSE;
4134
4135 #ifndef __WXUNIVERSAL__
4136 #ifndef __WXGTK20__
4137 // The following code will result in all window-less widgets
4138 // being redrawn because the wxWidgets class is allowed to
4139 // paint over the window-less widgets.
4140
4141 GList *children = pizza->children;
4142 while (children)
4143 {
4144 GtkPizzaChild *child = (GtkPizzaChild*) children->data;
4145 children = children->next;
4146
4147 if (GTK_WIDGET_NO_WINDOW (child->widget) &&
4148 GTK_WIDGET_DRAWABLE (child->widget))
4149 {
4150 // Get intersection of widget area and update region
4151 wxRegion region( m_updateRegion );
4152
4153 GdkEventExpose gdk_event;
4154 gdk_event.type = GDK_EXPOSE;
4155 gdk_event.window = pizza->bin_window;
4156 gdk_event.count = 0;
4157
4158 wxRegionIterator upd( m_updateRegion );
4159 while (upd)
4160 {
4161 GdkRectangle rect;
4162 rect.x = upd.GetX();
4163 rect.y = upd.GetY();
4164 rect.width = upd.GetWidth();
4165 rect.height = upd.GetHeight();
4166
4167 if (gtk_widget_intersect (child->widget, &rect, &gdk_event.area))
4168 {
4169 gtk_widget_event (child->widget, (GdkEvent*) &gdk_event);
4170 }
4171
4172 upd ++;
4173 }
4174 }
4175 }
4176 #endif
4177 #endif
4178
4179 m_updateRegion.Clear();
4180 }
4181
4182 void wxWindowGTK::ClearBackground()
4183 {
4184 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4185
4186 #ifndef __WXGTK20__
4187 if (m_wxwindow && m_wxwindow->window)
4188 {
4189 m_clearRegion.Clear();
4190 wxSize size( GetClientSize() );
4191 m_clearRegion.Union( 0,0,size.x,size.y );
4192
4193 // Better do this in idle?
4194 GtkUpdate();
4195 }
4196 #endif
4197 }
4198
4199 #if wxUSE_TOOLTIPS
4200 void wxWindowGTK::DoSetToolTip( wxToolTip *tip )
4201 {
4202 wxWindowBase::DoSetToolTip(tip);
4203
4204 if (m_tooltip)
4205 m_tooltip->Apply( (wxWindow *)this );
4206 }
4207
4208 void wxWindowGTK::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
4209 {
4210 wxString tmp( tip );
4211 gtk_tooltips_set_tip( tips, GetConnectWidget(), wxGTK_CONV(tmp), (gchar*) NULL );
4212 }
4213 #endif // wxUSE_TOOLTIPS
4214
4215 bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
4216 {
4217 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
4218
4219 if (!wxWindowBase::SetBackgroundColour(colour))
4220 return false;
4221
4222 if (colour.Ok())
4223 {
4224 // We need the pixel value e.g. for background clearing.
4225 m_backgroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
4226 }
4227
4228 // apply style change (forceStyle=true so that new style is applied
4229 // even if the bg colour changed from valid to wxNullColour)
4230 if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM)
4231 ApplyWidgetStyle(true);
4232
4233 return true;
4234 }
4235
4236 bool wxWindowGTK::SetForegroundColour( const wxColour &colour )
4237 {
4238 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
4239
4240 if (!wxWindowBase::SetForegroundColour(colour))
4241 {
4242 return false;
4243 }
4244
4245 if (colour.Ok())
4246 {
4247 // We need the pixel value e.g. for background clearing.
4248 m_foregroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
4249 }
4250
4251 // apply style change (forceStyle=true so that new style is applied
4252 // even if the bg colour changed from valid to wxNullColour):
4253 ApplyWidgetStyle(true);
4254
4255 return true;
4256 }
4257
4258 #ifdef __WXGTK20__
4259 PangoContext *wxWindowGTK::GtkGetPangoDefaultContext()
4260 {
4261 return gtk_widget_get_pango_context( m_widget );
4262 }
4263
4264 PangoContext *wxWindowGTK::GtkGetPangoX11Context()
4265 {
4266 if (!m_x11Context)
4267 m_x11Context = pango_x_get_context( gdk_display );
4268
4269 return m_x11Context;
4270 }
4271 #endif
4272
4273 GtkRcStyle *wxWindowGTK::CreateWidgetStyle(bool forceStyle)
4274 {
4275 // do we need to apply any changes at all?
4276 if ( !forceStyle &&
4277 !m_font.Ok() &&
4278 !m_foregroundColour.Ok() && !m_backgroundColour.Ok() )
4279 {
4280 return NULL;
4281 }
4282
4283 GtkRcStyle *style = gtk_rc_style_new();
4284
4285 if ( m_font.Ok() )
4286 {
4287 #ifdef __WXGTK20__
4288 style->font_desc =
4289 pango_font_description_copy( m_font.GetNativeFontInfo()->description );
4290 #else
4291 wxString xfontname = m_font.GetNativeFontInfo()->GetXFontName();
4292 style->fontset_name = g_strdup(xfontname.c_str());
4293 #endif
4294 }
4295
4296 if ( m_foregroundColour.Ok() )
4297 {
4298 GdkColor *fg = m_foregroundColour.GetColor();
4299
4300 style->fg[GTK_STATE_NORMAL] = *fg;
4301 style->color_flags[GTK_STATE_NORMAL] = GTK_RC_FG;
4302
4303 style->fg[GTK_STATE_PRELIGHT] = *fg;
4304 style->color_flags[GTK_STATE_PRELIGHT] = GTK_RC_FG;
4305
4306 style->fg[GTK_STATE_ACTIVE] = *fg;
4307 style->color_flags[GTK_STATE_ACTIVE] = GTK_RC_FG;
4308 }
4309
4310 if ( m_backgroundColour.Ok() )
4311 {
4312 GdkColor *bg = m_backgroundColour.GetColor();
4313
4314 style->bg[GTK_STATE_NORMAL] = *bg;
4315 style->base[GTK_STATE_NORMAL] = *bg;
4316 style->color_flags[GTK_STATE_NORMAL] = (GtkRcFlags)
4317 (style->color_flags[GTK_STATE_NORMAL] | GTK_RC_BG | GTK_RC_BASE);
4318
4319 style->bg[GTK_STATE_PRELIGHT] = *bg;
4320 style->base[GTK_STATE_PRELIGHT] = *bg;
4321 style->color_flags[GTK_STATE_PRELIGHT] = (GtkRcFlags)
4322 (style->color_flags[GTK_STATE_PRELIGHT] | GTK_RC_BG | GTK_RC_BASE);
4323
4324 style->bg[GTK_STATE_ACTIVE] = *bg;
4325 style->base[GTK_STATE_ACTIVE] = *bg;
4326 style->color_flags[GTK_STATE_ACTIVE] = (GtkRcFlags)
4327 (style->color_flags[GTK_STATE_ACTIVE] | GTK_RC_BG | GTK_RC_BASE);
4328
4329 style->bg[GTK_STATE_INSENSITIVE] = *bg;
4330 style->base[GTK_STATE_INSENSITIVE] = *bg;
4331 style->color_flags[GTK_STATE_INSENSITIVE] = (GtkRcFlags)
4332 (style->color_flags[GTK_STATE_INSENSITIVE] | GTK_RC_BG | GTK_RC_BASE);
4333 }
4334
4335 return style;
4336 }
4337
4338 void wxWindowGTK::ApplyWidgetStyle(bool forceStyle)
4339 {
4340 GtkRcStyle *style = CreateWidgetStyle(forceStyle);
4341 if ( style )
4342 {
4343 DoApplyWidgetStyle(style);
4344 gtk_rc_style_unref(style);
4345 }
4346
4347 // Style change may affect GTK+'s size calculation:
4348 InvalidateBestSize();
4349 }
4350
4351 void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle *style)
4352 {
4353 if (m_wxwindow)
4354 gtk_widget_modify_style(m_wxwindow, style);
4355 gtk_widget_modify_style(m_widget, style);
4356 }
4357
4358 bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style)
4359 {
4360 wxWindowBase::SetBackgroundStyle(style);
4361
4362 if (style == wxBG_STYLE_CUSTOM)
4363 {
4364 GdkWindow *window = (GdkWindow*) NULL;
4365 if (m_wxwindow)
4366 window = GTK_PIZZA(m_wxwindow)->bin_window;
4367 else
4368 window = GetConnectWidget()->window;
4369
4370 if (window)
4371 {
4372 // Make sure GDK/X11 doesn't refresh the window
4373 // automatically.
4374 gdk_window_set_back_pixmap( window, None, False );
4375 #ifdef __X__
4376 Display* display = GDK_WINDOW_DISPLAY(window);
4377 XFlush(display);
4378 #endif
4379 m_needsStyleChange = false;
4380 }
4381 else
4382 // Do in OnIdle, because the window is not yet available
4383 m_needsStyleChange = true;
4384
4385 // Don't apply widget style, or we get a grey background
4386 }
4387 else
4388 {
4389 // apply style change (forceStyle=true so that new style is applied
4390 // even if the bg colour changed from valid to wxNullColour):
4391 ApplyWidgetStyle(true);
4392 }
4393 return true;
4394 }
4395
4396 //-----------------------------------------------------------------------------
4397 // Pop-up menu stuff
4398 //-----------------------------------------------------------------------------
4399
4400 #if wxUSE_MENUS_NATIVE
4401
4402 extern "C"
4403 void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting )
4404 {
4405 *is_waiting = FALSE;
4406 }
4407
4408 void SetInvokingWindow( wxMenu *menu, wxWindow* win )
4409 {
4410 menu->SetInvokingWindow( win );
4411
4412 wxMenuItemList::compatibility_iterator node = menu->GetMenuItems().GetFirst();
4413 while (node)
4414 {
4415 wxMenuItem *menuitem = node->GetData();
4416 if (menuitem->IsSubMenu())
4417 {
4418 SetInvokingWindow( menuitem->GetSubMenu(), win );
4419 }
4420
4421 node = node->GetNext();
4422 }
4423 }
4424
4425 extern "C" void wxPopupMenuPositionCallback( GtkMenu *menu,
4426 gint *x, gint *y,
4427 #ifdef __WXGTK20__
4428 gboolean * WXUNUSED(whatever),
4429 #endif
4430 gpointer user_data )
4431 {
4432 // ensure that the menu appears entirely on screen
4433 GtkRequisition req;
4434 gtk_widget_get_child_requisition(GTK_WIDGET(menu), &req);
4435
4436 wxSize sizeScreen = wxGetDisplaySize();
4437 wxPoint *pos = (wxPoint*)user_data;
4438
4439 gint xmax = sizeScreen.x - req.width,
4440 ymax = sizeScreen.y - req.height;
4441
4442 *x = pos->x < xmax ? pos->x : xmax;
4443 *y = pos->y < ymax ? pos->y : ymax;
4444 }
4445
4446 bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
4447 {
4448 wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
4449
4450 wxCHECK_MSG( menu != NULL, false, wxT("invalid popup-menu") );
4451
4452 // NOTE: if you change this code, you need to update
4453 // the same code in taskbar.cpp as well. This
4454 // is ugly code duplication, I know,
4455
4456 SetInvokingWindow( menu, this );
4457
4458 menu->UpdateUI();
4459
4460 bool is_waiting = true;
4461
4462 gulong handler = gtk_signal_connect( GTK_OBJECT(menu->m_menu),
4463 "hide",
4464 GTK_SIGNAL_FUNC(gtk_pop_hide_callback),
4465 (gpointer)&is_waiting );
4466
4467 wxPoint pos;
4468 gpointer userdata;
4469 GtkMenuPositionFunc posfunc;
4470 if ( x == -1 && y == -1 )
4471 {
4472 // use GTK's default positioning algorithm
4473 userdata = NULL;
4474 posfunc = NULL;
4475 }
4476 else
4477 {
4478 pos = ClientToScreen(wxPoint(x, y));
4479 userdata = &pos;
4480 posfunc = wxPopupMenuPositionCallback;
4481 }
4482
4483 gtk_menu_popup(
4484 GTK_MENU(menu->m_menu),
4485 (GtkWidget *) NULL, // parent menu shell
4486 (GtkWidget *) NULL, // parent menu item
4487 posfunc, // function to position it
4488 userdata, // client data
4489 0, // button used to activate it
4490 #ifdef __WXGTK20__
4491 gtk_get_current_event_time()
4492 #else
4493 gs_timeLastClick // the time of activation
4494 #endif
4495 );
4496
4497 while (is_waiting)
4498 {
4499 gtk_main_iteration();
4500 }
4501
4502 gtk_signal_disconnect(GTK_OBJECT(menu->m_menu), handler);
4503
4504 return true;
4505 }
4506
4507 #endif // wxUSE_MENUS_NATIVE
4508
4509 #if wxUSE_DRAG_AND_DROP
4510
4511 void wxWindowGTK::SetDropTarget( wxDropTarget *dropTarget )
4512 {
4513 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4514
4515 GtkWidget *dnd_widget = GetConnectWidget();
4516
4517 if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
4518
4519 if (m_dropTarget) delete m_dropTarget;
4520 m_dropTarget = dropTarget;
4521
4522 if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
4523 }
4524
4525 #endif // wxUSE_DRAG_AND_DROP
4526
4527 GtkWidget* wxWindowGTK::GetConnectWidget()
4528 {
4529 GtkWidget *connect_widget = m_widget;
4530 if (m_wxwindow) connect_widget = m_wxwindow;
4531
4532 return connect_widget;
4533 }
4534
4535 bool wxWindowGTK::IsOwnGtkWindow( GdkWindow *window )
4536 {
4537 if (m_wxwindow)
4538 return (window == GTK_PIZZA(m_wxwindow)->bin_window);
4539
4540 return (window == m_widget->window);
4541 }
4542
4543 bool wxWindowGTK::SetFont( const wxFont &font )
4544 {
4545 wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
4546
4547 if (!wxWindowBase::SetFont(font))
4548 return false;
4549
4550 // apply style change (forceStyle=true so that new style is applied
4551 // even if the font changed from valid to wxNullFont):
4552 ApplyWidgetStyle(true);
4553
4554 return true;
4555 }
4556
4557 void wxWindowGTK::DoCaptureMouse()
4558 {
4559 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4560
4561 GdkWindow *window = (GdkWindow*) NULL;
4562 if (m_wxwindow)
4563 window = GTK_PIZZA(m_wxwindow)->bin_window;
4564 else
4565 window = GetConnectWidget()->window;
4566
4567 wxCHECK_RET( window, _T("CaptureMouse() failed") );
4568
4569 wxCursor* cursor = & m_cursor;
4570 if (!cursor->Ok())
4571 cursor = wxSTANDARD_CURSOR;
4572
4573 gdk_pointer_grab( window, FALSE,
4574 (GdkEventMask)
4575 (GDK_BUTTON_PRESS_MASK |
4576 GDK_BUTTON_RELEASE_MASK |
4577 GDK_POINTER_MOTION_HINT_MASK |
4578 GDK_POINTER_MOTION_MASK),
4579 (GdkWindow *) NULL,
4580 cursor->GetCursor(),
4581 (guint32)GDK_CURRENT_TIME );
4582 g_captureWindow = this;
4583 g_captureWindowHasMouse = TRUE;
4584 }
4585
4586 void wxWindowGTK::DoReleaseMouse()
4587 {
4588 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4589
4590 wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") );
4591
4592 g_captureWindow = (wxWindowGTK*) NULL;
4593
4594 GdkWindow *window = (GdkWindow*) NULL;
4595 if (m_wxwindow)
4596 window = GTK_PIZZA(m_wxwindow)->bin_window;
4597 else
4598 window = GetConnectWidget()->window;
4599
4600 if (!window)
4601 return;
4602
4603 gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
4604 }
4605
4606 /* static */
4607 wxWindow *wxWindowBase::GetCapture()
4608 {
4609 return (wxWindow *)g_captureWindow;
4610 }
4611
4612 bool wxWindowGTK::IsRetained() const
4613 {
4614 return FALSE;
4615 }
4616
4617 void wxWindowGTK::SetScrollbar( int orient, int pos, int thumbVisible,
4618 int range, bool refresh )
4619 {
4620 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4621
4622 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
4623
4624 m_hasScrolling = TRUE;
4625
4626 if (orient == wxHORIZONTAL)
4627 {
4628 float fpos = (float)pos;
4629 float frange = (float)range;
4630 float fthumb = (float)thumbVisible;
4631 if (fpos > frange-fthumb) fpos = frange-fthumb;
4632 if (fpos < 0.0) fpos = 0.0;
4633
4634 if ((fabs(frange-m_hAdjust->upper) < 0.2) &&
4635 (fabs(fthumb-m_hAdjust->page_size) < 0.2))
4636 {
4637 SetScrollPos( orient, pos, refresh );
4638 return;
4639 }
4640
4641 m_oldHorizontalPos = fpos;
4642
4643 m_hAdjust->lower = 0.0;
4644 m_hAdjust->upper = frange;
4645 m_hAdjust->value = fpos;
4646 m_hAdjust->step_increment = 1.0;
4647 m_hAdjust->page_increment = (float)(wxMax(fthumb,0));
4648 m_hAdjust->page_size = fthumb;
4649 }
4650 else
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_vAdjust->upper) < 0.2) &&
4659 (fabs(fthumb-m_vAdjust->page_size) < 0.2))
4660 {
4661 SetScrollPos( orient, pos, refresh );
4662 return;
4663 }
4664
4665 m_oldVerticalPos = fpos;
4666
4667 m_vAdjust->lower = 0.0;
4668 m_vAdjust->upper = frange;
4669 m_vAdjust->value = fpos;
4670 m_vAdjust->step_increment = 1.0;
4671 m_vAdjust->page_increment = (float)(wxMax(fthumb,0));
4672 m_vAdjust->page_size = fthumb;
4673 }
4674
4675 if (orient == wxHORIZONTAL)
4676 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
4677 else
4678 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
4679 }
4680
4681 void wxWindowGTK::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
4682 {
4683 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4684
4685 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
4686
4687 if (orient == wxHORIZONTAL)
4688 {
4689 float fpos = (float)pos;
4690 if (fpos > m_hAdjust->upper - m_hAdjust->page_size) fpos = m_hAdjust->upper - m_hAdjust->page_size;
4691 if (fpos < 0.0) fpos = 0.0;
4692 m_oldHorizontalPos = fpos;
4693
4694 if (fabs(fpos-m_hAdjust->value) < 0.2) return;
4695 m_hAdjust->value = fpos;
4696 }
4697 else
4698 {
4699 float fpos = (float)pos;
4700 if (fpos > m_vAdjust->upper - m_vAdjust->page_size) fpos = m_vAdjust->upper - m_vAdjust->page_size;
4701 if (fpos < 0.0) fpos = 0.0;
4702 m_oldVerticalPos = fpos;
4703
4704 if (fabs(fpos-m_vAdjust->value) < 0.2) return;
4705 m_vAdjust->value = fpos;
4706 }
4707
4708 if (m_wxwindow->window)
4709 {
4710 if (orient == wxHORIZONTAL)
4711 {
4712 gtk_signal_disconnect_by_func( GTK_OBJECT(m_hAdjust),
4713 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
4714
4715 gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
4716
4717 gtk_signal_connect( GTK_OBJECT(m_hAdjust), "value_changed",
4718 (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
4719 }
4720 else
4721 {
4722 gtk_signal_disconnect_by_func( GTK_OBJECT(m_vAdjust),
4723 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
4724
4725 gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
4726
4727 gtk_signal_connect( GTK_OBJECT(m_vAdjust), "value_changed",
4728 (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
4729 }
4730 }
4731 }
4732
4733 int wxWindowGTK::GetScrollThumb( int orient ) const
4734 {
4735 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
4736
4737 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
4738
4739 if (orient == wxHORIZONTAL)
4740 return (int)(m_hAdjust->page_size+0.5);
4741 else
4742 return (int)(m_vAdjust->page_size+0.5);
4743 }
4744
4745 int wxWindowGTK::GetScrollPos( int orient ) const
4746 {
4747 wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
4748
4749 wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
4750
4751 if (orient == wxHORIZONTAL)
4752 return (int)(m_hAdjust->value+0.5);
4753 else
4754 return (int)(m_vAdjust->value+0.5);
4755 }
4756
4757 int wxWindowGTK::GetScrollRange( 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->upper+0.5);
4765 else
4766 return (int)(m_vAdjust->upper+0.5);
4767 }
4768
4769 void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
4770 {
4771 wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
4772
4773 wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
4774
4775 // No scrolling requested.
4776 if ((dx == 0) && (dy == 0)) return;
4777
4778 #ifndef __WXGTK20__
4779 if (!m_updateRegion.IsEmpty())
4780 {
4781 m_updateRegion.Offset( dx, dy );
4782
4783 int cw = 0;
4784 int ch = 0;
4785 GetClientSize( &cw, &ch );
4786 m_updateRegion.Intersect( 0, 0, cw, ch );
4787 }
4788
4789 if (!m_clearRegion.IsEmpty())
4790 {
4791 m_clearRegion.Offset( dx, dy );
4792
4793 int cw = 0;
4794 int ch = 0;
4795 GetClientSize( &cw, &ch );
4796 m_clearRegion.Intersect( 0, 0, cw, ch );
4797 }
4798 #endif
4799
4800 m_clipPaintRegion = TRUE;
4801
4802 gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
4803
4804 m_clipPaintRegion = FALSE;
4805 }
4806
4807
4808 // Find the wxWindow at the current mouse position, also returning the mouse
4809 // position.
4810 wxWindow* wxFindWindowAtPointer(wxPoint& pt)
4811 {
4812 pt = wxGetMousePosition();
4813 wxWindow* found = wxFindWindowAtPoint(pt);
4814 return found;
4815 }
4816
4817 // Get the current mouse position.
4818 wxPoint wxGetMousePosition()
4819 {
4820 /* This crashes when used within wxHelpContext,
4821 so we have to use the X-specific implementation below.
4822 gint x, y;
4823 GdkModifierType *mask;
4824 (void) gdk_window_get_pointer(NULL, &x, &y, mask);
4825
4826 return wxPoint(x, y);
4827 */
4828
4829 int x, y;
4830 GdkWindow* windowAtPtr = gdk_window_at_pointer(& x, & y);
4831
4832 Display *display = windowAtPtr ? GDK_WINDOW_XDISPLAY(windowAtPtr) : GDK_DISPLAY();
4833 Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
4834 Window rootReturn, childReturn;
4835 int rootX, rootY, winX, winY;
4836 unsigned int maskReturn;
4837
4838 XQueryPointer (display,
4839 rootWindow,
4840 &rootReturn,
4841 &childReturn,
4842 &rootX, &rootY, &winX, &winY, &maskReturn);
4843 return wxPoint(rootX, rootY);
4844
4845 }
4846
4847 // ----------------------------------------------------------------------------
4848 // wxDCModule
4849 // ----------------------------------------------------------------------------
4850
4851 class wxWinModule : public wxModule
4852 {
4853 public:
4854 bool OnInit();
4855 void OnExit();
4856
4857 private:
4858 DECLARE_DYNAMIC_CLASS(wxWinModule)
4859 };
4860
4861 IMPLEMENT_DYNAMIC_CLASS(wxWinModule, wxModule)
4862
4863 bool wxWinModule::OnInit()
4864 {
4865 // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
4866 // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
4867
4868 return TRUE;
4869 }
4870
4871 void wxWinModule::OnExit()
4872 {
4873 if (g_eraseGC)
4874 gdk_gc_unref( g_eraseGC );
4875 }
4876
4877 // vi:sts=4:sw=4:et