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