/////////////////////////////////////////////////////////////////////////////
-// Name: window.cpp
+// Name: src/gtk/window.cpp
// Purpose:
// Author: Robert Roebling
-// Created: 01/02/97
-// Id:
-// Copyright: (c) 1998 Robert Roebling, Julian Smart and Markus Holzem
+// Id: $Id$
+// Copyright: (c) 1998 Robert Roebling, Julian Smart
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
-#ifdef __GNUG__
-#pragma implementation "window.h"
+#ifdef __VMS
+#define XWarpPointer XWARPPOINTER
#endif
-#include "wx/defs.h"
#include "wx/window.h"
-#include "wx/dc.h"
-#include "wx/frame.h"
-#include "wx/app.h"
-#include "wx/layout.h"
-#include "wx/utils.h"
-#include "wx/dialog.h"
-#include "wx/msgdlg.h"
-#include "wx/dcclient.h"
+
+#ifndef WX_PRECOMP
+ #include "wx/log.h"
+ #include "wx/app.h"
+ #include "wx/frame.h"
+ #include "wx/dcclient.h"
+ #include "wx/menu.h"
+ #include "wx/settings.h"
+ #include "wx/msgdlg.h"
+ #include "wx/textctrl.h"
+ #include "wx/radiobut.h"
+ #include "wx/toolbar.h"
+ #include "wx/combobox.h"
+ #include "wx/layout.h"
+ #include "wx/math.h"
+#endif
+
#include "wx/dnd.h"
-#include "wx/mdi.h"
-#include "wx/menu.h"
-#include "wx/notebook.h"
-#include "wx/statusbr.h"
-#include <wx/intl.h>
-#include "gdk/gdkkeysyms.h"
-#include <math.h>
+#include "wx/tooltip.h"
+#include "wx/caret.h"
+#include "wx/fontutil.h"
+
+#ifdef __WXDEBUG__
+ #include "wx/thread.h"
+#endif
+
+#include <ctype.h>
+
+// FIXME: Due to a hack we use GtkCombo in here, which is deprecated since gtk2.3.0
+#include <gtk/gtkversion.h>
+#if defined(GTK_DISABLE_DEPRECATED) && GTK_CHECK_VERSION(2,3,0)
+ #undef GTK_DISABLE_DEPRECATED
+ #include <gtk/gtkcombo.h>
+ #define GTK_DISABLE_DEPRECATED
+#endif
+
+#include "wx/gtk/private.h"
#include "wx/gtk/win_gtk.h"
-#include "gdk/gdkprivate.h"
+#include <gdk/gdkkeysyms.h>
+#include <gdk/gdkx.h>
+
+//-----------------------------------------------------------------------------
+// documentation on internals
+//-----------------------------------------------------------------------------
+
+/*
+ I have been asked several times about writing some documentation about
+ the GTK port of wxWidgets, especially its internal structures. Obviously,
+ you cannot understand wxGTK without knowing a little about the GTK, but
+ some more information about what the wxWindow, which is the base class
+ for all other window classes, does seems required as well.
+
+ I)
+
+ What does wxWindow do? It contains the common interface for the following
+ jobs of its descendants:
+
+ 1) Define the rudimentary behaviour common to all window classes, such as
+ resizing, intercepting user input (so as to make it possible to use these
+ events for special purposes in a derived class), window names etc.
+
+ 2) Provide the possibility to contain and manage children, if the derived
+ class is allowed to contain children, which holds true for those window
+ classes which do not display a native GTK widget. To name them, these
+ classes are wxPanel, wxScrolledWindow, wxDialog, wxFrame. The MDI frame-
+ work classes are a special case and are handled a bit differently from
+ the rest. The same holds true for the wxNotebook class.
+
+ 3) Provide the possibility to draw into a client area of a window. This,
+ too, only holds true for classes that do not display a native GTK widget
+ as above.
+
+ 4) Provide the entire mechanism for scrolling widgets. This actual inter-
+ face for this is usually in wxScrolledWindow, but the GTK implementation
+ is in this class.
+
+ 5) A multitude of helper or extra methods for special purposes, such as
+ Drag'n'Drop, managing validators etc.
+
+ 6) Display a border (sunken, raised, simple or none).
+
+ Normally one might expect, that one wxWidgets window would always correspond
+ to one GTK widget. Under GTK, there is no such all-round widget that has all
+ the functionality. Moreover, the GTK defines a client area as a different
+ widget from the actual widget you are handling. Last but not least some
+ special classes (e.g. wxFrame) handle different categories of widgets and
+ still have the possibility to draw something in the client area.
+ It was therefore required to write a special purpose GTK widget, that would
+ represent a client area in the sense of wxWidgets capable to do the jobs
+ 2), 3) and 4). I have written this class and it resides in win_gtk.c of
+ this directory.
+
+ All windows must have a widget, with which they interact with other under-
+ lying GTK widgets. It is this widget, e.g. that has to be resized etc and
+ the wxWindow class has a member variable called m_widget which holds a
+ pointer to this widget. When the window class represents a GTK native widget,
+ this is (in most cases) the only GTK widget the class manages. E.g. the
+ wxStaticText class handles only a GtkLabel widget a pointer to which you
+ can find in m_widget (defined in wxWindow)
+
+ When the class has a client area for drawing into and for containing children
+ it has to handle the client area widget (of the type GtkPizza, defined in
+ win_gtk.c), but there could be any number of widgets, handled by a class
+ The common rule for all windows is only, that the widget that interacts with
+ the rest of GTK must be referenced in m_widget and all other widgets must be
+ children of this widget on the GTK level. The top-most widget, which also
+ represents the client area, must be in the m_wxwindow field and must be of
+ the type GtkPizza.
+
+ As I said, the window classes that display a GTK native widget only have
+ one widget, so in the case of e.g. the wxButton class m_widget holds a
+ pointer to a GtkButton widget. But windows with client areas (for drawing
+ and children) have a m_widget field that is a pointer to a GtkScrolled-
+ Window and a m_wxwindow field that is pointer to a GtkPizza and this
+ one is (in the GTK sense) a child of the GtkScrolledWindow.
+
+ If the m_wxwindow field is set, then all input to this widget is inter-
+ cepted and sent to the wxWidgets class. If not, all input to the widget
+ that gets pointed to by m_widget gets intercepted and sent to the class.
+
+ II)
+
+ The design of scrolling in wxWidgets is markedly different from that offered
+ by the GTK itself and therefore we cannot simply take it as it is. In GTK,
+ clicking on a scrollbar belonging to scrolled window will inevitably move
+ the window. In wxWidgets, the scrollbar will only emit an event, send this
+ to (normally) a wxScrolledWindow and that class will call ScrollWindow()
+ which actually moves the window and its sub-windows. Note that GtkPizza
+ memorizes how much it has been scrolled but that wxWidgets forgets this
+ so that the two coordinates systems have to be kept in synch. This is done
+ in various places using the pizza->xoffset and pizza->yoffset values.
+
+ III)
+
+ Singularly the most broken code in GTK is the code that is supposed to
+ inform subwindows (child windows) about new positions. Very often, duplicate
+ events are sent without changes in size or position, equally often no
+ events are sent at all (All this is due to a bug in the GtkContainer code
+ which got fixed in GTK 1.2.6). For that reason, wxGTK completely ignores
+ GTK's own system and it simply waits for size events for toplevel windows
+ and then iterates down the respective size events to all window. This has
+ the disadvantage that windows might get size events before the GTK widget
+ actually has the reported size. This doesn't normally pose any problem, but
+ the OpenGL drawing routines rely on correct behaviour. Therefore, I have
+ added the m_nativeSizeEvents flag, which is true only for the OpenGL canvas,
+ i.e. the wxGLCanvas will emit a size event, when (and not before) the X11
+ window that is used for OpenGL output really has that size (as reported by
+ GTK).
+
+ IV)
+
+ If someone at some point of time feels the immense desire to have a look at,
+ change or attempt to optimise the Refresh() logic, this person will need an
+ intimate understanding of what "draw" and "expose" events are and what
+ they are used for, in particular when used in connection with GTK's
+ own windowless widgets. Beware.
+
+ V)
+
+ Cursors, too, have been a constant source of pleasure. The main difficulty
+ is that a GdkWindow inherits a cursor if the programmer sets a new cursor
+ for the parent. To prevent this from doing too much harm, I use idle time
+ to set the cursor over and over again, starting from the toplevel windows
+ and ending with the youngest generation (speaking of parent and child windows).
+ Also don't forget that cursors (like much else) are connected to GdkWindows,
+ not GtkWidgets and that the "window" field of a GtkWidget might very well
+ point to the GdkWindow of the parent widget (-> "window-less widget") and
+ that the two obviously have very different meanings.
+
+*/
//-----------------------------------------------------------------------------
// data
//-----------------------------------------------------------------------------
-extern wxList wxPendingDelete;
-extern wxList wxTopLevelWindows;
-extern bool g_blockEventsOnDrag;
+// Don't allow event propagation during drag
+bool g_blockEventsOnDrag;
+// Don't allow mouse event propagation during scroll
+bool g_blockEventsOnScroll;
+extern wxCursor g_globalCursor;
+
+// mouse capture state: the window which has it and if the mouse is currently
+// inside it
+static wxWindowGTK *g_captureWindow = (wxWindowGTK*) NULL;
+static bool g_captureWindowHasMouse = false;
+
+wxWindowGTK *g_focusWindow = (wxWindowGTK*) NULL;
+
+// the last window which had the focus - this is normally never NULL (except
+// if we never had focus at all) as even when g_focusWindow is NULL it still
+// keeps its previous value
+wxWindowGTK *g_focusWindowLast = (wxWindowGTK*) NULL;
+
+// If a window get the focus set but has not been realized
+// yet, defer setting the focus to idle time.
+wxWindowGTK *g_delayedFocus = (wxWindowGTK*) NULL;
+
+// global variables because GTK+ DnD want to have the
+// mouse event that caused it
+GdkEvent *g_lastMouseEvent = (GdkEvent*) NULL;
+int g_lastButtonNumber = 0;
+
+extern bool g_mainThreadLocked;
//-----------------------------------------------------------------------------
-// "expose_event" (of m_wxwindow, not of m_widget)
+// debug
//-----------------------------------------------------------------------------
-static void gtk_window_expose_callback( GtkWidget *WXUNUSED(widget), GdkEventExpose *gdk_event, wxWindow *win )
-{
- if (!win->HasVMT()) return;
- if (g_blockEventsOnDrag) return;
-
- win->m_updateRegion.Union( gdk_event->area.x,
- gdk_event->area.y,
- gdk_event->area.width,
- gdk_event->area.height );
-
- if (gdk_event->count > 0) return;
-
- wxPaintEvent event( win->GetId() );
- event.SetEventObject( win );
- win->GetEventHandler()->ProcessEvent( event );
-
- win->m_updateRegion.Clear();
-}
+#ifdef __WXDEBUG__
+
+#if wxUSE_THREADS
+# define DEBUG_MAIN_THREAD if (wxThread::IsMain() && g_mainThreadLocked) printf("gui reentrance");
+#else
+# define DEBUG_MAIN_THREAD
+#endif
+#else
+#define DEBUG_MAIN_THREAD
+#endif // Debug
+
+// the trace mask used for the focus debugging messages
+#define TRACE_FOCUS _T("focus")
//-----------------------------------------------------------------------------
-// "draw" (of m_wxwindow, not of m_widget)
+// missing gdk functions
//-----------------------------------------------------------------------------
-static void gtk_window_draw_callback( GtkWidget *WXUNUSED(widget), GdkRectangle *rect, wxWindow *win )
-{
- if (!win->HasVMT()) return;
- if (g_blockEventsOnDrag) return;
-
- win->m_updateRegion.Union( rect->x, rect->y, rect->width, rect->height );
-
- wxPaintEvent event( win->GetId() );
- event.SetEventObject( win );
- win->GetEventHandler()->ProcessEvent( event );
-
- win->m_updateRegion.Clear();
+void
+gdk_window_warp_pointer (GdkWindow *window,
+ gint x,
+ gint y)
+{
+ if (!window)
+ window = gdk_get_default_root_window();
+
+ if (!GDK_WINDOW_DESTROYED(window))
+ {
+ XWarpPointer (GDK_WINDOW_XDISPLAY(window),
+ None, /* not source window -> move from anywhere */
+ GDK_WINDOW_XID(window), /* dest window */
+ 0, 0, 0, 0, /* not source window -> move from anywhere */
+ x, y );
+ }
}
//-----------------------------------------------------------------------------
-// "key_press_event"
+// local code (see below)
//-----------------------------------------------------------------------------
-static gint gtk_window_key_press_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindow *win )
-{
- if (!win->HasVMT()) return FALSE;
- if (g_blockEventsOnDrag) return FALSE;
+// returns the child of win which currently has focus or NULL if not found
+//
+// Note: can't be static, needed by textctrl.cpp.
+wxWindow *wxFindFocusedChild(wxWindowGTK *win)
+{
+ wxWindow *winFocus = wxWindowGTK::FindFocus();
+ if ( !winFocus )
+ return (wxWindow *)NULL;
-/*
- printf( "OnKeyPress from " );
- if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
- printf( win->GetClassInfo()->GetClassName() );
- printf( ".\n" );
-*/
+ if ( winFocus == win )
+ return (wxWindow *)win;
- long key_code = 0;
- switch (gdk_event->keyval)
- {
- case GDK_BackSpace: key_code = WXK_BACK; break;
- case GDK_Tab: key_code = WXK_TAB; break;
- case GDK_Linefeed: key_code = WXK_RETURN; break;
- case GDK_Clear: key_code = WXK_CLEAR; break;
- case GDK_Return: key_code = WXK_RETURN; break;
- case GDK_Pause: key_code = WXK_PAUSE; break;
- case GDK_Scroll_Lock: key_code = WXK_SCROLL; break;
- case GDK_Escape: key_code = WXK_ESCAPE; break;
- case GDK_Delete: key_code = WXK_DELETE; break;
- case GDK_Home: key_code = WXK_HOME; break;
- case GDK_Left: key_code = WXK_LEFT; break;
- case GDK_Up: key_code = WXK_UP; break;
- case GDK_Right: key_code = WXK_RIGHT; break;
- case GDK_Down: key_code = WXK_DOWN; break;
- case GDK_Prior: key_code = WXK_PRIOR; break;
-// case GDK_Page_Up: key_code = WXK_PAGEUP; break;
- case GDK_Next: key_code = WXK_NEXT; break;
-// case GDK_Page_Down: key_code = WXK_PAGEDOWN; break;
- case GDK_End: key_code = WXK_END; break;
- case GDK_Begin: key_code = WXK_HOME; break;
- case GDK_Select: key_code = WXK_SELECT; break;
- case GDK_Print: key_code = WXK_PRINT; break;
- case GDK_Execute: key_code = WXK_EXECUTE; break;
- case GDK_Insert: key_code = WXK_INSERT; break;
- case GDK_Num_Lock: key_code = WXK_NUMLOCK; break;
- case GDK_KP_Tab: key_code = WXK_TAB; break;
- case GDK_KP_Enter: key_code = WXK_RETURN; break;
- case GDK_KP_Home: key_code = WXK_HOME; break;
- case GDK_KP_Left: key_code = WXK_LEFT; break;
- case GDK_KP_Up: key_code = WXK_UP; break;
- case GDK_KP_Right: key_code = WXK_RIGHT; break;
- case GDK_KP_Down: key_code = WXK_DOWN; break;
- case GDK_KP_Prior: key_code = WXK_PRIOR; break;
-// case GDK_KP_Page_Up: key_code = WXK_PAGEUP; break;
- case GDK_KP_Next: key_code = WXK_NEXT; break;
-// case GDK_KP_Page_Down: key_code = WXK_PAGEDOWN; break;
- case GDK_KP_End: key_code = WXK_END; break;
- case GDK_KP_Begin: key_code = WXK_HOME; break;
- case GDK_KP_Insert: key_code = WXK_INSERT; break;
- case GDK_KP_Delete: key_code = WXK_DELETE; break;
- case GDK_KP_Multiply: key_code = WXK_MULTIPLY; break;
- case GDK_KP_Add: key_code = WXK_ADD; break;
- case GDK_KP_Separator: key_code = WXK_SEPARATOR; break;
- case GDK_KP_Subtract: key_code = WXK_SUBTRACT; break;
- case GDK_KP_Decimal: key_code = WXK_DECIMAL; break;
- case GDK_KP_Divide: key_code = WXK_DIVIDE; break;
- case GDK_KP_0: key_code = WXK_NUMPAD0; break;
- case GDK_KP_1: key_code = WXK_NUMPAD1; break;
- case GDK_KP_2: key_code = WXK_NUMPAD2; break;
- case GDK_KP_3: key_code = WXK_NUMPAD3; break;
- case GDK_KP_4: key_code = WXK_NUMPAD4; break;
- case GDK_KP_5: key_code = WXK_NUMPAD5; break;
- case GDK_KP_6: key_code = WXK_NUMPAD6; break;
- case GDK_KP_7: key_code = WXK_NUMPAD7; break;
- case GDK_KP_8: key_code = WXK_NUMPAD7; break;
- case GDK_KP_9: key_code = WXK_NUMPAD9; break;
- case GDK_F1: key_code = WXK_F1; break;
- case GDK_F2: key_code = WXK_F2; break;
- case GDK_F3: key_code = WXK_F3; break;
- case GDK_F4: key_code = WXK_F4; break;
- case GDK_F5: key_code = WXK_F5; break;
- case GDK_F6: key_code = WXK_F6; break;
- case GDK_F7: key_code = WXK_F7; break;
- case GDK_F8: key_code = WXK_F8; break;
- case GDK_F9: key_code = WXK_F9; break;
- case GDK_F10: key_code = WXK_F10; break;
- case GDK_F11: key_code = WXK_F11; break;
- case GDK_F12: key_code = WXK_F12; break;
- default:
- {
- if ((gdk_event->keyval >= 0x20) && (gdk_event->keyval <= 0xFF))
- key_code = gdk_event->keyval;
+ for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
+ node;
+ node = node->GetNext() )
+ {
+ wxWindow *child = wxFindFocusedChild(node->GetData());
+ if ( child )
+ return child;
}
- }
- if (!key_code) return FALSE;
-
- wxKeyEvent event( wxEVT_CHAR );
- event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
- event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
- event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
- event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
- event.m_keyCode = key_code;
- event.m_x = 0;
- event.m_y = 0;
- event.SetEventObject( win );
-
- bool ret = win->GetEventHandler()->ProcessEvent( event );
-
- if (!ret)
- {
- wxWindow *ancestor = win;
- while (ancestor)
- {
- int command = ancestor->GetAcceleratorTable()->GetCommand( event );
- if (command != -1)
- {
- wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
- ret = ancestor->GetEventHandler()->ProcessEvent( command_event );
- break;
- }
- ancestor = ancestor->GetParent();
- }
- }
-
- if (ret)
- {
- if ((gdk_event->keyval >= 0x20) && (gdk_event->keyval <= 0xFF))
- gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
- }
-
- return ret;
+ return (wxWindow *)NULL;
}
-//-----------------------------------------------------------------------------
-// "button_press_event"
-//-----------------------------------------------------------------------------
+static void GetScrollbarWidth(GtkWidget* widget, int& w, int& h)
+{
+ GtkScrolledWindow* scroll_window = GTK_SCROLLED_WINDOW(widget);
+ GtkScrolledWindowClass* scroll_class = GTK_SCROLLED_WINDOW_CLASS(GTK_OBJECT_GET_CLASS(scroll_window));
+ GtkRequisition scroll_req;
+
+ w = 0;
+ if (scroll_window->vscrollbar_visible)
+ {
+ scroll_req.width = 2;
+ scroll_req.height = 2;
+ (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
+ (scroll_window->vscrollbar, &scroll_req );
+ w = scroll_req.width +
+ scroll_class->scrollbar_spacing;
+ }
-static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindow *win )
+ h = 0;
+ if (scroll_window->hscrollbar_visible)
+ {
+ scroll_req.width = 2;
+ scroll_req.height = 2;
+ (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
+ (scroll_window->hscrollbar, &scroll_req );
+ h = scroll_req.height +
+ scroll_class->scrollbar_spacing;
+ }
+}
+
+static void draw_frame( GtkWidget *widget, wxWindowGTK *win )
{
- if (!win->IsOwnGtkWindow( gdk_event->window )) return TRUE;
-
- if (g_blockEventsOnDrag) return TRUE;
+ // wxUniversal widgets draw the borders and scrollbars themselves
+#ifndef __WXUNIVERSAL__
+ if (!win->m_hasVMT)
+ return;
- if (win->m_wxwindow)
- {
- if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow) && !GTK_WIDGET_HAS_FOCUS (win->m_wxwindow) )
+ int dx = 0;
+ int dy = 0;
+ if (GTK_WIDGET_NO_WINDOW (widget))
{
- gtk_widget_grab_focus (win->m_wxwindow);
-
-/*
- printf( "GrabFocus from " );
- if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
- printf( win->GetClassInfo()->GetClassName() );
- printf( ".\n" );
-*/
-
+ dx += widget->allocation.x;
+ dy += widget->allocation.y;
}
- }
-
- if (!win->HasVMT()) return TRUE;
-
-/*
- printf( "OnButtonPress from " );
- if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
- printf( win->GetClassInfo()->GetClassName() );
- printf( ".\n" );
-*/
- wxEventType event_type = wxEVT_LEFT_DOWN;
-
- if (gdk_event->button == 1)
- {
- switch (gdk_event->type)
+ int x = dx;
+ int y = dy;
+
+ int dw = 0;
+ int dh = 0;
+ if (win->m_hasScrolling)
+ {
+ GetScrollbarWidth(widget, dw, dh);
+
+ if (win->GetLayoutDirection() == wxLayout_RightToLeft)
+ {
+ // This is actually wrong for old GTK+ version
+ // which do not display the scrollbar on the
+ // left side in RTL
+ x += dw;
+ }
+ }
+
+ int w = widget->allocation.width-dw;
+ int h = widget->allocation.height-dh;
+
+ if (win->HasFlag(wxRAISED_BORDER))
{
- case GDK_BUTTON_PRESS: event_type = wxEVT_LEFT_DOWN; break;
- case GDK_2BUTTON_PRESS: event_type = wxEVT_LEFT_DCLICK; break;
- default: break;
+ gtk_paint_shadow (widget->style,
+ widget->window,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_OUT,
+ NULL, NULL, NULL, // FIXME: No clipping?
+ x, y, w, h );
+ return;
}
- }
- else if (gdk_event->button == 2)
- {
- switch (gdk_event->type)
+
+ if (win->HasFlag(wxSUNKEN_BORDER))
{
- case GDK_BUTTON_PRESS: event_type = wxEVT_MIDDLE_DOWN; break;
- case GDK_2BUTTON_PRESS: event_type = wxEVT_MIDDLE_DCLICK; break;
- default: break;
+ gtk_paint_shadow (widget->style,
+ widget->window,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_IN,
+ NULL, NULL, NULL, // FIXME: No clipping?
+ x, y, w, h );
+ return;
}
- }
- else if (gdk_event->button == 3)
- {
- switch (gdk_event->type)
+
+ if (win->HasFlag(wxSIMPLE_BORDER))
{
- case GDK_BUTTON_PRESS: event_type = wxEVT_RIGHT_DOWN; break;
- case GDK_2BUTTON_PRESS: event_type = wxEVT_RIGHT_DCLICK; break;
- default: break;
+ GdkGC *gc;
+ gc = gdk_gc_new( widget->window );
+ gdk_gc_set_foreground( gc, &widget->style->black );
+ gdk_draw_rectangle( widget->window, gc, FALSE, x, y, w-1, h-1 );
+ g_object_unref (gc);
+ return;
}
- }
-
- wxMouseEvent event( event_type );
- event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
- event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
- event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
- event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
- event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
- event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
- event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
-
- event.m_x = (long)gdk_event->x;
- event.m_y = (long)gdk_event->y;
-
- // Some control don't have their own X window and thus cannot get
- // any events.
-
- wxNode *node = win->GetChildren()->First();
- while (node)
- {
- wxWindow *child = (wxWindow*)node->Data();
- if ((child->m_x <= event.m_x) &&
- (child->m_y <= event.m_y) &&
- (child->m_x+child->m_width >= event.m_x) &&
- (child->m_y+child->m_height >= event.m_y))
- {
- win = child;
- event.m_x -= child->m_x;
- event.m_y -= child->m_y;
- break;
- }
- node = node->Next();
- }
-
- event.SetEventObject( win );
-
- if (win->GetEventHandler()->ProcessEvent( event ))
- gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_press_event" );
-
- return TRUE;
+#endif // __WXUNIVERSAL__
}
//-----------------------------------------------------------------------------
-// "button_release"
+// "expose_event" of m_widget
//-----------------------------------------------------------------------------
-static gint gtk_window_button_release_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindow *win )
-{
- if (!win->IsOwnGtkWindow( gdk_event->window )) return TRUE;
- if (g_blockEventsOnDrag) return TRUE;
-
- if (!win->HasVMT()) return TRUE;
-
-/*
- printf( "OnButtonRelease from " );
- if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
- printf( win->GetClassInfo()->GetClassName() );
- printf( ".\n" );
-*/
-
- wxEventType event_type = wxEVT_NULL;
-
- switch (gdk_event->button)
- {
- case 1: event_type = wxEVT_LEFT_UP; break;
- case 2: event_type = wxEVT_MIDDLE_UP; break;
- case 3: event_type = wxEVT_RIGHT_UP; break;
- }
-
- wxMouseEvent event( event_type );
- event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
- event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
- event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
- event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
- event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
- event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
- event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
- event.m_x = (long)gdk_event->x;
- event.m_y = (long)gdk_event->y;
-
- // Some control don't have their own X window and thus cannot get
- // any events.
-
- wxNode *node = win->GetChildren()->First();
- while (node)
- {
- wxWindow *child = (wxWindow*)node->Data();
- if ((child->m_x <= event.m_x) &&
- (child->m_y <= event.m_y) &&
- (child->m_x+child->m_width >= event.m_x) &&
- (child->m_y+child->m_height >= event.m_y))
- {
- win = child;
- event.m_x -= child->m_x;
- event.m_y -= child->m_y;
- break;
- }
- node = node->Next();
- }
-
- event.SetEventObject( win );
-
- if (win->GetEventHandler()->ProcessEvent( event ))
- gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "button_release_event" );
-
- return TRUE;
+extern "C" {
+static gboolean
+gtk_window_own_expose_callback( GtkWidget *widget,
+ GdkEventExpose *gdk_event,
+ wxWindowGTK *win )
+{
+ if (gdk_event->count == 0)
+ draw_frame(widget, win);
+ return false;
+}
}
//-----------------------------------------------------------------------------
-// "motion_notify_event"
+// "size_request" of m_widget
//-----------------------------------------------------------------------------
-static gint gtk_window_motion_notify_callback( GtkWidget *widget, GdkEventMotion *gdk_event, wxWindow *win )
-{
- if (!win->IsOwnGtkWindow( gdk_event->window )) return TRUE;
- if (g_blockEventsOnDrag) return TRUE;
+// make it extern because wxStaticText needs to disconnect this one
+extern "C" {
+void wxgtk_window_size_request_callback(GtkWidget *widget,
+ GtkRequisition *requisition,
+ wxWindow *win)
+{
+ int w, h;
+ win->GetSize( &w, &h );
+ if (w < 2)
+ w = 2;
+ if (h < 2)
+ h = 2;
- if (!win->HasVMT()) return TRUE;
-
-/*
- printf( "OnMotion from " );
- if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
- printf( win->GetClassInfo()->GetClassName() );
- printf( ".\n" );
-*/
-
- wxMouseEvent event( wxEVT_MOTION );
- event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
- event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
- event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
- event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
- event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
- event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
- event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
-
- event.m_x = (long)gdk_event->x;
- event.m_y = (long)gdk_event->y;
-
- // Some control don't have their own X window and thus cannot get
- // any events.
-
- wxNode *node = win->GetChildren()->First();
- while (node)
- {
- wxWindow *child = (wxWindow*)node->Data();
- if ((child->m_x <= event.m_x) &&
- (child->m_y <= event.m_y) &&
- (child->m_x+child->m_width >= event.m_x) &&
- (child->m_y+child->m_height >= event.m_y))
- {
- win = child;
- event.m_x -= child->m_x;
- event.m_y -= child->m_y;
- break;
- }
- node = node->Next();
- }
-
- event.SetEventObject( win );
-
- if (win->GetEventHandler()->ProcessEvent( event ))
- gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "motion_notify_event" );
-
- return TRUE;
+ requisition->height = h;
+ requisition->width = w;
+}
+}
+
+extern "C" {
+static
+void wxgtk_combo_size_request_callback(GtkWidget *widget,
+ GtkRequisition *requisition,
+ wxComboBox *win)
+{
+ // This callback is actually hooked into the text entry
+ // of the combo box, not the GtkHBox.
+
+ int w, h;
+ win->GetSize( &w, &h );
+ if (w < 2)
+ w = 2;
+ if (h < 2)
+ h = 2;
+
+ GtkCombo *gcombo = GTK_COMBO(win->m_widget);
+
+ GtkRequisition entry_req;
+ entry_req.width = 2;
+ entry_req.height = 2;
+ (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo->entry) )->size_request )
+ (gcombo->entry, &entry_req );
+
+ GtkRequisition button_req;
+ button_req.width = 2;
+ button_req.height = 2;
+ (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(gcombo->button) )->size_request )
+ (gcombo->button, &button_req );
+
+ requisition->width = w - button_req.width;
+ requisition->height = entry_req.height;
+}
}
//-----------------------------------------------------------------------------
-// "focus_in_event"
+// "expose_event" of m_wxwindow
//-----------------------------------------------------------------------------
-static gint gtk_window_focus_in_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindow *win )
+extern "C" {
+static gboolean
+gtk_window_expose_callback( GtkWidget *widget,
+ GdkEventExpose *gdk_event,
+ wxWindow *win )
{
- if (g_blockEventsOnDrag) return TRUE;
- if (win->m_wxwindow)
- {
- if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow))
- {
- GTK_WIDGET_SET_FLAGS (win->m_wxwindow, GTK_HAS_FOCUS);
-/*
- printf( "SetFocus flag from " );
- if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
- printf( win->GetClassInfo()->GetClassName() );
- printf( ".\n" );
-*/
+ DEBUG_MAIN_THREAD
+
+ // This callback gets called in drawing-idle time under
+ // GTK 2.0, so we don't need to defer anything to idle
+ // time anymore.
+
+ GtkPizza *pizza = GTK_PIZZA( widget );
+ if (gdk_event->window != pizza->bin_window)
+ {
+ // block expose events on GTK_WIDGET(pizza)->window,
+ // all drawing is done on pizza->bin_window
+ return true;
}
- }
-
- if (!win->HasVMT()) return TRUE;
-
-/*
- printf( "OnSetFocus from " );
- if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
- printf( win->GetClassInfo()->GetClassName() );
- printf( " " );
- printf( WXSTRINGCAST win->GetLabel() );
- printf( ".\n" );
-*/
-
- wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() );
- event.SetEventObject( win );
-
- if (win->GetEventHandler()->ProcessEvent( event ))
- gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
-
- return TRUE;
+
+
+#if 0
+ if (win->GetName())
+ {
+ wxPrintf( wxT("OnExpose from ") );
+ if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
+ wxPrintf( win->GetClassInfo()->GetClassName() );
+ wxPrintf( wxT(" %d %d %d %d\n"), (int)gdk_event->area.x,
+ (int)gdk_event->area.y,
+ (int)gdk_event->area.width,
+ (int)gdk_event->area.height );
+ }
+
+ gtk_paint_box
+ (
+ win->m_wxwindow->style,
+ pizza->bin_window,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_OUT,
+ (GdkRectangle*) NULL,
+ win->m_wxwindow,
+ (char *)"button", // const_cast
+ 20,20,24,24
+ );
+#endif
+
+ win->GetUpdateRegion() = wxRegion( gdk_event->region );
+
+ win->GtkSendPaintEvents();
+
+ // Let parent window draw window-less widgets
+ return FALSE;
+}
}
//-----------------------------------------------------------------------------
-// "focus_out_event"
+// "key_press_event" from any window
//-----------------------------------------------------------------------------
-static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindow *win )
+// These are used when transforming Ctrl-alpha to ascii values 1-26
+inline bool wxIsLowerChar(int code)
+{
+ return (code >= 'a' && code <= 'z' );
+}
+
+inline bool wxIsUpperChar(int code)
+{
+ return (code >= 'A' && code <= 'Z' );
+}
+
+
+// set WXTRACE to this to see the key event codes on the console
+#define TRACE_KEYS _T("keyevent")
+
+// translates an X key symbol to WXK_XXX value
+//
+// if isChar is true it means that the value returned will be used for EVT_CHAR
+// event and then we choose the logical WXK_XXX, i.e. '/' for GDK_KP_Divide,
+// for example, while if it is false it means that the value is going to be
+// used for KEY_DOWN/UP events and then we translate GDK_KP_Divide to
+// WXK_NUMPAD_DIVIDE
+static long wxTranslateKeySymToWXKey(KeySym keysym, bool isChar)
+{
+ long key_code;
+
+ switch ( keysym )
+ {
+ // Shift, Control and Alt don't generate the CHAR events at all
+ case GDK_Shift_L:
+ case GDK_Shift_R:
+ key_code = isChar ? 0 : WXK_SHIFT;
+ break;
+ case GDK_Control_L:
+ case GDK_Control_R:
+ key_code = isChar ? 0 : WXK_CONTROL;
+ break;
+ case GDK_Meta_L:
+ case GDK_Meta_R:
+ case GDK_Alt_L:
+ case GDK_Alt_R:
+ case GDK_Super_L:
+ case GDK_Super_R:
+ key_code = isChar ? 0 : WXK_ALT;
+ break;
+
+ // neither do the toggle modifies
+ case GDK_Scroll_Lock:
+ key_code = isChar ? 0 : WXK_SCROLL;
+ break;
+
+ case GDK_Caps_Lock:
+ key_code = isChar ? 0 : WXK_CAPITAL;
+ break;
+
+ case GDK_Num_Lock:
+ key_code = isChar ? 0 : WXK_NUMLOCK;
+ break;
+
+
+ // various other special keys
+ case GDK_Menu:
+ key_code = WXK_MENU;
+ break;
+
+ case GDK_Help:
+ key_code = WXK_HELP;
+ break;
+
+ case GDK_BackSpace:
+ key_code = WXK_BACK;
+ break;
+
+ case GDK_ISO_Left_Tab:
+ case GDK_Tab:
+ key_code = WXK_TAB;
+ break;
+
+ case GDK_Linefeed:
+ case GDK_Return:
+ key_code = WXK_RETURN;
+ break;
+
+ case GDK_Clear:
+ key_code = WXK_CLEAR;
+ break;
+
+ case GDK_Pause:
+ key_code = WXK_PAUSE;
+ break;
+
+ case GDK_Select:
+ key_code = WXK_SELECT;
+ break;
+
+ case GDK_Print:
+ key_code = WXK_PRINT;
+ break;
+
+ case GDK_Execute:
+ key_code = WXK_EXECUTE;
+ break;
+
+ case GDK_Escape:
+ key_code = WXK_ESCAPE;
+ break;
+
+ // cursor and other extended keyboard keys
+ case GDK_Delete:
+ key_code = WXK_DELETE;
+ break;
+
+ case GDK_Home:
+ key_code = WXK_HOME;
+ break;
+
+ case GDK_Left:
+ key_code = WXK_LEFT;
+ break;
+
+ case GDK_Up:
+ key_code = WXK_UP;
+ break;
+
+ case GDK_Right:
+ key_code = WXK_RIGHT;
+ break;
+
+ case GDK_Down:
+ key_code = WXK_DOWN;
+ break;
+
+ case GDK_Prior: // == GDK_Page_Up
+ key_code = WXK_PAGEUP;
+ break;
+
+ case GDK_Next: // == GDK_Page_Down
+ key_code = WXK_PAGEDOWN;
+ break;
+
+ case GDK_End:
+ key_code = WXK_END;
+ break;
+
+ case GDK_Begin:
+ key_code = WXK_HOME;
+ break;
+
+ case GDK_Insert:
+ key_code = WXK_INSERT;
+ break;
+
+
+ // numpad keys
+ case GDK_KP_0:
+ case GDK_KP_1:
+ case GDK_KP_2:
+ case GDK_KP_3:
+ case GDK_KP_4:
+ case GDK_KP_5:
+ case GDK_KP_6:
+ case GDK_KP_7:
+ case GDK_KP_8:
+ case GDK_KP_9:
+ key_code = (isChar ? '0' : WXK_NUMPAD0) + keysym - GDK_KP_0;
+ break;
+
+ case GDK_KP_Space:
+ key_code = isChar ? ' ' : WXK_NUMPAD_SPACE;
+ break;
+
+ case GDK_KP_Tab:
+ key_code = isChar ? WXK_TAB : WXK_NUMPAD_TAB;
+ break;
+
+ case GDK_KP_Enter:
+ key_code = isChar ? WXK_RETURN : WXK_NUMPAD_ENTER;
+ break;
+
+ case GDK_KP_F1:
+ key_code = isChar ? WXK_F1 : WXK_NUMPAD_F1;
+ break;
+
+ case GDK_KP_F2:
+ key_code = isChar ? WXK_F2 : WXK_NUMPAD_F2;
+ break;
+
+ case GDK_KP_F3:
+ key_code = isChar ? WXK_F3 : WXK_NUMPAD_F3;
+ break;
+
+ case GDK_KP_F4:
+ key_code = isChar ? WXK_F4 : WXK_NUMPAD_F4;
+ break;
+
+ case GDK_KP_Home:
+ key_code = isChar ? WXK_HOME : WXK_NUMPAD_HOME;
+ break;
+
+ case GDK_KP_Left:
+ key_code = isChar ? WXK_LEFT : WXK_NUMPAD_LEFT;
+ break;
+
+ case GDK_KP_Up:
+ key_code = isChar ? WXK_UP : WXK_NUMPAD_UP;
+ break;
+
+ case GDK_KP_Right:
+ key_code = isChar ? WXK_RIGHT : WXK_NUMPAD_RIGHT;
+ break;
+
+ case GDK_KP_Down:
+ key_code = isChar ? WXK_DOWN : WXK_NUMPAD_DOWN;
+ break;
+
+ case GDK_KP_Prior: // == GDK_KP_Page_Up
+ key_code = isChar ? WXK_PAGEUP : WXK_NUMPAD_PAGEUP;
+ break;
+
+ case GDK_KP_Next: // == GDK_KP_Page_Down
+ key_code = isChar ? WXK_PAGEDOWN : WXK_NUMPAD_PAGEDOWN;
+ break;
+
+ case GDK_KP_End:
+ key_code = isChar ? WXK_END : WXK_NUMPAD_END;
+ break;
+
+ case GDK_KP_Begin:
+ key_code = isChar ? WXK_HOME : WXK_NUMPAD_BEGIN;
+ break;
+
+ case GDK_KP_Insert:
+ key_code = isChar ? WXK_INSERT : WXK_NUMPAD_INSERT;
+ break;
+
+ case GDK_KP_Delete:
+ key_code = isChar ? WXK_DELETE : WXK_NUMPAD_DELETE;
+ break;
+
+ case GDK_KP_Equal:
+ key_code = isChar ? '=' : WXK_NUMPAD_EQUAL;
+ break;
+
+ case GDK_KP_Multiply:
+ key_code = isChar ? '*' : WXK_NUMPAD_MULTIPLY;
+ break;
+
+ case GDK_KP_Add:
+ key_code = isChar ? '+' : WXK_NUMPAD_ADD;
+ break;
+
+ case GDK_KP_Separator:
+ // FIXME: what is this?
+ key_code = isChar ? '.' : WXK_NUMPAD_SEPARATOR;
+ break;
+
+ case GDK_KP_Subtract:
+ key_code = isChar ? '-' : WXK_NUMPAD_SUBTRACT;
+ break;
+
+ case GDK_KP_Decimal:
+ key_code = isChar ? '.' : WXK_NUMPAD_DECIMAL;
+ break;
+
+ case GDK_KP_Divide:
+ key_code = isChar ? '/' : WXK_NUMPAD_DIVIDE;
+ break;
+
+
+ // function keys
+ case GDK_F1:
+ case GDK_F2:
+ case GDK_F3:
+ case GDK_F4:
+ case GDK_F5:
+ case GDK_F6:
+ case GDK_F7:
+ case GDK_F8:
+ case GDK_F9:
+ case GDK_F10:
+ case GDK_F11:
+ case GDK_F12:
+ key_code = WXK_F1 + keysym - GDK_F1;
+ break;
+
+ default:
+ key_code = 0;
+ }
+
+ return key_code;
+}
+
+static inline bool wxIsAsciiKeysym(KeySym ks)
+{
+ return ks < 256;
+}
+
+static void wxFillOtherKeyEventFields(wxKeyEvent& event,
+ wxWindowGTK *win,
+ GdkEventKey *gdk_event)
+{
+ int x = 0;
+ int y = 0;
+ GdkModifierType state;
+ if (gdk_event->window)
+ gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
+
+ event.SetTimestamp( gdk_event->time );
+ event.SetId(win->GetId());
+ event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK) != 0;
+ event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK) != 0;
+ event.m_altDown = (gdk_event->state & GDK_MOD1_MASK) != 0;
+ event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK) != 0;
+ event.m_scanCode = gdk_event->keyval;
+ event.m_rawCode = (wxUint32) gdk_event->keyval;
+ event.m_rawFlags = 0;
+#if wxUSE_UNICODE
+ event.m_uniChar = gdk_keyval_to_unicode(gdk_event->keyval);
+#endif
+ wxGetMousePosition( &x, &y );
+ win->ScreenToClient( &x, &y );
+ event.m_x = x;
+ event.m_y = y;
+ event.SetEventObject( win );
+}
+
+
+static bool
+wxTranslateGTKKeyEventToWx(wxKeyEvent& event,
+ wxWindowGTK *win,
+ GdkEventKey *gdk_event)
+{
+ // VZ: it seems that GDK_KEY_RELEASE event doesn't set event->string
+ // but only event->keyval which is quite useless to us, so remember
+ // the last character from GDK_KEY_PRESS and reuse it as last resort
+ //
+ // NB: should be MT-safe as we're always called from the main thread only
+ static struct
+ {
+ KeySym keysym;
+ long keycode;
+ } s_lastKeyPress = { 0, 0 };
+
+ KeySym keysym = gdk_event->keyval;
+
+ wxLogTrace(TRACE_KEYS, _T("Key %s event: keysym = %ld"),
+ event.GetEventType() == wxEVT_KEY_UP ? _T("release")
+ : _T("press"),
+ keysym);
+
+ long key_code = wxTranslateKeySymToWXKey(keysym, false /* !isChar */);
+
+ if ( !key_code )
+ {
+ // do we have the translation or is it a plain ASCII character?
+ if ( (gdk_event->length == 1) || wxIsAsciiKeysym(keysym) )
+ {
+ // we should use keysym if it is ASCII as X does some translations
+ // like "I pressed while Control is down" => "Ctrl-I" == "TAB"
+ // which we don't want here (but which we do use for OnChar())
+ if ( !wxIsAsciiKeysym(keysym) )
+ {
+ keysym = (KeySym)gdk_event->string[0];
+ }
+
+ // we want to always get the same key code when the same key is
+ // pressed regardless of the state of the modifiers, i.e. on a
+ // standard US keyboard pressing '5' or '%' ('5' key with
+ // Shift) should result in the same key code in OnKeyDown():
+ // '5' (although OnChar() will get either '5' or '%').
+ //
+ // to do it we first translate keysym to keycode (== scan code)
+ // and then back but always using the lower register
+ Display *dpy = (Display *)wxGetDisplay();
+ KeyCode keycode = XKeysymToKeycode(dpy, keysym);
+
+ wxLogTrace(TRACE_KEYS, _T("\t-> keycode %d"), keycode);
+
+ KeySym keysymNormalized = XKeycodeToKeysym(dpy, keycode, 0);
+
+ // use the normalized, i.e. lower register, keysym if we've
+ // got one
+ key_code = keysymNormalized ? keysymNormalized : keysym;
+
+ // as explained above, we want to have lower register key codes
+ // normally but for the letter keys we want to have the upper ones
+ //
+ // NB: don't use XConvertCase() here, we want to do it for letters
+ // only
+ key_code = toupper(key_code);
+ }
+ else // non ASCII key, what to do?
+ {
+ // by default, ignore it
+ key_code = 0;
+
+ // but if we have cached information from the last KEY_PRESS
+ if ( gdk_event->type == GDK_KEY_RELEASE )
+ {
+ // then reuse it
+ if ( keysym == s_lastKeyPress.keysym )
+ {
+ key_code = s_lastKeyPress.keycode;
+ }
+ }
+ }
+
+ if ( gdk_event->type == GDK_KEY_PRESS )
+ {
+ // remember it to be reused for KEY_UP event later
+ s_lastKeyPress.keysym = keysym;
+ s_lastKeyPress.keycode = key_code;
+ }
+ }
+
+ wxLogTrace(TRACE_KEYS, _T("\t-> wxKeyCode %ld"), key_code);
+
+ // sending unknown key events doesn't really make sense
+ if ( !key_code )
+ return false;
+
+ // now fill all the other fields
+ wxFillOtherKeyEventFields(event, win, gdk_event);
+
+ event.m_keyCode = key_code;
+#if wxUSE_UNICODE
+ if ( gdk_event->type == GDK_KEY_PRESS || gdk_event->type == GDK_KEY_RELEASE )
+ {
+ event.m_uniChar = key_code;
+ }
+#endif
+
+ return true;
+}
+
+
+struct wxGtkIMData
+{
+ GtkIMContext *context;
+ GdkEventKey *lastKeyEvent;
+
+ wxGtkIMData()
+ {
+ context = gtk_im_multicontext_new();
+ lastKeyEvent = NULL;
+ }
+ ~wxGtkIMData()
+ {
+ g_object_unref (context);
+ }
+};
+
+extern "C" {
+static gboolean
+gtk_window_key_press_callback( GtkWidget *widget,
+ GdkEventKey *gdk_event,
+ wxWindow *win )
+{
+ DEBUG_MAIN_THREAD
+
+ if (!win->m_hasVMT)
+ return FALSE;
+ if (g_blockEventsOnDrag)
+ return FALSE;
+
+
+ wxKeyEvent event( wxEVT_KEY_DOWN );
+ bool ret = false;
+ bool return_after_IM = false;
+
+ if( wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
+ {
+ // Emit KEY_DOWN event
+ ret = win->GetEventHandler()->ProcessEvent( event );
+ }
+ else
+ {
+ // Return after IM processing as we cannot do
+ // anything with it anyhow.
+ return_after_IM = true;
+ }
+
+ // 2005.01.26 modified by Hong Jen Yee (hzysoft@sina.com.tw):
+ // When we get a key_press event here, it could be originate
+ // from the current widget or its child widgets. However, only the widget
+ // with the INPUT FOCUS can generate the INITIAL key_press event. That is,
+ // if the CURRENT widget doesn't have the FOCUS at all, this event definitely
+ // originated from its child widgets and shouldn't be passed to IM context.
+ // In fact, what a GTK+ IM should do is filtering keyEvents and convert them
+ // into text input ONLY WHEN THE WIDGET HAS INPUT FOCUS. Besides, when current
+ // widgets has both IM context and input focus, the event should be filtered
+ // by gtk_im_context_filter_keypress().
+ // Then, we should, according to GTK+ 2.0 API doc, return whatever it returns.
+ if ((!ret) && (win->m_imData != NULL) && ( wxWindow::FindFocus() == win ))
+ {
+ // We should let GTK+ IM filter key event first. According to GTK+ 2.0 API
+ // docs, if IM filter returns true, no further processing should be done.
+ // we should send the key_down event anyway.
+ bool intercepted_by_IM = gtk_im_context_filter_keypress(win->m_imData->context, gdk_event);
+ win->m_imData->lastKeyEvent = NULL;
+ if (intercepted_by_IM)
+ {
+ wxLogTrace(TRACE_KEYS, _T("Key event intercepted by IM"));
+ return TRUE;
+ }
+ }
+
+ if (return_after_IM)
+ return FALSE;
+
+#if wxUSE_ACCEL
+ if (!ret)
+ {
+ wxWindowGTK *ancestor = win;
+ while (ancestor)
+ {
+ int command = ancestor->GetAcceleratorTable()->GetCommand( event );
+ if (command != -1)
+ {
+ wxCommandEvent command_event( wxEVT_COMMAND_MENU_SELECTED, command );
+ ret = ancestor->GetEventHandler()->ProcessEvent( command_event );
+ break;
+ }
+ if (ancestor->IsTopLevel())
+ break;
+ ancestor = ancestor->GetParent();
+ }
+ }
+#endif // wxUSE_ACCEL
+
+ // Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
+ // will only be sent if it is not in an accelerator table.
+ if (!ret)
+ {
+ long key_code;
+ KeySym keysym = gdk_event->keyval;
+ // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
+ key_code = wxTranslateKeySymToWXKey(keysym, true /* isChar */);
+ if ( !key_code )
+ {
+ if ( wxIsAsciiKeysym(keysym) )
+ {
+ // ASCII key
+ key_code = (unsigned char)keysym;
+ }
+ // gdk_event->string is actually deprecated
+ else if ( gdk_event->length == 1 )
+ {
+ key_code = (unsigned char)gdk_event->string[0];
+ }
+ }
+
+ if ( key_code )
+ {
+ wxLogTrace(TRACE_KEYS, _T("Char event: %ld"), key_code);
+
+ event.m_keyCode = key_code;
+
+ // To conform to the docs we need to translate Ctrl-alpha
+ // characters to values in the range 1-26.
+ if ( event.ControlDown() &&
+ ( wxIsLowerChar(key_code) || wxIsUpperChar(key_code) ))
+ {
+ if ( wxIsLowerChar(key_code) )
+ event.m_keyCode = key_code - 'a' + 1;
+ if ( wxIsUpperChar(key_code) )
+ event.m_keyCode = key_code - 'A' + 1;
+#if wxUSE_UNICODE
+ event.m_uniChar = event.m_keyCode;
+#endif
+ }
+
+ // Implement OnCharHook by checking ancestor top level windows
+ wxWindow *parent = win;
+ while (parent && !parent->IsTopLevel())
+ parent = parent->GetParent();
+ if (parent)
+ {
+ event.SetEventType( wxEVT_CHAR_HOOK );
+ ret = parent->GetEventHandler()->ProcessEvent( event );
+ }
+
+ if (!ret)
+ {
+ event.SetEventType(wxEVT_CHAR);
+ ret = win->GetEventHandler()->ProcessEvent( event );
+ }
+ }
+ }
+
+ return ret;
+}
+}
+
+extern "C" {
+static void
+gtk_wxwindow_commit_cb (GtkIMContext *context,
+ const gchar *str,
+ wxWindow *window)
+{
+ wxKeyEvent event( wxEVT_KEY_DOWN );
+
+ // take modifiers, cursor position, timestamp etc. from the last
+ // key_press_event that was fed into Input Method:
+ if (window->m_imData->lastKeyEvent)
+ {
+ wxFillOtherKeyEventFields(event,
+ window, window->m_imData->lastKeyEvent);
+ }
+
+ const wxWxCharBuffer data(wxGTK_CONV_BACK_SYS(str));
+ if( !data )
+ return;
+
+ bool ret = false;
+
+ // Implement OnCharHook by checking ancestor top level windows
+ wxWindow *parent = window;
+ while (parent && !parent->IsTopLevel())
+ parent = parent->GetParent();
+
+ for( const wxChar* pstr = data; *pstr; pstr++ )
+ {
+#if wxUSE_UNICODE
+ event.m_uniChar = *pstr;
+ // Backward compatible for ISO-8859-1
+ event.m_keyCode = *pstr < 256 ? event.m_uniChar : 0;
+ wxLogTrace(TRACE_KEYS, _T("IM sent character '%c'"), event.m_uniChar);
+#else
+ event.m_keyCode = *pstr;
+#endif // wxUSE_UNICODE
+
+ // To conform to the docs we need to translate Ctrl-alpha
+ // characters to values in the range 1-26.
+ if ( event.ControlDown() &&
+ ( wxIsLowerChar(*pstr) || wxIsUpperChar(*pstr) ))
+ {
+ if ( wxIsLowerChar(*pstr) )
+ event.m_keyCode = *pstr - 'a' + 1;
+ if ( wxIsUpperChar(*pstr) )
+ event.m_keyCode = *pstr - 'A' + 1;
+
+ event.m_keyCode = *pstr - 'a' + 1;
+#if wxUSE_UNICODE
+ event.m_uniChar = event.m_keyCode;
+#endif
+ }
+
+ if (parent)
+ {
+ event.SetEventType( wxEVT_CHAR_HOOK );
+ ret = parent->GetEventHandler()->ProcessEvent( event );
+ }
+
+ if (!ret)
+ {
+ event.SetEventType(wxEVT_CHAR);
+ ret = window->GetEventHandler()->ProcessEvent( event );
+ }
+ }
+}
+}
+
+
+//-----------------------------------------------------------------------------
+// "key_release_event" from any window
+//-----------------------------------------------------------------------------
+
+extern "C" {
+static gboolean
+gtk_window_key_release_callback( GtkWidget *widget,
+ GdkEventKey *gdk_event,
+ wxWindowGTK *win )
+{
+ DEBUG_MAIN_THREAD
+
+ if (!win->m_hasVMT)
+ return FALSE;
+
+ if (g_blockEventsOnDrag)
+ return FALSE;
+
+ wxKeyEvent event( wxEVT_KEY_UP );
+ if ( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
+ {
+ // unknown key pressed, ignore (the event would be useless anyhow)
+ return FALSE;
+ }
+
+ return win->GTKProcessEvent(event);
+}
+}
+
+// ============================================================================
+// the mouse events
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// mouse event processing helpers
+// ----------------------------------------------------------------------------
+
+// init wxMouseEvent with the info from GdkEventXXX struct
+template<typename T> void InitMouseEvent(wxWindowGTK *win,
+ wxMouseEvent& event,
+ T *gdk_event)
+{
+ event.SetTimestamp( gdk_event->time );
+ event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
+ event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
+ event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
+ event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
+ event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
+ event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
+ event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
+ if (event.GetEventType() == wxEVT_MOUSEWHEEL)
+ {
+ event.m_linesPerAction = 3;
+ event.m_wheelDelta = 120;
+ if (((GdkEventButton*)gdk_event)->button == 4)
+ event.m_wheelRotation = 120;
+ else if (((GdkEventButton*)gdk_event)->button == 5)
+ event.m_wheelRotation = -120;
+ }
+
+ wxPoint pt = win->GetClientAreaOrigin();
+ event.m_x = (wxCoord)gdk_event->x - pt.x;
+ event.m_y = (wxCoord)gdk_event->y - pt.y;
+
+ if ((win->m_wxwindow) && (win->GetLayoutDirection() == wxLayout_RightToLeft))
+ {
+ // origin in the upper right corner
+ int window_width = gtk_pizza_get_rtl_offset( GTK_PIZZA(win->m_wxwindow) );
+ event.m_x = window_width - event.m_x;
+ }
+
+ event.SetEventObject( win );
+ event.SetId( win->GetId() );
+ event.SetTimestamp( gdk_event->time );
+}
+
+static void AdjustEventButtonState(wxMouseEvent& event)
+{
+ // GDK reports the old state of the button for a button press event, but
+ // for compatibility with MSW and common sense we want m_leftDown be TRUE
+ // for a LEFT_DOWN event, not FALSE, so we will invert
+ // left/right/middleDown for the corresponding click events
+
+ if ((event.GetEventType() == wxEVT_LEFT_DOWN) ||
+ (event.GetEventType() == wxEVT_LEFT_DCLICK) ||
+ (event.GetEventType() == wxEVT_LEFT_UP))
+ {
+ event.m_leftDown = !event.m_leftDown;
+ return;
+ }
+
+ if ((event.GetEventType() == wxEVT_MIDDLE_DOWN) ||
+ (event.GetEventType() == wxEVT_MIDDLE_DCLICK) ||
+ (event.GetEventType() == wxEVT_MIDDLE_UP))
+ {
+ event.m_middleDown = !event.m_middleDown;
+ return;
+ }
+
+ if ((event.GetEventType() == wxEVT_RIGHT_DOWN) ||
+ (event.GetEventType() == wxEVT_RIGHT_DCLICK) ||
+ (event.GetEventType() == wxEVT_RIGHT_UP))
+ {
+ event.m_rightDown = !event.m_rightDown;
+ return;
+ }
+}
+
+// find the window to send the mouse event too
+static
+wxWindowGTK *FindWindowForMouseEvent(wxWindowGTK *win, wxCoord& x, wxCoord& y)
+{
+ wxCoord xx = x;
+ wxCoord yy = y;
+
+ if (win->m_wxwindow)
+ {
+ GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
+ xx += gtk_pizza_get_xoffset( pizza );
+ yy += gtk_pizza_get_yoffset( pizza );
+ }
+
+ wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
+ while (node)
+ {
+ wxWindowGTK *child = node->GetData();
+
+ node = node->GetNext();
+ if (!child->IsShown())
+ continue;
+
+ if (child->IsTransparentForMouse())
+ {
+ // wxStaticBox is transparent in the box itself
+ int xx1 = child->m_x;
+ int yy1 = child->m_y;
+ int xx2 = child->m_x + child->m_width;
+ int yy2 = child->m_y + child->m_height;
+
+ // left
+ if (((xx >= xx1) && (xx <= xx1+10) && (yy >= yy1) && (yy <= yy2)) ||
+ // right
+ ((xx >= xx2-10) && (xx <= xx2) && (yy >= yy1) && (yy <= yy2)) ||
+ // top
+ ((xx >= xx1) && (xx <= xx2) && (yy >= yy1) && (yy <= yy1+10)) ||
+ // bottom
+ ((xx >= xx1) && (xx <= xx2) && (yy >= yy2-1) && (yy <= yy2)))
+ {
+ win = child;
+ x -= child->m_x;
+ y -= child->m_y;
+ break;
+ }
+
+ }
+ else
+ {
+ if ((child->m_wxwindow == (GtkWidget*) NULL) &&
+ (child->m_x <= xx) &&
+ (child->m_y <= yy) &&
+ (child->m_x+child->m_width >= xx) &&
+ (child->m_y+child->m_height >= yy))
+ {
+ win = child;
+ x -= child->m_x;
+ y -= child->m_y;
+ break;
+ }
+ }
+ }
+
+ return win;
+}
+
+// ----------------------------------------------------------------------------
+// common event handlers helpers
+// ----------------------------------------------------------------------------
+
+bool wxWindowGTK::GTKProcessEvent(wxEvent& event) const
+{
+ // nothing special at this level
+ return GetEventHandler()->ProcessEvent(event);
+}
+
+int wxWindowGTK::GTKCallbackCommonPrologue(GdkEventAny *event) const
+{
+ DEBUG_MAIN_THREAD
+
+ if (!m_hasVMT)
+ return FALSE;
+ if (g_blockEventsOnDrag)
+ return TRUE;
+ if (g_blockEventsOnScroll)
+ return TRUE;
+
+ if (!GTKIsOwnWindow(event->window))
+ return FALSE;
+
+ return -1;
+}
+
+// overloads for all GDK event types we use here: we need to have this as
+// GdkEventXXX can't be implicitly cast to GdkEventAny even if it, in fact,
+// derives from it in the sense that the structs have the same layout
+#define wxDEFINE_COMMON_PROLOGUE_OVERLOAD(T) \
+ static int wxGtkCallbackCommonPrologue(T *event, wxWindowGTK *win) \
+ { \
+ return win->GTKCallbackCommonPrologue((GdkEventAny *)event); \
+ }
+
+wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventButton)
+wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventMotion)
+wxDEFINE_COMMON_PROLOGUE_OVERLOAD(GdkEventCrossing)
+
+#undef wxDEFINE_COMMON_PROLOGUE_OVERLOAD
+
+#define wxCOMMON_CALLBACK_PROLOGUE(event, win) \
+ const int rc = wxGtkCallbackCommonPrologue(event, win); \
+ if ( rc != -1 ) \
+ return rc
+
+// send the wxChildFocusEvent and wxFocusEvent, common code of
+// gtk_window_focus_in_callback() and SetFocus()
+static bool DoSendFocusEvents(wxWindow *win)
+{
+ // Notify the parent keeping track of focus for the kbd navigation
+ // purposes that we got it.
+ wxChildFocusEvent eventChildFocus(win);
+ (void)win->GetEventHandler()->ProcessEvent(eventChildFocus);
+
+ wxFocusEvent eventFocus(wxEVT_SET_FOCUS, win->GetId());
+ eventFocus.SetEventObject(win);
+
+ return win->GetEventHandler()->ProcessEvent(eventFocus);
+}
+
+// all event handlers must have C linkage as they're called from GTK+ C code
+extern "C"
+{
+
+//-----------------------------------------------------------------------------
+// "button_press_event"
+//-----------------------------------------------------------------------------
+
+static gboolean
+gtk_window_button_press_callback( GtkWidget *widget,
+ GdkEventButton *gdk_event,
+ wxWindowGTK *win )
+{
+ wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
+
+ g_lastButtonNumber = gdk_event->button;
+
+ if (win->m_wxwindow && (g_focusWindow != win) && win->CanAcceptFocus())
+ {
+ gtk_widget_grab_focus( win->m_wxwindow );
+ }
+
+ // GDK sends surplus button down events
+ // before a double click event. We
+ // need to filter these out.
+ if ((gdk_event->type == GDK_BUTTON_PRESS) && (win->m_wxwindow))
+ {
+ GdkEvent *peek_event = gdk_event_peek();
+ if (peek_event)
+ {
+ if ((peek_event->type == GDK_2BUTTON_PRESS) ||
+ (peek_event->type == GDK_3BUTTON_PRESS))
+ {
+ gdk_event_free( peek_event );
+ return TRUE;
+ }
+ else
+ {
+ gdk_event_free( peek_event );
+ }
+ }
+ }
+
+ wxEventType event_type = wxEVT_NULL;
+
+ // GdkDisplay is a GTK+ 2.2.0 thing
+#if defined(__WXGTK20__) && GTK_CHECK_VERSION(2, 2, 0)
+ if ( gdk_event->type == GDK_2BUTTON_PRESS &&
+ !gtk_check_version(2,2,0) &&
+ gdk_event->button >= 1 && gdk_event->button <= 3 )
+ {
+ // Reset GDK internal timestamp variables in order to disable GDK
+ // triple click events. GDK will then next time believe no button has
+ // been clicked just before, and send a normal button click event.
+ GdkDisplay* display = gtk_widget_get_display (widget);
+ display->button_click_time[1] = 0;
+ display->button_click_time[0] = 0;
+ }
+#endif // GTK 2+
+
+ if (gdk_event->button == 1)
+ {
+ // note that GDK generates triple click events which are not supported
+ // by wxWidgets but still have to be passed to the app as otherwise
+ // clicks would simply go missing
+ switch (gdk_event->type)
+ {
+ // we shouldn't get triple clicks at all for GTK2 because we
+ // suppress them artificially using the code above but we still
+ // should map them to something for GTK1 and not just ignore them
+ // as this would lose clicks
+ case GDK_3BUTTON_PRESS: // we could also map this to DCLICK...
+ case GDK_BUTTON_PRESS:
+ event_type = wxEVT_LEFT_DOWN;
+ break;
+
+ case GDK_2BUTTON_PRESS:
+ event_type = wxEVT_LEFT_DCLICK;
+ break;
+
+ default:
+ // just to silence gcc warnings
+ ;
+ }
+ }
+ else if (gdk_event->button == 2)
+ {
+ switch (gdk_event->type)
+ {
+ case GDK_3BUTTON_PRESS:
+ case GDK_BUTTON_PRESS:
+ event_type = wxEVT_MIDDLE_DOWN;
+ break;
+
+ case GDK_2BUTTON_PRESS:
+ event_type = wxEVT_MIDDLE_DCLICK;
+ break;
+
+ default:
+ ;
+ }
+ }
+ else if (gdk_event->button == 3)
+ {
+ switch (gdk_event->type)
+ {
+ case GDK_3BUTTON_PRESS:
+ case GDK_BUTTON_PRESS:
+ event_type = wxEVT_RIGHT_DOWN;
+ break;
+
+ case GDK_2BUTTON_PRESS:
+ event_type = wxEVT_RIGHT_DCLICK;
+ break;
+
+ default:
+ ;
+ }
+ }
+ else if (gdk_event->button == 4 || gdk_event->button == 5)
+ {
+ if (gdk_event->type == GDK_BUTTON_PRESS )
+ {
+ event_type = wxEVT_MOUSEWHEEL;
+ }
+ }
+
+ if ( event_type == wxEVT_NULL )
+ {
+ // unknown mouse button or click type
+ return FALSE;
+ }
+
+ g_lastMouseEvent = (GdkEvent*) gdk_event;
+
+ wxMouseEvent event( event_type );
+ InitMouseEvent( win, event, gdk_event );
+
+ AdjustEventButtonState(event);
+
+ // wxListBox actually gets mouse events from the item, so we need to give it
+ // a chance to correct this
+ win->FixUpMouseEvent(widget, event.m_x, event.m_y);
+
+ // find the correct window to send the event to: it may be a different one
+ // from the one which got it at GTK+ level because some controls don't have
+ // their own X window and thus cannot get any events.
+ if ( !g_captureWindow )
+ win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
+
+ // reset the event object and id in case win changed.
+ event.SetEventObject( win );
+ event.SetId( win->GetId() );
+
+ bool ret = win->GTKProcessEvent( event );
+ g_lastMouseEvent = NULL;
+ if ( ret )
+ return TRUE;
+
+ if ((event_type == wxEVT_LEFT_DOWN) && !win->IsOfStandardClass() &&
+ (g_focusWindow != win) && win->CanAcceptFocus())
+ {
+ gtk_widget_grab_focus( win->m_wxwindow );
+ }
+
+ if (event_type == wxEVT_RIGHT_DOWN)
+ {
+ // generate a "context menu" event: this is similar to right mouse
+ // click under many GUIs except that it is generated differently
+ // (right up under MSW, ctrl-click under Mac, right down here) and
+ //
+ // (a) it's a command event and so is propagated to the parent
+ // (b) under some ports it can be generated from kbd too
+ // (c) it uses screen coords (because of (a))
+ wxContextMenuEvent evtCtx(
+ wxEVT_CONTEXT_MENU,
+ win->GetId(),
+ win->ClientToScreen(event.GetPosition()));
+ evtCtx.SetEventObject(win);
+ return win->GTKProcessEvent(evtCtx);
+ }
+
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// "button_release_event"
+//-----------------------------------------------------------------------------
+
+static gboolean
+gtk_window_button_release_callback( GtkWidget *widget,
+ GdkEventButton *gdk_event,
+ wxWindowGTK *win )
+{
+ wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
+
+ g_lastButtonNumber = 0;
+
+ wxEventType event_type = wxEVT_NULL;
+
+ switch (gdk_event->button)
+ {
+ case 1:
+ event_type = wxEVT_LEFT_UP;
+ break;
+
+ case 2:
+ event_type = wxEVT_MIDDLE_UP;
+ break;
+
+ case 3:
+ event_type = wxEVT_RIGHT_UP;
+ break;
+
+ default:
+ // unknown button, don't process
+ return FALSE;
+ }
+
+ g_lastMouseEvent = (GdkEvent*) gdk_event;
+
+ wxMouseEvent event( event_type );
+ InitMouseEvent( win, event, gdk_event );
+
+ AdjustEventButtonState(event);
+
+ // same wxListBox hack as above
+ win->FixUpMouseEvent(widget, event.m_x, event.m_y);
+
+ if ( !g_captureWindow )
+ win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
+
+ // reset the event object and id in case win changed.
+ event.SetEventObject( win );
+ event.SetId( win->GetId() );
+
+ bool ret = win->GTKProcessEvent(event);
+
+ g_lastMouseEvent = NULL;
+
+ return ret;
+}
+
+//-----------------------------------------------------------------------------
+// "motion_notify_event"
+//-----------------------------------------------------------------------------
+
+static gboolean
+gtk_window_motion_notify_callback( GtkWidget *widget,
+ GdkEventMotion *gdk_event,
+ wxWindowGTK *win )
+{
+ wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
+
+ if (gdk_event->is_hint)
+ {
+ int x = 0;
+ int y = 0;
+ GdkModifierType state;
+ gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
+ gdk_event->x = x;
+ gdk_event->y = y;
+ }
+
+ g_lastMouseEvent = (GdkEvent*) gdk_event;
+
+ wxMouseEvent event( wxEVT_MOTION );
+ InitMouseEvent(win, event, gdk_event);
+
+ if ( g_captureWindow )
+ {
+ // synthesise a mouse enter or leave event if needed
+ GdkWindow *winUnderMouse = gdk_window_at_pointer(NULL, NULL);
+ // This seems to be necessary and actually been added to
+ // GDK itself in version 2.0.X
+ gdk_flush();
+
+ bool hasMouse = winUnderMouse == gdk_event->window;
+ if ( hasMouse != g_captureWindowHasMouse )
+ {
+ // the mouse changed window
+ g_captureWindowHasMouse = hasMouse;
+
+ wxMouseEvent eventM(g_captureWindowHasMouse ? wxEVT_ENTER_WINDOW
+ : wxEVT_LEAVE_WINDOW);
+ InitMouseEvent(win, eventM, gdk_event);
+ eventM.SetEventObject(win);
+ win->GTKProcessEvent(eventM);
+ }
+ }
+ else // no capture
+ {
+ win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
+
+ // reset the event object and id in case win changed.
+ event.SetEventObject( win );
+ event.SetId( win->GetId() );
+ }
+
+ if ( !g_captureWindow )
+ {
+ wxSetCursorEvent cevent( event.m_x, event.m_y );
+ if (win->GTKProcessEvent( cevent ))
+ {
+ win->SetCursor( cevent.GetCursor() );
+ }
+ }
+
+ bool ret = win->GTKProcessEvent(event);
+
+ g_lastMouseEvent = NULL;
+
+ return ret;
+}
+
+//-----------------------------------------------------------------------------
+// "scroll_event", (mouse wheel event)
+//-----------------------------------------------------------------------------
+
+static gboolean
+window_scroll_event(GtkWidget*, GdkEventScroll* gdk_event, wxWindow* win)
+{
+ DEBUG_MAIN_THREAD
+
+ if (gdk_event->direction != GDK_SCROLL_UP &&
+ gdk_event->direction != GDK_SCROLL_DOWN)
+ {
+ return false;
+ }
+
+ wxMouseEvent event(wxEVT_MOUSEWHEEL);
+ // Can't use InitMouse macro because scroll events don't have button
+ event.SetTimestamp( gdk_event->time );
+ event.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
+ event.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
+ event.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
+ event.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
+ event.m_leftDown = (gdk_event->state & GDK_BUTTON1_MASK);
+ event.m_middleDown = (gdk_event->state & GDK_BUTTON2_MASK);
+ event.m_rightDown = (gdk_event->state & GDK_BUTTON3_MASK);
+ event.m_linesPerAction = 3;
+ event.m_wheelDelta = 120;
+ if (gdk_event->direction == GDK_SCROLL_UP)
+ event.m_wheelRotation = 120;
+ else
+ event.m_wheelRotation = -120;
+
+ wxPoint pt = win->GetClientAreaOrigin();
+ event.m_x = (wxCoord)gdk_event->x - pt.x;
+ event.m_y = (wxCoord)gdk_event->y - pt.y;
+
+ event.SetEventObject( win );
+ event.SetId( win->GetId() );
+ event.SetTimestamp( gdk_event->time );
+
+ return win->GTKProcessEvent(event);
+}
+
+//-----------------------------------------------------------------------------
+// "popup-menu"
+//-----------------------------------------------------------------------------
+
+static gboolean wxgtk_window_popup_menu_callback(GtkWidget*, wxWindowGTK* win)
+{
+ wxContextMenuEvent event(wxEVT_CONTEXT_MENU, win->GetId(), wxPoint(-1, -1));
+ event.SetEventObject(win);
+ return win->GTKProcessEvent(event);
+}
+
+//-----------------------------------------------------------------------------
+// "focus_in_event"
+//-----------------------------------------------------------------------------
+
+static gboolean
+gtk_window_focus_in_callback( GtkWidget *widget,
+ GdkEventFocus *WXUNUSED(event),
+ wxWindow *win )
+{
+ DEBUG_MAIN_THREAD
+
+ if (win->m_imData)
+ gtk_im_context_focus_in(win->m_imData->context);
+
+ g_focusWindowLast =
+ g_focusWindow = win;
+
+ wxLogTrace(TRACE_FOCUS,
+ _T("%s: focus in"), win->GetName().c_str());
+
+#if wxUSE_CARET
+ // caret needs to be informed about focus change
+ wxCaret *caret = win->GetCaret();
+ if ( caret )
+ {
+ caret->OnSetFocus();
+ }
+#endif // wxUSE_CARET
+
+ gboolean ret = FALSE;
+
+ // does the window itself think that it has the focus?
+ if ( !win->m_hasFocus )
+ {
+ // not yet, notify it
+ win->m_hasFocus = true;
+
+ (void)DoSendFocusEvents(win);
+
+ ret = TRUE;
+ }
+
+ // Disable default focus handling for custom windows
+ // since the default GTK+ handler issues a repaint
+ if (win->m_wxwindow)
+ return ret;
+
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// "focus_out_event"
+//-----------------------------------------------------------------------------
+
+static gboolean
+gtk_window_focus_out_callback( GtkWidget *widget,
+ GdkEventFocus *gdk_event,
+ wxWindowGTK *win )
+{
+ DEBUG_MAIN_THREAD
+
+ if (win->m_imData)
+ gtk_im_context_focus_out(win->m_imData->context);
+
+ wxLogTrace( TRACE_FOCUS,
+ _T("%s: focus out"), win->GetName().c_str() );
+
+
+ wxWindowGTK *winFocus = wxFindFocusedChild(win);
+ if ( winFocus )
+ win = winFocus;
+
+ g_focusWindow = (wxWindowGTK *)NULL;
+
+#if wxUSE_CARET
+ // caret needs to be informed about focus change
+ wxCaret *caret = win->GetCaret();
+ if ( caret )
+ {
+ caret->OnKillFocus();
+ }
+#endif // wxUSE_CARET
+
+ // don't send the window a kill focus event if it thinks that it doesn't
+ // have focus already
+ if ( win->m_hasFocus )
+ {
+ // the event handler might delete the window when it loses focus, so
+ // check whether this is a custom window before calling it
+ const bool has_wxwindow = win->m_wxwindow != NULL;
+
+ win->m_hasFocus = false;
+
+ wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
+ event.SetEventObject( win );
+
+ (void)win->GTKProcessEvent( event );
+
+ // Disable default focus handling for custom windows
+ // since the default GTK+ handler issues a repaint
+ if ( has_wxwindow )
+ return TRUE;
+ }
+
+ // continue with normal processing
+ return FALSE;
+}
+
+static gboolean
+wx_window_focus_callback(GtkWidget *widget,
+ GtkDirectionType direction,
+ wxWindowGTK *win)
+{
+ // the default handler for focus signal in GtkPizza (or, rather, in
+ // GtkScrolledWindow from which GtkPizza inherits this behaviour) sets
+ // focus to the window itself even if it doesn't accept focus, i.e. has no
+ // GTK_CAN_FOCUS in its style -- work around this by forcibly preventing
+ // the signal from reaching gtk_scrolled_window_focus() if we don't have
+ // any children which might accept focus (we know we don't accept the focus
+ // ourselves as this signal is only connected in this case)
+ if ( win->GetChildren().empty() )
+ g_signal_stop_emission_by_name(widget, "focus");
+
+ // we didn't change the focus
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// "enter_notify_event"
+//-----------------------------------------------------------------------------
+
+static gboolean
+gtk_window_enter_callback( GtkWidget *widget,
+ GdkEventCrossing *gdk_event,
+ wxWindowGTK *win )
+{
+ wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
+
+ // Event was emitted after a grab
+ if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
+
+ int x = 0;
+ int y = 0;
+ GdkModifierType state = (GdkModifierType)0;
+
+ gdk_window_get_pointer( widget->window, &x, &y, &state );
+
+ wxMouseEvent event( wxEVT_ENTER_WINDOW );
+ InitMouseEvent(win, event, gdk_event);
+ wxPoint pt = win->GetClientAreaOrigin();
+ event.m_x = x + pt.x;
+ event.m_y = y + pt.y;
+
+ if ( !g_captureWindow )
+ {
+ wxSetCursorEvent cevent( event.m_x, event.m_y );
+ if (win->GTKProcessEvent( cevent ))
+ {
+ win->SetCursor( cevent.GetCursor() );
+ }
+ }
+
+ return win->GTKProcessEvent(event);
+}
+
+//-----------------------------------------------------------------------------
+// "leave_notify_event"
+//-----------------------------------------------------------------------------
+
+static gboolean
+gtk_window_leave_callback( GtkWidget *widget,
+ GdkEventCrossing *gdk_event,
+ wxWindowGTK *win )
+{
+ wxCOMMON_CALLBACK_PROLOGUE(gdk_event, win);
+
+ // Event was emitted after an ungrab
+ if (gdk_event->mode != GDK_CROSSING_NORMAL) return FALSE;
+
+ wxMouseEvent event( wxEVT_LEAVE_WINDOW );
+ event.SetTimestamp( gdk_event->time );
+ event.SetEventObject( win );
+
+ int x = 0;
+ int y = 0;
+ GdkModifierType state = (GdkModifierType)0;
+
+ gdk_window_get_pointer( widget->window, &x, &y, &state );
+
+ event.m_shiftDown = (state & GDK_SHIFT_MASK) != 0;
+ event.m_controlDown = (state & GDK_CONTROL_MASK) != 0;
+ event.m_altDown = (state & GDK_MOD1_MASK) != 0;
+ event.m_metaDown = (state & GDK_MOD2_MASK) != 0;
+ event.m_leftDown = (state & GDK_BUTTON1_MASK) != 0;
+ event.m_middleDown = (state & GDK_BUTTON2_MASK) != 0;
+ event.m_rightDown = (state & GDK_BUTTON3_MASK) != 0;
+
+ wxPoint pt = win->GetClientAreaOrigin();
+ event.m_x = x + pt.x;
+ event.m_y = y + pt.y;
+
+ return win->GTKProcessEvent(event);
+}
+
+//-----------------------------------------------------------------------------
+// "value_changed" from scrollbar
+//-----------------------------------------------------------------------------
+
+static void
+gtk_scrollbar_value_changed(GtkRange* range, wxWindow* win)
+{
+ wxEventType eventType = win->GetScrollEventType(range);
+ if (eventType != wxEVT_NULL)
+ {
+ // Convert scroll event type to scrollwin event type
+ eventType += wxEVT_SCROLLWIN_TOP - wxEVT_SCROLL_TOP;
+
+ // find the scrollbar which generated the event
+ wxWindowGTK::ScrollDir dir = win->ScrollDirFromRange(range);
+
+ // generate the corresponding wx event
+ const int orient = wxWindow::OrientFromScrollDir(dir);
+ wxScrollWinEvent event(eventType, win->GetScrollPos(orient), orient);
+ event.SetEventObject(win);
+
+ win->m_blockValueChanged[dir] = true;
+ win->GTKProcessEvent(event);
+ win->m_blockValueChanged[dir] = false;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// "button_press_event" from scrollbar
+//-----------------------------------------------------------------------------
+
+static gboolean
+gtk_scrollbar_button_press_event(GtkRange*, GdkEventButton*, wxWindow* win)
+{
+ DEBUG_MAIN_THREAD
+
+ g_blockEventsOnScroll = true;
+ win->m_mouseButtonDown = true;
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// "event_after" from scrollbar
+//-----------------------------------------------------------------------------
+
+static void
+gtk_scrollbar_event_after(GtkRange* range, GdkEvent* event, wxWindow* win)
+{
+ if (event->type == GDK_BUTTON_RELEASE)
+ {
+ g_signal_handlers_block_by_func(range, (void*)gtk_scrollbar_event_after, win);
+
+ const int orient = wxWindow::OrientFromScrollDir(
+ win->ScrollDirFromRange(range));
+ wxScrollWinEvent event(wxEVT_SCROLLWIN_THUMBRELEASE, win->GetScrollPos(orient), orient);
+ event.SetEventObject(win);
+ win->GTKProcessEvent(event);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// "button_release_event" from scrollbar
+//-----------------------------------------------------------------------------
+
+static gboolean
+gtk_scrollbar_button_release_event(GtkRange* range, GdkEventButton*, wxWindow* win)
+{
+ DEBUG_MAIN_THREAD
+
+ g_blockEventsOnScroll = false;
+ win->m_mouseButtonDown = false;
+ // If thumb tracking
+ if (win->m_isScrolling)
+ {
+ win->m_isScrolling = false;
+ // Hook up handler to send thumb release event after this emission is finished.
+ // To allow setting scroll position from event handler, sending event must
+ // be deferred until after the GtkRange handler for this signal has run
+ g_signal_handlers_unblock_by_func(range, (void*)gtk_scrollbar_event_after, win);
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// "realize" from m_widget
+//-----------------------------------------------------------------------------
+
+static void
+gtk_window_realized_callback( GtkWidget *m_widget, wxWindow *win )
+{
+ DEBUG_MAIN_THREAD
+
+ if (win->m_imData)
+ {
+ GtkPizza *pizza = GTK_PIZZA( m_widget );
+ gtk_im_context_set_client_window( win->m_imData->context,
+ pizza->bin_window );
+ }
+
+ // We cannot set colours and fonts before the widget
+ // been realized, so we do this directly after realization
+ // or otherwise in idle time
+
+ if (win->m_needsStyleChange)
+ {
+ win->SetBackgroundStyle(win->GetBackgroundStyle());
+ win->m_needsStyleChange = false;
+ }
+
+ wxWindowCreateEvent event( win );
+ event.SetEventObject( win );
+ win->GTKProcessEvent( event );
+}
+
+//-----------------------------------------------------------------------------
+// "size_allocate"
+//-----------------------------------------------------------------------------
+
+static
+void gtk_window_size_callback( GtkWidget *WXUNUSED(widget),
+ GtkAllocation *alloc,
+ wxWindow *win )
+{
+ int client_width = 0;
+ int client_height = 0;
+ win->GetClientSize( &client_width, &client_height );
+ if ((client_width == win->m_oldClientWidth) && (client_height == win->m_oldClientHeight))
+ return;
+
+ if ( !client_width && !client_height )
+ {
+ // the window is currently unmapped, don't generate size events
+ return;
+ }
+
+ win->m_oldClientWidth = client_width;
+ win->m_oldClientHeight = client_height;
+
+ if (!win->m_nativeSizeEvent)
+ {
+ wxSizeEvent event( win->GetSize(), win->GetId() );
+ event.SetEventObject( win );
+ win->GTKProcessEvent( event );
+ }
+}
+
+} // extern "C"
+
+// ----------------------------------------------------------------------------
+// this wxWindowBase function is implemented here (in platform-specific file)
+// because it is static and so couldn't be made virtual
+// ----------------------------------------------------------------------------
+
+wxWindow *wxWindowBase::DoFindFocus()
+{
+ // the cast is necessary when we compile in wxUniversal mode
+ return (wxWindow *)g_focusWindow;
+}
+
+//-----------------------------------------------------------------------------
+// InsertChild for wxWindowGTK.
+//-----------------------------------------------------------------------------
+
+/* Callback for wxWindowGTK. This very strange beast has to be used because
+ * C++ has no virtual methods in a constructor. We have to emulate a
+ * virtual function here as wxNotebook requires a different way to insert
+ * a child in it. I had opted for creating a wxNotebookPage window class
+ * which would have made this superfluous (such in the MDI window system),
+ * but no-one was listening to me... */
+
+static void wxInsertChildInWindow( wxWindowGTK* parent, wxWindowGTK* child )
+{
+ /* the window might have been scrolled already, do we
+ have to adapt the position */
+ GtkPizza *pizza = GTK_PIZZA(parent->m_wxwindow);
+ child->m_x += gtk_pizza_get_xoffset( pizza );
+ child->m_y += gtk_pizza_get_yoffset( pizza );
+
+ gtk_pizza_put( GTK_PIZZA(parent->m_wxwindow),
+ child->m_widget,
+ child->m_x,
+ child->m_y,
+ child->m_width,
+ child->m_height );
+}
+
+//-----------------------------------------------------------------------------
+// global functions
+//-----------------------------------------------------------------------------
+
+wxWindow *wxGetActiveWindow()
+{
+ return wxWindow::FindFocus();
+}
+
+
+wxMouseState wxGetMouseState()
+{
+ wxMouseState ms;
+
+ gint x;
+ gint y;
+ GdkModifierType mask;
+
+ gdk_window_get_pointer(NULL, &x, &y, &mask);
+
+ ms.SetX(x);
+ ms.SetY(y);
+ ms.SetLeftDown(mask & GDK_BUTTON1_MASK);
+ ms.SetMiddleDown(mask & GDK_BUTTON2_MASK);
+ ms.SetRightDown(mask & GDK_BUTTON3_MASK);
+
+ ms.SetControlDown(mask & GDK_CONTROL_MASK);
+ ms.SetShiftDown(mask & GDK_SHIFT_MASK);
+ ms.SetAltDown(mask & GDK_MOD1_MASK);
+ ms.SetMetaDown(mask & GDK_MOD2_MASK);
+
+ return ms;
+}
+
+//-----------------------------------------------------------------------------
+// wxWindowGTK
+//-----------------------------------------------------------------------------
+
+// in wxUniv/MSW this class is abstract because it doesn't have DoPopupMenu()
+// method
+#ifdef __WXUNIVERSAL__
+ IMPLEMENT_ABSTRACT_CLASS(wxWindowGTK, wxWindowBase)
+#else // __WXGTK__
+ IMPLEMENT_DYNAMIC_CLASS(wxWindow, wxWindowBase)
+#endif // __WXUNIVERSAL__/__WXGTK__
+
+void wxWindowGTK::Init()
+{
+ // GTK specific
+ m_widget = (GtkWidget *) NULL;
+ m_wxwindow = (GtkWidget *) NULL;
+ m_focusWidget = (GtkWidget *) NULL;
+
+ // position/size
+ m_x = 0;
+ m_y = 0;
+ m_width = 0;
+ m_height = 0;
+
+ m_sizeSet = false;
+ m_hasVMT = false;
+ m_isBeingDeleted = false;
+
+ m_showOnIdle= false;
+
+ m_noExpose = false;
+ m_nativeSizeEvent = false;
+
+ m_hasScrolling = false;
+ m_isScrolling = false;
+ m_mouseButtonDown = false;
+ m_blockScrollEvent = false;
+
+ // initialize scrolling stuff
+ for ( int dir = 0; dir < ScrollDir_Max; dir++ )
+ {
+ m_scrollBar[dir] = NULL;
+ m_scrollPos[dir] = 0;
+ m_blockValueChanged[dir] = false;
+ }
+
+ m_oldClientWidth =
+ m_oldClientHeight = 0;
+
+ m_resizing = false;
+
+ m_insertCallback = (wxInsertChildFunction) NULL;
+
+ m_hasFocus = false;
+
+ m_clipPaintRegion = false;
+
+ m_needsStyleChange = false;
+
+ m_cursor = *wxSTANDARD_CURSOR;
+
+ m_imData = NULL;
+ m_dirtyTabOrder = false;
+}
+
+wxWindowGTK::wxWindowGTK()
+{
+ Init();
+}
+
+wxWindowGTK::wxWindowGTK( wxWindow *parent,
+ wxWindowID id,
+ const wxPoint &pos,
+ const wxSize &size,
+ long style,
+ const wxString &name )
+{
+ Init();
+
+ Create( parent, id, pos, size, style, name );
+}
+
+bool wxWindowGTK::Create( wxWindow *parent,
+ wxWindowID id,
+ const wxPoint &pos,
+ const wxSize &size,
+ long style,
+ const wxString &name )
+{
+ if (!PreCreation( parent, pos, size ) ||
+ !CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
+ {
+ wxFAIL_MSG( wxT("wxWindowGTK creation failed") );
+ return false;
+ }
+
+ m_insertCallback = wxInsertChildInWindow;
+
+
+ if (!HasFlag(wxHSCROLL) && !HasFlag(wxVSCROLL))
+ {
+ m_wxwindow = gtk_pizza_new_no_scroll();
+
+#ifndef __WXUNIVERSAL__
+ if (HasFlag(wxSIMPLE_BORDER))
+ gtk_container_set_border_width((GtkContainer*)m_wxwindow, 1);
+ else if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
+ gtk_container_set_border_width((GtkContainer*)m_wxwindow, 2);
+#endif // __WXUNIVERSAL__
+
+ m_widget = m_wxwindow;
+ }
+ else
+ {
+ m_wxwindow = gtk_pizza_new();
+
+#ifndef __WXUNIVERSAL__
+ if (HasFlag(wxSIMPLE_BORDER))
+ gtk_container_set_border_width((GtkContainer*)m_wxwindow, 1);
+ else if (HasFlag(wxRAISED_BORDER) || HasFlag(wxSUNKEN_BORDER))
+ gtk_container_set_border_width((GtkContainer*)m_wxwindow, 2);
+#endif // __WXUNIVERSAL__
+
+ m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
+
+ GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(m_widget);
+
+ GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(m_widget) );
+ scroll_class->scrollbar_spacing = 0;
+
+ // There is a conflict with default bindings at GTK+
+ // level between scrolled windows and notebooks both of which want to use
+ // Ctrl-PageUp/Down: scrolled windows for scrolling in the horizontal
+ // direction and notebooks for changing pages -- we decide that if we don't
+ // have wxHSCROLL style we can safely sacrifice horizontal scrolling if it
+ // means we can get working keyboard navigation in notebooks
+ if ( !HasFlag(wxHSCROLL) )
+ {
+ GtkBindingSet *
+ bindings = gtk_binding_set_by_class(G_OBJECT_GET_CLASS(m_widget));
+ if ( bindings )
+ {
+ gtk_binding_entry_remove(bindings, GDK_Page_Up, GDK_CONTROL_MASK);
+ gtk_binding_entry_remove(bindings, GDK_Page_Down, GDK_CONTROL_MASK);
+ }
+ }
+
+ if (HasFlag(wxALWAYS_SHOW_SB))
+ {
+ gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_ALWAYS, GTK_POLICY_ALWAYS );
+
+ scrolledWindow->hscrollbar_visible = TRUE;
+ scrolledWindow->vscrollbar_visible = TRUE;
+ }
+ else
+ {
+ gtk_scrolled_window_set_policy( scrolledWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
+ }
+
+ m_scrollBar[ScrollDir_Horz] = GTK_RANGE(scrolledWindow->hscrollbar);
+ m_scrollBar[ScrollDir_Vert] = GTK_RANGE(scrolledWindow->vscrollbar);
+ if (GetLayoutDirection() == wxLayout_RightToLeft)
+ gtk_range_set_inverted( m_scrollBar[ScrollDir_Horz], TRUE );
+
+ gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
+
+ // connect various scroll-related events
+ for ( int dir = 0; dir < ScrollDir_Max; dir++ )
+ {
+ // these handlers block mouse events to any window during scrolling
+ // such as motion events and prevent GTK and wxWidgets from fighting
+ // over where the slider should be
+ g_signal_connect(m_scrollBar[dir], "button_press_event",
+ G_CALLBACK(gtk_scrollbar_button_press_event), this);
+ g_signal_connect(m_scrollBar[dir], "button_release_event",
+ G_CALLBACK(gtk_scrollbar_button_release_event), this);
+
+ gulong handler_id = g_signal_connect(m_scrollBar[dir], "event_after",
+ G_CALLBACK(gtk_scrollbar_event_after), this);
+ g_signal_handler_block(m_scrollBar[dir], handler_id);
+
+ // these handlers get notified when scrollbar slider moves
+ g_signal_connect(m_scrollBar[dir], "value_changed",
+ G_CALLBACK(gtk_scrollbar_value_changed), this);
+ }
+
+ gtk_widget_show( m_wxwindow );
+ }
+
+ if (m_parent)
+ m_parent->DoAddChild( this );
+
+ m_focusWidget = m_wxwindow;
+
+ PostCreation();
+
+ return true;
+}
+
+wxWindowGTK::~wxWindowGTK()
+{
+ SendDestroyEvent();
+
+ if (g_focusWindow == this)
+ g_focusWindow = NULL;
+
+ if ( g_delayedFocus == this )
+ g_delayedFocus = NULL;
+
+ m_isBeingDeleted = true;
+ m_hasVMT = false;
+
+ // destroy children before destroying this window itself
+ DestroyChildren();
+
+ // unhook focus handlers to prevent stray events being
+ // propagated to this (soon to be) dead object
+ if (m_focusWidget != NULL)
+ {
+ g_signal_handlers_disconnect_by_func (m_focusWidget,
+ (gpointer) gtk_window_focus_in_callback,
+ this);
+ g_signal_handlers_disconnect_by_func (m_focusWidget,
+ (gpointer) gtk_window_focus_out_callback,
+ this);
+ }
+
+ if (m_widget)
+ Show( false );
+
+ // delete before the widgets to avoid a crash on solaris
+ delete m_imData;
+
+ if (m_wxwindow && (m_wxwindow != m_widget))
+ {
+ gtk_widget_destroy( m_wxwindow );
+ m_wxwindow = (GtkWidget*) NULL;
+ }
+
+ if (m_widget)
+ {
+ gtk_widget_destroy( m_widget );
+ m_widget = (GtkWidget*) NULL;
+ }
+}
+
+bool wxWindowGTK::PreCreation( wxWindowGTK *parent, const wxPoint &pos, const wxSize &size )
+{
+ if ( GTKNeedsParent() )
+ {
+ wxCHECK_MSG( parent, false, wxT("Must have non-NULL parent") );
+ }
+
+ // Use either the given size, or the default if -1 is given.
+ // See wxWindowBase for these functions.
+ m_width = WidthDefault(size.x) ;
+ m_height = HeightDefault(size.y);
+
+ m_x = (int)pos.x;
+ m_y = (int)pos.y;
+
+ return true;
+}
+
+void wxWindowGTK::PostCreation()
+{
+ wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
+
+ if (m_wxwindow)
+ {
+ if (!m_noExpose)
+ {
+ // these get reported to wxWidgets -> wxPaintEvent
+
+ g_signal_connect (m_wxwindow, "expose_event",
+ G_CALLBACK (gtk_window_expose_callback), this);
+
+ if (GetLayoutDirection() == wxLayout_LeftToRight)
+ gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), HasFlag( wxFULL_REPAINT_ON_RESIZE ) );
+ }
+
+ // Create input method handler
+ m_imData = new wxGtkIMData;
+
+ // Cannot handle drawing preedited text yet
+ gtk_im_context_set_use_preedit( m_imData->context, FALSE );
+
+ g_signal_connect (m_imData->context, "commit",
+ G_CALLBACK (gtk_wxwindow_commit_cb), this);
+
+ // these are called when the "sunken" or "raised" borders are drawn
+ g_signal_connect (m_widget, "expose_event",
+ G_CALLBACK (gtk_window_own_expose_callback), this);
+ }
+
+ // focus handling
+
+ if (!GTK_IS_WINDOW(m_widget))
+ {
+ if (m_focusWidget == NULL)
+ m_focusWidget = m_widget;
+
+ if (m_wxwindow)
+ {
+ g_signal_connect (m_focusWidget, "focus_in_event",
+ G_CALLBACK (gtk_window_focus_in_callback), this);
+ g_signal_connect (m_focusWidget, "focus_out_event",
+ G_CALLBACK (gtk_window_focus_out_callback), this);
+ }
+ else
+ {
+ g_signal_connect_after (m_focusWidget, "focus_in_event",
+ G_CALLBACK (gtk_window_focus_in_callback), this);
+ g_signal_connect_after (m_focusWidget, "focus_out_event",
+ G_CALLBACK (gtk_window_focus_out_callback), this);
+ }
+ }
+
+ if ( !AcceptsFocusFromKeyboard() )
+ {
+ SetCanFocus(false);
+
+ g_signal_connect(m_widget, "focus",
+ G_CALLBACK(wx_window_focus_callback), this);
+ }
+
+ // connect to the various key and mouse handlers
+
+ GtkWidget *connect_widget = GetConnectWidget();
+
+ ConnectWidget( connect_widget );
+
+ /* We cannot set colours, fonts and cursors before the widget has
+ been realized, so we do this directly after realization */
+ g_signal_connect (connect_widget, "realize",
+ G_CALLBACK (gtk_window_realized_callback), this);
+
+ if (m_wxwindow)
+ {
+ // Catch native resize events
+ g_signal_connect (m_wxwindow, "size_allocate",
+ G_CALLBACK (gtk_window_size_callback), this);
+ }
+
+ if (GTK_IS_COMBO(m_widget))
+ {
+ GtkCombo *gcombo = GTK_COMBO(m_widget);
+
+ g_signal_connect (gcombo->entry, "size_request",
+ G_CALLBACK (wxgtk_combo_size_request_callback),
+ this);
+ }
+#ifdef GTK_IS_FILE_CHOOSER_BUTTON
+ else if (!gtk_check_version(2,6,0) && GTK_IS_FILE_CHOOSER_BUTTON(m_widget))
+ {
+ // If we connect to the "size_request" signal of a GtkFileChooserButton
+ // then that control won't be sized properly when placed inside sizers
+ // (this can be tested removing this elseif and running XRC or WIDGETS samples)
+ // FIXME: what should be done here ?
+ }
+#endif
+ else if ( !IsTopLevel() ) // top level windows use their own callback
+ {
+ // This is needed if we want to add our windows into native
+ // GTK controls, such as the toolbar. With this callback, the
+ // toolbar gets to know the correct size (the one set by the
+ // programmer). Sadly, it misbehaves for wxComboBox.
+ g_signal_connect (m_widget, "size_request",
+ G_CALLBACK (wxgtk_window_size_request_callback),
+ this);
+ }
+
+ InheritAttributes();
+
+ m_hasVMT = true;
+
+ SetLayoutDirection(wxLayout_Default);
+
+ // unless the window was created initially hidden (i.e. Hide() had been
+ // called before Create()), we should show it at GTK+ level as well
+ if ( IsShown() )
+ gtk_widget_show( m_widget );
+}
+
+void wxWindowGTK::ConnectWidget( GtkWidget *widget )
+{
+ g_signal_connect (widget, "key_press_event",
+ G_CALLBACK (gtk_window_key_press_callback), this);
+ g_signal_connect (widget, "key_release_event",
+ G_CALLBACK (gtk_window_key_release_callback), this);
+ g_signal_connect (widget, "button_press_event",
+ G_CALLBACK (gtk_window_button_press_callback), this);
+ g_signal_connect (widget, "button_release_event",
+ G_CALLBACK (gtk_window_button_release_callback), this);
+ g_signal_connect (widget, "motion_notify_event",
+ G_CALLBACK (gtk_window_motion_notify_callback), this);
+ g_signal_connect (widget, "scroll_event",
+ G_CALLBACK (window_scroll_event), this);
+ g_signal_connect (widget, "popup_menu",
+ G_CALLBACK (wxgtk_window_popup_menu_callback), this);
+ g_signal_connect (widget, "enter_notify_event",
+ G_CALLBACK (gtk_window_enter_callback), this);
+ g_signal_connect (widget, "leave_notify_event",
+ G_CALLBACK (gtk_window_leave_callback), this);
+}
+
+bool wxWindowGTK::Destroy()
+{
+ wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
+
+ m_hasVMT = false;
+
+ return wxWindowBase::Destroy();
+}
+
+void wxWindowGTK::DoMoveWindow(int x, int y, int width, int height)
+{
+ // inform the parent to perform the move
+ gtk_pizza_set_size( GTK_PIZZA(m_parent->m_wxwindow), m_widget, x, y, width, height );
+
+}
+
+void wxWindowGTK::ConstrainSize()
+{
+#ifdef __WXGPE__
+ // GPE's window manager doesn't like size hints at all, esp. when the user
+ // has to use the virtual keyboard, so don't constrain size there
+ if (!IsTopLevel())
+#endif
+ {
+ const wxSize minSize = GetMinSize();
+ const wxSize maxSize = GetMaxSize();
+ if (minSize.x > 0 && m_width < minSize.x) m_width = minSize.x;
+ if (minSize.y > 0 && m_height < minSize.y) m_height = minSize.y;
+ if (maxSize.x > 0 && m_width > maxSize.x) m_width = maxSize.x;
+ if (maxSize.y > 0 && m_height > maxSize.y) m_height = maxSize.y;
+ }
+}
+
+void wxWindowGTK::DoSetSize( int x, int y, int width, int height, int sizeFlags )
+{
+ wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
+ wxASSERT_MSG( (m_parent != NULL), wxT("wxWindowGTK::SetSize requires parent.\n") );
+
+ if (m_resizing) return; /* I don't like recursions */
+ m_resizing = true;
+
+ int currentX, currentY;
+ GetPosition(¤tX, ¤tY);
+ if (x == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
+ x = currentX;
+ if (y == -1 && !(sizeFlags & wxSIZE_ALLOW_MINUS_ONE))
+ y = currentY;
+ AdjustForParentClientOrigin(x, y, sizeFlags);
+
+ // calculate the best size if we should auto size the window
+ if ( ((sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1) ||
+ ((sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1) )
+ {
+ const wxSize sizeBest = GetBestSize();
+ if ( (sizeFlags & wxSIZE_AUTO_WIDTH) && width == -1 )
+ width = sizeBest.x;
+ if ( (sizeFlags & wxSIZE_AUTO_HEIGHT) && height == -1 )
+ height = sizeBest.y;
+ }
+
+ if (width != -1)
+ m_width = width;
+ if (height != -1)
+ m_height = height;
+
+ ConstrainSize();
+
+#if wxUSE_TOOLBAR_NATIVE
+ if (wxDynamicCast(GetParent(), wxToolBar))
+ {
+ // don't take the x,y values, they're wrong because toolbar sets them
+ GtkWidget *widget = m_widget;
+ gtk_widget_set_size_request (widget, m_width, m_height);
+ }
+ else
+#endif
+ if (m_parent->m_wxwindow == NULL) // i.e. wxNotebook
+ {
+ // don't set the size for children of wxNotebook, just take the values.
+ m_x = x;
+ m_y = y;
+ m_width = width;
+ m_height = height;
+ }
+ else
+ {
+ GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
+ if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
+ {
+ if (x != -1) m_x = x + gtk_pizza_get_xoffset( pizza );
+ if (y != -1) m_y = y + gtk_pizza_get_yoffset( pizza );
+ }
+ else
+ {
+ m_x = x + gtk_pizza_get_xoffset( pizza );
+ m_y = y + gtk_pizza_get_yoffset( pizza );
+ }
+
+ int left_border = 0;
+ int right_border = 0;
+ int top_border = 0;
+ int bottom_border = 0;
+
+ /* the default button has a border around it */
+ if (GTK_WIDGET_CAN_DEFAULT(m_widget))
+ {
+ GtkBorder *default_border = NULL;
+ gtk_widget_style_get( m_widget, "default_border", &default_border, NULL );
+ if (default_border)
+ {
+ left_border += default_border->left;
+ right_border += default_border->right;
+ top_border += default_border->top;
+ bottom_border += default_border->bottom;
+ g_free( default_border );
+ }
+ }
+
+ DoMoveWindow( m_x-top_border,
+ m_y-left_border,
+ m_width+left_border+right_border,
+ m_height+top_border+bottom_border );
+ }
+
+ if (m_hasScrolling)
+ {
+ /* Sometimes the client area changes size without the
+ whole windows's size changing, but if the whole
+ windows's size doesn't change, no wxSizeEvent will
+ normally be sent. Here we add an extra test if
+ the client test has been changed and this will
+ be used then. */
+ GetClientSize( &m_oldClientWidth, &m_oldClientHeight );
+ }
+
+/*
+ wxPrintf( "OnSize sent from " );
+ if (GetClassInfo() && GetClassInfo()->GetClassName())
+ wxPrintf( GetClassInfo()->GetClassName() );
+ wxPrintf( " %d %d %d %d\n", (int)m_x, (int)m_y, (int)m_width, (int)m_height );
+*/
+
+ if (!m_nativeSizeEvent)
+ {
+ wxSizeEvent event( wxSize(m_width,m_height), GetId() );
+ event.SetEventObject( this );
+ GetEventHandler()->ProcessEvent( event );
+ }
+
+ m_resizing = false;
+}
+
+bool wxWindowGTK::GtkShowFromOnIdle()
+{
+ if (IsShown() && m_showOnIdle && !GTK_WIDGET_VISIBLE (m_widget))
+ {
+ GtkAllocation alloc;
+ alloc.x = m_x;
+ alloc.y = m_y;
+ alloc.width = m_width;
+ alloc.height = m_height;
+ gtk_widget_size_allocate( m_widget, &alloc );
+ gtk_widget_show( m_widget );
+ wxShowEvent eventShow(GetId(), true);
+ eventShow.SetEventObject(this);
+ GetEventHandler()->ProcessEvent(eventShow);
+ m_showOnIdle = false;
+ return true;
+ }
+
+ return false;
+}
+
+void wxWindowGTK::OnInternalIdle()
+{
+ // Check if we have to show window now
+ if (GtkShowFromOnIdle()) return;
+
+ if ( m_dirtyTabOrder )
+ {
+ m_dirtyTabOrder = false;
+ RealizeTabOrder();
+ }
+
+ // Update style if the window was not yet realized
+ // and SetBackgroundStyle(wxBG_STYLE_CUSTOM) was called
+ if (m_needsStyleChange)
+ {
+ SetBackgroundStyle(GetBackgroundStyle());
+ m_needsStyleChange = false;
+ }
+
+ wxCursor cursor = m_cursor;
+ if (g_globalCursor.Ok()) cursor = g_globalCursor;
+
+ if (cursor.Ok())
+ {
+ /* I now set the cursor anew in every OnInternalIdle call
+ as setting the cursor in a parent window also effects the
+ windows above so that checking for the current cursor is
+ not possible. */
+
+ if (m_wxwindow && (m_wxwindow != m_widget))
+ {
+ GdkWindow *window = GTK_PIZZA(m_wxwindow)->bin_window;
+ if (window)
+ gdk_window_set_cursor( window, cursor.GetCursor() );
+
+ if (!g_globalCursor.Ok())
+ cursor = *wxSTANDARD_CURSOR;
+
+ window = m_widget->window;
+ if ((window) && !(GTK_WIDGET_NO_WINDOW(m_widget)))
+ gdk_window_set_cursor( window, cursor.GetCursor() );
+
+ }
+ else if ( m_widget )
+ {
+ GdkWindow *window = m_widget->window;
+ if ( window && !GTK_WIDGET_NO_WINDOW(m_widget) )
+ gdk_window_set_cursor( window, cursor.GetCursor() );
+ }
+ }
+
+ if (wxUpdateUIEvent::CanUpdate(this))
+ UpdateWindowUI(wxUPDATE_UI_FROMIDLE);
+}
+
+void wxWindowGTK::DoGetSize( int *width, int *height ) const
+{
+ wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
+
+ if (width) (*width) = m_width;
+ if (height) (*height) = m_height;
+}
+
+void wxWindowGTK::DoSetClientSize( int width, int height )
+{
+ wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
+
+ if (m_wxwindow)
+ {
+ int dw = 0;
+ int dh = 0;
+
+ if (m_hasScrolling)
+ {
+ GetScrollbarWidth(m_widget, dw, dh);
+ }
+
+ const int border = GTK_CONTAINER(m_wxwindow)->border_width;
+ dw += 2 * border;
+ dh += 2 * border;
+
+ width += dw;
+ height += dh;
+ }
+
+ SetSize(width, height);
+}
+
+void wxWindowGTK::DoGetClientSize( int *width, int *height ) const
+{
+ wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
+
+ int w = m_width;
+ int h = m_height;
+
+ if (m_wxwindow)
+ {
+ int dw = 0;
+ int dh = 0;
+
+ if (m_hasScrolling)
+ GetScrollbarWidth(m_widget, dw, dh);
+
+ const int border = GTK_CONTAINER(m_wxwindow)->border_width;
+ dw += 2 * border;
+ dh += 2 * border;
+
+ w -= dw;
+ h -= dh;
+ if (w < 0)
+ w = 0;
+ if (h < 0)
+ h = 0;
+ }
+
+ if (width) *width = w;
+ if (height) *height = h;
+}
+
+void wxWindowGTK::DoGetPosition( int *x, int *y ) const
+{
+ wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
+
+ int dx = 0;
+ int dy = 0;
+ if (m_parent && m_parent->m_wxwindow)
+ {
+ GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
+ dx = gtk_pizza_get_xoffset( pizza );
+ dy = gtk_pizza_get_yoffset( pizza );
+ }
+
+ if (m_x == -1 && m_y == -1)
+ {
+ GdkWindow *source = (GdkWindow *) NULL;
+ if (m_wxwindow)
+ source = GTK_PIZZA(m_wxwindow)->bin_window;
+ else
+ source = m_widget->window;
+
+ if (source)
+ {
+ int org_x = 0;
+ int org_y = 0;
+ gdk_window_get_origin( source, &org_x, &org_y );
+
+ if (m_parent)
+ m_parent->ScreenToClient(&org_x, &org_y);
+
+ wx_const_cast(wxWindowGTK*, this)->m_x = org_x;
+ wx_const_cast(wxWindowGTK*, this)->m_y = org_y;
+ }
+ }
+
+ if (x) (*x) = m_x - dx;
+ if (y) (*y) = m_y - dy;
+}
+
+void wxWindowGTK::DoClientToScreen( int *x, int *y ) const
+{
+ wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
+
+ if (!m_widget->window) return;
+
+ GdkWindow *source = (GdkWindow *) NULL;
+ if (m_wxwindow)
+ source = GTK_PIZZA(m_wxwindow)->bin_window;
+ else
+ source = m_widget->window;
+
+ int org_x = 0;
+ int org_y = 0;
+ gdk_window_get_origin( source, &org_x, &org_y );
+
+ if (!m_wxwindow)
+ {
+ if (GTK_WIDGET_NO_WINDOW (m_widget))
+ {
+ org_x += m_widget->allocation.x;
+ org_y += m_widget->allocation.y;
+ }
+ }
+
+
+ if (x)
+ {
+ if (GetLayoutDirection() == wxLayout_RightToLeft)
+ *x = (GetClientSize().x - *x) + org_x;
+ else
+ *x += org_x;
+ }
+
+ if (y) *y += org_y;
+}
+
+void wxWindowGTK::DoScreenToClient( int *x, int *y ) const
+{
+ wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
+
+ if (!m_widget->window) return;
+
+ GdkWindow *source = (GdkWindow *) NULL;
+ if (m_wxwindow)
+ source = GTK_PIZZA(m_wxwindow)->bin_window;
+ else
+ source = m_widget->window;
+
+ int org_x = 0;
+ int org_y = 0;
+ gdk_window_get_origin( source, &org_x, &org_y );
+
+ if (!m_wxwindow)
+ {
+ if (GTK_WIDGET_NO_WINDOW (m_widget))
+ {
+ org_x += m_widget->allocation.x;
+ org_y += m_widget->allocation.y;
+ }
+ }
+
+ if (x)
+ {
+ if (GetLayoutDirection() == wxLayout_RightToLeft)
+ *x = (GetClientSize().x - *x) - org_x;
+ else
+ *x -= org_x;
+ }
+ if (y) *y -= org_y;
+}
+
+bool wxWindowGTK::Show( bool show )
+{
+ wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
+
+ if (!wxWindowBase::Show(show))
+ {
+ // nothing to do
+ return false;
+ }
+
+ if (show)
+ {
+ if (!m_showOnIdle)
+ {
+ gtk_widget_show( m_widget );
+ wxShowEvent eventShow(GetId(), show);
+ eventShow.SetEventObject(this);
+ GetEventHandler()->ProcessEvent(eventShow);
+ }
+ }
+ else
+ {
+ gtk_widget_hide( m_widget );
+ wxShowEvent eventShow(GetId(), show);
+ eventShow.SetEventObject(this);
+ GetEventHandler()->ProcessEvent(eventShow);
+ }
+
+ return true;
+}
+
+void wxWindowGTK::DoEnable( bool enable )
+{
+ wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
+
+ gtk_widget_set_sensitive( m_widget, enable );
+ if (m_wxwindow && (m_wxwindow != m_widget))
+ gtk_widget_set_sensitive( m_wxwindow, enable );
+}
+
+int wxWindowGTK::GetCharHeight() const
+{
+ wxCHECK_MSG( (m_widget != NULL), 12, wxT("invalid window") );
+
+ wxFont font = GetFont();
+ wxCHECK_MSG( font.Ok(), 12, wxT("invalid font") );
+
+ PangoContext *context = NULL;
+ if (m_widget)
+ context = gtk_widget_get_pango_context( m_widget );
+
+ if (!context)
+ return 0;
+
+ PangoFontDescription *desc = font.GetNativeFontInfo()->description;
+ PangoLayout *layout = pango_layout_new(context);
+ pango_layout_set_font_description(layout, desc);
+ pango_layout_set_text(layout, "H", 1);
+ PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
+
+ PangoRectangle rect;
+ pango_layout_line_get_extents(line, NULL, &rect);
+
+ g_object_unref (layout);
+
+ return (int) PANGO_PIXELS(rect.height);
+}
+
+int wxWindowGTK::GetCharWidth() const
+{
+ wxCHECK_MSG( (m_widget != NULL), 8, wxT("invalid window") );
+
+ wxFont font = GetFont();
+ wxCHECK_MSG( font.Ok(), 8, wxT("invalid font") );
+
+ PangoContext *context = NULL;
+ if (m_widget)
+ context = gtk_widget_get_pango_context( m_widget );
+
+ if (!context)
+ return 0;
+
+ PangoFontDescription *desc = font.GetNativeFontInfo()->description;
+ PangoLayout *layout = pango_layout_new(context);
+ pango_layout_set_font_description(layout, desc);
+ pango_layout_set_text(layout, "g", 1);
+ PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
+
+ PangoRectangle rect;
+ pango_layout_line_get_extents(line, NULL, &rect);
+
+ g_object_unref (layout);
+
+ return (int) PANGO_PIXELS(rect.width);
+}
+
+void wxWindowGTK::GetTextExtent( const wxString& string,
+ int *x,
+ int *y,
+ int *descent,
+ int *externalLeading,
+ const wxFont *theFont ) const
+{
+ wxFont fontToUse = theFont ? *theFont : GetFont();
+
+ wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
+
+ if (string.empty())
+ {
+ if (x) (*x) = 0;
+ if (y) (*y) = 0;
+ return;
+ }
+
+ PangoContext *context = NULL;
+ if (m_widget)
+ context = gtk_widget_get_pango_context( m_widget );
+
+ if (!context)
+ {
+ if (x) (*x) = 0;
+ if (y) (*y) = 0;
+ return;
+ }
+
+ PangoFontDescription *desc = fontToUse.GetNativeFontInfo()->description;
+ PangoLayout *layout = pango_layout_new(context);
+ pango_layout_set_font_description(layout, desc);
+ {
+ const wxCharBuffer data = wxGTK_CONV( string );
+ if ( data )
+ pango_layout_set_text(layout, data, strlen(data));
+ }
+
+ PangoRectangle rect;
+ pango_layout_get_extents(layout, NULL, &rect);
+
+ if (x) (*x) = (wxCoord) PANGO_PIXELS(rect.width);
+ if (y) (*y) = (wxCoord) PANGO_PIXELS(rect.height);
+ if (descent)
+ {
+ PangoLayoutIter *iter = pango_layout_get_iter(layout);
+ int baseline = pango_layout_iter_get_baseline(iter);
+ pango_layout_iter_free(iter);
+ *descent = *y - PANGO_PIXELS(baseline);
+ }
+ if (externalLeading) (*externalLeading) = 0; // ??
+
+ g_object_unref (layout);
+}
+
+bool wxWindowGTK::GTKSetDelayedFocusIfNeeded()
+{
+ if ( g_delayedFocus == this )
+ {
+ if ( GTK_WIDGET_REALIZED(m_widget) )
+ {
+ gtk_widget_grab_focus(m_widget);
+ g_delayedFocus = NULL;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void wxWindowGTK::SetFocus()
+{
+ wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
+ if ( m_hasFocus )
+ {
+ // don't do anything if we already have focus
+ return;
+ }
+
+ if (m_wxwindow)
+ {
+ if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
+ {
+ gtk_widget_grab_focus (m_wxwindow);
+ }
+ }
+ else if (m_widget)
+ {
+ if (GTK_IS_CONTAINER(m_widget))
+ {
+ if (IsKindOf(CLASSINFO(wxRadioButton)))
+ {
+ gtk_widget_grab_focus (m_widget);
+ return;
+ }
+
+ gtk_widget_child_focus( m_widget, GTK_DIR_TAB_FORWARD );
+ }
+ else
+ if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
+ {
+
+ if (!GTK_WIDGET_REALIZED(m_widget))
+ {
+ // we can't set the focus to the widget now so we remember that
+ // it should be focused and will do it later, during the idle
+ // time, as soon as we can
+ wxLogTrace(TRACE_FOCUS,
+ _T("Delaying setting focus to %s(%s)"),
+ GetClassInfo()->GetClassName(), GetLabel().c_str());
+
+ g_delayedFocus = this;
+ }
+ else
+ {
+ wxLogTrace(TRACE_FOCUS,
+ _T("Setting focus to %s(%s)"),
+ GetClassInfo()->GetClassName(), GetLabel().c_str());
+
+ gtk_widget_grab_focus (m_widget);
+ }
+ }
+ else
+ {
+ wxLogTrace(TRACE_FOCUS,
+ _T("Can't set focus to %s(%s)"),
+ GetClassInfo()->GetClassName(), GetLabel().c_str());
+ }
+ }
+}
+
+void wxWindowGTK::SetCanFocus(bool canFocus)
+{
+ if ( canFocus )
+ GTK_WIDGET_SET_FLAGS(m_widget, GTK_CAN_FOCUS);
+ else
+ GTK_WIDGET_UNSET_FLAGS(m_widget, GTK_CAN_FOCUS);
+
+ if ( m_wxwindow && (m_widget != m_wxwindow) )
+ {
+ if ( canFocus )
+ GTK_WIDGET_SET_FLAGS(m_wxwindow, GTK_CAN_FOCUS);
+ else
+ GTK_WIDGET_UNSET_FLAGS(m_wxwindow, GTK_CAN_FOCUS);
+ }
+}
+
+bool wxWindowGTK::Reparent( wxWindowBase *newParentBase )
{
- if (g_blockEventsOnDrag) return TRUE;
- if (win->m_wxwindow)
- {
- if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow))
- GTK_WIDGET_UNSET_FLAGS (win->m_wxwindow, GTK_HAS_FOCUS);
- }
-
- if (!win->HasVMT()) return TRUE;
-
-/*
- printf( "OnKillFocus from " );
- if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
- printf( win->GetClassInfo()->GetClassName() );
- printf( ".\n" );
-*/
-
- wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
- event.SetEventObject( win );
-
- if (win->GetEventHandler()->ProcessEvent( event ))
- gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_out_event" );
+ wxCHECK_MSG( (m_widget != NULL), false, wxT("invalid window") );
- return TRUE;
-}
+ wxWindowGTK *oldParent = m_parent,
+ *newParent = (wxWindowGTK *)newParentBase;
-//-----------------------------------------------------------------------------
-// "value_changed" from m_vAdjust
-//-----------------------------------------------------------------------------
+ wxASSERT( GTK_IS_WIDGET(m_widget) );
-static void gtk_window_vscroll_callback( GtkWidget *WXUNUSED(widget), wxWindow *win )
-{
- if (g_blockEventsOnDrag) return;
+ if ( !wxWindowBase::Reparent(newParent) )
+ return false;
-/*
- printf( "OnVScroll from " );
- if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
- printf( win->GetClassInfo()->GetClassName() );
- printf( ".\n" );
-*/
-
- if (!win->HasVMT()) return;
-
- float diff = win->m_vAdjust->value - win->m_oldVerticalPos;
- if (fabs(diff) < 0.2) return;
-
- wxEventType command = wxEVT_NULL;
-
- float line_step = win->m_vAdjust->step_increment;
- float page_step = win->m_vAdjust->page_increment;
-
- if (fabs(diff-line_step) < 0.2) command = wxEVT_SCROLL_LINEDOWN;
- else if (fabs(diff+line_step) < 0.2) command = wxEVT_SCROLL_LINEUP;
- else if (fabs(diff-page_step) < 0.2) command = wxEVT_SCROLL_PAGEDOWN;
- else if (fabs(diff+page_step) < 0.2) command = wxEVT_SCROLL_PAGEUP;
- else command = wxEVT_SCROLL_THUMBTRACK;
-
- int value = (int)(win->m_vAdjust->value+0.5);
-
- wxScrollEvent event( command, win->GetId(), value, wxVERTICAL );
- event.SetEventObject( win );
- win->GetEventHandler()->ProcessEvent( event );
-}
+ wxASSERT( GTK_IS_WIDGET(m_widget) );
-//-----------------------------------------------------------------------------
-// "value_changed" from m_hAdjust
-//-----------------------------------------------------------------------------
+ /* prevent GTK from deleting the widget arbitrarily */
+ gtk_widget_ref( m_widget );
-static void gtk_window_hscroll_callback( GtkWidget *WXUNUSED(widget), wxWindow *win )
-{
- if (g_blockEventsOnDrag) return;
-
-/*
- printf( "OnHScroll from " );
- if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
- printf( win->GetClassInfo()->GetClassName() );
- printf( ".\n" );
-*/
-
- if (!win->HasVMT()) return;
-
- float diff = win->m_hAdjust->value - win->m_oldHorizontalPos;
- if (fabs(diff) < 0.2) return;
-
- wxEventType command = wxEVT_NULL;
-
- float line_step = win->m_hAdjust->step_increment;
- float page_step = win->m_hAdjust->page_increment;
-
- if (fabs(diff-line_step) < 0.2) command = wxEVT_SCROLL_LINEDOWN;
- else if (fabs(diff+line_step) < 0.2) command = wxEVT_SCROLL_LINEUP;
- else if (fabs(diff-page_step) < 0.2) command = wxEVT_SCROLL_PAGEDOWN;
- else if (fabs(diff+page_step) < 0.2) command = wxEVT_SCROLL_PAGEUP;
- else command = wxEVT_SCROLL_THUMBTRACK;
-
- int value = (int)(win->m_hAdjust->value+0.5);
-
- wxScrollEvent event( command, win->GetId(), value, wxHORIZONTAL );
- event.SetEventObject( win );
- win->GetEventHandler()->ProcessEvent( event );
-}
+ if (oldParent)
+ {
+ gtk_container_remove( GTK_CONTAINER(m_widget->parent), m_widget );
+ }
-//-----------------------------------------------------------------------------
-// "changed" from m_vAdjust
-//-----------------------------------------------------------------------------
+ wxASSERT( GTK_IS_WIDGET(m_widget) );
-static void gtk_window_vscroll_change_callback( GtkWidget *WXUNUSED(widget), wxWindow *win )
-{
- if (g_blockEventsOnDrag) return;
+ if (newParent)
+ {
+ if (GTK_WIDGET_VISIBLE (newParent->m_widget))
+ {
+ m_showOnIdle = true;
+ gtk_widget_hide( m_widget );
+ }
-/*
- printf( "OnVScroll change from " );
- if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
- printf( win->GetClassInfo()->GetClassName() );
- printf( ".\n" );
-*/
-
- if (!win->HasVMT()) return;
-
- wxEventType command = wxEVT_SCROLL_THUMBTRACK;
- int value = (int)(win->m_vAdjust->value+0.5);
+ /* insert GTK representation */
+ (*(newParent->m_insertCallback))(newParent, this);
+ }
- wxScrollEvent event( command, win->GetId(), value, wxVERTICAL );
- event.SetEventObject( win );
- win->GetEventHandler()->ProcessEvent( event );
-}
+ /* reverse: prevent GTK from deleting the widget arbitrarily */
+ gtk_widget_unref( m_widget );
-//-----------------------------------------------------------------------------
-// "changed" from m_hAdjust
-//-----------------------------------------------------------------------------
+ SetLayoutDirection(wxLayout_Default);
-static void gtk_window_hscroll_change_callback( GtkWidget *WXUNUSED(widget), wxWindow *win )
-{
- if (g_blockEventsOnDrag) return;
-
-/*
- printf( "OnHScroll change from " );
- if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
- printf( win->GetClassInfo()->GetClassName() );
- printf( ".\n" );
-*/
-
- if (!win->HasVMT()) return;
-
- wxEventType command = wxEVT_SCROLL_THUMBTRACK;
- int value = (int)(win->m_hAdjust->value+0.5);
-
- wxScrollEvent event( command, win->GetId(), value, wxHORIZONTAL );
- event.SetEventObject( win );
- win->GetEventHandler()->ProcessEvent( event );
+ return true;
}
-//-----------------------------------------------------------------------------
-// "drop_data_available_event"
-//-----------------------------------------------------------------------------
-
-static void gtk_window_drop_callback( GtkWidget *widget, GdkEvent *event, wxWindow *win )
+void wxWindowGTK::DoAddChild(wxWindowGTK *child)
{
- if (!win->HasVMT()) return;
-
- if (win->GetDropTarget())
- {
- int x = 0;
- int y = 0;
- gdk_window_get_pointer( widget->window, &x, &y, (GdkModifierType *) NULL );
- win->GetDropTarget()->Drop( event, x, y );
- }
-
-/*
- g_free (event->dropdataavailable.data);
- g_free (event->dropdataavailable.data_type);
-*/
-}
+ wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
-//-----------------------------------------------------------------------------
-// "enter_notify_event"
-//-----------------------------------------------------------------------------
+ wxASSERT_MSG( (child != NULL), wxT("invalid child window") );
-static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindow *win )
-{
- if (widget->window != gdk_event->window) return TRUE;
- if (g_blockEventsOnDrag) return TRUE;
- if (!win->HasVMT()) return TRUE;
-
- if (widget->window)
- gdk_window_set_cursor( widget->window, win->m_cursor->GetCursor() );
-
- wxMouseEvent event( wxEVT_ENTER_WINDOW );
- event.SetEventObject( win );
- return win->GetEventHandler()->ProcessEvent( event );
+ wxASSERT_MSG( (m_insertCallback != NULL), wxT("invalid child insertion function") );
+
+ /* add to list */
+ AddChild( child );
+
+ /* insert GTK representation */
+ (*m_insertCallback)(this, child);
}
-
-//-----------------------------------------------------------------------------
-// "leave_notify_event"
-//-----------------------------------------------------------------------------
-static gint gtk_window_leave_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindow *win )
+void wxWindowGTK::AddChild(wxWindowBase *child)
{
- if (widget->window != gdk_event->window) return TRUE;
- if (!win->HasVMT()) return TRUE;
- if (g_blockEventsOnDrag) return TRUE;
-
- if (widget->window)
- gdk_window_set_cursor( widget->window, wxSTANDARD_CURSOR->GetCursor() );
-
- wxMouseEvent event( wxEVT_LEAVE_WINDOW );
- event.SetEventObject( win );
- return win->GetEventHandler()->ProcessEvent( event );
+ wxWindowBase::AddChild(child);
+ m_dirtyTabOrder = true;
+ wxTheApp->WakeUpIdle();
}
-
-//-----------------------------------------------------------------------------
-// wxWindow
-//-----------------------------------------------------------------------------
-IMPLEMENT_DYNAMIC_CLASS(wxWindow,wxEvtHandler)
-
-BEGIN_EVENT_TABLE(wxWindow, wxEvtHandler)
- EVT_SIZE(wxWindow::OnSize)
- EVT_SYS_COLOUR_CHANGED(wxWindow::OnSysColourChanged)
- EVT_INIT_DIALOG(wxWindow::OnInitDialog)
- EVT_IDLE(wxWindow::OnIdle)
-END_EVENT_TABLE()
-
-wxWindow::wxWindow()
-{
- m_widget = (GtkWidget *) NULL;
- m_wxwindow = (GtkWidget *) NULL;
- m_parent = (wxWindow *) NULL;
- m_children.DeleteContents( FALSE );
- m_x = 0;
- m_y = 0;
- m_width = 0;
- m_height = 0;
- m_minWidth = -1;
- m_minHeight = -1;
- m_maxWidth = -1;
- m_maxHeight = -1;
- m_retCode = 0;
- m_eventHandler = this;
- m_windowValidator = (wxValidator *) NULL;
- m_windowId = -1;
- m_cursor = new wxCursor( wxCURSOR_ARROW );
- m_font = *wxSWISS_FONT;
- m_windowStyle = 0;
- m_windowName = "noname";
- m_constraints = (wxLayoutConstraints *) NULL;
- m_constraintsInvolvedIn = (wxList *) NULL;
- m_windowSizer = (wxSizer *) NULL;
- m_sizerParent = (wxWindow *) NULL;
- m_autoLayout = FALSE;
- m_sizeSet = FALSE;
- m_hasVMT = FALSE;
- m_needParent = TRUE;
- m_hasScrolling = FALSE;
- m_hAdjust = (GtkAdjustment *) NULL;
- m_vAdjust = (GtkAdjustment *) NULL;
- m_oldHorizontalPos = 0.0;
- m_oldVerticalPos = 0.0;
- m_isShown = FALSE;
- m_isEnabled = TRUE;
- m_pDropTarget = (wxDropTarget *) NULL;
- m_resizing = FALSE;
-}
-
-bool wxWindow::Create( wxWindow *parent, wxWindowID id,
- const wxPoint &pos, const wxSize &size,
- long style, const wxString &name )
-{
- m_isShown = FALSE;
- m_isEnabled = TRUE;
- m_needParent = TRUE;
-
- m_cursor = (wxCursor *) NULL;
-
- PreCreation( parent, id, pos, size, style, name );
-
- m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
- m_hasScrolling = TRUE;
-
- GtkScrolledWindow *s_window;
- s_window = GTK_SCROLLED_WINDOW(m_widget);
-
- GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(m_widget)->klass );
- scroll_class->scrollbar_spacing = 0;
-
- gtk_scrolled_window_set_policy( s_window, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
-
- m_oldHorizontalPos = 0.0;
- m_oldVerticalPos = 0.0;
-
- m_hAdjust = gtk_range_get_adjustment( GTK_RANGE(s_window->hscrollbar) );
- m_vAdjust = gtk_range_get_adjustment( GTK_RANGE(s_window->vscrollbar) );
-
- gtk_signal_connect (GTK_OBJECT (m_hAdjust), "value_changed",
- (GtkSignalFunc) gtk_window_hscroll_callback, (gpointer) this );
- gtk_signal_connect (GTK_OBJECT (m_vAdjust), "value_changed",
- (GtkSignalFunc) gtk_window_vscroll_callback, (gpointer) this );
-
- gtk_signal_connect (GTK_OBJECT (m_hAdjust), "changed",
- (GtkSignalFunc) gtk_window_hscroll_change_callback, (gpointer) this );
- gtk_signal_connect (GTK_OBJECT (m_vAdjust), "changed",
- (GtkSignalFunc) gtk_window_vscroll_change_callback, (gpointer) this );
-
- GtkViewport *viewport;
- viewport = GTK_VIEWPORT(s_window->viewport);
-
- if (m_windowStyle & wxRAISED_BORDER)
- {
- gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_OUT );
- }
- else if (m_windowStyle & wxSUNKEN_BORDER)
- {
- gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_IN );
- }
- else
- {
- gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_NONE );
- }
-
- m_wxwindow = gtk_myfixed_new();
-
- if (m_wxwindow) GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
-
- if (m_windowStyle & wxTAB_TRAVERSAL == wxTAB_TRAVERSAL)
- GTK_WIDGET_UNSET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
- else
- GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
-
- gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
-
- // shut the viewport up
- gtk_viewport_set_hadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
- gtk_viewport_set_vadjustment( viewport, (GtkAdjustment*) gtk_adjustment_new( 0.0, 0.0, 0.0, 0.0, 0.0, 0.0) );
-
- // I _really_ don't want scrollbars in the beginning
- m_vAdjust->lower = 0.0;
- m_vAdjust->upper = 1.0;
- m_vAdjust->value = 0.0;
- m_vAdjust->step_increment = 1.0;
- m_vAdjust->page_increment = 1.0;
- m_vAdjust->page_size = 5.0;
- gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
- m_hAdjust->lower = 0.0;
- m_hAdjust->upper = 1.0;
- m_hAdjust->value = 0.0;
- m_hAdjust->step_increment = 1.0;
- m_hAdjust->page_increment = 1.0;
- m_hAdjust->page_size = 5.0;
- gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
-
- gtk_widget_show( m_wxwindow );
-
- PostCreation();
-
- Show( TRUE );
-
- return TRUE;
-}
-
-wxWindow::~wxWindow(void)
-{
- m_hasVMT = FALSE;
-
- if (m_pDropTarget) delete m_pDropTarget;
-
- if (m_parent) m_parent->RemoveChild( this );
- if (m_widget) Show( FALSE );
-
- DestroyChildren();
-
- if (m_wxwindow) gtk_widget_destroy( m_wxwindow );
-
- if (m_widget) gtk_widget_destroy( m_widget );
-
- wxDELETE(m_cursor);
-
- DeleteRelatedConstraints();
- if (m_constraints)
- {
- // This removes any dangling pointers to this window
- // in other windows' constraintsInvolvedIn lists.
- UnsetConstraints(m_constraints);
- delete m_constraints;
- m_constraints = (wxLayoutConstraints *) NULL;
- }
- if (m_windowSizer)
- {
- delete m_windowSizer;
- m_windowSizer = (wxSizer *) NULL;
- }
- // If this is a child of a sizer, remove self from parent
- if (m_sizerParent) m_sizerParent->RemoveChild((wxWindow *)this);
-
- // Just in case the window has been Closed, but
- // we're then deleting immediately: don't leave
- // dangling pointers.
- wxPendingDelete.DeleteObject(this);
-
- // Just in case we've loaded a top-level window via
- // wxWindow::LoadNativeDialog but we weren't a dialog
- // class
- wxTopLevelWindows.DeleteObject(this);
-
- if (m_windowValidator) delete m_windowValidator;
-}
-
-void wxWindow::PreCreation( wxWindow *parent, wxWindowID id,
- const wxPoint &pos, const wxSize &size,
- long style, const wxString &name )
-{
- if (m_needParent && (parent == NULL))
- wxFatalError( "Need complete parent.", name );
-
- m_widget = (GtkWidget *) NULL;
- m_hasVMT = FALSE;
- m_parent = parent;
- m_children.DeleteContents( FALSE );
- m_x = (int)pos.x;
- m_y = (int)pos.y;
- m_width = size.x;
- if (m_width == -1) m_width = 20;
- m_height = size.y;
- if (m_height == -1) m_height = 20;
- m_minWidth = -1;
- m_minHeight = -1;
- m_maxWidth = -1;
- m_maxHeight = -1;
- m_retCode = 0;
- m_eventHandler = this;
- m_windowId = id;
- m_sizeSet = FALSE;
- if (m_cursor == NULL)
- m_cursor = new wxCursor( wxCURSOR_ARROW );
- m_font = *wxSWISS_FONT;
- m_backgroundColour = wxWHITE;
- m_foregroundColour = wxBLACK;
- m_windowStyle = style;
- m_windowName = name;
- m_constraints = (wxLayoutConstraints *) NULL;
- m_constraintsInvolvedIn = (wxList *) NULL;
- m_windowSizer = (wxSizer *) NULL;
- m_sizerParent = (wxWindow *) NULL;
- m_autoLayout = FALSE;
- m_pDropTarget = (wxDropTarget *) NULL;
- m_resizing = FALSE;
- m_windowValidator = (wxValidator *) NULL;
-}
-
-void wxWindow::PostCreation(void)
-{
- if (m_parent) m_parent->AddChild( this );
-
-// GtkStyle *style = m_widget->style;
-// style->font = m_font.GetInternalFont( 1.0 ); // destroy old font ?
-
- GtkWidget *connect_widget = GetConnectWidget();
-
- if (m_wxwindow)
- {
- gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
- GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
-
- gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
- GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
- }
-
- gtk_signal_connect( GTK_OBJECT(connect_widget), "key_press_event",
- GTK_SIGNAL_FUNC(gtk_window_key_press_callback), (gpointer)this );
-
- gtk_signal_connect( GTK_OBJECT(connect_widget), "button_press_event",
- GTK_SIGNAL_FUNC(gtk_window_button_press_callback), (gpointer)this );
-
- gtk_signal_connect( GTK_OBJECT(connect_widget), "button_release_event",
- GTK_SIGNAL_FUNC(gtk_window_button_release_callback), (gpointer)this );
-
- gtk_signal_connect( GTK_OBJECT(connect_widget), "motion_notify_event",
- GTK_SIGNAL_FUNC(gtk_window_motion_notify_callback), (gpointer)this );
-
- gtk_signal_connect( GTK_OBJECT(connect_widget), "focus_in_event",
- GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
-
- gtk_signal_connect( GTK_OBJECT(connect_widget), "focus_out_event",
- GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
-
- // Only for cursor handling
-
- gtk_signal_connect( GTK_OBJECT(m_widget), "enter_notify_event",
- GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
-
- gtk_signal_connect( GTK_OBJECT(m_widget), "leave_notify_event",
- GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
-
- if (m_wxwindow)
- {
- gtk_signal_connect( GTK_OBJECT(m_wxwindow), "enter_notify_event",
- GTK_SIGNAL_FUNC(gtk_window_enter_callback), (gpointer)this );
-
- gtk_signal_connect( GTK_OBJECT(m_wxwindow), "leave_notify_event",
- GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
- }
-
- if (m_widget && m_parent) gtk_widget_realize( m_widget );
-
- if (m_wxwindow)
- {
- gtk_widget_realize( m_wxwindow );
- gdk_gc_set_exposures( m_wxwindow->style->fg_gc[0], TRUE );
- }
-
- SetCursor( wxSTANDARD_CURSOR );
-
- m_hasVMT = TRUE;
+void wxWindowGTK::RemoveChild(wxWindowBase *child)
+{
+ wxWindowBase::RemoveChild(child);
+ m_dirtyTabOrder = true;
+ wxTheApp->WakeUpIdle();
}
-bool wxWindow::HasVMT(void)
+/* static */
+wxLayoutDirection wxWindowGTK::GTKGetLayout(GtkWidget *widget)
{
- return m_hasVMT;
+ return gtk_widget_get_direction(widget) == GTK_TEXT_DIR_RTL
+ ? wxLayout_RightToLeft
+ : wxLayout_LeftToRight;
}
-bool wxWindow::Close( bool force )
+/* static */
+void wxWindowGTK::GTKSetLayout(GtkWidget *widget, wxLayoutDirection dir)
{
- wxCloseEvent event(wxEVT_CLOSE_WINDOW, m_windowId);
- event.SetEventObject(this);
- event.SetForce(force);
+ wxASSERT_MSG( dir != wxLayout_Default, _T("invalid layout direction") );
- return GetEventHandler()->ProcessEvent(event);
+ gtk_widget_set_direction(widget,
+ dir == wxLayout_RightToLeft ? GTK_TEXT_DIR_RTL
+ : GTK_TEXT_DIR_LTR);
}
-bool wxWindow::Destroy(void)
+wxLayoutDirection wxWindowGTK::GetLayoutDirection() const
{
- m_hasVMT = FALSE;
- delete this;
- return TRUE;
+ return GTKGetLayout(m_widget);
}
-bool wxWindow::DestroyChildren(void)
+void wxWindowGTK::SetLayoutDirection(wxLayoutDirection dir)
{
- if (GetChildren())
- {
- wxNode *node;
- while ((node = GetChildren()->First()) != (wxNode *)NULL)
+ if ( dir == wxLayout_Default )
{
- wxWindow *child;
- if ((child = (wxWindow *)node->Data()) != (wxWindow *)NULL)
- {
- delete child;
- if (GetChildren()->Member(child)) delete node;
- }
+ const wxWindow *const parent = GetParent();
+ if ( parent )
+ {
+ // inherit layout from parent.
+ dir = parent->GetLayoutDirection();
+ }
+ else // no parent, use global default layout
+ {
+ dir = wxTheApp->GetLayoutDirection();
+ }
}
- }
- return TRUE;
-}
-
-void wxWindow::PrepareDC( wxDC &WXUNUSED(dc) )
-{
- // are we to set fonts here ?
-}
-void wxWindow::ImplementSetSize(void)
-{
- if ((m_minWidth != -1) && (m_width < m_minWidth)) m_width = m_minWidth;
- if ((m_minHeight != -1) && (m_height < m_minHeight)) m_height = m_minHeight;
- if ((m_maxWidth != -1) && (m_width > m_maxWidth)) m_width = m_minWidth;
- if ((m_maxHeight != -1) && (m_height > m_maxHeight)) m_height = m_minHeight;
- gtk_widget_set_usize( m_widget, m_width, m_height );
-}
+ if ( dir == wxLayout_Default )
+ return;
-void wxWindow::ImplementSetPosition(void)
-{
- if (IS_KIND_OF(this,wxFrame) || IS_KIND_OF(this,wxDialog))
- {
- if ((m_x != -1) || (m_y != -1))
- gtk_widget_set_uposition( m_widget, m_x, m_y );
- return;
- }
-
- if (!m_parent)
- {
- wxFAIL_MSG( "wxWindow::SetSize error.\n" );
- return;
- }
-
- if ((m_parent) && (m_parent->m_wxwindow))
- gtk_myfixed_move( GTK_MYFIXED(m_parent->m_wxwindow), m_widget, m_x, m_y );
-
- // Don't do anything for children of wxNotebook and wxMDIChildFrame
-}
-
-void wxWindow::SetSize( int x, int y, int width, int height, int sizeFlags )
-{
- if (m_resizing) return; // I don't like recursions
- m_resizing = TRUE;
-
- int newX = x;
- int newY = y;
- int newW = width;
- int newH = height;
-
- if ((sizeFlags & wxSIZE_USE_EXISTING) == wxSIZE_USE_EXISTING)
- {
- if (newX == -1) newX = m_x;
- if (newY == -1) newY = m_y;
- if (newW == -1) newW = m_width;
- if (newH == -1) newH = m_height;
- }
-
- if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
- {
- if (newW == -1) newW = 80;
- }
-
- if ((sizeFlags & wxSIZE_AUTO_HEIGHT) == wxSIZE_AUTO_HEIGHT)
- {
- if (newH == -1) newH = 26;
- }
-
- if ((m_x != newX) || (m_y != newY) || (!m_sizeSet))
- {
- m_x = newX;
- m_y = newY;
- ImplementSetPosition();
- }
- if ((m_width != newW) || (m_height != newH) || (!m_sizeSet))
- {
- m_width = newW;
- m_height = newH;
- ImplementSetSize();
- }
- m_sizeSet = TRUE;
-
- wxSizeEvent event( wxSize(m_width,m_height), GetId() );
- event.SetEventObject( this );
- ProcessEvent( event );
-
- m_resizing = FALSE;
-}
+ GTKSetLayout(m_widget, dir);
-void wxWindow::SetSize( int width, int height )
-{
- SetSize( -1, -1, width, height, wxSIZE_USE_EXISTING );
+ if (m_wxwindow && (m_wxwindow != m_widget))
+ GTKSetLayout(m_wxwindow, dir);
}
-void wxWindow::Move( int x, int y )
+wxCoord
+wxWindowGTK::AdjustForLayoutDirection(wxCoord x,
+ wxCoord WXUNUSED(width),
+ wxCoord WXUNUSED(widthTotal)) const
{
- SetSize( x, y, -1, -1, wxSIZE_USE_EXISTING );
+ // We now mirrors the coordinates of RTL windows in GtkPizza
+ return x;
}
-void wxWindow::GetSize( int *width, int *height ) const
+void wxWindowGTK::DoMoveInTabOrder(wxWindow *win, MoveKind move)
{
- if (width) (*width) = m_width;
- if (height) (*height) = m_height;
+ wxWindowBase::DoMoveInTabOrder(win, move);
+ m_dirtyTabOrder = true;
+ wxTheApp->WakeUpIdle();
}
-void wxWindow::SetClientSize( int width, int height )
+bool wxWindowGTK::DoNavigateIn(int flags)
{
- if (!m_wxwindow)
- {
- SetSize( width, height );
- }
- else
- {
- int dw = 0;
- int dh = 0;
-
- if (!m_hasScrolling)
+ if ( flags & wxNavigationKeyEvent::WinChange )
{
-/*
- do we have sunken dialogs ?
-
- GtkStyleClass *window_class = m_wxwindow->style->klass;
-
- dw += 2 * window_class->xthickness;
- dh += 2 * window_class->ythickness;
-*/
+ wxFAIL_MSG( _T("not implemented") );
+
+ return false;
}
- else
+ else // navigate inside the container
{
- GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
- GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(m_widget)->klass );
-
- GtkWidget *viewport = scroll_window->viewport;
- GtkStyleClass *viewport_class = viewport->style->klass;
-
- GtkWidget *hscrollbar = scroll_window->hscrollbar;
- GtkWidget *vscrollbar = scroll_window->vscrollbar;
-
- if ((m_windowStyle & wxRAISED_BORDER) ||
- (m_windowStyle & wxSUNKEN_BORDER))
- {
- dw += 2 * viewport_class->xthickness;
- dh += 2 * viewport_class->ythickness;
- }
-
- if (GTK_WIDGET_VISIBLE(vscrollbar))
- {
- dw += vscrollbar->allocation.width;
- dw += scroll_class->scrollbar_spacing;
- }
-
- if (GTK_WIDGET_VISIBLE(hscrollbar))
- {
- dh += hscrollbar->allocation.height;
- dw += scroll_class->scrollbar_spacing;
- }
- }
-
- SetSize( width+dw, height+dh );
- }
-}
+ wxWindow *parent = wxGetTopLevelParent(this);
+ wxCHECK_MSG( parent, false, _T("every window must have a TLW parent") );
-void wxWindow::GetClientSize( int *width, int *height ) const
-{
- if (!m_wxwindow)
- {
- if (width) (*width) = m_width;
- if (height) (*height) = m_height;
- }
- else
- {
- int dw = 0;
- int dh = 0;
-
- if (!m_hasScrolling)
- {
-/*
- do we have sunken dialogs ?
-
- GtkStyleClass *window_class = m_wxwindow->style->klass;
-
- dw += 2 * window_class->xthickness;
- dh += 2 * window_class->ythickness;
-*/
+ GtkDirectionType dir;
+ dir = flags & wxNavigationKeyEvent::IsForward ? GTK_DIR_TAB_FORWARD
+ : GTK_DIR_TAB_BACKWARD;
+
+ gboolean rc;
+ g_signal_emit_by_name(parent->m_widget, "focus", dir, &rc);
+
+ return rc == TRUE;
}
- else
- {
- GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(m_widget);
- GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT(m_widget)->klass );
-
- GtkWidget *viewport = scroll_window->viewport;
- GtkStyleClass *viewport_class = viewport->style->klass;
-
- GtkWidget *hscrollbar = scroll_window->hscrollbar;
- GtkWidget *vscrollbar = scroll_window->vscrollbar;
-
- if ((m_windowStyle & wxRAISED_BORDER) ||
- (m_windowStyle & wxSUNKEN_BORDER))
- {
- dw += 2 * viewport_class->xthickness;
- dh += 2 * viewport_class->ythickness;
- }
-
- if (GTK_WIDGET_VISIBLE(vscrollbar))
- {
-// dw += vscrollbar->allocation.width;
- dw += 15; // range.slider_width = 11 + 2*2pts edge
- dw += scroll_class->scrollbar_spacing;
- }
-
- if (GTK_WIDGET_VISIBLE(hscrollbar))
- {
-// dh += hscrollbar->allocation.height;
- dh += 15;
- dh += scroll_class->scrollbar_spacing;
- }
- }
-
- if (width) (*width) = m_width - dw;
- if (height) (*height) = m_height - dh;
- }
}
-void wxWindow::GetPosition( int *x, int *y ) const
+bool wxWindowGTK::GTKWidgetNeedsMnemonic() const
{
- if (x) (*x) = m_x;
- if (y) (*y) = m_y;
+ // none needed by default
+ return false;
}
-void wxWindow::ClientToScreen( int *x, int *y )
+void wxWindowGTK::GTKWidgetDoSetMnemonic(GtkWidget* WXUNUSED(w))
{
- GdkWindow *source = (GdkWindow *) NULL;
- if (m_wxwindow)
- source = m_wxwindow->window;
- else
- source = m_widget->window;
-
- int org_x = 0;
- int org_y = 0;
- gdk_window_get_origin( source, &org_x, &org_y );
+ // nothing to do by default since none is needed
+}
- if (!m_wxwindow)
- {
- if (GTK_WIDGET_NO_WINDOW (m_widget))
+void wxWindowGTK::RealizeTabOrder()
+{
+ if (m_wxwindow)
{
- org_x += m_widget->allocation.x;
- org_y += m_widget->allocation.y;
+ if ( !m_children.empty() )
+ {
+ // we don't only construct the correct focus chain but also use
+ // this opportunity to update the mnemonic widgets for the widgets
+ // that need them
+
+ GList *chain = NULL;
+ wxWindowGTK* mnemonicWindow = NULL;
+
+ for ( wxWindowList::const_iterator i = m_children.begin();
+ i != m_children.end();
+ ++i )
+ {
+ wxWindowGTK *win = *i;
+
+ if ( mnemonicWindow )
+ {
+ if ( win->AcceptsFocusFromKeyboard() )
+ {
+ // wxComboBox et al. needs to focus on on a different
+ // widget than m_widget, so if the main widget isn't
+ // focusable try the connect widget
+ GtkWidget* w = win->m_widget;
+ if ( !GTK_WIDGET_CAN_FOCUS(w) )
+ {
+ w = win->GetConnectWidget();
+ if ( !GTK_WIDGET_CAN_FOCUS(w) )
+ w = NULL;
+ }
+
+ if ( w )
+ {
+ mnemonicWindow->GTKWidgetDoSetMnemonic(w);
+ mnemonicWindow = NULL;
+ }
+ }
+ }
+ else if ( win->GTKWidgetNeedsMnemonic() )
+ {
+ mnemonicWindow = win;
+ }
+
+ chain = g_list_prepend(chain, win->m_widget);
+ }
+
+ chain = g_list_reverse(chain);
+
+ gtk_container_set_focus_chain(GTK_CONTAINER(m_wxwindow), chain);
+ g_list_free(chain);
+ }
+ else // no children
+ {
+ gtk_container_unset_focus_chain(GTK_CONTAINER(m_wxwindow));
+ }
}
- }
-
- if (x) *x += org_x;
- if (y) *y += org_y;
}
-void wxWindow::ScreenToClient( int *x, int *y )
+void wxWindowGTK::Raise()
{
- GdkWindow *source = (GdkWindow *) NULL;
- if (m_wxwindow)
- source = m_wxwindow->window;
- else
- source = m_widget->window;
-
- int org_x = 0;
- int org_y = 0;
- gdk_window_get_origin( source, &org_x, &org_y );
+ wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
- if (!m_wxwindow)
- {
- if (GTK_WIDGET_NO_WINDOW (m_widget))
+ if (m_wxwindow && m_wxwindow->window)
{
- org_x += m_widget->allocation.x;
- org_y += m_widget->allocation.y;
+ gdk_window_raise( m_wxwindow->window );
+ }
+ else if (m_widget->window)
+ {
+ gdk_window_raise( m_widget->window );
}
- }
-
- if (x) *x -= org_x;
- if (y) *y -= org_y;
}
-void wxWindow::Centre( int direction )
+void wxWindowGTK::Lower()
{
- if (IS_KIND_OF(this,wxDialog) || IS_KIND_OF(this,wxFrame))
- {
- if (direction & wxHORIZONTAL == wxHORIZONTAL) m_x = (gdk_screen_width () - m_width) / 2;
- if (direction & wxVERTICAL == wxVERTICAL) m_y = (gdk_screen_height () - m_height) / 2;
- ImplementSetPosition();
- }
- else
- {
- if (m_parent)
+ wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
+
+ if (m_wxwindow && m_wxwindow->window)
{
- int p_w = 0;
- int p_h = 0;
- m_parent->GetSize( &p_w, &p_h );
- if (direction & wxHORIZONTAL == wxHORIZONTAL) m_x = (p_w - m_width) / 2;
- if (direction & wxVERTICAL == wxVERTICAL) m_y = (p_h - m_height) / 2;
- ImplementSetPosition();
+ gdk_window_lower( m_wxwindow->window );
+ }
+ else if (m_widget->window)
+ {
+ gdk_window_lower( m_widget->window );
}
- }
}
-void wxWindow::Fit(void)
+bool wxWindowGTK::SetCursor( const wxCursor &cursor )
{
- int maxX = 0;
- int maxY = 0;
- wxNode *node = GetChildren()->First();
- while ( node )
- {
- wxWindow *win = (wxWindow *)node->Data();
- int wx, wy, ww, wh;
- win->GetPosition(&wx, &wy);
- win->GetSize(&ww, &wh);
- if ( wx + ww > maxX )
- maxX = wx + ww;
- if ( wy + wh > maxY )
- maxY = wy + wh;
-
- node = node->Next();
- }
- SetClientSize(maxX + 5, maxY + 10);
-}
+ if ( !wxWindowBase::SetCursor(cursor.Ok() ? cursor : *wxSTANDARD_CURSOR) )
+ return false;
-void wxWindow::SetSizeHints( int minW, int minH, int maxW, int maxH, int WXUNUSED(incW), int WXUNUSED(incH) )
-{
- m_minWidth = minW;
- m_minHeight = minH;
- m_maxWidth = maxW;
- m_maxHeight = maxH;
-}
+ GTKUpdateCursor();
-void wxWindow::OnSize( wxSizeEvent &WXUNUSED(event) )
-{
- //if (GetAutoLayout()) Layout();
+ return true;
}
-bool wxWindow::Show( bool show )
+void wxWindowGTK::GTKUpdateCursor()
{
- if (show)
- gtk_widget_show( m_widget );
- else
- gtk_widget_hide( m_widget );
- m_isShown = show;
- return TRUE;
+ wxCursor cursor(g_globalCursor.Ok() ? g_globalCursor : GetCursor());
+ if ( cursor.Ok() )
+ {
+ wxArrayGdkWindows windowsThis;
+ GdkWindow * const winThis = GTKGetWindow(windowsThis);
+ if ( winThis )
+ {
+ gdk_window_set_cursor(winThis, cursor.GetCursor());
+ }
+ else
+ {
+ const size_t count = windowsThis.size();
+ for ( size_t n = 0; n < count; n++ )
+ {
+ GdkWindow *win = windowsThis[n];
+ if ( !win )
+ {
+ wxFAIL_MSG(_T("NULL window returned by GTKGetWindow()?"));
+ continue;
+ }
+
+ gdk_window_set_cursor(win, cursor.GetCursor());
+ }
+ }
+ }
}
-void wxWindow::Enable( bool enable )
+void wxWindowGTK::WarpPointer( int x, int y )
{
- m_isEnabled = enable;
- gtk_widget_set_sensitive( m_widget, enable );
- if (m_wxwindow) gtk_widget_set_sensitive( m_wxwindow, enable );
-}
+ wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
-int wxWindow::GetCharHeight(void) const
-{
- GdkFont *font = m_font.GetInternalFont( 1.0 );
- return font->ascent + font->descent;
-}
+ // We provide this function ourselves as it is
+ // missing in GDK (top of this file).
-int wxWindow::GetCharWidth(void) const
-{
- GdkFont *font = m_font.GetInternalFont( 1.0 );
- return gdk_string_width( font, "H" );
+ GdkWindow *window = (GdkWindow*) NULL;
+ if (m_wxwindow)
+ window = GTK_PIZZA(m_wxwindow)->bin_window;
+ else
+ window = GetConnectWidget()->window;
+
+ if (window)
+ gdk_window_warp_pointer( window, x, y );
}
-void wxWindow::GetTextExtent( const wxString& string, int *x, int *y,
- int *descent, int *externalLeading, const wxFont *theFont, bool WXUNUSED(use16) ) const
+wxWindowGTK::ScrollDir wxWindowGTK::ScrollDirFromRange(GtkRange *range) const
{
- wxFont fontToUse = m_font;
- if (theFont) fontToUse = *theFont;
-
- GdkFont *font = fontToUse.GetInternalFont( 1.0 );
- if (x) (*x) = gdk_string_width( font, string );
- if (y) (*y) = font->ascent + font->descent;
- if (descent) (*descent) = font->descent;
- if (externalLeading) (*externalLeading) = 0; // ??
+ // find the scrollbar which generated the event
+ for ( int dir = 0; dir < ScrollDir_Max; dir++ )
+ {
+ if ( range == m_scrollBar[dir] )
+ return (ScrollDir)dir;
+ }
+
+ wxFAIL_MSG( _T("event from unknown scrollbar received") );
+
+ return ScrollDir_Max;
}
-void wxWindow::MakeModal( bool modal )
+bool wxWindowGTK::DoScrollByUnits(ScrollDir dir, ScrollUnit unit, int units)
{
- return;
- // Disable all other windows
- if (this->IsKindOf(CLASSINFO(wxDialog)) || this->IsKindOf(CLASSINFO(wxFrame)))
- {
- wxNode *node = wxTopLevelWindows.First();
- while (node)
+ bool changed = false;
+ GtkRange* range = m_scrollBar[dir];
+ if ( range && units )
{
- wxWindow *win = (wxWindow *)node->Data();
- if (win != this)
- win->Enable(!modal);
+ GtkAdjustment* adj = range->adjustment;
+ gdouble inc = unit == ScrollUnit_Line ? adj->step_increment
+ : adj->page_increment;
- node = node->Next();
+ const int posOld = int(adj->value + 0.5);
+ gtk_range_set_value(range, posOld + units*inc);
+
+ changed = int(adj->value + 0.5) != posOld;
}
- }
+
+ return changed;
}
-void wxWindow::SetFocus(void)
+bool wxWindowGTK::ScrollLines(int lines)
{
- GtkWidget *connect_widget = GetConnectWidget();
- if (connect_widget)
- {
- if (GTK_WIDGET_CAN_FOCUS(connect_widget) && !GTK_WIDGET_HAS_FOCUS (connect_widget) )
- {
- gtk_widget_grab_focus (connect_widget);
- }
- }
+ return DoScrollByUnits(ScrollDir_Vert, ScrollUnit_Line, lines);
}
-bool wxWindow::OnClose(void)
+bool wxWindowGTK::ScrollPages(int pages)
{
- return TRUE;
+ return DoScrollByUnits(ScrollDir_Vert, ScrollUnit_Page, pages);
}
-void wxWindow::AddChild( wxWindow *child )
+void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
{
- // Addchild is (often) called before the program
- // has left the parents constructor so that no
- // virtual tables work yet. The approach below
- // practically imitates virtual tables, i.e. it
- // implements a different AddChild() behaviour
- // for wxFrame, wxDialog, wxWindow and
- // wxMDIParentFrame.
+ if (!m_widget)
+ return;
+ if (!m_widget->window)
+ return;
- // wxFrame and wxDialog as children aren't placed into the parents
-
- if (( IS_KIND_OF(child,wxFrame) || IS_KIND_OF(child,wxDialog) ) &&
- (!IS_KIND_OF(child,wxMDIChildFrame)))
- {
- m_children.Append( child );
-
- if ((child->m_x != -1) && (child->m_y != -1))
- gtk_widget_set_uposition( child->m_widget, child->m_x, child->m_y );
-
- return;
- }
-
- // In the case of an wxMDIChildFrame descendant, we use the
- // client windows's AddChild()
-
- if (IS_KIND_OF(this,wxMDIParentFrame))
- {
- if (IS_KIND_OF(child,wxMDIChildFrame))
+ if (m_wxwindow)
{
- wxMDIClientWindow *client = ((wxMDIParentFrame*)this)->GetClientWindow();
- if (client)
- {
- client->AddChild( child );
- return;
- }
- }
- }
-
- // wxNotebook is very special, so it has a private AddChild()
-
- if (IS_KIND_OF(this,wxNotebook))
- {
- wxNotebook *tab = (wxNotebook*)this;
- tab->AddChild( child );
- return;
- }
-
- // wxFrame has a private AddChild
-
- if (IS_KIND_OF(this,wxFrame) && !IS_KIND_OF(this,wxMDIChildFrame))
- {
- wxFrame *frame = (wxFrame*)this;
- frame->AddChild( child );
- return;
- }
-
- // All the rest
-
- m_children.Append( child );
- if (m_wxwindow) gtk_myfixed_put( GTK_MYFIXED(m_wxwindow), child->m_widget,
- child->m_x, child->m_y );
-
- gtk_widget_set_usize( child->m_widget, child->m_width, child->m_height );
-}
+ if (!GTK_PIZZA(m_wxwindow)->bin_window) return;
-wxList *wxWindow::GetChildren(void)
-{
- return (&m_children);
-}
+ GdkRectangle gdk_rect,
+ *p;
+ if (rect)
+ {
+ gdk_rect.x = rect->x;
+ gdk_rect.y = rect->y;
+ gdk_rect.width = rect->width;
+ gdk_rect.height = rect->height;
+ if (GetLayoutDirection() == wxLayout_RightToLeft)
+ gdk_rect.x = GetClientSize().x - gdk_rect.x - gdk_rect.width;
+
+ p = &gdk_rect;
+ }
+ else // invalidate everything
+ {
+ p = NULL;
+ }
-void wxWindow::RemoveChild( wxWindow *child )
-{
- if (GetChildren())
- GetChildren()->DeleteObject( child );
- child->m_parent = (wxWindow *) NULL;
+ gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow)->bin_window, p, TRUE );
+ }
}
-void wxWindow::SetReturnCode( int retCode )
+void wxWindowGTK::Update()
{
- m_retCode = retCode;
-}
+ GtkUpdate();
-int wxWindow::GetReturnCode(void)
-{
- return m_retCode;
+ // when we call Update() we really want to update the window immediately on
+ // screen, even if it means flushing the entire queue and hence slowing down
+ // everything -- but it should still be done, it's just that Update() should
+ // be called very rarely
+ gdk_flush();
}
-void wxWindow::Raise(void)
+void wxWindowGTK::GtkUpdate()
{
- if (m_widget) gdk_window_raise( m_widget->window );
-}
+ if (m_wxwindow && GTK_PIZZA(m_wxwindow)->bin_window)
+ gdk_window_process_updates( GTK_PIZZA(m_wxwindow)->bin_window, FALSE );
+ if (m_widget && m_widget->window && (m_wxwindow != m_widget))
+ gdk_window_process_updates( m_widget->window, FALSE );
-void wxWindow::Lower(void)
-{
- if (m_widget) gdk_window_lower( m_widget->window );
+ // for consistency with other platforms (and also because it's convenient
+ // to be able to update an entire TLW by calling Update() only once), we
+ // should also update all our children here
+ for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
+ node;
+ node = node->GetNext() )
+ {
+ node->GetData()->GtkUpdate();
+ }
}
-wxEvtHandler *wxWindow::GetEventHandler(void)
+bool wxWindowGTK::DoIsExposed( int x, int y ) const
{
- return m_eventHandler;
+ return m_updateRegion.Contains(x, y) != wxOutRegion;
}
-void wxWindow::SetEventHandler( wxEvtHandler *handler )
-{
- m_eventHandler = handler;
-}
-void wxWindow::PushEventHandler(wxEvtHandler *handler)
+bool wxWindowGTK::DoIsExposed( int x, int y, int w, int h ) const
{
- handler->SetNextHandler(GetEventHandler());
- SetEventHandler(handler);
+ if (GetLayoutDirection() == wxLayout_RightToLeft)
+ return m_updateRegion.Contains(x-w, y, w, h) != wxOutRegion;
+ else
+ return m_updateRegion.Contains(x, y, w, h) != wxOutRegion;
}
-wxEvtHandler *wxWindow::PopEventHandler(bool deleteHandler)
+void wxWindowGTK::GtkSendPaintEvents()
{
- if ( GetEventHandler() )
- {
- wxEvtHandler *handlerA = GetEventHandler();
- wxEvtHandler *handlerB = handlerA->GetNextHandler();
- handlerA->SetNextHandler((wxEvtHandler *) NULL);
- SetEventHandler(handlerB);
- if ( deleteHandler )
- {
- delete handlerA;
- return (wxEvtHandler *) NULL;
- }
- else
- return handlerA;
- }
- else
- return (wxEvtHandler *) NULL;
-}
+ if (!m_wxwindow)
+ {
+ m_updateRegion.Clear();
+ return;
+ }
-wxValidator *wxWindow::GetValidator(void)
-{
- return m_windowValidator;
-}
+ // Clip to paint region in wxClientDC
+ m_clipPaintRegion = true;
-void wxWindow::SetValidator( const wxValidator& validator )
-{
- if (m_windowValidator) delete m_windowValidator;
- m_windowValidator = validator.Clone();
- if (m_windowValidator) m_windowValidator->SetWindow(this);
-}
+ m_nativeUpdateRegion = m_updateRegion;
-bool wxWindow::IsBeingDeleted(void)
-{
- return FALSE;
-}
+ if (GetLayoutDirection() == wxLayout_RightToLeft)
+ {
+ // Transform m_updateRegion under RTL
+ m_updateRegion.Clear();
-void wxWindow::SetId( wxWindowID id )
-{
- m_windowId = id;
-}
+ gint width;
+ gdk_window_get_geometry( GTK_PIZZA(m_wxwindow)->bin_window,
+ NULL, NULL, &width, NULL, NULL );
-wxWindowID wxWindow::GetId(void)
-{
- return m_windowId;
-}
+ wxRegionIterator upd( m_nativeUpdateRegion );
+ while (upd)
+ {
+ wxRect rect;
+ rect.x = upd.GetX();
+ rect.y = upd.GetY();
+ rect.width = upd.GetWidth();
+ rect.height = upd.GetHeight();
-void wxWindow::SetCursor( const wxCursor &cursor )
-{
- wxASSERT(m_cursor != NULL);
+ rect.x = width - rect.x - rect.width;
+ m_updateRegion.Union( rect );
- if (m_cursor != NULL)
- if (*m_cursor == cursor)
- return;
- (*m_cursor) = cursor;
- if (m_widget->window)
- gdk_window_set_cursor( m_widget->window, m_cursor->GetCursor() );
- if (m_wxwindow && m_wxwindow->window)
- gdk_window_set_cursor( m_wxwindow->window, m_cursor->GetCursor() );
-}
+ ++upd;
+ }
+ }
-void wxWindow::Refresh( bool eraseBackground, const wxRect *rect )
-{
- if (eraseBackground && m_wxwindow && m_wxwindow->window)
- {
- if (rect)
- gdk_window_clear_area( m_wxwindow->window,
- rect->x,
- rect->y,
- rect->width,
- rect->height );
- else
- Clear();
- }
- if (!rect)
- {
- if (m_wxwindow)
+ // widget to draw on
+ GtkPizza *pizza = GTK_PIZZA (m_wxwindow);
+
+ if (GetThemeEnabled() && (GetBackgroundStyle() == wxBG_STYLE_SYSTEM))
{
- int w = 0;
- int h = 0;
- GetClientSize( &w, &h );
-
- GdkRectangle gdk_rect;
- gdk_rect.x = 0;
- gdk_rect.y = 0;
- gdk_rect.width = w;
- gdk_rect.height = h;
- gtk_widget_draw( m_wxwindow, &gdk_rect );
+ // find ancestor from which to steal background
+ wxWindow *parent = wxGetTopLevelParent((wxWindow *)this);
+ if (!parent)
+ parent = (wxWindow*)this;
+
+ if (GTK_WIDGET_MAPPED(parent->m_widget))
+ {
+ wxRegionIterator upd( m_nativeUpdateRegion );
+ while (upd)
+ {
+ GdkRectangle rect;
+ rect.x = upd.GetX();
+ rect.y = upd.GetY();
+ rect.width = upd.GetWidth();
+ rect.height = upd.GetHeight();
+
+ gtk_paint_flat_box( parent->m_widget->style,
+ pizza->bin_window,
+ (GtkStateType)GTK_WIDGET_STATE(m_wxwindow),
+ GTK_SHADOW_NONE,
+ &rect,
+ parent->m_widget,
+ (char *)"base",
+ 0, 0, -1, -1 );
+
+ ++upd;
+ }
+ }
}
- }
- else
- {
- GdkRectangle gdk_rect;
- gdk_rect.x = rect->x;
- gdk_rect.y = rect->y;
- gdk_rect.width = rect->width;
- gdk_rect.height = rect->height;
-
- if (m_wxwindow)
- gtk_widget_draw( m_wxwindow, &gdk_rect );
- else
- gtk_widget_draw( m_widget, &gdk_rect );
- }
-}
+ else
+ {
+ wxWindowDC dc( (wxWindow*)this );
+ dc.SetClippingRegion( m_updateRegion );
-wxRegion wxWindow::GetUpdateRegion() const
-{
- return m_updateRegion;
-}
+ wxEraseEvent erase_event( GetId(), &dc );
+ erase_event.SetEventObject( this );
-bool wxWindow::IsExposed( int x, int y) const
-{
- return (m_updateRegion.Contains( x, y ) != wxOutRegion );
-}
+ GetEventHandler()->ProcessEvent(erase_event);
+ }
-bool wxWindow::IsExposed( int x, int y, int w, int h ) const
-{
- return (m_updateRegion.Contains( x, y, w, h ) != wxOutRegion );
-}
+ wxNcPaintEvent nc_paint_event( GetId() );
+ nc_paint_event.SetEventObject( this );
+ GetEventHandler()->ProcessEvent( nc_paint_event );
-bool wxWindow::IsExposed( const wxPoint& pt ) const
-{
- return (m_updateRegion.Contains( pt.x, pt.y ) != wxOutRegion );
-}
+ wxPaintEvent paint_event( GetId() );
+ paint_event.SetEventObject( this );
+ GetEventHandler()->ProcessEvent( paint_event );
-bool wxWindow::IsExposed( const wxRect& rect ) const
-{
- return (m_updateRegion.Contains( rect.x, rect.y, rect.width, rect.height ) != wxOutRegion );
-}
+ m_clipPaintRegion = false;
-void wxWindow::Clear(void)
-{
- if (m_wxwindow && m_wxwindow->window) gdk_window_clear( m_wxwindow->window );
+ m_updateRegion.Clear();
+ m_nativeUpdateRegion.Clear();
}
-wxColour wxWindow::GetBackgroundColour(void) const
+void wxWindowGTK::SetDoubleBuffered( bool on )
{
- return m_backgroundColour;
-}
+ wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
-void wxWindow::SetBackgroundColour( const wxColour &colour )
-{
- m_backgroundColour = colour;
- if (m_wxwindow)
- {
- m_backgroundColour.CalcPixel( m_wxwindow->style->colormap );
- gdk_window_set_background( m_wxwindow->window, m_backgroundColour.GetColor() );
- gdk_window_clear( m_wxwindow->window );
- }
- // do something ?
+ if ( m_wxwindow )
+ gtk_widget_set_double_buffered( m_wxwindow, on );
}
-wxColour wxWindow::GetForegroundColour(void) const
+bool wxWindowGTK::IsDoubleBuffered() const
{
- return m_foregroundColour;
+ return GTK_WIDGET_DOUBLE_BUFFERED( m_wxwindow );
}
-void wxWindow::SetForegroundColour( const wxColour &colour )
+void wxWindowGTK::ClearBackground()
{
- m_foregroundColour = colour;
+ wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
}
-bool wxWindow::Validate(void)
+#if wxUSE_TOOLTIPS
+void wxWindowGTK::DoSetToolTip( wxToolTip *tip )
{
- wxNode *node = GetChildren()->First();
- while (node)
- {
- wxWindow *child = (wxWindow *)node->Data();
- if (child->GetValidator() && /* child->GetValidator()->Ok() && */ !child->GetValidator()->Validate(this))
- { return FALSE; }
- node = node->Next();
- }
- return TRUE;
+ wxWindowBase::DoSetToolTip(tip);
+
+ if (m_tooltip)
+ m_tooltip->Apply( (wxWindow *)this );
}
-bool wxWindow::TransferDataToWindow(void)
+void wxWindowGTK::ApplyToolTip( GtkTooltips *tips, const wxChar *tip )
{
- wxNode *node = GetChildren()->First();
- while (node)
- {
- wxWindow *child = (wxWindow *)node->Data();
- if (child->GetValidator() && /* child->GetValidator()->Ok() && */
- !child->GetValidator()->TransferToWindow() )
+ if (tip)
{
- wxMessageBox( _("Application Error"), _("Could not transfer data to window"), wxOK|wxICON_EXCLAMATION );
- return FALSE;
+ wxString tmp( tip );
+ gtk_tooltips_set_tip( tips, GetConnectWidget(), wxGTK_CONV(tmp), (gchar*) NULL );
+ }
+ else
+ {
+ gtk_tooltips_set_tip( tips, GetConnectWidget(), NULL, NULL);
}
- node = node->Next();
- }
- return TRUE;
}
+#endif // wxUSE_TOOLTIPS
-bool wxWindow::TransferDataFromWindow(void)
+bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
{
- wxNode *node = GetChildren()->First();
- while (node)
- {
- wxWindow *child = (wxWindow *)node->Data();
- if ( child->GetValidator() && /* child->GetValidator()->Ok() && */ !child->GetValidator()->TransferFromWindow() )
- { return FALSE; }
- node = node->Next();
- }
- return TRUE;
-}
+ wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
-void wxWindow::SetAcceleratorTable( const wxAcceleratorTable& accel )
-{
- m_acceleratorTable = accel;
-}
+ if (!wxWindowBase::SetBackgroundColour(colour))
+ return false;
-void wxWindow::OnInitDialog( wxInitDialogEvent &WXUNUSED(event) )
-{
- TransferDataToWindow();
-}
+ if (colour.Ok())
+ {
+ // We need the pixel value e.g. for background clearing.
+ m_backgroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
+ }
-void wxWindow::InitDialog(void)
-{
- wxInitDialogEvent event(GetId());
- event.SetEventObject( this );
- GetEventHandler()->ProcessEvent(event);
-}
+ // apply style change (forceStyle=true so that new style is applied
+ // even if the bg colour changed from valid to wxNullColour)
+ if (GetBackgroundStyle() != wxBG_STYLE_CUSTOM)
+ ApplyWidgetStyle(true);
-static void SetInvokingWindow( wxMenu *menu, wxWindow *win )
-{
- menu->SetInvokingWindow( win );
- wxNode *node = menu->m_items.First();
- while (node)
- {
- wxMenuItem *menuitem = (wxMenuItem*)node->Data();
- if (menuitem->IsSubMenu())
- SetInvokingWindow( menuitem->GetSubMenu(), win );
- node = node->Next();
- }
+ return true;
}
-bool wxWindow::PopupMenu( wxMenu *menu, int WXUNUSED(x), int WXUNUSED(y) )
+bool wxWindowGTK::SetForegroundColour( const wxColour &colour )
{
- SetInvokingWindow( menu, this );
- gtk_menu_popup( GTK_MENU(menu->m_menu), (GtkWidget *) NULL, (GtkWidget *) NULL, (GtkMenuPositionFunc) NULL, NULL, 0, 0 );
- return TRUE;
-}
+ wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
-void wxWindow::SetDropTarget( wxDropTarget *dropTarget )
-{
- GtkWidget *dnd_widget = GetConnectWidget();
-
- if (m_pDropTarget)
- {
- gtk_signal_disconnect_by_func( GTK_OBJECT(dnd_widget),
- GTK_SIGNAL_FUNC(gtk_window_drop_callback), (gpointer)this );
-
- m_pDropTarget->UnregisterWidget( dnd_widget );
- delete m_pDropTarget;
- }
- m_pDropTarget = dropTarget;
- if (m_pDropTarget)
- {
- m_pDropTarget->RegisterWidget( dnd_widget );
-
- gtk_signal_connect( GTK_OBJECT(dnd_widget), "drop_data_available_event",
- GTK_SIGNAL_FUNC(gtk_window_drop_callback), (gpointer)this );
- }
-}
+ if (!wxWindowBase::SetForegroundColour(colour))
+ {
+ return false;
+ }
-wxDropTarget *wxWindow::GetDropTarget() const
-{
- return m_pDropTarget;
-}
+ if (colour.Ok())
+ {
+ // We need the pixel value e.g. for background clearing.
+ m_foregroundColour.CalcPixel(gtk_widget_get_colormap(m_widget));
+ }
-GtkWidget* wxWindow::GetConnectWidget(void)
-{
- GtkWidget *connect_widget = m_widget;
- if (m_wxwindow) connect_widget = m_wxwindow;
-
- return connect_widget;
-}
-
-bool wxWindow::IsOwnGtkWindow( GdkWindow *window )
-{
- if (m_wxwindow) return (window == m_wxwindow->window);
- return (window == m_widget->window);
-}
+ // apply style change (forceStyle=true so that new style is applied
+ // even if the bg colour changed from valid to wxNullColour):
+ ApplyWidgetStyle(true);
-void wxWindow::SetFont( const wxFont &font )
-{
- m_font = font;
-/*
- create new style
- copy old style values to new one
- set font in new style
- -> takes to many resources
-
- GtkStyle *style = gtk_style_new();
- ...
-*/
+ return true;
}
-wxFont *wxWindow::GetFont(void)
+PangoContext *wxWindowGTK::GtkGetPangoDefaultContext()
{
- return &m_font;
+ return gtk_widget_get_pango_context( m_widget );
}
-void wxWindow::SetWindowStyleFlag( long flag )
+GtkRcStyle *wxWindowGTK::CreateWidgetStyle(bool forceStyle)
{
- m_windowStyle = flag;
-}
+ // do we need to apply any changes at all?
+ if ( !forceStyle &&
+ !m_font.Ok() &&
+ !m_foregroundColour.Ok() && !m_backgroundColour.Ok() )
+ {
+ return NULL;
+ }
-long wxWindow::GetWindowStyleFlag(void) const
-{
- return m_windowStyle;
-}
+ GtkRcStyle *style = gtk_rc_style_new();
-void wxWindow::CaptureMouse(void)
-{
- GtkWidget *connect_widget = GetConnectWidget();
- gtk_grab_add( connect_widget );
- gdk_pointer_grab ( connect_widget->window, FALSE,
- (GdkEventMask)
- (GDK_BUTTON_PRESS_MASK |
- GDK_BUTTON_RELEASE_MASK |
- GDK_POINTER_MOTION_MASK),
- (GdkWindow *) NULL, (GdkCursor *) NULL, GDK_CURRENT_TIME );
-}
+ if ( m_font.Ok() )
+ {
+ style->font_desc =
+ pango_font_description_copy( m_font.GetNativeFontInfo()->description );
+ }
-void wxWindow::ReleaseMouse(void)
-{
- GtkWidget *connect_widget = GetConnectWidget();
- gtk_grab_remove( connect_widget );
- gdk_pointer_ungrab ( GDK_CURRENT_TIME );
-}
+ int flagsNormal = 0,
+ flagsPrelight = 0,
+ flagsActive = 0,
+ flagsInsensitive = 0;
-void wxWindow::SetTitle( const wxString &WXUNUSED(title) )
-{
-}
+ if ( m_foregroundColour.Ok() )
+ {
+ const GdkColor *fg = m_foregroundColour.GetColor();
-wxString wxWindow::GetTitle(void) const
-{
- return (wxString&)m_windowName;
-}
+ style->fg[GTK_STATE_NORMAL] =
+ style->text[GTK_STATE_NORMAL] = *fg;
+ flagsNormal |= GTK_RC_FG | GTK_RC_TEXT;
-wxString wxWindow::GetLabel(void) const
-{
- return GetTitle();
-}
+ style->fg[GTK_STATE_PRELIGHT] =
+ style->text[GTK_STATE_PRELIGHT] = *fg;
+ flagsPrelight |= GTK_RC_FG | GTK_RC_TEXT;
-void wxWindow::SetName( const wxString &name )
-{
- m_windowName = name;
-}
+ style->fg[GTK_STATE_ACTIVE] =
+ style->text[GTK_STATE_ACTIVE] = *fg;
+ flagsActive |= GTK_RC_FG | GTK_RC_TEXT;
+ }
-wxString wxWindow::GetName(void) const
-{
- return (wxString&)m_windowName;
-}
+ if ( m_backgroundColour.Ok() )
+ {
+ const GdkColor *bg = m_backgroundColour.GetColor();
-bool wxWindow::IsShown(void) const
-{
- return m_isShown;
-}
+ style->bg[GTK_STATE_NORMAL] =
+ style->base[GTK_STATE_NORMAL] = *bg;
+ flagsNormal |= GTK_RC_BG | GTK_RC_BASE;
-bool wxWindow::IsRetained(void)
-{
- return FALSE;
-}
+ style->bg[GTK_STATE_PRELIGHT] =
+ style->base[GTK_STATE_PRELIGHT] = *bg;
+ flagsPrelight |= GTK_RC_BG | GTK_RC_BASE;
-wxWindow *wxWindow::FindWindow( long id )
-{
- if (id == m_windowId) return this;
- wxNode *node = m_children.First();
- while (node)
- {
- wxWindow *child = (wxWindow*)node->Data();
- wxWindow *res = child->FindWindow( id );
- if (res) return res;
- node = node->Next();
- }
- return (wxWindow *) NULL;
+ style->bg[GTK_STATE_ACTIVE] =
+ style->base[GTK_STATE_ACTIVE] = *bg;
+ flagsActive |= GTK_RC_BG | GTK_RC_BASE;
+
+ style->bg[GTK_STATE_INSENSITIVE] =
+ style->base[GTK_STATE_INSENSITIVE] = *bg;
+ flagsInsensitive |= GTK_RC_BG | GTK_RC_BASE;
+ }
+
+ style->color_flags[GTK_STATE_NORMAL] = (GtkRcFlags)flagsNormal;
+ style->color_flags[GTK_STATE_PRELIGHT] = (GtkRcFlags)flagsPrelight;
+ style->color_flags[GTK_STATE_ACTIVE] = (GtkRcFlags)flagsActive;
+ style->color_flags[GTK_STATE_INSENSITIVE] = (GtkRcFlags)flagsInsensitive;
+
+ return style;
}
-wxWindow *wxWindow::FindWindow( const wxString& name )
+void wxWindowGTK::ApplyWidgetStyle(bool forceStyle)
{
- if (name == m_windowName) return this;
- wxNode *node = m_children.First();
- while (node)
- {
- wxWindow *child = (wxWindow*)node->Data();
- wxWindow *res = child->FindWindow( name );
- if (res) return res;
- node = node->Next();
- }
- return (wxWindow *) NULL;
+ GtkRcStyle *style = CreateWidgetStyle(forceStyle);
+ if ( style )
+ {
+ DoApplyWidgetStyle(style);
+ gtk_rc_style_unref(style);
+ }
+
+ // Style change may affect GTK+'s size calculation:
+ InvalidateBestSize();
}
-void wxWindow::SetScrollbar( int orient, int pos, int thumbVisible,
- int range, bool WXUNUSED(refresh) )
+void wxWindowGTK::DoApplyWidgetStyle(GtkRcStyle *style)
{
- if (!m_wxwindow) return;
-
- if (orient == wxHORIZONTAL)
- {
- float fpos = (float)pos;
- m_oldHorizontalPos = fpos;
- float frange = (float)range;
- float fthumb = (float)thumbVisible;
-
- if ((fabs(fpos-m_hAdjust->value) < 0.2) &&
- (fabs(frange-m_hAdjust->upper) < 0.2) &&
- (fabs(fthumb-m_hAdjust->page_size) < 0.2))
- return;
-
- m_hAdjust->lower = 0.0;
- m_hAdjust->upper = frange;
- m_hAdjust->value = fpos;
- m_hAdjust->step_increment = 1.0;
- m_hAdjust->page_increment = (float)(wxMax(fthumb-2,0));
- m_hAdjust->page_size = fthumb;
- }
- else
- {
- float fpos = (float)pos;
- m_oldVerticalPos = fpos;
- float frange = (float)range;
- float fthumb = (float)thumbVisible;
-
- if ((fabs(fpos-m_vAdjust->value) < 0.2) &&
- (fabs(frange-m_vAdjust->upper) < 0.2) &&
- (fabs(fthumb-m_vAdjust->page_size) < 0.2))
- return;
-
- m_vAdjust->lower = 0.0;
- m_vAdjust->upper = frange;
- m_vAdjust->value = fpos;
- m_vAdjust->step_increment = 1.0;
- m_vAdjust->page_increment = (float)(wxMax(fthumb-2,0));
- m_vAdjust->page_size = fthumb;
- }
-
- if (m_wxwindow->window)
- {
- if (orient == wxHORIZONTAL)
- gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "changed" );
+ if (m_wxwindow)
+ gtk_widget_modify_style(m_wxwindow, style);
else
- gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "changed" );
-
- gtk_widget_set_usize( m_widget, m_width, m_height );
- }
+ gtk_widget_modify_style(m_widget, style);
}
-void wxWindow::SetScrollPos( int orient, int pos, bool WXUNUSED(refresh) )
+bool wxWindowGTK::SetBackgroundStyle(wxBackgroundStyle style)
{
- if (!m_wxwindow) return;
-
- if (orient == wxHORIZONTAL)
- {
- float fpos = (float)pos;
- m_oldHorizontalPos = fpos;
+ wxWindowBase::SetBackgroundStyle(style);
- if (fabs(fpos-m_hAdjust->value) < 0.2) return;
- m_hAdjust->value = fpos;
- }
- else
- {
- float fpos = (float)pos;
- m_oldVerticalPos = fpos;
- if (fabs(fpos-m_vAdjust->value) < 0.2) return;
- m_vAdjust->value = fpos;
- }
-
- if (m_wxwindow->window)
- {
- if (orient == wxHORIZONTAL)
- gtk_signal_emit_by_name( GTK_OBJECT(m_hAdjust), "value_changed" );
- else
- gtk_signal_emit_by_name( GTK_OBJECT(m_vAdjust), "value_changed" );
- }
-}
+ if (style == wxBG_STYLE_CUSTOM)
+ {
+ GdkWindow *window = (GdkWindow*) NULL;
+ if (m_wxwindow)
+ window = GTK_PIZZA(m_wxwindow)->bin_window;
+ else
+ window = GetConnectWidget()->window;
-int wxWindow::GetScrollThumb( int orient ) const
-{
- if (!m_wxwindow) return 0;
+ if (window)
+ {
+ // Make sure GDK/X11 doesn't refresh the window
+ // automatically.
+ gdk_window_set_back_pixmap( window, None, False );
+#ifdef __X__
+ Display* display = GDK_WINDOW_DISPLAY(window);
+ XFlush(display);
+#endif
+ m_needsStyleChange = false;
+ }
+ else
+ // Do in OnIdle, because the window is not yet available
+ m_needsStyleChange = true;
- if (orient == wxHORIZONTAL)
- return (int)(m_hAdjust->page_size+0.5);
- else
- return (int)(m_vAdjust->page_size+0.5);
+ // Don't apply widget style, or we get a grey background
+ }
+ else
+ {
+ // apply style change (forceStyle=true so that new style is applied
+ // even if the bg colour changed from valid to wxNullColour):
+ ApplyWidgetStyle(true);
+ }
+ return true;
}
-int wxWindow::GetScrollPos( int orient ) const
+#if wxUSE_DRAG_AND_DROP
+
+void wxWindowGTK::SetDropTarget( wxDropTarget *dropTarget )
{
- if (!m_wxwindow) return 0;
+ wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
- if (orient == wxHORIZONTAL)
- return (int)(m_hAdjust->value+0.5);
- else
- return (int)(m_vAdjust->value+0.5);
-}
+ GtkWidget *dnd_widget = GetConnectWidget();
-int wxWindow::GetScrollRange( int orient ) const
-{
- if (!m_wxwindow) return 0;
+ if (m_dropTarget) m_dropTarget->UnregisterWidget( dnd_widget );
- if (orient == wxHORIZONTAL)
- return (int)(m_hAdjust->upper+0.5);
- else
- return (int)(m_vAdjust->upper+0.5);
+ if (m_dropTarget) delete m_dropTarget;
+ m_dropTarget = dropTarget;
+
+ if (m_dropTarget) m_dropTarget->RegisterWidget( dnd_widget );
}
-void wxWindow::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
+#endif // wxUSE_DRAG_AND_DROP
+
+GtkWidget* wxWindowGTK::GetConnectWidget()
{
- if (!m_wxwindow) return;
-
-/*
- bool refresh = FALSE;
-
- if ((m_drawingOffsetX == 0) && (m_drawingOffsetY == 0))
- {
- m_drawingOffsetX = -16000;
- m_drawingOffsetY = -16000;
- refresh = TRUE;
- }
- else
- {
- m_drawingOffsetX += dx;
- m_drawingOffsetY += dy;
- }
-
-// printf( "X: %d Y: %d \n", (int)m_drawingOffsetX, (int)m_drawingOffsetY );
-
- gtk_myfixed_set_offset( GTK_MYFIXED(m_wxwindow), m_drawingOffsetX, m_drawingOffsetY );
-
- if (refresh) Refresh();
-
- The code here is very nifty, but it doesn't work with
- overlapping windows...
-*/
+ GtkWidget *connect_widget = m_widget;
+ if (m_wxwindow) connect_widget = m_wxwindow;
- int cw = 0;
- int ch = 0;
- GetClientSize( &cw, &ch );
-
- int w = cw - abs(dx);
- int h = ch - abs(dy);
- if ((h < 0) || (w < 0))
- {
- Refresh();
- return;
- }
- int s_x = 0;
- int s_y = 0;
- if (dx < 0) s_x = -dx;
- if (dy < 0) s_y = -dy;
- int d_x = 0;
- int d_y = 0;
- if (dx > 0) d_x = dx;
- if (dy > 0) d_y = dy;
- gdk_window_copy_area( m_wxwindow->window, m_wxwindow->style->fg_gc[0], d_x, d_y,
- m_wxwindow->window, s_x, s_y, w, h );
-
- wxRect rect;
- if (dx < 0) rect.x = cw+dx; else rect.x = 0;
- if (dy < 0) rect.y = ch+dy; else rect.y = 0;
- if (dy != 0) rect.width = cw; else rect.width = abs(dx);
- if (dx != 0) rect.height = ch; else rect.height = abs(dy);
-
- Refresh( TRUE, &rect );
-}
-
-//-------------------------------------------------------------------------------------
-// Layout
-//-------------------------------------------------------------------------------------
-
-wxLayoutConstraints *wxWindow::GetConstraints(void) const
-{
- return m_constraints;
-}
-
-void wxWindow::SetConstraints( wxLayoutConstraints *constraints )
-{
- if (m_constraints)
- {
- UnsetConstraints(m_constraints);
- delete m_constraints;
- }
- m_constraints = constraints;
- if (m_constraints)
- {
- // Make sure other windows know they're part of a 'meaningful relationship'
- if (m_constraints->left.GetOtherWindow() && (m_constraints->left.GetOtherWindow() != this))
- m_constraints->left.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
- if (m_constraints->top.GetOtherWindow() && (m_constraints->top.GetOtherWindow() != this))
- m_constraints->top.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
- if (m_constraints->right.GetOtherWindow() && (m_constraints->right.GetOtherWindow() != this))
- m_constraints->right.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
- if (m_constraints->bottom.GetOtherWindow() && (m_constraints->bottom.GetOtherWindow() != this))
- m_constraints->bottom.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
- if (m_constraints->width.GetOtherWindow() && (m_constraints->width.GetOtherWindow() != this))
- m_constraints->width.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
- if (m_constraints->height.GetOtherWindow() && (m_constraints->height.GetOtherWindow() != this))
- m_constraints->height.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
- if (m_constraints->centreX.GetOtherWindow() && (m_constraints->centreX.GetOtherWindow() != this))
- m_constraints->centreX.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
- if (m_constraints->centreY.GetOtherWindow() && (m_constraints->centreY.GetOtherWindow() != this))
- m_constraints->centreY.GetOtherWindow()->AddConstraintReference((wxWindow *)this);
- }
-;
+ return connect_widget;
}
-;
-void wxWindow::SetAutoLayout( bool autoLayout )
+bool wxWindowGTK::GTKIsOwnWindow(GdkWindow *window) const
{
- m_autoLayout = autoLayout;
-}
+ wxArrayGdkWindows windowsThis;
+ GdkWindow * const winThis = GTKGetWindow(windowsThis);
-bool wxWindow::GetAutoLayout(void) const
-{
- return m_autoLayout;
+ return winThis ? window == winThis
+ : windowsThis.Index(window) != wxNOT_FOUND;
}
-wxSizer *wxWindow::GetSizer(void) const
+GdkWindow *wxWindowGTK::GTKGetWindow(wxArrayGdkWindows& WXUNUSED(windows)) const
{
- return m_windowSizer;
+ return m_wxwindow ? GTK_PIZZA(m_wxwindow)->bin_window : m_widget->window;
}
-void wxWindow::SetSizerParent( wxWindow *win )
+bool wxWindowGTK::SetFont( const wxFont &font )
{
- m_sizerParent = win;
-}
+ wxCHECK_MSG( m_widget != NULL, false, wxT("invalid window") );
-wxWindow *wxWindow::GetSizerParent(void) const
-{
- return m_sizerParent;
-}
+ if (!wxWindowBase::SetFont(font))
+ return false;
-// This removes any dangling pointers to this window
-// in other windows' constraintsInvolvedIn lists.
-void wxWindow::UnsetConstraints(wxLayoutConstraints *c)
-{
- if (c)
- {
- if (c->left.GetOtherWindow() && (c->top.GetOtherWindow() != this))
- c->left.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
- if (c->top.GetOtherWindow() && (c->top.GetOtherWindow() != this))
- c->top.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
- if (c->right.GetOtherWindow() && (c->right.GetOtherWindow() != this))
- c->right.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
- if (c->bottom.GetOtherWindow() && (c->bottom.GetOtherWindow() != this))
- c->bottom.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
- if (c->width.GetOtherWindow() && (c->width.GetOtherWindow() != this))
- c->width.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
- if (c->height.GetOtherWindow() && (c->height.GetOtherWindow() != this))
- c->height.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
- if (c->centreX.GetOtherWindow() && (c->centreX.GetOtherWindow() != this))
- c->centreX.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
- if (c->centreY.GetOtherWindow() && (c->centreY.GetOtherWindow() != this))
- c->centreY.GetOtherWindow()->RemoveConstraintReference((wxWindow *)this);
- }
-}
+ // apply style change (forceStyle=true so that new style is applied
+ // even if the font changed from valid to wxNullFont):
+ ApplyWidgetStyle(true);
-// Back-pointer to other windows we're involved with, so if we delete
-// this window, we must delete any constraints we're involved with.
-void wxWindow::AddConstraintReference(wxWindow *otherWin)
-{
- if (!m_constraintsInvolvedIn)
- m_constraintsInvolvedIn = new wxList;
- if (!m_constraintsInvolvedIn->Member(otherWin))
- m_constraintsInvolvedIn->Append(otherWin);
+ return true;
}
-// REMOVE back-pointer to other windows we're involved with.
-void wxWindow::RemoveConstraintReference(wxWindow *otherWin)
+void wxWindowGTK::DoCaptureMouse()
{
- if (m_constraintsInvolvedIn)
- m_constraintsInvolvedIn->DeleteObject(otherWin);
-}
+ wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
-// Reset any constraints that mention this window
-void wxWindow::DeleteRelatedConstraints(void)
-{
- if (m_constraintsInvolvedIn)
- {
- wxNode *node = m_constraintsInvolvedIn->First();
- while (node)
- {
- wxWindow *win = (wxWindow *)node->Data();
- wxNode *next = node->Next();
- wxLayoutConstraints *constr = win->GetConstraints();
-
- // Reset any constraints involving this window
- if (constr)
- {
- constr->left.ResetIfWin((wxWindow *)this);
- constr->top.ResetIfWin((wxWindow *)this);
- constr->right.ResetIfWin((wxWindow *)this);
- constr->bottom.ResetIfWin((wxWindow *)this);
- constr->width.ResetIfWin((wxWindow *)this);
- constr->height.ResetIfWin((wxWindow *)this);
- constr->centreX.ResetIfWin((wxWindow *)this);
- constr->centreY.ResetIfWin((wxWindow *)this);
- }
- delete node;
- node = next;
- }
- delete m_constraintsInvolvedIn;
- m_constraintsInvolvedIn = (wxList *) NULL;
- }
+ GdkWindow *window = (GdkWindow*) NULL;
+ if (m_wxwindow)
+ window = GTK_PIZZA(m_wxwindow)->bin_window;
+ else
+ window = GetConnectWidget()->window;
+
+ wxCHECK_RET( window, _T("CaptureMouse() failed") );
+
+ const wxCursor* cursor = &m_cursor;
+ if (!cursor->Ok())
+ cursor = wxSTANDARD_CURSOR;
+
+ gdk_pointer_grab( window, FALSE,
+ (GdkEventMask)
+ (GDK_BUTTON_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_POINTER_MOTION_HINT_MASK |
+ GDK_POINTER_MOTION_MASK),
+ (GdkWindow *) NULL,
+ cursor->GetCursor(),
+ (guint32)GDK_CURRENT_TIME );
+ g_captureWindow = this;
+ g_captureWindowHasMouse = true;
}
-void wxWindow::SetSizer(wxSizer *sizer)
+void wxWindowGTK::DoReleaseMouse()
{
- m_windowSizer = sizer;
- if (sizer)
- sizer->SetSizerParent((wxWindow *)this);
-}
+ wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
-/*
- * New version
- */
+ wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") );
-bool wxWindow::Layout(void)
-{
- if (GetConstraints())
- {
- int w, h;
- GetClientSize(&w, &h);
- GetConstraints()->width.SetValue(w);
- GetConstraints()->height.SetValue(h);
- }
-
- // If top level (one sizer), evaluate the sizer's constraints.
- if (GetSizer())
- {
- int noChanges;
- GetSizer()->ResetConstraints(); // Mark all constraints as unevaluated
- GetSizer()->LayoutPhase1(&noChanges);
- GetSizer()->LayoutPhase2(&noChanges);
- GetSizer()->SetConstraintSizes(); // Recursively set the real window sizes
- return TRUE;
- }
- else
- {
- // Otherwise, evaluate child constraints
- ResetConstraints(); // Mark all constraints as unevaluated
- DoPhase(1); // Just one phase need if no sizers involved
- DoPhase(2);
- SetConstraintSizes(); // Recursively set the real window sizes
- }
- return TRUE;
-}
+ g_captureWindow = (wxWindowGTK*) NULL;
+
+ GdkWindow *window = (GdkWindow*) NULL;
+ if (m_wxwindow)
+ window = GTK_PIZZA(m_wxwindow)->bin_window;
+ else
+ window = GetConnectWidget()->window;
+
+ if (!window)
+ return;
+ gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
+}
-// Do a phase of evaluating constraints:
-// the default behaviour. wxSizers may do a similar
-// thing, but also impose their own 'constraints'
-// and order the evaluation differently.
-bool wxWindow::LayoutPhase1(int *noChanges)
+/* static */
+wxWindow *wxWindowBase::GetCapture()
{
- wxLayoutConstraints *constr = GetConstraints();
- if (constr)
- {
- return constr->SatisfyConstraints((wxWindow *)this, noChanges);
- }
- else
- return TRUE;
+ return (wxWindow *)g_captureWindow;
}
-bool wxWindow::LayoutPhase2(int *noChanges)
+bool wxWindowGTK::IsRetained() const
{
- *noChanges = 0;
-
- // Layout children
- DoPhase(1);
- DoPhase(2);
- return TRUE;
+ return false;
}
-// Do a phase of evaluating child constraints
-bool wxWindow::DoPhase(int phase)
+void wxWindowGTK::BlockScrollEvent()
{
- int noIterations = 0;
- int maxIterations = 500;
- int noChanges = 1;
- int noFailures = 0;
- wxList succeeded;
- while ((noChanges > 0) && (noIterations < maxIterations))
- {
- noChanges = 0;
- noFailures = 0;
- wxNode *node = GetChildren()->First();
- while (node)
- {
- wxWindow *child = (wxWindow *)node->Data();
- if (!child->IsKindOf(CLASSINFO(wxFrame)) && !child->IsKindOf(CLASSINFO(wxDialog)))
- {
- wxLayoutConstraints *constr = child->GetConstraints();
- if (constr)
- {
- if (succeeded.Member(child))
- {
- }
- else
- {
- int tempNoChanges = 0;
- bool success = ( (phase == 1) ? child->LayoutPhase1(&tempNoChanges) : child->LayoutPhase2(&tempNoChanges) ) ;
- noChanges += tempNoChanges;
- if (success)
- {
- succeeded.Append(child);
- }
- }
- }
- }
- node = node->Next();
- }
- noIterations ++;
- }
- return TRUE;
+ wxASSERT(!m_blockScrollEvent);
+ m_blockScrollEvent = true;
}
-void wxWindow::ResetConstraints(void)
+void wxWindowGTK::UnblockScrollEvent()
{
- wxLayoutConstraints *constr = GetConstraints();
- if (constr)
- {
- constr->left.SetDone(FALSE);
- constr->top.SetDone(FALSE);
- constr->right.SetDone(FALSE);
- constr->bottom.SetDone(FALSE);
- constr->width.SetDone(FALSE);
- constr->height.SetDone(FALSE);
- constr->centreX.SetDone(FALSE);
- constr->centreY.SetDone(FALSE);
- }
- wxNode *node = GetChildren()->First();
- while (node)
- {
- wxWindow *win = (wxWindow *)node->Data();
- if (!win->IsKindOf(CLASSINFO(wxFrame)) && !win->IsKindOf(CLASSINFO(wxDialog)))
- win->ResetConstraints();
- node = node->Next();
- }
+ wxASSERT(m_blockScrollEvent);
+ m_blockScrollEvent = false;
}
-// Need to distinguish between setting the 'fake' size for
-// windows and sizers, and setting the real values.
-void wxWindow::SetConstraintSizes(bool recurse)
+void wxWindowGTK::SetScrollbar(int orient,
+ int pos,
+ int thumbVisible,
+ int range,
+ bool WXUNUSED(update))
{
- wxLayoutConstraints *constr = GetConstraints();
- if (constr && constr->left.GetDone() && constr->right.GetDone() &&
- constr->width.GetDone() && constr->height.GetDone())
- {
- int x = constr->left.GetValue();
- int y = constr->top.GetValue();
- int w = constr->width.GetValue();
- int h = constr->height.GetValue();
+ wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
+ wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
+ wxCHECK_RET( m_wxwindow != m_widget, wxT("no scrolling for this wxWindow, use wxHSCROLL or wxVSCROLL") );
- // If we don't want to resize this window, just move it...
- if ((constr->width.GetRelationship() != wxAsIs) ||
- (constr->height.GetRelationship() != wxAsIs))
+ if (range > 0)
{
- // Calls Layout() recursively. AAAGH. How can we stop that.
- // Simply take Layout() out of non-top level OnSizes.
- SizerSetSize(x, y, w, h);
+ m_hasScrolling = true;
}
else
{
- SizerMove(x, y);
+ // GtkRange requires upper > lower
+ range =
+ thumbVisible = 1;
}
- }
- else if (constr)
- {
- char *windowClass = this->GetClassInfo()->GetClassName();
-
- wxString winName;
- if (GetName() == "")
- winName = _("unnamed");
- else
- winName = GetName();
- wxDebugMsg(_("Constraint(s) not satisfied for window of type %s, name %s:\n"), (const char *)windowClass, (const char *)winName);
- if (!constr->left.GetDone())
- wxDebugMsg(_(" unsatisfied 'left' constraint.\n"));
- if (!constr->right.GetDone())
- wxDebugMsg(_(" unsatisfied 'right' constraint.\n"));
- if (!constr->width.GetDone())
- wxDebugMsg(_(" unsatisfied 'width' constraint.\n"));
- if (!constr->height.GetDone())
- wxDebugMsg(_(" unsatisfied 'height' constraint.\n"));
- wxDebugMsg(_("Please check constraints: try adding AsIs() constraints.\n"));
- }
- if (recurse)
- {
- wxNode *node = GetChildren()->First();
- while (node)
+ if (pos > range - thumbVisible)
+ pos = range - thumbVisible;
+ if (pos < 0)
+ pos = 0;
+ GtkAdjustment* adj = m_scrollBar[ScrollDirFromOrient(orient)]->adjustment;
+ adj->step_increment = 1;
+ adj->page_increment =
+ adj->page_size = thumbVisible;
+ adj->upper = range;
+ SetScrollPos(orient, pos);
+ gtk_adjustment_changed(adj);
+}
+
+void wxWindowGTK::SetScrollPos(int orient, int pos, bool WXUNUSED(refresh))
+{
+ wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
+ wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
+ wxCHECK_RET( m_wxwindow != m_widget, wxT("no scrolling for this wxWindow, use wxHSCROLL or wxVSCROLL") );
+
+ // This check is more than an optimization. Without it, the slider
+ // will not move smoothly while tracking when using wxScrollHelper.
+ if (GetScrollPos(orient) != pos)
{
- wxWindow *win = (wxWindow *)node->Data();
- if (!win->IsKindOf(CLASSINFO(wxFrame)) && !win->IsKindOf(CLASSINFO(wxDialog)))
- win->SetConstraintSizes();
- node = node->Next();
+ const int dir = ScrollDirFromOrient(orient);
+ GtkAdjustment* adj = m_scrollBar[dir]->adjustment;
+ const int max = int(adj->upper - adj->page_size);
+ if (pos > max)
+ pos = max;
+ if (pos < 0)
+ pos = 0;
+ m_scrollPos[dir] = adj->value = pos;
+
+ // If a "value_changed" signal emission is not already in progress
+ if (!m_blockValueChanged[dir])
+ {
+ gtk_adjustment_value_changed(adj);
+ }
}
- }
}
-// This assumes that all sizers are 'on' the same
-// window, i.e. the parent of this window.
-void wxWindow::TransformSizerToActual(int *x, int *y) const
+int wxWindowGTK::GetScrollThumb(int orient) const
{
- if (!m_sizerParent || m_sizerParent->IsKindOf(CLASSINFO(wxDialog)) ||
- m_sizerParent->IsKindOf(CLASSINFO(wxFrame)) )
- return;
-
- int xp, yp;
- m_sizerParent->GetPosition(&xp, &yp);
- m_sizerParent->TransformSizerToActual(&xp, &yp);
- *x += xp;
- *y += yp;
+ wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
+ wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
+ wxCHECK_MSG( m_wxwindow != m_widget, 0, wxT("no scrolling for this wxWindow, use wxHSCROLL or wxVSCROLL") );
+
+ return int(m_scrollBar[ScrollDirFromOrient(orient)]->adjustment->page_size);
}
-void wxWindow::SizerSetSize(int x, int y, int w, int h)
+int wxWindowGTK::GetScrollPos( int orient ) const
{
- int xx = x;
- int yy = y;
- TransformSizerToActual(&xx, &yy);
- SetSize(xx, yy, w, h);
+ wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
+ wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
+ wxCHECK_MSG( m_wxwindow != m_widget, 0, wxT("no scrolling for this wxWindow, use wxHSCROLL or wxVSCROLL") );
+
+ return int(m_scrollBar[ScrollDirFromOrient(orient)]->adjustment->value + 0.5);
}
-void wxWindow::SizerMove(int x, int y)
+int wxWindowGTK::GetScrollRange( int orient ) const
{
- int xx = x;
- int yy = y;
- TransformSizerToActual(&xx, &yy);
- Move(xx, yy);
+ wxCHECK_MSG( m_widget != NULL, 0, wxT("invalid window") );
+ wxCHECK_MSG( m_wxwindow != NULL, 0, wxT("window needs client area for scrolling") );
+ wxCHECK_MSG( m_wxwindow != m_widget, 0, wxT("no scrolling for this wxWindow, use wxHSCROLL or wxVSCROLL") );
+
+ return int(m_scrollBar[ScrollDirFromOrient(orient)]->adjustment->upper);
}
-// Only set the size/position of the constraint (if any)
-void wxWindow::SetSizeConstraint(int x, int y, int w, int h)
+// Determine if increment is the same as +/-x, allowing for some small
+// difference due to possible inexactness in floating point arithmetic
+static inline bool IsScrollIncrement(double increment, double x)
{
- wxLayoutConstraints *constr = GetConstraints();
- if (constr)
- {
- if (x != -1)
- {
- constr->left.SetValue(x);
- constr->left.SetDone(TRUE);
- }
- if (y != -1)
- {
- constr->top.SetValue(y);
- constr->top.SetDone(TRUE);
- }
- if (w != -1)
+ wxASSERT(increment > 0);
+ const double tolerance = 1.0 / 1024;
+ return fabs(increment - fabs(x)) < tolerance;
+}
+
+wxEventType wxWindowGTK::GetScrollEventType(GtkRange* range)
+{
+ DEBUG_MAIN_THREAD
+
+ wxASSERT(range == m_scrollBar[0] || range == m_scrollBar[1]);
+
+ const int barIndex = range == m_scrollBar[1];
+ GtkAdjustment* adj = range->adjustment;
+
+ const int value = int(adj->value + 0.5);
+
+ // save previous position
+ const double oldPos = m_scrollPos[barIndex];
+ // update current position
+ m_scrollPos[barIndex] = adj->value;
+ // If event should be ignored, or integral position has not changed
+ if (!m_hasVMT || g_blockEventsOnDrag || value == int(oldPos + 0.5))
{
- constr->width.SetValue(w);
- constr->width.SetDone(TRUE);
+ return wxEVT_NULL;
}
- if (h != -1)
+
+ wxEventType eventType = wxEVT_SCROLL_THUMBTRACK;
+ if (!m_isScrolling)
{
- constr->height.SetValue(h);
- constr->height.SetDone(TRUE);
+ // Difference from last change event
+ const double diff = adj->value - oldPos;
+ const bool isDown = diff > 0;
+
+ if (IsScrollIncrement(adj->step_increment, diff))
+ {
+ eventType = isDown ? wxEVT_SCROLL_LINEDOWN : wxEVT_SCROLL_LINEUP;
+ }
+ else if (IsScrollIncrement(adj->page_increment, diff))
+ {
+ eventType = isDown ? wxEVT_SCROLL_PAGEDOWN : wxEVT_SCROLL_PAGEUP;
+ }
+ else if (m_mouseButtonDown)
+ {
+ // Assume track event
+ m_isScrolling = true;
+ }
}
- }
+ return eventType;
}
-void wxWindow::MoveConstraint(int x, int y)
+void wxWindowGTK::ScrollWindow( int dx, int dy, const wxRect* WXUNUSED(rect) )
{
- wxLayoutConstraints *constr = GetConstraints();
- if (constr)
- {
- if (x != -1)
+ wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
+
+ wxCHECK_RET( m_wxwindow != NULL, wxT("window needs client area for scrolling") );
+
+ // No scrolling requested.
+ if ((dx == 0) && (dy == 0)) return;
+
+ m_clipPaintRegion = true;
+
+ if (GetLayoutDirection() == wxLayout_RightToLeft)
+ gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), dx, -dy );
+ else
+ gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
+
+ m_clipPaintRegion = false;
+
+#if wxUSE_CARET
+ bool restoreCaret = (GetCaret() != NULL && GetCaret()->IsVisible());
+ if (restoreCaret)
{
- constr->left.SetValue(x);
- constr->left.SetDone(TRUE);
+ wxRect caretRect(GetCaret()->GetPosition(), GetCaret()->GetSize());
+ if (dx > 0)
+ caretRect.width += dx;
+ else
+ {
+ caretRect.x += dx; caretRect.width -= dx;
+ }
+ if (dy > 0)
+ caretRect.height += dy;
+ else
+ {
+ caretRect.y += dy; caretRect.height -= dy;
+ }
+
+ RefreshRect(caretRect);
}
- if (y != -1)
+#endif // wxUSE_CARET
+}
+
+void wxWindowGTK::GtkScrolledWindowSetBorder(GtkWidget* w, int wxstyle)
+{
+ //RN: Note that static controls usually have no border on gtk, so maybe
+ //it makes sense to treat that as simply no border at the wx level
+ //as well...
+ if (!(wxstyle & wxNO_BORDER) && !(wxstyle & wxBORDER_STATIC))
{
- constr->top.SetValue(y);
- constr->top.SetDone(TRUE);
+ GtkShadowType gtkstyle;
+
+ if(wxstyle & wxBORDER_RAISED)
+ gtkstyle = GTK_SHADOW_OUT;
+ else if (wxstyle & wxBORDER_SUNKEN)
+ gtkstyle = GTK_SHADOW_IN;
+ else if (wxstyle & wxBORDER_DOUBLE)
+ gtkstyle = GTK_SHADOW_ETCHED_IN;
+ else //default
+ gtkstyle = GTK_SHADOW_IN;
+
+ gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW(w),
+ gtkstyle );
}
- }
}
-void wxWindow::GetSizeConstraint(int *w, int *h) const
+void wxWindowGTK::SetWindowStyleFlag( long style )
{
- wxLayoutConstraints *constr = GetConstraints();
- if (constr)
- {
- *w = constr->width.GetValue();
- *h = constr->height.GetValue();
- }
- else
- GetSize(w, h);
+ // Updates the internal variable. NB: Now m_windowStyle bits carry the _new_ style values already
+ wxWindowBase::SetWindowStyleFlag(style);
}
-void wxWindow::GetClientSizeConstraint(int *w, int *h) const
+// Find the wxWindow at the current mouse position, also returning the mouse
+// position.
+wxWindow* wxFindWindowAtPointer(wxPoint& pt)
{
- wxLayoutConstraints *constr = GetConstraints();
- if (constr)
- {
- *w = constr->width.GetValue();
- *h = constr->height.GetValue();
- }
- else
- GetClientSize(w, h);
+ pt = wxGetMousePosition();
+ wxWindow* found = wxFindWindowAtPoint(pt);
+ return found;
}
-void wxWindow::GetPositionConstraint(int *x, int *y) const
+// Get the current mouse position.
+wxPoint wxGetMousePosition()
{
- wxLayoutConstraints *constr = GetConstraints();
- if (constr)
- {
- *x = constr->left.GetValue();
- *y = constr->top.GetValue();
- }
- else
- GetPosition(x, y);
+ /* This crashes when used within wxHelpContext,
+ so we have to use the X-specific implementation below.
+ gint x, y;
+ GdkModifierType *mask;
+ (void) gdk_window_get_pointer(NULL, &x, &y, mask);
+
+ return wxPoint(x, y);
+ */
+
+ int x, y;
+ GdkWindow* windowAtPtr = gdk_window_at_pointer(& x, & y);
+
+ Display *display = windowAtPtr ? GDK_WINDOW_XDISPLAY(windowAtPtr) : GDK_DISPLAY();
+ Window rootWindow = RootWindowOfScreen (DefaultScreenOfDisplay(display));
+ Window rootReturn, childReturn;
+ int rootX, rootY, winX, winY;
+ unsigned int maskReturn;
+
+ XQueryPointer (display,
+ rootWindow,
+ &rootReturn,
+ &childReturn,
+ &rootX, &rootY, &winX, &winY, &maskReturn);
+ return wxPoint(rootX, rootY);
+
}
-bool wxWindow::AcceptsFocus() const
+// Needed for implementing e.g. combobox on wxGTK within a modal dialog.
+void wxAddGrab(wxWindow* window)
{
- return IsEnabled() && IsShown();
+ gtk_grab_add( (GtkWidget*) window->GetHandle() );
}
-void wxWindow::OnIdle(wxIdleEvent& WXUNUSED(event) )
+void wxRemoveGrab(wxWindow* window)
{
- UpdateWindowUI();
+ gtk_grab_remove( (GtkWidget*) window->GetHandle() );
}