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