#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 <math.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;
return p;
}
-
static void draw_frame( GtkWidget *widget, wxWindowGTK *win )
{
// wxUniversal widgets draw the borders and scrollbars themselves
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 )
-{
- // 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 resue it as last resort
- //
- // NB: should be MT-neutral as always called from main thread only
- static struct
- {
- KeySym keysym;
- long keycode;
- } s_lastKeyPress = { 0, 0 };
-
- KeySym keysym = event->keyval;
- long key_code;
-
- 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:
- {
- // do we have the translation?
- if ( event->length == 1 )
- {
- keysym = (KeySym)event->string[0];
- }
- else if ( (keysym & 0xFF) != keysym )
- {
- // non ASCII key, what to do?
-
- if ( event->type == GDK_KEY_RELEASE )
- {
- // reuse the one from the last keypress if any
- if ( keysym == s_lastKeyPress.keysym )
- {
- key_code = s_lastKeyPress.keycode;
-
- // skip "return 0"
- break;
- }
- }
-
- // ignore this one, we don't know it
- return 0;
- }
- //else: ASCII key, ok
-
- guint upper = gdk_keyval_to_upper( (guint)keysym );
- key_code = upper ? upper : keysym;
-
- if ( event->type == GDK_KEY_PRESS )
- {
- // remember it to be reused below later
- s_lastKeyPress.keysym = keysym;
- s_lastKeyPress.keycode = key_code;
- }
- }
- }
-
- 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
}
*/
+#ifndef __WXUNIVERSAL__
GtkPizza *pizza = GTK_PIZZA (widget);
if (win->GetThemeEnabled())
(char *)"base",
0, 0, -1, -1);
}
+#endif
win->GetUpdateRegion().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 );
+ // Actual redrawing takes place in idle time.
+ win->Update();
- 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;
+#ifdef __WXGTK20__
- GdkEventExpose child_event = *gdk_event;
+ (* GTK_WIDGET_CLASS (pizza_parent_class)->expose_event) (widget, 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);
- }
- }
+#endif
return TRUE;
}
// "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))
{
}
*/
+#ifndef __WXUNIVERSAL__
GtkPizza *pizza = GTK_PIZZA (widget);
if (win->GetThemeEnabled())
gdk_window_clear_area( pizza->bin_window,
rect->x, rect->y, rect->width, rect->height);
}
+#endif
win->GetUpdateRegion().Union( rect->x, rect->y, rect->width, rect->height );
- win->m_clipPaintRegion = TRUE;
+ // Actual redrawing takes place in idle time.
- wxWindowDC dc(win);
- dc.SetClippingRegion(win->GetUpdateRegion());
- wxEraseEvent eevent( win->GetId(), &dc );
- eevent.SetEventObject( win );
+ win->Update();
-#if 1
- (void)win->GetEventHandler()->ProcessEvent(eevent);
-#else
- if (!win->GetEventHandler()->ProcessEvent(eevent))
+#ifndef __WXUNIVERSAL__
+ // Redraw child widgets
+ GList *children = pizza->children;
+ while (children)
{
- if (!win->GetEventHandler()->ProcessEvent(eevent))
- {
- wxClientDC dc( win );
- dc.SetBrush( wxBrush( win->GetBackgroundColour(), wxSOLID ) );
- dc.SetPen( *wxTRANSPARENT_PEN );
+ GtkPizzaChild *child = (GtkPizzaChild*) children->data;
+ children = children->next;
- wxRegionIterator upd( win->GetUpdateRegion() );
- while (upd)
- {
- dc.DrawRectangle( upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
- upd ++;
- }
+ GdkRectangle child_area;
+ if (gtk_widget_intersect (child->widget, rect, &child_area))
+ {
+ gtk_widget_draw (child->widget, &child_area /* (GdkRectangle*) NULL*/ );
}
}
#endif
+}
- wxNcPaintEvent eventNc( win->GetId() );
- eventNc.SetEventObject( win );
- win->GetEventHandler()->ProcessEvent( eventNc );
-
- wxPaintEvent event( win->GetId() );
- event.SetEventObject( win );
- win->GetEventHandler()->ProcessEvent( event );
+#endif
- win->GetUpdateRegion().Clear();
+//-----------------------------------------------------------------------------
+// "key_press_event" from any window
+//-----------------------------------------------------------------------------
- win->m_clipPaintRegion = FALSE;
+// 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;
- GList *children = pizza->children;
- while (children)
+ switch ( keysym )
{
- GtkPizzaChild *child = (GtkPizzaChild*) children->data;
- children = children->next;
+ // 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;
- GdkRectangle child_area;
- if (gtk_widget_intersect (child->widget, rect, &child_area))
- {
- gtk_widget_draw (child->widget, &child_area /* (GdkRectangle*) NULL*/ );
- }
+ // 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_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;
}
-}
-//-----------------------------------------------------------------------------
-// "key_press_event" from any window
-//-----------------------------------------------------------------------------
+ return key_code;
+}
-// turn on to see the key event codes on the console
-#undef DEBUG_KEY_EVENTS
+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 = %d"),
+ event.GetEventType() == wxEVT_KEY_UP ? _T("release")
+ : _T("press"),
+ keysym);
+ long key_code = wxTranslateKeySymToWXKey(keysym, FALSE /* !isChar */);
- int x = 0;
- int y = 0;
- GdkModifierType state;
- if (gdk_event->window)
- gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
+ 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];
+ }
- bool ret = FALSE;
+ // 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;
- long key_code = map_to_unmodified_wx_keysym( gdk_event );
+ // 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;
+ }
+ }
-#ifdef DEBUG_KEY_EVENTS
- wxPrintf(_T("Key press event: %d => %ld\n"), gdk_event->keyval, key_code);
-#endif // DEBUG_KEY_EVENTS
+ wxLogTrace(TRACE_KEYS, _T("\t-> wxKeyCode %d"), key_code);
- /* sending unknown key events doesn't really make sense */
- if (key_code == 0)
+ // sending unknown key events doesn't really make sense
+ if ( !key_code )
return FALSE;
- wxKeyEvent event( wxEVT_KEY_DOWN );
+ // 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);
+
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;
+ }
+
+ bool ret = win->GetEventHandler()->ProcessEvent( event );
#if wxUSE_ACCEL
if (!ret)
will only be sent if it is not in an accelerator table. */
if ( !ret )
{
- key_code = map_to_wx_keysym( gdk_event );
+ 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 ( key_code )
{
-#ifdef DEBUG_KEY_EVENTS
- wxPrintf(_T("Char event: %ld\n"), key_code);
-#endif // DEBUG_KEY_EVENTS
+ wxLogTrace(TRACE_KEYS, _T("Char event: %ld"), key_code);
- // reuse the ame event object, just change its type and use the
+ // reuse the same event object, just change its type and use the
// translated keycode instead of the raw one
event.SetEventType(wxEVT_CHAR);
event.m_keyCode = key_code;
// "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;
-
- long key_code = map_to_unmodified_wx_keysym( gdk_event );
-
-#ifdef DEBUG_KEY_EVENTS
- wxPrintf(_T("Key release event: %d => %ld\n"), gdk_event->keyval, key_code);
-#endif // DEBUG_KEY_EVENTS
-
- /* sending unknown key events doesn't really make sense */
- if (key_code == 0) return FALSE;
-
- int x = 0;
- int y = 0;
- GdkModifierType state;
- if (gdk_event->window)
- gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
-
- 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->m_hasVMT)
+ return FALSE;
- if (win->GetEventHandler()->ProcessEvent( event ))
+ if (g_blockEventsOnDrag)
+ return FALSE;
+
+ wxKeyEvent event( wxEVT_KEY_UP );
+ 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;
}
// ============================================================================
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;
g_focusWindow = win;
#if 0
- wxPrintf( "OnSetFocus from " );
- if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
- wxPrintf( win->GetClassInfo()->GetClassName() );
- wxPrintf( ".\n" );
+ wxLogDebug( wxT("OnSetFocus from %s\n"), win->GetName().c_str() );
#endif
// notify the parent keeping track of focus for the kbd navigation
// "focus_out_event"
//-----------------------------------------------------------------------------
-static GtkWidget *gs_widgetLastFocus = NULL;
-
-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;
- // VZ: this is really weird but GTK+ seems to call us from inside
- // gtk_widget_grab_focus(), i.e. it first sends "focus_out" signal to
- // this widget and then "focus_in". This is totally unexpected and
- // completely breaks wxUniv code so ignore this dummy event (we can't
- // be losing focus if we're about to acquire it!)
- if ( widget == gs_widgetLastFocus )
- {
- gs_widgetLastFocus = NULL;
-
- return FALSE;
- }
+#if 0
+ wxLogDebug( wxT("OnKillFocus from %s"), win->GetName().c_str() );
+#endif
if ( !g_activeFrameLostFocus && g_activeFrame )
{
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();
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;
wxPoint pt = win->GetClientAreaOrigin();
event.m_x = x + pt.x;
// "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;
+ wxEventType command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(win->m_widget));
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 );
+ wxEventType command = GtkScrollWinTypeToWx(GET_SCROLL_TYPE(win->m_widget));
- 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;
}
}
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;
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 );
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 (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.
+ Update();
+
+ // Synthetize activate events.
if ( g_sendActivateEvent != -1 )
{
bool activate = g_sendActivateEvent != 0;
{
if (!GTK_WIDGET_HAS_FOCUS (m_wxwindow))
{
- // see comment in gtk_window_focus_out_callback()
- gs_widgetLastFocus = m_wxwindow;
gtk_widget_grab_focus (m_wxwindow);
}
}
}
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
{
// ?
}
}
-
-#if 0
- wxPrintf( "SetFocus finished in " );
- if (GetClassInfo() && GetClassInfo()->GetClassName())
- wxPrintf( GetClassInfo()->GetClassName() );
- wxPrintf( ".\n" );
-#endif
-
}
bool wxWindowGTK::AcceptsFocus() const
{
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)
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 (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
+}
+
+void wxWindowGTK::Update()
+{
+#ifdef __WXGTK20__
+ if (m_wxwindow && GTK_PIZZA(m_wxwindow)->bin_window)
+ gdk_window_process_updates( GTK_PIZZA(m_wxwindow)->bin_window, FALSE );
+#endif
+
+ if (!m_updateRegion.IsEmpty())
+ GtkSendPaintEvents();
+}
+
+void wxWindowGTK::GtkSendPaintEvents()
+{
+ if (!m_wxwindow)
+ {
+ m_clearRegion.Clear();
+ m_updateRegion.Clear();
+ return;
+ }
+
+ m_clipPaintRegion = TRUE;
+
+ // if (!m_clearRegion.IsEmpty()) // always send an erase event
+ {
+ wxWindowDC dc( (wxWindow*)this );
+ dc.SetClippingRegion( m_clearRegion );
+
+ wxEraseEvent erase_event( GetId(), &dc );
+ erase_event.SetEventObject( this );
+
+ if (!GetEventHandler()->ProcessEvent(erase_event))
+ {
+ if (!g_eraseGC)
+ {
+ g_eraseGC = gdk_gc_new( GTK_PIZZA(m_wxwindow)->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( GTK_PIZZA(m_wxwindow)->bin_window, g_eraseGC, 1,
+ upd.GetX(), upd.GetY(), upd.GetWidth(), upd.GetHeight() );
+ upd ++;
+ }
+ }
+ m_clearRegion.Clear();
+ }
+
+ 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.
+
+ GtkPizza *pizza = GTK_PIZZA(m_wxwindow);
+
+ 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 );
- 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.window = pizza->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 );
- }
- else
- {
- 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 );
+
+ 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()
if (m_wxwindow && m_wxwindow->window)
{
-// gdk_window_clear( m_wxwindow->window );
+ gdk_window_clear( m_wxwindow->window );
}
}
m_delayedBackgroundColour = TRUE;
}
+ if (window)
+ {
+ // We need the pixel value e.g. for background clearing.
+ m_backgroundColour.CalcPixel( gdk_window_get_colormap( window ) );
+ }
+
if ((m_wxwindow) &&
(m_wxwindow->window) &&
(m_backgroundColour != wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)))
/* 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() );
}
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;
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())
extern "C" void wxPopupMenuPositionCallback( GtkMenu *menu,
gint *x, gint *y,
+#ifdef __WXGTK20__
+ gboolean * WXUNUSED(whatever),
+#endif
gpointer WXUNUSED(user_data) )
{
// ensure that the menu appears entirely on screen
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);
+ m_updateRegion.Offset( dx, dy );
- pizza->xoffset -= dx;
- pizza->yoffset -= dy;
+ int cw = 0;
+ int ch = 0;
+ GetClientSize( &cw, &ch );
+ m_updateRegion.Intersect( 0, 0, cw, ch );
+ }
- GdkGC *m_scrollGC = gdk_gc_new( pizza->bin_window );
- gdk_gc_set_exposures( m_scrollGC, TRUE );
+ if (!m_clearRegion.IsEmpty())
+ {
+ m_clearRegion.Offset( dx, dy );
int cw = 0;
int ch = 0;
GetClientSize( &cw, &ch );
- int w = cw - abs(dx);
- int h = ch - abs(dy);
+ m_clearRegion.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;
-
- gdk_window_copy_area( pizza->bin_window, m_scrollGC, d_x, d_y,
- pizza->bin_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 );
- }
+ m_clipPaintRegion = TRUE;
+
+ gtk_pizza_scroll( GTK_PIZZA(m_wxwindow), -dx, -dy );
+
+ m_clipPaintRegion = FALSE;
+#else
+
+ gdk_window_scroll( GTK_PIZZA(m_wxwindow)->bin_window, dx, dy );
+
+ GTK_PIZZA(m_wxwindow)->xoffset += dx;
+ GTK_PIZZA(m_wxwindow)->yoffset += dy;
+
+#endif
- gdk_gc_unref( m_scrollGC );
- }
-*/
}
+
// 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 );
+}
+