// 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 );
return FALSE;
}
+// ============================================================================
+// the mouse events
+// ============================================================================
+
+// init wxMouseEvent with the info from gdk_event
+#define InitMouseEvent(win, 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); \
+\
+ wxPoint pt = win->GetClientAreaOrigin(); \
+ event.m_x = (wxCoord)gdk_event->x - pt.x; \
+ event.m_y = (wxCoord)gdk_event->y - pt.y; \
+ }
+
// ----------------------------------------------------------------------------
// mouse event processing helper
// ----------------------------------------------------------------------------
}
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);
+
+ // wxListBox actually get mouse events from the item
+
+ if (win->m_isListBox)
+ {
+ event.m_x += widget->allocation.x;
+ event.m_y += widget->allocation.y;
+ }
// Some control don't have their own X window and thus cannot get
// any events.
}
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);
+ // wxListBox actually get mouse events from the item
+
+ if (win->m_isListBox)
+ {
+ event.m_x += widget->allocation.x;
+ event.m_y += widget->allocation.y;
+ }
+
// Some control don't have their own X window and thus cannot get
// any events.
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);
}
}
#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 )
+ {
+ // 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
}
#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 );
gdk_window_get_pointer( widget->window, &x, &y, &state );
- InitMouseEvent(event, gdk_event);
-
- event.m_x = x;
- event.m_y = y;
+ 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 ))
{
event.m_middleDown = (state & GDK_BUTTON2_MASK);
event.m_rightDown = (state & GDK_BUTTON3_MASK);
- 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 ))
{
m_isStaticBox = FALSE;
m_isRadioButton = FALSE;
+ m_isListBox = FALSE;
m_isFrame = FALSE;
m_acceptsFocus = FALSE;
if (g_focusWindow == this)
g_focusWindow = NULL;
+ if (g_activeFrame == this)
+ g_activeFrame = NULL;
+
m_isBeingDeleted = TRUE;
m_hasVMT = FALSE;
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. */
wxTheApp->SetActive(activate, (wxWindow *)g_focusWindowLast);
}
+ 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;
dx = pizza->xoffset;
dy = pizza->yoffset;
}
-
+
if (x) (*x) = m_x - dx;
if (y) (*y) = m_y - dy;
}
{
wxCHECK_RET( (m_widget != NULL), wxT("invalid window") );
+#if 0
+ wxPrintf( "SetFocus from " );
+ if (GetClassInfo() && GetClassInfo()->GetClassName())
+ wxPrintf( GetClassInfo()->GetClassName() );
+ wxPrintf( ".\n" );
+#endif
+
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) )
{
// ?
}
}
+
+#if 0
+ wxPrintf( "SetFocus finished in " );
+ if (GetClassInfo() && GetClassInfo()->GetClassName())
+ wxPrintf( GetClassInfo()->GetClassName() );
+ wxPrintf( ".\n" );
+#endif
+
}
bool wxWindowGTK::AcceptsFocus() const
}
}
+// 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 )
+static void wxPopupMenuPositionCallback( GtkMenu *menu,
+ gint *x, gint *y,
+ 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_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)