#include "wx/caret.h"
#endif // wxUSE_CARET
+#if wxUSE_TEXTCTRL
+#include "wx/textctrl.h"
+#endif
+
#include "wx/menu.h"
#include "wx/statusbr.h"
#include "wx/intl.h"
// keeps its previous value
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 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
// OnIdle() call and it is reset to -1: this value means that we shouldn't
return (wxWindow *)NULL;
}
+// Returns toplevel grandparent of given window:
+static wxWindowGTK* wxGetTopLevelParent(wxWindowGTK *win)
+{
+ wxWindowGTK *p = win;
+ while (p && !p->IsTopLevel())
+ p = p->GetParent();
+ return p;
+}
+
+
static void draw_frame( GtkWidget *widget, wxWindowGTK *win )
{
// wxUniversal widgets draw the borders and scrollbars themselves
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;
- guint key_code = 0;
+ long key_code;
- switch (keysym)
+ switch ( keysym )
{
case GDK_Shift_L:
case GDK_Shift_R: key_code = WXK_SHIFT; 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)
+ // do we have the translation?
+ if ( event->length == 1 )
{
- guint upper = gdk_keyval_to_upper( (guint)keysym );
- keysym = (upper != 0 ? upper : keysym ); /* to be MSW compatible */
- key_code = (guint)keysym;
+ 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);
+ return key_code;
}
static long map_to_wx_keysym( GdkEventKey *event )
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)
+ if (event->length == 1)
+ {
+ key_code = (unsigned char)*event->string;
+ }
+ else if ((keysym & 0xFF) == keysym)
{
key_code = (guint)keysym;
}
- }
}
- return (key_code);
+ return key_code;
}
//-----------------------------------------------------------------------------
// "key_press_event" from any window
//-----------------------------------------------------------------------------
+// turn on to see the key event codes on the console
+#undef DEBUG_KEY_EVENTS
+
static gint gtk_window_key_press_callback( GtkWidget *widget,
GdkEventKey *gdk_event,
wxWindow *win )
if (g_blockEventsOnDrag) return FALSE;
-/*
- 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 );
-*/
-
int x = 0;
int y = 0;
GdkModifierType state;
- if (gdk_event->window) gdk_window_get_pointer(gdk_event->window, &x, &y, &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 );
+
+#ifdef DEBUG_KEY_EVENTS
+ wxPrintf(_T("Key press 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;
+ if (key_code == 0)
+ return FALSE;
wxKeyEvent event( wxEVT_KEY_DOWN );
event.SetTimestamp( gdk_event->time );
}
#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 );
+ if ( !ret )
+ {
+ key_code = map_to_wx_keysym( gdk_event );
- 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 );
+ if ( key_code )
+ {
+#ifdef DEBUG_KEY_EVENTS
+ wxPrintf(_T("Char event: %ld\n"), key_code);
+#endif // DEBUG_KEY_EVENTS
+
+ // reuse the ame 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;
+
+ ret = win->GetEventHandler()->ProcessEvent( event );
+ }
}
/* win is a control: tab can be propagated up */
- if ( (!ret) &&
+ 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() );
}
/* generate wxID_CANCEL if <esc> has been pressed (typically in dialogs) */
- if ( (!ret) &&
+ 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. */
-/*
+#if 0 // (GTK_MINOR_VERSION > 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)
{
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 );
+#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);
+ if (gdk_event->window)
+ gdk_window_get_pointer(gdk_event->window, &x, &y, &state);
wxKeyEvent event( wxEVT_KEY_UP );
event.SetTimestamp( gdk_event->time );
switch ( g_sendActivateEvent )
{
case -1:
- // we've got focus from outside, synthtize wxActivateEvent
+ // we've got focus from outside, synthetize wxActivateEvent
g_sendActivateEvent = 1;
break;
g_focusWindowLast =
g_focusWindow = win;
-/*
- printf( "OnSetFocus from " );
+#if 0
+ wxPrintf( "OnSetFocus from " );
if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
- printf( win->GetClassInfo()->GetClassName() );
- printf( " " );
- printf( WXSTRINGCAST win->GetLabel() );
- printf( ".\n" );
-*/
+ wxPrintf( win->GetClassInfo()->GetClassName() );
+ wxPrintf( ".\n" );
+#endif
- wxPanel *panel = wxDynamicCast(win->GetParent(), wxPanel);
- if (panel)
- {
- panel->SetLastFocus(win);
- }
+ // notify the parent keeping track of focus for the kbd navigation
+ // purposes that we got it
+ wxChildFocusEvent eventFocus(win);
+ (void)win->GetEventHandler()->ProcessEvent(eventFocus);
#ifdef HAVE_XIM
if (win->m_ic)
}
#endif // wxUSE_CARET
- if (win->IsTopLevel())
+ 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);
}
+ g_activeFrameLostFocus = FALSE;
+
wxFocusEvent event( wxEVT_SET_FOCUS, win->GetId() );
event.SetEventObject( win );
// "focus_out_event"
//-----------------------------------------------------------------------------
+static GtkWidget *gs_widgetLastFocus = NULL;
+
static gint gtk_window_focus_out_callback( GtkWidget *widget, GdkEvent *WXUNUSED(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 ( !g_activeFrameLostFocus && g_activeFrame )
+ {
+ wxASSERT_MSG( wxGetTopLevelParent(win) == g_activeFrame, wxT("unfocusing window that haven't gained focus properly") )
+ 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;
-/*
- printf( "OnKillFocus from " );
+#if 0
+ wxPrintf( "OnKillFocus from " );
if (win->GetClassInfo() && win->GetClassInfo()->GetClassName())
- printf( win->GetClassInfo()->GetClassName() );
- printf( ".\n" );
-*/
+ wxPrintf( win->GetClassInfo()->GetClassName() );
+ wxPrintf( ".\n" );
+#endif
#ifdef HAVE_XIM
if (win->m_ic)
}
#endif // wxUSE_CARET
- if (win->IsTopLevel())
- {
- wxActivateEvent event( wxEVT_ACTIVATE, FALSE, win->GetId() );
- event.SetEventObject( win );
-
- // ignore return value
- win->GetEventHandler()->ProcessEvent( event );
- }
-
wxFocusEvent event( wxEVT_KILL_FOCUS, win->GetId() );
event.SetEventObject( win );
if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
wxMouseEvent event( wxEVT_ENTER_WINDOW );
-#if (GTK_MINOR_VERSION > 0)
event.SetTimestamp( gdk_event->time );
-#endif
event.SetEventObject( win );
int x = 0;
if (!win->IsOwnGtkWindow( gdk_event->window )) return FALSE;
wxMouseEvent event( wxEVT_LEAVE_WINDOW );
-#if (GTK_MINOR_VERSION > 0)
event.SetTimestamp( gdk_event->time );
-#endif
event.SetEventObject( win );
int x = 0;
// GTK specific
m_widget = (GtkWidget *) NULL;
m_wxwindow = (GtkWidget *) NULL;
+ m_focusWidget = (GtkWidget *) NULL;
// position/size
m_x = 0;
m_noExpose = FALSE;
m_nativeSizeEvent = FALSE;
-
+
m_hasScrolling = FALSE;
m_isScrolling = FALSE;
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;
+
m_isBeingDeleted = TRUE;
m_hasVMT = FALSE;
void wxWindowGTK::PostCreation()
{
wxASSERT_MSG( (m_widget != NULL), wxT("invalid window") );
-
+
if (m_wxwindow)
{
if (!m_noExpose)
{
- /* these get reported to wxWindows -> wxPaintEvent */
+ // these get reported to wxWindows -> wxPaintEvent
gtk_pizza_set_external( GTK_PIZZA(m_wxwindow), TRUE );
}
}
-#if (GTK_MINOR_VERSION > 0)
- /* 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 );
gtk_signal_connect( GTK_OBJECT(m_widget), "draw",
GTK_SIGNAL_FUNC(gtk_window_own_draw_callback), (gpointer)this );
-#endif
}
- if (m_wxwindow && m_needParent)
- {
- gtk_signal_connect( GTK_OBJECT(m_wxwindow), "focus_in_event",
- GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
+ // focus handling
- gtk_signal_connect( GTK_OBJECT(m_wxwindow), "focus_out_event",
- GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
- }
- else
- {
- // For dialogs and frames, we are interested mainly in
- // m_widget's focus.
+ if (m_focusWidget == NULL)
+ m_focusWidget = m_widget;
- gtk_signal_connect( GTK_OBJECT(m_widget), "focus_in_event",
- GTK_SIGNAL_FUNC(gtk_window_focus_in_callback), (gpointer)this );
+#if 0
+ if (GetClassInfo() && GetClassInfo()->GetClassName())
+ wxPrintf( GetClassInfo()->GetClassName() );
+ wxPrintf( ".\n" );
+#endif
- gtk_signal_connect( GTK_OBJECT(m_widget), "focus_out_event",
- GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
- }
+ 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(m_focusWidget), "focus_out_event",
+ GTK_SIGNAL_FUNC(gtk_window_focus_out_callback), (gpointer)this );
+
+ // connect to the various key and mouse handlers
GtkWidget *connect_widget = GetConnectWidget();
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. */
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;
dx = pizza->xoffset;
dy = pizza->yoffset;
}
-
+
if (x) (*x) = m_x - dx;
if (y) (*y) = m_y - dy;
}
if (m_wxwindow)
{
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);
- return;
+ }
}
-
- if (m_widget)
+ else if (m_widget)
{
if (GTK_WIDGET_CAN_FOCUS(m_widget) && !GTK_WIDGET_HAS_FOCUS (m_widget) )
{