#include "wx/utils.h"
#include "wx/dialog.h"
#include "wx/msgdlg.h"
+#include "wx/module.h"
#if wxUSE_DRAG_AND_DROP
#include "wx/dnd.h"
#endif // wxUSE_CARET
#if wxUSE_TEXTCTRL
-#include "wx/textctrl.h"
+ #include "wx/textctrl.h"
#endif
#include "wx/menu.h"
#include "wx/intl.h"
#include "wx/settings.h"
#include "wx/log.h"
+#include "wx/fontutil.h"
#ifdef __WXDEBUG__
#include "wx/thread.h"
#endif
#include <math.h>
+#include <ctype.h>
-#include <gdk/gdk.h>
-#include <gtk/gtk.h>
+#include "wx/gtk/private.h"
#include <gdk/gdkprivate.h>
#include <gdk/gdkkeysyms.h>
#include <gdk/gdkx.h>
#include "wx/gtk/win_gtk.h"
+#ifdef __WXGTK20__
+ #define SET_CONTAINER_FOCUS(w, d) gtk_widget_child_focus((w), (d))
+#else
+ #define SET_CONTAINER_FOCUS(w, d) gtk_container_focus(GTK_CONTAINER(w), (d))
+#endif
+
+#ifdef __WXGTK20__
+ #ifdef HAVE_XIM
+ #undef HAVE_XIM
+ #endif
+#endif
+
+#ifdef __WXGTK20__
+extern GtkContainerClass *pizza_parent_class;
+#endif
+
//-----------------------------------------------------------------------------
// documentation on internals
//-----------------------------------------------------------------------------
extern bool g_blockEventsOnScroll;
extern wxCursor g_globalCursor;
+static GdkGC *g_eraseGC = NULL;
+
// mouse capture state: the window which has it and if the mouse is currently
// inside it
static wxWindowGTK *g_captureWindow = (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
-static wxWindowGTK *g_focusWindowLast = (wxWindowGTK *)NULL;
+static wxWindowGTK *g_focusWindowLast = (wxWindowGTK*) NULL;
+
+// the frame that is currently active (i.e. its child has focus). It is
+// used to generate wxActivateEvents
+static wxWindowGTK *g_activeFrame = (wxWindowGTK*) NULL;
+static bool g_activeFrameLostFocus = FALSE;
+
+// 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;
// if we detect that the app has got/lost the focus, we set this variable to
// either TRUE or FALSE and an activate event will be sent during the next
#else
# define DEBUG_MAIN_THREAD
#endif
-
-static gint gtk_debug_focus_in_callback( GtkWidget *WXUNUSED(widget),
- GdkEvent *WXUNUSED(event),
- const wxChar *WXUNUSED(name) )
-{
-/*
- static bool s_done = FALSE;
- if ( !s_done )
- {
- wxLog::AddTraceMask("focus");
- s_done = TRUE;
- }
- wxLogTrace(wxT("FOCUS NOW AT: %s"), name);
-*/
-
- return FALSE;
-}
-
-void debug_focus_in( GtkWidget* widget, const wxChar* name, const wxChar *window )
-{
- // suppress warnings about gtk_debug_focus_in_callback being unused with
- // this "if ( 0 )"
- if ( 0 )
- {
- wxString tmp = name;
- tmp += wxT(" FROM ");
- tmp += window;
-
- wxChar *s = new wxChar[tmp.Length()+1];
-
- wxStrcpy( s, tmp );
-
- gtk_signal_connect( GTK_OBJECT(widget), "focus_in_event",
- GTK_SIGNAL_FUNC(gtk_debug_focus_in_callback), (gpointer)s );
- }
-}
-
#else
#define DEBUG_MAIN_THREAD
#endif // Debug
+// the trace mask used for the focus debugging messages
+#define TRACE_FOCUS _T("focus")
+
//-----------------------------------------------------------------------------
// missing gdk functions
//-----------------------------------------------------------------------------
if (win->m_hasScrolling)
{
- GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(widget);
+ GtkScrolledWindow *scroll_window = GTK_SCROLLED_WINDOW(widget);
- GtkRequisition vscroll_req;
- vscroll_req.width = 2;
- vscroll_req.height = 2;
- (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
- (scroll_window->vscrollbar, &vscroll_req );
+ GtkRequisition vscroll_req;
+ vscroll_req.width = 2;
+ vscroll_req.height = 2;
+ (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->vscrollbar) )->size_request )
+ (scroll_window->vscrollbar, &vscroll_req );
- GtkRequisition hscroll_req;
- hscroll_req.width = 2;
- hscroll_req.height = 2;
- (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
- (scroll_window->hscrollbar, &hscroll_req );
+ GtkRequisition hscroll_req;
+ hscroll_req.width = 2;
+ hscroll_req.height = 2;
+ (* GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS(scroll_window->hscrollbar) )->size_request )
+ (scroll_window->hscrollbar, &hscroll_req );
- GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget) );
+ GtkScrolledWindowClass *scroll_class = GTK_SCROLLED_WINDOW_CLASS( GTK_OBJECT_GET_CLASS(widget) );
- if (scroll_window->vscrollbar_visible)
- {
- dw += vscroll_req.width;
- dw += scroll_class->scrollbar_spacing;
- }
+ if (scroll_window->vscrollbar_visible)
+ {
+ dw += vscroll_req.width;
+ dw += scroll_class->scrollbar_spacing;
+ }
- if (scroll_window->hscrollbar_visible)
- {
- dh += hscroll_req.height;
- dh += scroll_class->scrollbar_spacing;
- }
- }
+ if (scroll_window->hscrollbar_visible)
+ {
+ dh += hscroll_req.height;
+ dh += scroll_class->scrollbar_spacing;
+ }
+}
int dx = 0;
int dy = 0;
draw_frame( widget, win );
+#ifdef __WXGTK20__
+
+ (* GTK_WIDGET_CLASS (pizza_parent_class)->expose_event) (widget, gdk_event);
+
+#endif
return TRUE;
}
// "draw" of m_widget
//-----------------------------------------------------------------------------
+#ifndef __WXGTK20__
+
static void gtk_window_own_draw_callback( GtkWidget *widget, GdkRectangle *WXUNUSED(rect), wxWindowGTK *win )
{
draw_frame( widget, win );
}
-//-----------------------------------------------------------------------------
-// key code mapping routines
-//-----------------------------------------------------------------------------
-
-static long map_to_unmodified_wx_keysym( GdkEventKey *event )
-{
- KeySym keysym = event->keyval;
- guint key_code = 0;
-
- switch (keysym)
- {
- case GDK_Shift_L:
- case GDK_Shift_R: key_code = WXK_SHIFT; break;
- case GDK_Control_L:
- case GDK_Control_R: key_code = 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 = WXK_ALT; break;
- 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: 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_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_NUMPAD8; break;
- case GDK_KP_9: key_code = WXK_NUMPAD9; break;
- case GDK_KP_Space: key_code = WXK_NUMPAD_SPACE; break;
- case GDK_KP_Tab: key_code = WXK_NUMPAD_TAB; break;
- case GDK_KP_Enter: key_code = WXK_NUMPAD_ENTER; break;
- case GDK_KP_F1: key_code = WXK_NUMPAD_F1; break;
- case GDK_KP_F2: key_code = WXK_NUMPAD_F2; break;
- case GDK_KP_F3: key_code = WXK_NUMPAD_F3; break;
- case GDK_KP_F4: key_code = WXK_NUMPAD_F4; break;
- case GDK_KP_Home: key_code = WXK_NUMPAD_HOME; break;
- case GDK_KP_Left: key_code = WXK_NUMPAD_LEFT; break;
- case GDK_KP_Up: key_code = WXK_NUMPAD_UP; break;
- case GDK_KP_Right: key_code = WXK_NUMPAD_RIGHT; break;
- case GDK_KP_Down: key_code = WXK_NUMPAD_DOWN; break;
- case GDK_KP_Prior: key_code = WXK_NUMPAD_PRIOR; break;
-// case GDK_KP_Page_Up: key_code = WXK_NUMPAD_PAGEUP; break;
- case GDK_KP_Next: key_code = WXK_NUMPAD_NEXT; break;
-// case GDK_KP_Page_Down: key_code = WXK_NUMPAD_PAGEDOWN; break;
- case GDK_KP_End: key_code = WXK_NUMPAD_END; break;
- case GDK_KP_Begin: key_code = WXK_NUMPAD_BEGIN; break;
- case GDK_KP_Insert: key_code = WXK_NUMPAD_INSERT; break;
- case GDK_KP_Delete: key_code = WXK_NUMPAD_DELETE; break;
- case GDK_KP_Equal: key_code = WXK_NUMPAD_EQUAL; break;
- case GDK_KP_Multiply: key_code = WXK_NUMPAD_MULTIPLY; break;
- case GDK_KP_Add: key_code = WXK_NUMPAD_ADD; break;
- case GDK_KP_Separator: key_code = WXK_NUMPAD_SEPARATOR; break;
- case GDK_KP_Subtract: key_code = WXK_NUMPAD_SUBTRACT; break;
- case GDK_KP_Decimal: key_code = WXK_NUMPAD_DECIMAL; break;
- case GDK_KP_Divide: key_code = WXK_NUMPAD_DIVIDE; 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 (event->length == 1)
- {
- key_code = toupper( (unsigned char)*event->string );
- }
- else if ((keysym & 0xFF) == keysym)
- {
- guint upper = gdk_keyval_to_upper( (guint)keysym );
- keysym = (upper != 0 ? upper : keysym ); /* to be MSW compatible */
- key_code = (guint)keysym;
- }
- }
- }
-
- return (key_code);
-}
-
-static long map_to_wx_keysym( GdkEventKey *event )
-{
- KeySym keysym = event->keyval;
- guint key_code = 0;
-
- switch (keysym)
- {
- 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: 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_0: key_code = '0'; break;
- case GDK_KP_1: key_code = '1'; break;
- case GDK_KP_2: key_code = '2'; break;
- case GDK_KP_3: key_code = '3'; break;
- case GDK_KP_4: key_code = '4'; break;
- case GDK_KP_5: key_code = '5'; break;
- case GDK_KP_6: key_code = '6'; break;
- case GDK_KP_7: key_code = '7'; break;
- case GDK_KP_8: key_code = '8'; break;
- case GDK_KP_9: key_code = '9'; break;
- case GDK_KP_Space: key_code = ' '; break;
- case GDK_KP_Tab: key_code = WXK_TAB; break; /* or '\t' ??? */
- case GDK_KP_Enter: key_code = WXK_RETURN; break; /* or '\r' ??? */
- case GDK_KP_F1: key_code = WXK_NUMPAD_F1; break;
- case GDK_KP_F2: key_code = WXK_NUMPAD_F2; break;
- case GDK_KP_F3: key_code = WXK_NUMPAD_F3; break;
- case GDK_KP_F4: key_code = WXK_NUMPAD_F4; 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_Equal: key_code = '='; break;
- case GDK_KP_Multiply: key_code = '*'; break;
- case GDK_KP_Add: key_code = '+'; break;
- case GDK_KP_Separator: key_code = ','; break;
- case GDK_KP_Subtract: key_code = '-'; break;
- case GDK_KP_Decimal: key_code = '.'; break;
- case GDK_KP_Divide: key_code = '/'; 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 (event->length == 1)
- {
- key_code = (unsigned char)*event->string;
- }
- else if ((keysym & 0xFF) == keysym)
- {
- key_code = (guint)keysym;
- }
- }
- }
-
- return (key_code);
-}
+#endif // GTK+ < 2.0
//-----------------------------------------------------------------------------
// "size_request" of m_widget
if (g_isIdle)
wxapp_install_idle_handler();
-/*
- if (win->GetName() == wxT("panel"))
+#ifdef __WXGTK20__
+ // 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) return FALSE;
+
+#if 0
+ if (win->GetName())
{
wxPrintf( wxT("OnExpose from ") );
if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
(int)gdk_event->area.width,
(int)gdk_event->area.height );
}
-*/
-
- GtkPizza *pizza = GTK_PIZZA (widget);
+#endif
- if (win->GetThemeEnabled())
- {
- wxWindow *parent = win->GetParent();
- while (parent && !parent->IsTopLevel())
- parent = parent->GetParent();
- if (!parent)
- parent = win;
+ win->GetUpdateRegion() = wxRegion( gdk_event->region );
- gtk_paint_flat_box (parent->m_widget->style, pizza->bin_window, GTK_STATE_NORMAL,
- GTK_SHADOW_NONE, &gdk_event->area, parent->m_widget, "base", 0, 0, -1, -1);
- }
+ win->GtkSendPaintEvents();
+ // Let parent window draw window less widgets
+ (* GTK_WIDGET_CLASS (pizza_parent_class)->expose_event) (widget, gdk_event);
+#else
+ // This gets called immediately after an expose event
+ // under GTK 1.2 so we collect the calls and wait for
+ // the idle handler to pick things up.
+
win->GetUpdateRegion().Union( gdk_event->area.x,
gdk_event->area.y,
gdk_event->area.width,
gdk_event->area.height );
+ win->m_clearRegion.Union( gdk_event->area.x,
+ gdk_event->area.y,
+ gdk_event->area.width,
+ gdk_event->area.height );
- if (gdk_event->count == 0)
- {
- win->m_clipPaintRegion = TRUE;
-
- wxWindowDC dc(win);
- dc.SetClippingRegion(win->GetUpdateRegion());
- wxEraseEvent eevent( win->GetId(), &dc );
- eevent.SetEventObject( win );
-#if 1
- (void)win->GetEventHandler()->ProcessEvent(eevent);
-#else // 0
- if (!win->GetEventHandler()->ProcessEvent(eevent))
- {
- wxClientDC dc( win );
- dc.SetBrush( wxBrush( win->GetBackgroundColour(), wxSOLID ) );
- dc.SetPen( *wxTRANSPARENT_PEN );
-
- wxRegionIterator upd( win->GetUpdateRegion() );
- while (upd)
- {
- dc.DrawRectangle( upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
- upd ++;
- }
- }
-#endif // 1/0
-
- wxNcPaintEvent eventNc( win->GetId() );
- eventNc.SetEventObject( win );
- win->GetEventHandler()->ProcessEvent( eventNc );
-
- wxPaintEvent event( win->GetId() );
- event.SetEventObject( win );
- win->GetEventHandler()->ProcessEvent( event );
-
- win->GetUpdateRegion().Clear();
-
- win->m_clipPaintRegion = FALSE;
- }
-
- /* The following code will result in all window-less widgets
- being redrawn if the wxWindows class is given a chance to
- paint *anything* because it will then be allowed to paint
- over the window-less widgets */
- GList *children = pizza->children;
- while (children)
- {
- GtkPizzaChild *child = (GtkPizzaChild*) children->data;
- children = children->next;
-
- GdkEventExpose child_event = *gdk_event;
-
- if (GTK_WIDGET_NO_WINDOW (child->widget) &&
- GTK_WIDGET_DRAWABLE (child->widget) /* &&
- gtk_widget_intersect (child->widget, &gdk_event->area, &child_event.area)*/ )
- {
- child_event.area.x = child->widget->allocation.x;
- child_event.area.y = child->widget->allocation.y;
- child_event.area.width = child->widget->allocation.width;
- child_event.area.height = child->widget->allocation.height;
- gtk_widget_event (child->widget, (GdkEvent*) &child_event);
- }
- }
+ // Actual redrawing takes place in idle time.
+ // win->GtkUpdate();
+#endif
- return TRUE;
+ return FALSE;
}
//-----------------------------------------------------------------------------
// "event" of m_wxwindow
//-----------------------------------------------------------------------------
-/* GTK thinks it is clever and filters out a certain amount of "unneeded"
- expose events. We need them, of course, so we override the main event
- procedure in GtkWidget by giving our own handler for all system events.
- There, we look for expose events ourselves whereas all other events are
- handled normally. */
+// GTK thinks it is clever and filters out a certain amount of "unneeded"
+// expose events. We need them, of course, so we override the main event
+// procedure in GtkWidget by giving our own handler for all system events.
+// There, we look for expose events ourselves whereas all other events are
+// handled normally.
gint gtk_window_event_event_callback( GtkWidget *widget,
GdkEventExpose *event,
// "draw" of m_wxwindow
//-----------------------------------------------------------------------------
-/* This callback is a complete replacement of the gtk_pizza_draw() function,
- which disabled. */
+#ifndef __WXGTK20__
+
+// This callback is a complete replacement of the gtk_pizza_draw() function,
+// which is disabled.
static void gtk_window_draw_callback( GtkWidget *widget,
GdkRectangle *rect,
if (g_isIdle)
wxapp_install_idle_handler();
+ // The wxNO_FULL_REPAINT_ON_RESIZE flag only works if
+ // there are no child windows.
if ((win->HasFlag(wxNO_FULL_REPAINT_ON_RESIZE)) &&
(win->GetChildren().GetCount() == 0))
{
return;
}
-/*
- if (win->GetName() == wxT("panel"))
+#if 0
+ if (win->GetName())
{
wxPrintf( wxT("OnDraw from ") );
if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
(int)rect->width,
(int)rect->height );
}
-*/
+#endif
+#ifndef __WXUNIVERSAL__
GtkPizza *pizza = GTK_PIZZA (widget);
if (win->GetThemeEnabled())
if (!parent)
parent = win;
- gtk_paint_flat_box (parent->m_widget->style, pizza->bin_window, GTK_STATE_NORMAL,
- GTK_SHADOW_NONE, rect, parent->m_widget, "base", 0, 0, -1, -1);
+ gtk_paint_flat_box (parent->m_widget->style,
+ pizza->bin_window,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_NONE,
+ rect,
+ parent->m_widget,
+ (char *)"base",
+ 0, 0, -1, -1);
}
+#endif
+
+ win->m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height );
+ win->GetUpdateRegion().Union( rect->x, rect->y, rect->width, rect->height );
+ // Update immediately, not in idle time.
+ win->GtkUpdate();
- if (!(GTK_WIDGET_APP_PAINTABLE (widget)) &&
- (pizza->clear_on_draw))
+#ifndef __WXUNIVERSAL__
+ // Redraw child widgets
+ GList *children = pizza->children;
+ while (children)
{
- gdk_window_clear_area( pizza->bin_window,
- rect->x, rect->y, rect->width, rect->height);
+ GtkPizzaChild *child = (GtkPizzaChild*) children->data;
+ children = children->next;
+
+ GdkRectangle child_area;
+ if (gtk_widget_intersect (child->widget, rect, &child_area))
+ {
+ gtk_widget_draw (child->widget, &child_area /* (GdkRectangle*) NULL*/ );
+ }
}
+#endif
+}
- win->GetUpdateRegion().Union( rect->x, rect->y, rect->width, rect->height );
+#endif
- win->m_clipPaintRegion = TRUE;
+//-----------------------------------------------------------------------------
+// "key_press_event" from any window
+//-----------------------------------------------------------------------------
- wxWindowDC dc(win);
- dc.SetClippingRegion(win->GetUpdateRegion());
- wxEraseEvent eevent( win->GetId(), &dc );
- eevent.SetEventObject( win );
+// set WXTRACE to this to see the key event codes on the console
+#define TRACE_KEYS _T("keyevent")
-#if 1
- (void)win->GetEventHandler()->ProcessEvent(eevent);
-#else
- if (!win->GetEventHandler()->ProcessEvent(eevent))
+// 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 )
{
- if (!win->GetEventHandler()->ProcessEvent(eevent))
- {
- wxClientDC dc( win );
- dc.SetBrush( wxBrush( win->GetBackgroundColour(), wxSOLID ) );
- dc.SetPen( *wxTRANSPARENT_PEN );
+ // 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;
- wxRegionIterator upd( win->GetUpdateRegion() );
- while (upd)
- {
- dc.DrawRectangle( upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
- upd ++;
- }
- }
- }
-#endif
+ // neither do the toggle modifies
+ case GDK_Scroll_Lock:
+ key_code = isChar ? 0 : WXK_SCROLL;
+ break;
- wxNcPaintEvent eventNc( win->GetId() );
- eventNc.SetEventObject( win );
- win->GetEventHandler()->ProcessEvent( eventNc );
+ case GDK_Caps_Lock:
+ key_code = isChar ? 0 : WXK_CAPITAL;
+ break;
- wxPaintEvent event( win->GetId() );
- event.SetEventObject( win );
- win->GetEventHandler()->ProcessEvent( event );
+ case GDK_Num_Lock:
+ key_code = isChar ? 0 : WXK_NUMLOCK;
+ break;
- win->GetUpdateRegion().Clear();
- win->m_clipPaintRegion = FALSE;
+ // various other special keys
+ case GDK_Menu:
+ key_code = WXK_MENU;
+ break;
+ case GDK_Help:
+ key_code = WXK_HELP;
+ break;
- GList *children = pizza->children;
- while (children)
- {
- GtkPizzaChild *child = (GtkPizzaChild*) children->data;
- children = children->next;
+ case GDK_BackSpace:
+ key_code = WXK_BACK;
+ break;
- GdkRectangle child_area;
- if (gtk_widget_intersect (child->widget, rect, &child_area))
- {
- gtk_widget_draw (child->widget, &child_area /* (GdkRectangle*) NULL*/ );
- }
+ 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_PRIOR;
+ break;
+
+ case GDK_Next: // == GDK_Page_Down
+ key_code = WXK_NEXT;
+ 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_PRIOR : WXK_NUMPAD_PRIOR;
+ break;
+
+ case GDK_KP_Next: // == GDK_KP_Page_Down
+ key_code = isChar ? WXK_NEXT : WXK_NUMPAD_NEXT;
+ 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;
}
-//-----------------------------------------------------------------------------
-// "key_press_event" from any window
-//-----------------------------------------------------------------------------
+static inline bool wxIsAsciiKeysym(KeySym ks)
+{
+ return ks < 256;
+}
-static gint gtk_window_key_press_callback( GtkWidget *widget,
- GdkEventKey *gdk_event,
- wxWindow *win )
+static bool
+wxTranslateGTKKeyEventToWx(wxKeyEvent& event,
+ wxWindowGTK *win,
+ GdkEventKey *gdk_event)
{
- DEBUG_MAIN_THREAD
+ // 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 };
- if (g_isIdle)
- wxapp_install_idle_handler();
+ KeySym keysym = gdk_event->keyval;
- if (!win->m_hasVMT) return FALSE;
- if (g_blockEventsOnDrag) return FALSE;
+ 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 */);
-/*
- wxString tmp;
- tmp += (char)gdk_event->keyval;
- printf( "KeyDown-Code is: %s.\n", tmp.c_str() );
- printf( "KeyDown-ScanCode is: %d.\n", gdk_event->keyval );
-*/
+ 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 modifies, 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
int x = 0;
int y = 0;
GdkModifierType state;
- if (gdk_event->window) gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
-
- bool ret = FALSE;
-
- long key_code = map_to_unmodified_wx_keysym( gdk_event );
- /* sending unknown key events doesn't really make sense */
- if (key_code == 0) return FALSE;
+ if (gdk_event->window)
+ gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
- wxKeyEvent event( wxEVT_KEY_DOWN );
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_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_keyCode = key_code;
event.m_scanCode = gdk_event->keyval;
+ event.m_rawCode = (wxUint32) gdk_event->keyval;
+ event.m_rawFlags = 0;
event.m_x = x;
event.m_y = y;
event.SetEventObject( win );
- ret = win->GetEventHandler()->ProcessEvent( event );
+
+ return TRUE;
+}
+
+static gint gtk_window_key_press_callback( GtkWidget *widget,
+ GdkEventKey *gdk_event,
+ wxWindow *win )
+{
+ DEBUG_MAIN_THREAD
+
+ if (g_isIdle)
+ wxapp_install_idle_handler();
+
+ if (!win->m_hasVMT)
+ return FALSE;
+ if (g_blockEventsOnDrag)
+ return FALSE;
+
+
+ wxKeyEvent event( wxEVT_KEY_DOWN );
+ if ( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
+ {
+ // unknown key pressed, ignore (the event would be useless anyhow)
+ return FALSE;
+ }
+
+ // Emit KEY_DOWN event
+ bool ret = win->GetEventHandler()->ProcessEvent( event );
#if wxUSE_ACCEL
if (!ret)
}
#endif // wxUSE_ACCEL
- /* wxMSW doesn't send char events with Alt pressed */
- /* Only send wxEVT_CHAR event if not processed yet. Thus, ALT-x
- will only be sent if it is not in an accelerator table. */
- key_code = map_to_wx_keysym( gdk_event );
+ // 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)
+ {
+ // Find key code for EVT_CHAR and EVT_CHAR_HOOK events
+ KeySym keysym = gdk_event->keyval;
+ long key_code = wxTranslateKeySymToWXKey(keysym, TRUE /* isChar */);
+ if ( !key_code )
+ {
+ if ( gdk_event->length == 1 )
+ {
+ key_code = (unsigned char)gdk_event->string[0];
+ }
+ else if ( wxIsAsciiKeysym(keysym) )
+ {
+ // ASCII key
+ key_code = (unsigned char)keysym;
+ }
+ }
- if ( (!ret) &&
- (key_code != 0))
- {
- wxKeyEvent event2( wxEVT_CHAR );
- event2.SetTimestamp( gdk_event->time );
- event2.m_shiftDown = (gdk_event->state & GDK_SHIFT_MASK);
- event2.m_controlDown = (gdk_event->state & GDK_CONTROL_MASK);
- event2.m_altDown = (gdk_event->state & GDK_MOD1_MASK);
- event2.m_metaDown = (gdk_event->state & GDK_MOD2_MASK);
- event2.m_keyCode = key_code;
- event2.m_scanCode = gdk_event->keyval;
- event2.m_x = x;
- event2.m_y = y;
- event2.SetEventObject( win );
- ret = win->GetEventHandler()->ProcessEvent( event2 );
- }
-
- /* win is a control: tab can be propagated up */
- if ( (!ret) &&
+ if ( key_code )
+ {
+ wxLogTrace(TRACE_KEYS, _T("Char event: %ld"), key_code);
+
+ event.m_keyCode = key_code;
+
+ // Implement OnCharHook by checking ancesteror 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 );
+ }
+ }
+ }
+
+ // win is a control: tab can be propagated up
+ if ( !ret &&
((gdk_event->keyval == GDK_Tab) || (gdk_event->keyval == GDK_ISO_Left_Tab)) &&
// VZ: testing for wxTE_PROCESS_TAB shouldn't be done here the control may
// have this style, yet choose not to process this particular TAB in which
// case TAB must still work as a navigational character
#if 0
- (!win->HasFlag(wxTE_PROCESS_TAB)) &&
+ !win->HasFlag(wxTE_PROCESS_TAB) &&
#endif // 0
- (win->GetParent()) &&
- (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) )
+ win->GetParent() && (win->GetParent()->HasFlag( wxTAB_TRAVERSAL)) )
{
wxNavigationKeyEvent new_event;
new_event.SetEventObject( win->GetParent() );
- /* GDK reports GDK_ISO_Left_Tab for SHIFT-TAB */
+ // GDK reports GDK_ISO_Left_Tab for SHIFT-TAB
new_event.SetDirection( (gdk_event->keyval == GDK_Tab) );
- /* CTRL-TAB changes the (parent) window, i.e. switch notebook page */
+ // CTRL-TAB changes the (parent) window, i.e. switch notebook page
new_event.SetWindowChange( (gdk_event->state & GDK_CONTROL_MASK) );
new_event.SetCurrentFocus( win );
ret = win->GetParent()->GetEventHandler()->ProcessEvent( new_event );
}
- /* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
- if ( (!ret) &&
+ // generate wxID_CANCEL if <esc> has been pressed (typically in dialogs)
+ if ( !ret &&
(gdk_event->keyval == GDK_Escape) )
{
wxCommandEvent new_event(wxEVT_COMMAND_BUTTON_CLICKED,wxID_CANCEL);
ret = win->GetEventHandler()->ProcessEvent( new_event );
}
-#if (GTK_MINOR_VERSION > 0)
- /* Pressing F10 will activate the menu bar of the top frame. */
- /* Doesn't work. */
-/*
+ // Doesn't work.
+#if 0
+ // Pressing F10 will activate the menu bar of the top frame
if ( (!ret) &&
(gdk_event->keyval == GDK_F10) )
{
ancestor = ancestor->GetParent();
}
}
-*/
-#endif
+#endif // 0
if (ret)
{
gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_press_event" );
return TRUE;
}
-
+
return FALSE;
}
// "key_release_event" from any window
//-----------------------------------------------------------------------------
-static gint gtk_window_key_release_callback( GtkWidget *widget, GdkEventKey *gdk_event, wxWindowGTK *win )
+static gint gtk_window_key_release_callback( GtkWidget *widget,
+ GdkEventKey *gdk_event,
+ wxWindowGTK *win )
{
DEBUG_MAIN_THREAD
if (g_isIdle)
wxapp_install_idle_handler();
- if (!win->m_hasVMT) return FALSE;
- if (g_blockEventsOnDrag) return FALSE;
-
-/*
- printf( "KeyUp-ScanCode is: %d.\n", gdk_event->keyval );
- if (gdk_event->state & GDK_SHIFT_MASK)
- printf( "ShiftDown.\n" );
- else
- printf( "ShiftUp.\n" );
- if (gdk_event->state & GDK_CONTROL_MASK)
- printf( "ControlDown.\n" );
- else
- printf( "ControlUp.\n" );
- printf( "\n" );
-*/
-
- long key_code = map_to_unmodified_wx_keysym( gdk_event );
-
- /* sending unknown key events doesn't really make sense */
- if (key_code == 0) return FALSE;
+ if (!win->m_hasVMT)
+ return FALSE;
- int x = 0;
- int y = 0;
- GdkModifierType state;
- if (gdk_event->window) gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
+ if (g_blockEventsOnDrag)
+ return FALSE;
wxKeyEvent event( wxEVT_KEY_UP );
- 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_keyCode = key_code;
- event.m_scanCode = gdk_event->keyval;
- event.m_x = x;
- event.m_y = y;
- event.SetEventObject( win );
-
- if (win->GetEventHandler()->ProcessEvent( event ))
+ if ( !wxTranslateGTKKeyEventToWx(event, win, gdk_event) )
{
- gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_release_event" );
- return TRUE;
+ // unknown key pressed, ignore (the event would be useless anyhow
+ return FALSE;
}
- return FALSE;
+ if ( !win->GetEventHandler()->ProcessEvent( event ) )
+ return FALSE;
+
+ gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "key_release_event" );
+ return TRUE;
}
+// ============================================================================
+// the mouse events
+// ============================================================================
+
// ----------------------------------------------------------------------------
-// mouse event processing helper
+// mouse event processing helpers
// ----------------------------------------------------------------------------
+// init wxMouseEvent with the info from gdk_event
+//
+// NB: this has to be a macro as gdk_event type is different for different
+// events we're used with
+#define InitMouseEvent(/* wxWindowGTK * */ win, \
+ /* wxMouseEvent& */ event, \
+ /* GdkEventXXX * */ 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); \
+ \
+ 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 ); \
+} \
+
static void AdjustEventButtonState(wxMouseEvent& event)
{
// GDK reports the old state of the button for a button press event, but
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_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 += pizza->xoffset;
+ yy += pizza->yoffset;
+ }
+
+ wxNode *node = win->GetChildren().First();
+ while (node)
+ {
+ wxWindowGTK *child = (wxWindowGTK*)node->Data();
+
+ node = node->Next();
+ 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_x + 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;
+ }
+ }
}
- if ((event.GetEventType() == wxEVT_RIGHT_DOWN) ||
- (event.GetEventType() == wxEVT_RIGHT_DCLICK) ||
- (event.GetEventType() == wxEVT_RIGHT_UP))
- {
- event.m_rightDown = !event.m_rightDown;
- return;
- }
+ return win;
}
//-----------------------------------------------------------------------------
// "button_press_event"
//-----------------------------------------------------------------------------
-static gint gtk_window_button_press_callback( GtkWidget *widget, GdkEventButton *gdk_event, wxWindowGTK *win )
+static gint gtk_window_button_press_callback( GtkWidget *widget,
+ GdkEventButton *gdk_event,
+ wxWindowGTK *win )
{
DEBUG_MAIN_THREAD
if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
- if (win->m_wxwindow)
+ if (win->m_wxwindow && (g_focusWindow != win) && win->AcceptsFocus())
{
- if (GTK_WIDGET_CAN_FOCUS(win->m_wxwindow) && !GTK_WIDGET_HAS_FOCUS (win->m_wxwindow) )
- {
- gtk_widget_grab_focus (win->m_wxwindow);
-
+ gtk_widget_grab_focus( win->m_wxwindow );
/*
- wxPrintf( wxT("GrabFocus from ") );
- if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
- wxPrintf( win->GetClassInfo()->GetClassName() );
- wxPrintf( wxT(".\n") );
+ wxPrintf( wxT("GrabFocus from ") );
+ if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
+ wxPrintf( win->GetClassInfo()->GetClassName() );
+ wxPrintf( wxT(".\n") );
*/
-
- }
}
wxEventType event_type = wxEVT_NULL;
}
wxMouseEvent event( event_type );
- 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_x = (wxCoord)gdk_event->x;
- event.m_y = (wxCoord)gdk_event->y;
+ InitMouseEvent( win, event, gdk_event );
AdjustEventButtonState(event);
- // Some control don't have their own X window and thus cannot get
- // any events.
-
- if (!g_captureWindow)
- {
- wxCoord x = event.m_x;
- wxCoord y = event.m_y;
- if (win->m_wxwindow)
- {
- GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
- x += pizza->xoffset;
- y += pizza->yoffset;
- }
-
- wxNode *node = win->GetChildren().First();
- while (node)
- {
- wxWindowGTK *child = (wxWindowGTK*)node->Data();
-
- node = node->Next();
- if (!child->IsShown())
- continue;
-
- if (child->m_isStaticBox)
- {
- // 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_x + child->m_height;
-
- // left
- if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
- // right
- ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
- // top
- ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
- // bottom
- ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
- {
- win = child;
- event.m_x -= child->m_x;
- event.m_y -= child->m_y;
- break;
- }
-
- }
- else
- {
- if ((child->m_wxwindow == (GtkWidget*) NULL) &&
- (child->m_x <= x) &&
- (child->m_y <= y) &&
- (child->m_x+child->m_width >= x) &&
- (child->m_y+child->m_height >= y))
- {
- win = child;
- event.m_x -= child->m_x;
- event.m_y -= child->m_y;
- break;
- }
- }
- }
- }
+ // wxListBox actually get 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);
- event.SetEventObject( win );
+ // find the correct window to send the event too: it may be a different one
+ // from the one which got it at GTK+ level because some control 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);
gs_timeLastClick = gdk_event->time;
}
wxMouseEvent event( event_type );
- 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_x = (wxCoord)gdk_event->x;
- event.m_y = (wxCoord)gdk_event->y;
+ InitMouseEvent( win, event, gdk_event );
AdjustEventButtonState(event);
- // Some control don't have their own X window and thus cannot get
- // any events.
-
- if (!g_captureWindow)
- {
- wxCoord x = event.m_x;
- wxCoord y = event.m_y;
- if (win->m_wxwindow)
- {
- GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
- x += pizza->xoffset;
- y += pizza->yoffset;
- }
-
- wxNode *node = win->GetChildren().First();
- while (node)
- {
- wxWindowGTK *child = (wxWindowGTK*)node->Data();
-
- node = node->Next();
- if (!child->IsShown())
- continue;
-
- if (child->m_isStaticBox)
- {
- // 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_x + child->m_height;
-
- // left
- if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
- // right
- ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
- // top
- ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
- // bottom
- ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
- {
- win = child;
- event.m_x -= child->m_x;
- event.m_y -= child->m_y;
- break;
- }
-
- }
- else
- {
- if ((child->m_wxwindow == (GtkWidget*) NULL) &&
- (child->m_x <= x) &&
- (child->m_y <= y) &&
- (child->m_x+child->m_width >= x) &&
- (child->m_y+child->m_height >= y))
- {
- win = child;
- event.m_x -= child->m_x;
- event.m_y -= child->m_y;
- break;
- }
- }
- }
- }
+ // same wxListBox hack as above
+ win->FixUpMouseEvent(widget, event.m_x, event.m_y);
- event.SetEventObject( win );
+ if ( !g_captureWindow )
+ win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
if (win->GetEventHandler()->ProcessEvent( event ))
{
return FALSE;
}
-// ============================================================================
-// the mouse events
-// ============================================================================
-
-// init wxMouseEvent with the info from gdk_event
-#define InitMouseEvent(event, 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); \
-\
- event.m_x = (wxCoord)gdk_event->x; \
- event.m_y = (wxCoord)gdk_event->y \
-
//-----------------------------------------------------------------------------
// "motion_notify_event"
//-----------------------------------------------------------------------------
*/
wxMouseEvent event( wxEVT_MOTION );
- InitMouseEvent(event, gdk_event);
+ InitMouseEvent(win, event, gdk_event);
if ( g_captureWindow )
{
wxMouseEvent event(g_captureWindowHasMouse ? wxEVT_ENTER_WINDOW
: wxEVT_LEAVE_WINDOW);
- InitMouseEvent(event, gdk_event);
+ InitMouseEvent(win, event, gdk_event);
event.SetEventObject(win);
win->GetEventHandler()->ProcessEvent(event);
}
}
else // no capture
{
- // Some control don't have their own X window and thus cannot get
- // any events.
-
- wxCoord x = event.m_x;
- wxCoord y = event.m_y;
- if (win->m_wxwindow)
- {
- GtkPizza *pizza = GTK_PIZZA(win->m_wxwindow);
- x += pizza->xoffset;
- y += pizza->yoffset;
- }
-
- wxNode *node = win->GetChildren().First();
- while (node)
- {
- wxWindowGTK *child = (wxWindowGTK*)node->Data();
-
- node = node->Next();
- if (!child->IsShown())
- continue;
-
- if (child->m_isStaticBox)
- {
- // 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_x + child->m_height;
-
- // left
- if (((x >= xx1) && (x <= xx1+10) && (y >= yy1) && (y <= yy2)) ||
- // right
- ((x >= xx2-10) && (x <= xx2) && (y >= yy1) && (y <= yy2)) ||
- // top
- ((x >= xx1) && (x <= xx2) && (y >= yy1) && (y <= yy1+10)) ||
- // bottom
- ((x >= xx1) && (x <= xx2) && (y >= yy2-1) && (y <= yy2)))
- {
- win = child;
- event.m_x -= child->m_x;
- event.m_y -= child->m_y;
- break;
- }
-
- }
- else
- {
- if ((child->m_wxwindow == (GtkWidget*) NULL) &&
- (child->m_x <= x) &&
- (child->m_y <= y) &&
- (child->m_x+child->m_width >= x) &&
- (child->m_y+child->m_height >= y))
- {
- win = child;
- event.m_x -= child->m_x;
- event.m_y -= child->m_y;
- break;
- }
- }
- }
+ win = FindWindowForMouseEvent(win, event.m_x, event.m_y);
}
- event.SetEventObject( win );
-
if (win->GetEventHandler()->ProcessEvent( event ))
{
gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "motion_notify_event" );
// "focus_in_event"
//-----------------------------------------------------------------------------
+// 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);
+}
+
static gint gtk_window_focus_in_callback( GtkWidget *widget,
GdkEvent *WXUNUSED(event),
wxWindow *win )
g_focusWindowLast =
g_focusWindow = win;
-#if 0
- wxPrintf( "OnSetFocus from " );
- if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
- wxPrintf( win->GetClassInfo()->GetClassName() );
- wxPrintf( ".\n" );
-#endif
-
- // notify the parent keeping track of focus for the kbd navigation
- // purposes that we got it
- wxChildFocusEvent eventFocus(win);
- (void)win->GetEventHandler()->ProcessEvent(eventFocus);
+ wxLogTrace(TRACE_FOCUS,
+ _T("%s: focus in"), win->GetName().c_str());
#ifdef HAVE_XIM
if (win->m_ic)
}
#endif // wxUSE_CARET
- if (win->IsTopLevel())
+ g_activeFrameLostFocus = FALSE;
+
+ wxWindowGTK *active = wxGetTopLevelParent(win);
+ if ( active != g_activeFrame )
{
- wxActivateEvent event( wxEVT_ACTIVATE, TRUE, win->GetId() );
- event.SetEventObject( win );
+ if ( g_activeFrame )
+ {
+ wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from focus_in)"), g_activeFrame);
+ wxActivateEvent event(wxEVT_ACTIVATE, FALSE, g_activeFrame->GetId());
+ event.SetEventObject(g_activeFrame);
+ g_activeFrame->GetEventHandler()->ProcessEvent(event);
+ }
- // ignore return value
- win->GetEventHandler()->ProcessEvent( event );
+ wxLogTrace(wxT("activate"), wxT("Activating frame %p (from focus_in)"), active);
+ g_activeFrame = active;
+ wxActivateEvent event(wxEVT_ACTIVATE, TRUE, g_activeFrame->GetId());
+ event.SetEventObject(g_activeFrame);
+ g_activeFrame->GetEventHandler()->ProcessEvent(event);
+
+ // Don't send focus events in addition to activate
+ // if (win == g_activeFrame)
+ // return TRUE;
}
- wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() );
- event.SetEventObject( win );
-
- if (win->GetEventHandler()->ProcessEvent( event ))
+ // does the window itself think that it has the focus?
+ if ( !win->m_hasFocus )
{
- gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
- return TRUE;
- }
+ // not yet, notify it
+ win->m_hasFocus = TRUE;
+ if ( DoSendFocusEvents(win) )
+ {
+ gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_in_event" );
+ return TRUE;
+ }
+ }
return FALSE;
}
// "focus_out_event"
//-----------------------------------------------------------------------------
-static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED(event), wxWindowGTK *win )
+static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEventFocus *gdk_event, wxWindowGTK *win )
{
DEBUG_MAIN_THREAD
if (!win->m_hasVMT) return FALSE;
if (g_blockEventsOnDrag) return FALSE;
+ wxLogTrace( TRACE_FOCUS,
+ _T("%s: focus out"), win->GetName().c_str() );
+
+ if ( !g_activeFrameLostFocus && g_activeFrame )
+ {
+ // VZ: commenting this out because it does happen (although not easy
+ // to reproduce, I only see it when using wxMiniFrame and not
+ // always) and makes using Mahogany quite annoying
+#if 0
+ wxASSERT_MSG( wxGetTopLevelParent(win) == g_activeFrame,
+ wxT("unfocusing window that hasn't gained focus properly") );
+#endif // 0
+
+ g_activeFrameLostFocus = TRUE;
+ }
+
// if the focus goes out of our app alltogether, OnIdle() will send
// wxActivateEvent, otherwise gtk_window_focus_in_callback() will reset
// g_sendActivateEvent to -1
g_focusWindow = (wxWindowGTK *)NULL;
-#if 0
- wxPrintf( "OnKillFocus from " );
- if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
- wxPrintf( win->GetClassInfo()->GetClassName() );
- wxPrintf( ".\n" );
-#endif
-
#ifdef HAVE_XIM
if (win->m_ic)
gdk_im_end();
}
#endif // wxUSE_CARET
- if (win->IsTopLevel())
+ // don't send the window a kill focus event if it thinks that it doesn't
+ // have focus already
+ if ( win->m_hasFocus )
{
- wxActivateEvent event( wxEVT_ACTIVATE, FALSE, win->GetId() );
- event.SetEventObject( win );
-
- // ignore return value
- win->GetEventHandler()->ProcessEvent( event );
- }
+ win->m_hasFocus = FALSE;
- wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
- event.SetEventObject( win );
+ 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" );
- return TRUE;
+ if (win->GetEventHandler()->ProcessEvent( event ))
+ {
+ gtk_signal_emit_stop_by_name( GTK_OBJECT(widget), "focus_out_event" );
+ return TRUE;
+ }
}
return FALSE;
// "enter_notify_event"
//-----------------------------------------------------------------------------
-static gint gtk_window_enter_callback( GtkWidget *widget, GdkEventCrossing *gdk_event, wxWindowGTK *win )
+static
+gint gtk_window_enter_callback( GtkWidget *widget,
+ GdkEventCrossing *gdk_event,
+ wxWindowGTK *win )
{
DEBUG_MAIN_THREAD
if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
- wxMouseEvent event( wxEVT_ENTER_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 );
- InitMouseEvent(event, gdk_event);
-
- event.m_x = x;
- event.m_y = y;
+ 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 (win->GetEventHandler()->ProcessEvent( event ))
{
gdk_window_get_pointer( widget->window, &x, &y, &state );
- event.m_shiftDown = (state & GDK_SHIFT_MASK);
- event.m_controlDown = (state & GDK_CONTROL_MASK);
- event.m_altDown = (state & GDK_MOD1_MASK);
- event.m_metaDown = (state & GDK_MOD2_MASK);
- event.m_leftDown = (state & GDK_BUTTON1_MASK);
- event.m_middleDown = (state & GDK_BUTTON2_MASK);
- event.m_rightDown = (state & GDK_BUTTON3_MASK);
+ 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;
- event.m_x = x;
- event.m_y = y;
+ wxPoint pt = win->GetClientAreaOrigin();
+ event.m_x = x + pt.x;
+ event.m_y = y + pt.y;
if (win->GetEventHandler()->ProcessEvent( event ))
{
// "value_changed" from m_vAdjust
//-----------------------------------------------------------------------------
-static void gtk_window_vscroll_callback( GtkAdjustment *adjust, wxWindowGTK *win )
+static void gtk_window_vscroll_callback( GtkAdjustment *adjust,
+ SCROLLBAR_CBACK_ARG
+ wxWindowGTK *win )
{
DEBUG_MAIN_THREAD
win->m_oldVerticalPos = adjust->value;
- GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
- GtkRange *range = GTK_RANGE( scrolledWindow->vscrollbar );
-
- wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK;
- if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP;
- else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN;
- else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP;
- else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN;
+#ifndef __WXGTK20__
+ GtkScrolledWindow *sw = GTK_SCROLLED_WINDOW(win->m_widget);
+#endif
+ wxEventType command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw->vscrollbar));
int value = (int)(adjust->value+0.5);
// "value_changed" from m_hAdjust
//-----------------------------------------------------------------------------
-static void gtk_window_hscroll_callback( GtkAdjustment *adjust, wxWindowGTK *win )
+static void gtk_window_hscroll_callback( GtkAdjustment *adjust,
+ SCROLLBAR_CBACK_ARG
+ wxWindowGTK *win )
{
DEBUG_MAIN_THREAD
float diff = adjust->value - win->m_oldHorizontalPos;
if (fabs(diff) < 0.2) return;
- win->m_oldHorizontalPos = adjust->value;
-
- GtkScrolledWindow *scrolledWindow = GTK_SCROLLED_WINDOW(win->m_widget);
- GtkRange *range = GTK_RANGE( scrolledWindow->hscrollbar );
+#ifndef __WXGTK20__
+ GtkScrolledWindow *sw = GTK_SCROLLED_WINDOW(win->m_widget);
+#endif
+ wxEventType command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(sw->hscrollbar));
- wxEventType command = wxEVT_SCROLLWIN_THUMBTRACK;
- if (range->scroll_type == GTK_SCROLL_STEP_BACKWARD) command = wxEVT_SCROLLWIN_LINEUP;
- else if (range->scroll_type == GTK_SCROLL_STEP_FORWARD) command = wxEVT_SCROLLWIN_LINEDOWN;
- else if (range->scroll_type == GTK_SCROLL_PAGE_BACKWARD) command = wxEVT_SCROLLWIN_PAGEUP;
- else if (range->scroll_type == GTK_SCROLL_PAGE_FORWARD) command = wxEVT_SCROLLWIN_PAGEDOWN;
+ win->m_oldHorizontalPos = adjust->value;
int value = (int)(adjust->value+0.5);
g_blockEventsOnScroll = TRUE;
+
+ // FIXME: there is no 'slider' field in GTK+ 2.0 any more
+#ifndef __WXGTK20__
win->m_isScrolling = (gdk_event->window == widget->slider);
+#endif
return FALSE;
}
return (wxWindow *)g_focusWindow;
}
+//-----------------------------------------------------------------------------
+// "destroy" event
+//-----------------------------------------------------------------------------
+
+// VZ: Robert commented the code using out so it generates warnings: should
+// be either fixed or removed completely
+#if 0
+
+static void gtk_window_destroy_callback( GtkWidget* widget, wxWindow *win )
+{
+ wxWindowDestroyEvent event(win);
+ win->GetEventHandler()->ProcessEvent(event);
+}
+
+#endif // 0
+
//-----------------------------------------------------------------------------
// "realize" from m_widget
//-----------------------------------------------------------------------------
wxapp_install_idle_handler();
if (win->m_delayedBackgroundColour)
- win->SetBackgroundColour( win->GetBackgroundColour() );
+ win->GtkSetBackgroundColour( win->GetBackgroundColour() );
if (win->m_delayedForegroundColour)
- win->SetForegroundColour( win->GetForegroundColour() );
+ win->GtkSetForegroundColour( win->GetForegroundColour() );
wxWindowCreateEvent event( win );
event.SetEventObject( win );
wxWindow *wxGetActiveWindow()
{
- // the cast is necessary when we compile in wxUniversal mode
- return (wxWindow *)g_focusWindow;
+ return wxWindow::FindFocus();
}
//-----------------------------------------------------------------------------
m_noExpose = FALSE;
m_nativeSizeEvent = FALSE;
-
+
m_hasScrolling = FALSE;
m_isScrolling = FALSE;
m_insertCallback = (wxInsertChildFunction) NULL;
- m_isStaticBox = FALSE;
- m_isRadioButton = FALSE;
- m_isFrame = FALSE;
m_acceptsFocus = FALSE;
+ m_hasFocus = FALSE;
m_clipPaintRegion = FALSE;
}
m_insertCallback = wxInsertChildInWindow;
+
+ // always needed for background clearing
+ m_delayedBackgroundColour = TRUE;
m_widget = gtk_scrolled_window_new( (GtkAdjustment *) NULL, (GtkAdjustment *) NULL );
GTK_WIDGET_UNSET_FLAGS( m_widget, GTK_CAN_FOCUS );
m_wxwindow = gtk_pizza_new();
- gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
-
#ifndef __WXUNIVERSAL__
-#if (GTK_MINOR_VERSION > 0)
GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
if (HasFlag(wxRAISED_BORDER))
{
gtk_pizza_set_shadow_type( pizza, GTK_MYSHADOW_NONE );
}
-#else // GTK_MINOR_VERSION == 0
- GtkViewport *viewport = GTK_VIEWPORT(scrolledWindow->viewport);
-
- if (HasFlag(wxRAISED_BORDER))
- {
- gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_OUT );
- }
- else if (HasFlag(wxSUNKEN_BORDER))
- {
- gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_IN );
- }
- else
- {
- gtk_viewport_set_shadow_type( viewport, GTK_SHADOW_NONE );
- }
-#endif // GTK_MINOR_VERSION
#endif // __WXUNIVERSAL__
+ gtk_container_add( GTK_CONTAINER(m_widget), m_wxwindow );
+
GTK_WIDGET_SET_FLAGS( m_wxwindow, GTK_CAN_FOCUS );
m_acceptsFocus = TRUE;
-#if (GTK_MINOR_VERSION == 0)
- // 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) );
-#endif // GTK_MINOR_VERSION == 0
-
// I _really_ don't want scrollbars in the beginning
m_vAdjust->lower = 0.0;
m_vAdjust->upper = 1.0;
if (m_parent)
m_parent->DoAddChild( this );
-
+
m_focusWidget = m_wxwindow;
PostCreation();
if (g_focusWindow == this)
g_focusWindow = NULL;
+ if (g_activeFrame == this)
+ g_activeFrame = NULL;
+
+ if ( g_delayedFocus == this )
+ g_delayedFocus = NULL;
+
m_isBeingDeleted = TRUE;
m_hasVMT = FALSE;
{
wxCHECK_MSG( !m_needParent || parent, FALSE, wxT("Need complete parent.") );
- /* this turns -1 into 20 so that a minimal window is
- visible even although -1,-1 has been given as the
- size of the window. the same trick is used in other
- ports and should make debugging easier */
- m_width = WidthDefault(size.x);
+ // This turns -1 into 30 so that a minimal window is
+ // visible even although -1,-1 has been given as the
+ // size of the window. the same trick is used in other
+ // ports and should make debugging easier.
+ m_width = WidthDefault(size.x) ;
m_height = HeightDefault(size.y);
m_x = (int)pos.x;
m_y = (int)pos.y;
- /* some reasonable defaults */
+ // some reasonable defaults
if (!parent)
{
if (m_x == -1)
void wxWindowGTK::PostCreation()
{
wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
-
+
if (m_wxwindow)
{
if (!m_noExpose)
gtk_signal_connect( GTK_OBJECT(m_wxwindow), "expose_event",
GTK_SIGNAL_FUNC(gtk_window_expose_callback), (gpointer)this );
+#ifndef __WXGTK20__
gtk_signal_connect( GTK_OBJECT(m_wxwindow), "draw",
GTK_SIGNAL_FUNC(gtk_window_draw_callback), (gpointer)this );
gtk_signal_connect( GTK_OBJECT(m_wxwindow), "event",
GTK_SIGNAL_FUNC(gtk_window_event_event_callback), (gpointer)this );
}
+#else
+ gtk_widget_set_redraw_on_allocate( GTK_WIDGET(m_wxwindow), HasFlag( wxNO_FULL_REPAINT_ON_RESIZE ) );
+#endif
}
- // these are called when the "sunken" or "raised" borders are drawn */
+ // these are called when the "sunken" or "raised" borders are drawn
gtk_signal_connect( GTK_OBJECT(m_widget), "expose_event",
GTK_SIGNAL_FUNC(gtk_window_own_expose_callback), (gpointer)this );
+#ifndef __WXGTK20__
gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
+#endif
}
// focus handling
if (m_focusWidget == NULL)
m_focusWidget = m_widget;
-#if 0
- if (GetClassInfo() && GetClassInfo()->GetClassName())
- wxPrintf( GetClassInfo()->GetClassName() );
- wxPrintf( ".\n" );
-#endif
-
gtk_signal_connect( GTK_OBJECT(m_focusWidget), "focus_in_event",
GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
gtk_signal_connect( GTK_OBJECT(widget), "leave_notify_event",
GTK_SIGNAL_FUNC(gtk_window_leave_callback), (gpointer)this );
+
+ // This keeps crashing on me. RR.
+ //
+ // gtk_signal_connect( GTK_OBJECT(widget), "destroy",
+ // GTK_SIGNAL_FUNC(gtk_window_destroy_callback), (gpointer)this );
}
bool wxWindowGTK::Destroy()
if (m_resizing) return; /* I don't like recursions */
m_resizing = TRUE;
+ int currentX, currentY;
+ GetPosition(¤tX, ¤tY);
+ if (x == -1)
+ x = currentX;
+ if (y == -1)
+ y = currentY;
+ AdjustForParentClientOrigin(x, y, sizeFlags);
+
if (m_parent->m_wxwindow == NULL) /* i.e. wxNotebook */
{
/* don't set the size for children of wxNotebook, just take the values. */
else
{
GtkPizza *pizza = GTK_PIZZA(m_parent->m_wxwindow);
-
if ((sizeFlags & wxSIZE_ALLOW_MINUS_ONE) == 0)
{
if (x != -1) m_x = x + pizza->xoffset;
if (y != -1) m_y = y + pizza->yoffset;
- if (width != -1) m_width = width;
- if (height != -1) m_height = height;
}
else
{
m_x = x + pizza->xoffset;
m_y = y + pizza->yoffset;
- m_width = width;
- m_height = height;
}
+ if (width != -1) m_width = width;
+ if (height != -1) m_height = height;
if ((sizeFlags & wxSIZE_AUTO_WIDTH) == wxSIZE_AUTO_WIDTH)
{
if (height == -1) m_height = 26;
}
- 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_maxWidth;
- if ((m_maxHeight != -1) && (m_height > m_maxHeight)) m_height = m_maxHeight;
+ int minWidth = GetMinWidth(),
+ minHeight = GetMinHeight(),
+ maxWidth = GetMaxWidth(),
+ maxHeight = GetMaxHeight();
+
+ if ((minWidth != -1) && (m_width < minWidth)) m_width = minWidth;
+ if ((minHeight != -1) && (m_height < minHeight)) m_height = minHeight;
+ if ((maxWidth != -1) && (m_width > maxWidth)) m_width = maxWidth;
+ if ((maxHeight != -1) && (m_height > maxHeight)) m_height = maxHeight;
int border = 0;
int bottom_border = 0;
+#ifndef __WXGTK20__
if (GTK_WIDGET_CAN_DEFAULT(m_widget))
{
/* the default button has a border around it */
border = 6;
bottom_border = 5;
}
+#endif
DoMoveWindow( m_x-border,
m_y-border,
void wxWindowGTK::OnInternalIdle()
{
+ // Update invalidated regions.
+ GtkUpdate();
+
+ // Synthetize activate events.
if ( g_sendActivateEvent != -1 )
{
bool activate = g_sendActivateEvent != 0;
g_sendActivateEvent = -1;
wxTheApp->SetActive(activate, (wxWindow *)g_focusWindowLast);
-
- wxActivateEvent event(wxEVT_ACTIVATE_APP, activate, GetId());
- event.SetEventObject(this);
-
- (void)GetEventHandler()->ProcessEvent(event);
}
+ if ( g_activeFrameLostFocus )
+ {
+ if ( g_activeFrame )
+ {
+ wxLogTrace(wxT("activate"), wxT("Deactivating frame %p (from idle)"), g_activeFrame);
+ wxActivateEvent event(wxEVT_ACTIVATE, FALSE, g_activeFrame->GetId());
+ event.SetEventObject(g_activeFrame);
+ g_activeFrame->GetEventHandler()->ProcessEvent(event);
+ g_activeFrame = NULL;
+ }
+ g_activeFrameLostFocus = FALSE;
+ }
+
wxCursor cursor = m_cursor;
if (g_globalCursor.Ok()) cursor = g_globalCursor;
if (theFont) fontToUse = *theFont;
wxCHECK_RET( fontToUse.Ok(), wxT("invalid font") );
+
+ if (string.IsEmpty())
+ {
+ if (x) (*x) = 0;
+ if (y) (*y) = 0;
+ return;
+ }
+#ifdef __WXGTK20__
+ PangoContext *context = NULL;
+ if (m_widget)
+ 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);
+ {
+#if wxUSE_UNICODE
+ const wxCharBuffer data = wxConvUTF8.cWC2MB( string );
+ pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data ));
+#else
+ const wxWCharBuffer wdata = wxConvLocal.cMB2WC( string );
+ const wxCharBuffer data = wxConvUTF8.cWC2MB( wdata );
+ pango_layout_set_text(layout, (const char*) data, strlen( (const char*) data ));
+#endif
+ }
+ PangoLayoutLine *line = (PangoLayoutLine *)pango_layout_get_lines(layout)->data;
+
+ PangoRectangle rect;
+ pango_layout_line_get_extents(line, NULL, &rect);
+
+ if (x) (*x) = (wxCoord) (rect.width / PANGO_SCALE);
+ if (y) (*y) = (wxCoord) (rect.height / PANGO_SCALE);
+ if (descent)
+ {
+ // Do something about metrics here
+ (*descent) = 0;
+ }
+ if (externalLeading) (*externalLeading) = 0; // ??
+
+ g_object_unref( G_OBJECT( layout ) );
+#else
GdkFont *font = fontToUse.GetInternalFont( 1.0 );
- if (x) (*x) = gdk_string_width( font, string.mbc_str() );
+ if (x) (*x) = gdk_string_width( font, wxGTK_CONV( string ) );
if (y) (*y) = font->ascent + font->descent;
if (descent) (*descent) = font->descent;
if (externalLeading) (*externalLeading) = 0; // ??
+#endif
}
void wxWindowGTK::SetFocus()
{
- wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
+ 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);
- return;
+ }
}
-
- if (m_widget)
+ else if (m_widget)
{
if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
{
- gtk_widget_grab_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 if (GTK_IS_CONTAINER(m_widget))
{
- gtk_container_focus( GTK_CONTAINER(m_widget), GTK_DIR_TAB_FORWARD );
+ SET_CONTAINER_FOCUS( m_widget, GTK_DIR_TAB_FORWARD );
}
else
{
- // ?
+ wxLogTrace(TRACE_FOCUS,
+ _T("Can't set focus to %s(%s)"),
+ GetClassInfo()->GetClassName(), GetLabel().c_str());
}
}
}
{
wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
- /* we provide this function ourselves as it is
- missing in GDK (top of this file) */
+ // We provide this function ourselves as it is
+ // missing in GDK (top of this file).
GdkWindow *window = (GdkWindow*) NULL;
if (m_wxwindow)
gdk_window_warp_pointer( window, x, y );
}
+
void wxWindowGTK::Refresh( bool eraseBackground, const wxRect *rect )
{
if (!m_widget) return;
if (!m_widget->window) return;
-
- // temporarily hide the caret to avoid nasty interactions between caret
- // drawing and the window contents redraw
-#if 0 // def wxUSE_CARET -- doesn't seem to help :-(
- wxCaretSuspend cs((wxWindow *)this);
-#endif // wxUSE_CARET
-
+
+#ifndef __WXGTK20__
+ if (g_isIdle)
+ wxapp_install_idle_handler();
+
if (eraseBackground && m_wxwindow && m_wxwindow->window)
{
if (rect)
{
- gdk_window_clear_area( GTK_PIZZA(m_wxwindow)->bin_window,
- rect->x, rect->y,
- rect->width, rect->height );
+ // Schedule for later Updating in ::Update() or ::OnInternalIdle().
+ m_clearRegion.Union( rect->x, rect->y, rect->width, rect->height );
}
else
{
- gdk_window_clear( GTK_PIZZA(m_wxwindow)->bin_window );
+ // Schedule for later Updating in ::Update() or ::OnInternalIdle().
+ m_clearRegion.Clear();
+ m_clearRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
}
}
- /* there is no GTK equivalent of "draw only, don't clear" so we
- invent our own in the GtkPizza widget */
-
- if (!rect)
+ if (rect)
{
if (m_wxwindow)
{
-
-/*
- GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
- gboolean old_clear = pizza->clear_on_draw;
- gtk_pizza_set_clear( pizza, FALSE );
- gtk_widget_draw( m_wxwindow, (GdkRectangle*) NULL );
- gtk_pizza_set_clear( pizza, old_clear );
-*/
- GdkEventExpose gdk_event;
- gdk_event.type = GDK_EXPOSE;
- gdk_event.window = GTK_PIZZA(m_wxwindow)->bin_window;
- gdk_event.count = 0;
- gdk_event.area.x = 0;
- gdk_event.area.y = 0;
- gdk_event.area.width = m_wxwindow->allocation.width;
- gdk_event.area.height = m_wxwindow->allocation.height;
- gtk_window_expose_callback( m_wxwindow, &gdk_event, (wxWindow *)this );
+ // Schedule for later Updating in ::Update() or ::OnInternalIdle().
+ m_updateRegion.Union( rect->x, rect->y, rect->width, rect->height );
}
else
{
- gtk_widget_draw( m_widget, (GdkRectangle*) NULL );
+ GdkRectangle gdk_rect;
+ gdk_rect.x = rect->x;
+ gdk_rect.y = rect->y;
+ gdk_rect.width = rect->width;
+ gdk_rect.height = rect->height;
+ gtk_widget_draw( m_widget, &gdk_rect );
}
}
else
{
-
if (m_wxwindow)
{
-/*
- GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
- gboolean old_clear = pizza->clear_on_draw;
- gtk_pizza_set_clear( pizza, FALSE );
-
+ // Schedule for later Updating in ::Update() or ::OnInternalIdle().
+ m_updateRegion.Clear();
+ m_updateRegion.Union( 0, 0, m_wxwindow->allocation.width, m_wxwindow->allocation.height );
+ }
+ else
+ {
+ gtk_widget_draw( m_widget, (GdkRectangle*) NULL );
+ }
+ }
+#else
+ if (m_wxwindow)
+ {
+ if (rect)
+ {
GdkRectangle gdk_rect;
gdk_rect.x = rect->x;
gdk_rect.y = rect->y;
gdk_rect.width = rect->width;
gdk_rect.height = rect->height;
- gtk_widget_draw( m_wxwindow, &gdk_rect );
- gtk_window_draw_callback( m_wxwindow, &gdk_rect, this );
+ gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow)->bin_window, &gdk_rect, TRUE );
+ }
+ else
+ {
+ gdk_window_invalidate_rect( GTK_PIZZA(m_wxwindow)->bin_window, NULL, TRUE );
+ }
+ }
+#endif
+}
- gtk_pizza_set_clear( pizza, old_clear );
-*/
- GdkEventExpose gdk_event;
- gdk_event.type = GDK_EXPOSE;
- gdk_event.window = GTK_PIZZA(m_wxwindow)->bin_window;
- gdk_event.count = 0;
- gdk_event.area.x = rect->x;
- gdk_event.area.y = rect->y;
- gdk_event.area.width = rect->width;
- gdk_event.area.height = rect->height;
- gtk_window_expose_callback( m_wxwindow, &gdk_event, (wxWindow *)this );
+void wxWindowGTK::Update()
+{
+ GtkUpdate();
+}
+
+void wxWindowGTK::GtkUpdate()
+{
+#ifdef __WXGTK20__
+ if (m_wxwindow && GTK_PIZZA(m_wxwindow)->bin_window)
+ gdk_window_process_updates( GTK_PIZZA(m_wxwindow)->bin_window, FALSE );
+#else
+ if (!m_updateRegion.IsEmpty())
+ GtkSendPaintEvents();
+#endif
+}
+
+void wxWindowGTK::GtkSendPaintEvents()
+{
+ if (!m_wxwindow)
+ {
+#ifndef __WXGTK20__
+ m_clearRegion.Clear();
+#endif
+ m_updateRegion.Clear();
+ return;
+ }
+
+ // Clip to paint region in wxClientDC
+ m_clipPaintRegion = TRUE;
+
+#ifndef __WXGTK20__
+ // widget to draw on
+ GtkPizza *pizza = GTK_PIZZA (m_wxwindow);
+
+ // later for GTK 2.0, too.
+ if (GetThemeEnabled())
+ {
+ // find ancestor from which to steal background
+ wxWindow *parent = GetParent();
+ while (parent && !parent->IsTopLevel())
+ parent = parent->GetParent();
+ if (!parent)
+ parent = (wxWindow*)this;
+
+ wxRegionIterator upd( m_updateRegion );
+ 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,
+ GTK_STATE_NORMAL,
+ GTK_SHADOW_NONE,
+ &rect,
+ parent->m_widget,
+ (char *)"base",
+ 0, 0, -1, -1 );
+
+ upd ++;
}
+ }
+ else
+#endif
+
+#ifdef __WXGTK20__
+ {
+ wxWindowDC dc( (wxWindow*)this );
+ dc.SetClippingRegion( m_updateRegion );
+
+ wxEraseEvent erase_event( GetId(), &dc );
+ erase_event.SetEventObject( this );
+
+ GetEventHandler()->ProcessEvent(erase_event);
+ }
+#else
+ // if (!m_clearRegion.IsEmpty()) // Always send an erase event under GTK 1.2
+ {
+ wxWindowDC dc( (wxWindow*)this );
+ if (m_clearRegion.IsEmpty())
+ dc.SetClippingRegion( m_updateRegion );
else
+ dc.SetClippingRegion( m_clearRegion );
+
+ wxEraseEvent erase_event( GetId(), &dc );
+ erase_event.SetEventObject( this );
+
+ if (!GetEventHandler()->ProcessEvent(erase_event))
{
- GdkRectangle gdk_rect;
- gdk_rect.x = rect->x;
- gdk_rect.y = rect->y;
- gdk_rect.width = rect->width;
- gdk_rect.height = rect->height;
- gtk_widget_draw( m_widget, &gdk_rect );
+ if (!g_eraseGC)
+ {
+ g_eraseGC = gdk_gc_new( pizza->bin_window );
+ gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
+ }
+ gdk_gc_set_foreground( g_eraseGC, m_backgroundColour.GetColor() );
+
+ wxRegionIterator upd( m_clearRegion );
+ while (upd)
+ {
+ gdk_draw_rectangle( pizza->bin_window, g_eraseGC, 1,
+ upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
+ upd ++;
+ }
+ }
+ m_clearRegion.Clear();
+ }
+#endif
+
+ wxNcPaintEvent nc_paint_event( GetId() );
+ nc_paint_event.SetEventObject( this );
+ GetEventHandler()->ProcessEvent( nc_paint_event );
+
+ wxPaintEvent paint_event( GetId() );
+ paint_event.SetEventObject( this );
+ GetEventHandler()->ProcessEvent( paint_event );
+
+ m_clipPaintRegion = FALSE;
+
+#ifndef __WXUNIVERSAL__
+#ifndef __WXGTK20__
+ // The following code will result in all window-less widgets
+ // being redrawn because the wxWindows class is allowed to
+ // paint over the window-less widgets.
+
+ GList *children = pizza->children;
+ while (children)
+ {
+ GtkPizzaChild *child = (GtkPizzaChild*) children->data;
+ children = children->next;
+
+ if (GTK_WIDGET_NO_WINDOW (child->widget) &&
+ GTK_WIDGET_DRAWABLE (child->widget))
+ {
+ // Get intersection of widget area and update region
+ wxRegion region( m_updateRegion );
+
+ GdkEventExpose gdk_event;
+ gdk_event.type = GDK_EXPOSE;
+ gdk_event.window = pizza->bin_window;
+ gdk_event.count = 0;
+
+ wxRegionIterator upd( m_updateRegion );
+ while (upd)
+ {
+ GdkRectangle rect;
+ rect.x = upd.GetX();
+ rect.y = upd.GetY();
+ rect.width = upd.GetWidth();
+ rect.height = upd.GetHeight();
+
+ if (gtk_widget_intersect (child->widget, &rect, &gdk_event.area))
+ {
+ gtk_widget_event (child->widget, (GdkEvent*) &gdk_event);
+ }
+
+ upd ++;
+ }
}
}
+#endif
+#endif
+
+ m_updateRegion.Clear();
}
void wxWindowGTK::Clear()
{
wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
- if (!m_widget->window) return;
-
+#ifndef __WXGTK20__
if (m_wxwindow && m_wxwindow->window)
{
-// gdk_window_clear( m_wxwindow->window );
+ m_clearRegion.Clear();
+ wxSize size( GetClientSize() );
+ m_clearRegion.Union( 0,0,size.x,size.y );
+
+ // Better do this in idle?
+ GtkUpdate();
}
+#endif
}
#if wxUSE_TOOLTIPS
}
#endif // wxUSE_TOOLTIPS
+void wxWindowGTK::GtkSetBackgroundColour( const wxColour &colour )
+{
+ GdkWindow *window = (GdkWindow*) NULL;
+ if (m_wxwindow)
+ window = GTK_PIZZA(m_wxwindow)->bin_window;
+ else
+ window = GetConnectWidget()->window;
+
+ wxASSERT( window );
+
+ // We need the pixel value e.g. for background clearing.
+ m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
+
+ if (m_wxwindow)
+ {
+ // wxMSW doesn't clear the window here, either.
+ gdk_window_set_background( window, m_backgroundColour.GetColor() );
+ }
+
+ ApplyWidgetStyle();
+}
+
bool wxWindowGTK::SetBackgroundColour( const wxColour &colour )
{
wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
if (!wxWindowBase::SetBackgroundColour(colour))
- {
- // don't leave if the GTK widget has just
- // been realized
- if (!m_delayedBackgroundColour) return FALSE;
- }
+ return FALSE;
GdkWindow *window = (GdkWindow*) NULL;
if (m_wxwindow)
// but it couldn't get applied as the
// widget hasn't been realized yet.
m_delayedBackgroundColour = TRUE;
+ return TRUE;
}
-
- if ((m_wxwindow) &&
- (m_wxwindow->window) &&
- (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE)))
+ else
{
- /* wxMSW doesn't clear the window here. I don't do that either to
- provide compatibility. call Clear() to do the job. */
-
- m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
- gdk_window_set_background( window, m_backgroundColour.GetColor() );
+ GtkSetBackgroundColour( colour );
}
- ApplyWidgetStyle();
-
return TRUE;
}
+void wxWindowGTK::GtkSetForegroundColour( const wxColour &colour )
+{
+ GdkWindow *window = (GdkWindow*) NULL;
+ if (m_wxwindow)
+ window = GTK_PIZZA(m_wxwindow)->bin_window;
+ else
+ window = GetConnectWidget()->window;
+
+ wxASSERT( window );
+
+ ApplyWidgetStyle();
+}
+
bool wxWindowGTK::SetForegroundColour( const wxColour &colour )
{
wxCHECK_MSG( m_widget != NULL, FALSE, wxT("invalid window") );
// widget hasn't been realized yet.
m_delayedForegroundColour = TRUE;
}
-
- ApplyWidgetStyle();
+ else
+ {
+ GtkSetForegroundColour( colour );
+ }
return TRUE;
}
if (m_widgetStyle)
{
GtkStyle *remake = gtk_style_copy( m_widgetStyle );
-#ifdef __WXGTK20__
- /* FIXME: is this necessary? */
- _G_TYPE_IGC(remake, GtkObjectClass) = _G_TYPE_IGC(m_widgetStyle, GtkObjectClass);
-#else
+
+ // FIXME: no more klass in 2.0
+#ifndef __WXGTK20__
remake->klass = m_widgetStyle->klass;
#endif
def = gtk_widget_get_default_style();
m_widgetStyle = gtk_style_copy( def );
-#ifdef __WXGTK20__
- /* FIXME: is this necessary? */
- _G_TYPE_IGC(m_widgetStyle, GtkObjectClass) = _G_TYPE_IGC(def, GtkObjectClass);
-#else
+
+ // FIXME: no more klass in 2.0
+#ifndef __WXGTK20__
m_widgetStyle->klass = def->klass;
#endif
}
void wxWindowGTK::SetWidgetStyle()
{
-#if DISABLE_STYLE_IF_BROKEN_THEM
+#if DISABLE_STYLE_IF_BROKEN_THEME
if (m_widget->style->engine_data)
{
static bool s_warningPrinted = FALSE;
GtkStyle *style = GetWidgetStyle();
- if (m_font != wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT ))
+ if (m_font != wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ))
{
- gdk_font_unref( style->font );
- style->font = gdk_font_ref( m_font.GetInternalFont( 1.0 ) );
+ SET_STYLE_FONT(style, m_font.GetInternalFont( 1.0 ));
}
if (m_foregroundColour.Ok())
{
m_foregroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
- if (m_foregroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNTEXT))
+ if (m_foregroundColour != wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT))
{
style->fg[GTK_STATE_NORMAL] = *m_foregroundColour.GetColor();
style->fg[GTK_STATE_PRELIGHT] = *m_foregroundColour.GetColor();
if (m_backgroundColour.Ok())
{
m_backgroundColour.CalcPixel( gtk_widget_get_colormap( m_widget ) );
- if (m_backgroundColour != wxSystemSettings::GetSystemColour(wxSYS_COLOUR_BTNFACE))
+ if (m_backgroundColour != wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE))
{
style->bg[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
style->base[GTK_STATE_NORMAL] = *m_backgroundColour.GetColor();
#if wxUSE_MENUS_NATIVE
-static void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting )
+extern "C"
+void gtk_pop_hide_callback( GtkWidget *WXUNUSED(widget), bool* is_waiting )
{
*is_waiting = FALSE;
}
}
}
+// used to pass the coordinates from wxWindowGTK::DoPopupMenu() to
+// wxPopupMenuPositionCallback()
+//
+// should be safe even in the MT case as the user can hardly popup 2 menus
+// simultaneously, can he?
static gint gs_pop_x = 0;
static gint gs_pop_y = 0;
-static void pop_pos_callback( GtkMenu * WXUNUSED(menu),
- gint *x, gint *y,
- wxWindowGTK *win )
+extern "C" void wxPopupMenuPositionCallback( GtkMenu *menu,
+ gint *x, gint *y,
+#ifdef __WXGTK20__
+ gboolean * WXUNUSED(whatever),
+#endif
+ gpointer WXUNUSED(user_data) )
{
- win->ClientToScreen( &gs_pop_x, &gs_pop_y );
- *x = gs_pop_x;
- *y = gs_pop_y;
+ // ensure that the menu appears entirely on screen
+ GtkRequisition req;
+ gtk_widget_get_child_requisition(GTK_WIDGET(menu), &req);
+
+ wxSize sizeScreen = wxGetDisplaySize();
+
+ gint xmax = sizeScreen.x - req.width,
+ ymax = sizeScreen.y - req.height;
+
+ *x = gs_pop_x < xmax ? gs_pop_x : xmax;
+ *y = gs_pop_y < ymax ? gs_pop_y : ymax;
}
bool wxWindowGTK::DoPopupMenu( wxMenu *menu, int x, int y )
gs_pop_x = x;
gs_pop_y = y;
+ ClientToScreen( &gs_pop_x, &gs_pop_y );
bool is_waiting = TRUE;
- gtk_signal_connect( GTK_OBJECT(menu->m_menu), "hide",
- GTK_SIGNAL_FUNC(gtk_pop_hide_callback), (gpointer)&is_waiting );
+ gtk_signal_connect( GTK_OBJECT(menu->m_menu),
+ "hide",
+ GTK_SIGNAL_FUNC(gtk_pop_hide_callback),
+ (gpointer)&is_waiting );
gtk_menu_popup(
GTK_MENU(menu->m_menu),
- (GtkWidget *) NULL, // parent menu shell
- (GtkWidget *) NULL, // parent menu item
- (GtkMenuPositionFunc) pop_pos_callback,
- (gpointer) this, // client data
- 0, // button used to activate it
- gs_timeLastClick // the time of activation
+ (GtkWidget *) NULL, // parent menu shell
+ (GtkWidget *) NULL, // parent menu item
+ wxPopupMenuPositionCallback, // function to position it
+ NULL, // client data
+ 0, // button used to activate it
+ gs_timeLastClick // the time of activation
);
while (is_waiting)
return FALSE;
}
- wxColour sysbg = wxSystemSettings::GetSystemColour( wxSYS_COLOUR_BTNFACE );
+ wxColour sysbg = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE );
if ( sysbg == m_backgroundColour )
{
m_backgroundColour = wxNullColour;
return TRUE;
}
-void wxWindowGTK::CaptureMouse()
+void wxWindowGTK::DoCaptureMouse()
{
wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
g_captureWindowHasMouse = TRUE;
}
-void wxWindowGTK::ReleaseMouse()
+void wxWindowGTK::DoReleaseMouse()
{
wxCHECK_RET( m_widget != NULL, wxT("invalid window") );
wxCHECK_RET( g_captureWindow, wxT("can't release mouse - not captured") );
+ g_captureWindow = (wxWindowGTK*) NULL;
+
GdkWindow *window = (GdkWindow*) NULL;
if (m_wxwindow)
window = GTK_PIZZA(m_wxwindow)->bin_window;
return;
gdk_pointer_ungrab ( (guint32)GDK_CURRENT_TIME );
- g_captureWindow = (wxWindowGTK*) NULL;
}
/* static */
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;
- gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
- m_clipPaintRegion = FALSE;
-
-/*
- if (m_children.GetCount() > 0)
- {
- gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
- }
- else
+#ifndef __WXGTK20__
+ if (!m_updateRegion.IsEmpty())
{
- GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
-
- pizza->xoffset -= dx;
- pizza->yoffset -= dy;
-
- GdkGC *m_scrollGC = gdk_gc_new( pizza->bin_window );
- gdk_gc_set_exposures( m_scrollGC, TRUE );
+ m_updateRegion.Offset( dx, dy );
int cw = 0;
int ch = 0;
GetClientSize( &cw, &ch );
- int w = cw - abs(dx);
- int h = ch - abs(dy);
+ m_updateRegion.Intersect( 0, 0, cw, ch );
+ }
- if ((h < 0) || (w < 0))
- {
- Refresh();
- }
- else
- {
- 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;
+ if (!m_clearRegion.IsEmpty())
+ {
+ m_clearRegion.Offset( dx, dy );
- gdk_window_copy_area( pizza->bin_window, m_scrollGC, d_x, d_y,
- pizza->bin_window, s_x, s_y, w, h );
+ int cw = 0;
+ int ch = 0;
+ GetClientSize( &cw, &ch );
+ m_clearRegion.Intersect( 0, 0, cw, ch );
+ }
+#endif
- 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);
+ m_clipPaintRegion = TRUE;
- Refresh( TRUE, &rect );
- }
+ gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
- gdk_gc_unref( m_scrollGC );
- }
-*/
+ m_clipPaintRegion = FALSE;
}
+
// Find the wxWindow at the current mouse position, also returning the mouse
// position.
wxWindow* wxFindWindowAtPointer(wxPoint& pt)
}
+// ----------------------------------------------------------------------------
+// wxDCModule
+// ----------------------------------------------------------------------------
+
+class wxWinModule : public wxModule
+{
+public:
+ bool OnInit();
+ void OnExit();
+
+private:
+ DECLARE_DYNAMIC_CLASS(wxWinModule)
+};
+
+IMPLEMENT_DYNAMIC_CLASS(wxWinModule, wxModule)
+
+bool wxWinModule::OnInit()
+{
+ // g_eraseGC = gdk_gc_new( GDK_ROOT_PARENT() );
+ // gdk_gc_set_fill( g_eraseGC, GDK_SOLID );
+
+ return TRUE;
+}
+
+void wxWinModule::OnExit()
+{
+ if (g_eraseGC)
+ gdk_gc_unref( g_eraseGC );
+}
+
+// vi:sts=4:sw=4:et