[Libreoffice-commits] core.git: 3 commits - include/vcl vcl/inc vcl/source vcl/unx
Caolán McNamara
caolanm at redhat.com
Wed May 11 11:09:38 UTC 2016
include/vcl/taskpanelist.hxx | 1
vcl/inc/salmenu.hxx | 3
vcl/inc/unx/gtk/gloactiongroup.h | 2
vcl/inc/unx/gtk/gtkframe.hxx | 1
vcl/inc/unx/gtk/gtksalmenu.hxx | 6 +
vcl/source/window/menu.cxx | 21 ++++-
vcl/source/window/menubarwindow.cxx | 9 ++
vcl/source/window/taskpanelist.cxx | 7 +
vcl/unx/gtk/gloactiongroup.cxx | 6 -
vcl/unx/gtk/gtksalframe.cxx | 2
vcl/unx/gtk/gtksalmenu.cxx | 132 ++++++++++++++++++++++++++++--------
vcl/unx/gtk3/gtk3gtkframe.cxx | 2
12 files changed, 150 insertions(+), 42 deletions(-)
New commits:
commit 43896bcbea44aa92ee80ee7ba6cb39f5f514c751
Author: Caolán McNamara <caolanm at redhat.com>
Date: Tue May 10 16:21:17 2016 +0100
Resolves: tdf#99709 native gtk3 menubar isn't accessible with F6
Change-Id: If772231e824e71c327103e147e3eef69e82339f6
diff --git a/include/vcl/taskpanelist.hxx b/include/vcl/taskpanelist.hxx
index fd04365..e1b908d 100644
--- a/include/vcl/taskpanelist.hxx
+++ b/include/vcl/taskpanelist.hxx
@@ -41,6 +41,7 @@ public:
void AddWindow( vcl::Window *pWindow );
void RemoveWindow( vcl::Window *pWindow );
bool HandleKeyEvent(const KeyEvent& rKeyEvent);
+ static bool IsCycleKey(const vcl::KeyCode& rKeyCode);
};
#endif
diff --git a/vcl/inc/salmenu.hxx b/vcl/inc/salmenu.hxx
index 6457d9a..a792356 100644
--- a/vcl/inc/salmenu.hxx
+++ b/vcl/inc/salmenu.hxx
@@ -81,6 +81,7 @@ public:
virtual void Update() {}
virtual bool CanGetFocus() const { return false; }
+ virtual bool TakeFocus() { return false; }
// TODO: implement show/hide for the Win/Mac VCL native backends
virtual void ShowItem( unsigned nPos, bool bShow ) { EnableItem( nPos, bShow ); }
diff --git a/vcl/inc/unx/gtk/gtkframe.hxx b/vcl/inc/unx/gtk/gtkframe.hxx
index 38b6c1b..7c0803b 100644
--- a/vcl/inc/unx/gtk/gtkframe.hxx
+++ b/vcl/inc/unx/gtk/gtkframe.hxx
@@ -370,6 +370,7 @@ public:
static GdkDisplay* getGdkDisplay();
GtkWidget* getWindow() const { return m_pWindow; }
GtkFixed* getFixedContainer() const { return m_pFixedContainer; }
+ GtkEventBox* getEventBox() const { return m_pEventBox; }
GtkWidget* getMouseEventWidget() const;
#if GTK_CHECK_VERSION(3,0,0)
GtkGrid* getTopLevelGridWidget() const { return m_pTopLevelGrid; }
diff --git a/vcl/inc/unx/gtk/gtksalmenu.hxx b/vcl/inc/unx/gtk/gtksalmenu.hxx
index 966b7f8..8469659 100644
--- a/vcl/inc/unx/gtk/gtksalmenu.hxx
+++ b/vcl/inc/unx/gtk/gtksalmenu.hxx
@@ -47,6 +47,8 @@ private:
bool mbMenuBar;
bool mbNeedsUpdate;
+ bool mbReturnFocusToDocument;
+ GtkWidget* mpMenuBarContainerWidget;
GtkWidget* mpMenuBarWidget;
GtkWidget* mpCloseButton;
Menu* mpVCLMenu;
@@ -115,9 +117,13 @@ public:
void CreateMenuBarWidget();
void DestroyMenuBarWidget();
+ gboolean SignalKey(GdkEventKey* pEvent);
+ void ReturnFocus();
virtual bool ShowNativePopupMenu(FloatingWindow * pWin, const Rectangle& rRect, FloatWinPopupFlags nFlags) override;
virtual void ShowCloseButton(bool bShow) override;
+ virtual bool CanGetFocus() const override;
+ virtual bool TakeFocus() override;
};
class GtkSalMenuItem : public SalMenuItem
diff --git a/vcl/source/window/menu.cxx b/vcl/source/window/menu.cxx
index 810525b..096faee 100644
--- a/vcl/source/window/menu.cxx
+++ b/vcl/source/window/menu.cxx
@@ -2597,13 +2597,24 @@ void MenuBar::ImplDestroy( MenuBar* pMenu, bool bDelete )
bool MenuBar::ImplHandleKeyEvent( const KeyEvent& rKEvent )
{
- bool bDone = false;
+ // No keyboard processing when our menubar is invisible
+ if (!IsDisplayable())
+ return false;
- // No keyboard processing when system handles the menu or our menubar is invisible
- if( !IsDisplayable() ||
- ( ImplGetSalMenu() && ImplGetSalMenu()->VisibleMenuBar() ) )
- return bDone;
+ // No keyboard processing when system handles the menu.
+ SalMenu *pNativeMenu = ImplGetSalMenu();
+ if (pNativeMenu && pNativeMenu->VisibleMenuBar())
+ {
+ // Except when the event is the F6 cycle pane event and we can put our
+ // focus into it (i.e. the gtk3 menubar case but not the mac/unity case
+ // where its not part of the application window)
+ if (!TaskPaneList::IsCycleKey(rKEvent.GetKeyCode()))
+ return false;
+ if (!pNativeMenu->CanGetFocus())
+ return false;
+ }
+ bool bDone = false;
// check for enabled, if this method is called from another window...
vcl::Window* pWin = ImplGetWindow();
if (pWin && pWin->IsEnabled() && pWin->IsInputEnabled() && !pWin->IsInModalMode())
diff --git a/vcl/source/window/menubarwindow.cxx b/vcl/source/window/menubarwindow.cxx
index ac84120..16d3af5 100644
--- a/vcl/source/window/menubarwindow.cxx
+++ b/vcl/source/window/menubarwindow.cxx
@@ -1078,6 +1078,10 @@ void MenuBarWindow::LoseFocus()
void MenuBarWindow::GetFocus()
{
+ SalMenu *pNativeMenu = pMenu ? pMenu->ImplGetSalMenu() : nullptr;
+ if (pNativeMenu && pNativeMenu->TakeFocus())
+ return;
+
if ( nHighlightedItem == ITEMPOS_INVALID )
{
mbAutoPopup = false; // do not open menu when activated by focus handling like taskpane cycling
diff --git a/vcl/source/window/taskpanelist.cxx b/vcl/source/window/taskpanelist.cxx
index 3b9a3d9..4e995a5 100644
--- a/vcl/source/window/taskpanelist.cxx
+++ b/vcl/source/window/taskpanelist.cxx
@@ -146,6 +146,11 @@ bool TaskPaneList::IsInList( vcl::Window *pWindow )
return false;
}
+bool TaskPaneList::IsCycleKey(const vcl::KeyCode& rKeyCode)
+{
+ return rKeyCode.GetCode() == KEY_F6 && !rKeyCode.IsMod2(); // F6
+}
+
bool TaskPaneList::HandleKeyEvent(const KeyEvent& rKeyEvent)
{
@@ -160,7 +165,7 @@ bool TaskPaneList::HandleKeyEvent(const KeyEvent& rKeyEvent)
// and the shortcut conflicts with tab-control shortcut ), it is no more supported
vcl::KeyCode aKeyCode = rKeyEvent.GetKeyCode();
bool bForward = !aKeyCode.IsShift();
- if( aKeyCode.GetCode() == KEY_F6 && ! aKeyCode.IsMod2() ) // F6
+ if (TaskPaneList::IsCycleKey(aKeyCode))
{
bool bSplitterOnly = aKeyCode.IsMod1() && aKeyCode.IsShift();
diff --git a/vcl/unx/gtk/gtksalmenu.cxx b/vcl/unx/gtk/gtksalmenu.cxx
index 3f1a7fb..4145afa 100644
--- a/vcl/unx/gtk/gtksalmenu.cxx
+++ b/vcl/unx/gtk/gtksalmenu.cxx
@@ -417,6 +417,8 @@ bool GtkSalMenu::ShowNativePopupMenu(FloatingWindow* pWin, const Rectangle& rRec
GtkSalMenu::GtkSalMenu( bool bMenuBar ) :
mbMenuBar( bMenuBar ),
mbNeedsUpdate( false ),
+ mbReturnFocusToDocument( false ),
+ mpMenuBarContainerWidget( nullptr ),
mpMenuBarWidget( nullptr ),
mpCloseButton( nullptr ),
mpVCLMenu( nullptr ),
@@ -576,63 +578,139 @@ void GtkSalMenu::ShowCloseButton(bool bShow)
gtk_widget_set_valign(mpCloseButton, GTK_ALIGN_CENTER);
gtk_container_add(GTK_CONTAINER(mpCloseButton), image);
- gtk_grid_attach(GTK_GRID(mpMenuBarWidget), GTK_WIDGET(mpCloseButton), 1, 0, 1, 1);
+ gtk_grid_attach(GTK_GRID(mpMenuBarContainerWidget), GTK_WIDGET(mpCloseButton), 1, 0, 1, 1);
gtk_widget_show_all(mpCloseButton);
#else
(void)bShow;
- (void)mpMenuBarWidget;
+ (void)mpMenuBarContainerWidget;
(void)mpCloseButton;
#endif
}
+//Typically when the menubar is deactivated we want the focus to return
+//to where it came from. If the menubar was activated because of F6
+//moving focus into the associated VCL menubar then on pressing ESC
+//or any other normal reason for deactivation we want focus to return
+//to the document, defininitely not still stuck in the associated
+//VCL menubar. But if F6 is pressed while the menubar is activated
+//we want to pass that F6 back to the VCL menubar which will move
+//focus to the next pane by itself.
+void GtkSalMenu::ReturnFocus()
+{
+ if (!mbReturnFocusToDocument)
+ gtk_widget_grab_focus(GTK_WIDGET(mpFrame->getEventBox()));
+ else
+ mpFrame->GetWindow()->GrabFocusToDocument();
+ mbReturnFocusToDocument = false;
+}
+
+gboolean GtkSalMenu::SignalKey(GdkEventKey* pEvent)
+{
+ if (pEvent->keyval == GDK_F6)
+ {
+ mbReturnFocusToDocument = false;
+ gtk_menu_shell_cancel(GTK_MENU_SHELL(mpMenuBarWidget));
+ //because we return false here, the keypress will continue
+ //to propogate and in the case that vcl focus is in
+ //the vcl menubar then that will also process F6 and move
+ //to the next pane
+ }
+ return false;
+}
+
+//The GtkSalMenu is owner by a Vcl Menu/MenuBar. In the menubar
+//case the vcl menubar is present and "visible", but with a 0 height
+//so it not apparent. Normally it acts as though it is not there when
+//a Native menubar is active. If we return true here, then for keyboard
+//activation and traversal with F6 through panes then the vcl menubar
+//acts as though it *is* present and we translate its take focus and F6
+//traversal key events into the gtk menubar equivalents.
+bool GtkSalMenu::CanGetFocus() const
+{
+ return mpMenuBarWidget != nullptr;
+}
+
+bool GtkSalMenu::TakeFocus()
+{
+ if (!mpMenuBarWidget)
+ return false;
+
+ //Send a keyboard event to the gtk menubar to let it know it has been
+ //activated via the keyboard. Doesn't do anything except cause the gtk
+ //menubar "keyboard_mode" member to get set to true, so typically mnemonics
+ //are shown which will serve as indication that the menubar has focus
+ //(given that we wnt to show it with no menus popped down)
+ GdkEvent *event = gdk_event_new(GDK_KEY_PRESS);
+ event->key.window = GDK_WINDOW(g_object_ref(gtk_widget_get_window(mpMenuBarWidget)));
+ event->key.send_event = TRUE;
+ event->key.time = gtk_get_current_event_time();
+ event->key.state = 0;
+ event->key.keyval = 0;
+ event->key.length = 0;
+ event->key.string = nullptr;
+ event->key.hardware_keycode = 0;
+ event->key.group = 0;
+ event->key.is_modifier = false;
+ gtk_widget_event(mpMenuBarWidget, event);
+ gdk_event_free(event);
+
+ //this pairing results in a menubar with keyboard focus with no menus
+ //auto-popped down
+ gtk_menu_shell_select_first(GTK_MENU_SHELL(mpMenuBarWidget), false);
+ gtk_menu_shell_deselect(GTK_MENU_SHELL(mpMenuBarWidget));
+ mbReturnFocusToDocument = true;
+ return true;
+}
+
#if GTK_CHECK_VERSION(3,0,0)
-//hack-around https://bugzilla.gnome.org/show_bug.cgi?id=762756
-static void ReturnFocus(GtkMenuShell *, gpointer pWidget)
+
+static void MenuBarReturnFocus(GtkMenuShell*, gpointer menu)
{
- GtkWidget* pTopLevel = static_cast<GtkWidget*>(pWidget);
- GdkWindow *window = gtk_widget_get_window(pTopLevel);
- GdkEvent *fevent = gdk_event_new(GDK_FOCUS_CHANGE);
+ GtkSalMenu* pMenu = static_cast<GtkSalMenu*>(menu);
+ pMenu->ReturnFocus();
+}
- fevent->focus_change.type = GDK_FOCUS_CHANGE;
- fevent->focus_change.window = GDK_WINDOW(g_object_ref(window));
- fevent->focus_change.in = static_cast<gint16>(TRUE);
- gtk_widget_send_focus_change(pTopLevel, fevent);
- gdk_event_free(fevent);
+static gboolean MenuBarSignalKey(GtkWidget*, GdkEventKey* pEvent, gpointer menu)
+{
+ GtkSalMenu* pMenu = static_cast<GtkSalMenu*>(menu);
+ return pMenu->SignalKey(pEvent);
}
+
#endif
void GtkSalMenu::CreateMenuBarWidget()
{
#if GTK_CHECK_VERSION(3,0,0)
GtkGrid* pGrid = mpFrame->getTopLevelGridWidget();
- mpMenuBarWidget = gtk_grid_new();
+ mpMenuBarContainerWidget = gtk_grid_new();
- gtk_widget_set_hexpand(GTK_WIDGET(mpMenuBarWidget), true);
+ gtk_widget_set_hexpand(GTK_WIDGET(mpMenuBarContainerWidget), true);
gtk_grid_insert_row(pGrid, 0);
- gtk_grid_attach(pGrid, mpMenuBarWidget, 0, 0, 1, 1);
+ gtk_grid_attach(pGrid, mpMenuBarContainerWidget, 0, 0, 1, 1);
- GtkWidget *pMenuBarWidget = gtk_menu_bar_new_from_model(mpMenuModel);
- gtk_widget_insert_action_group(pMenuBarWidget, "win", mpActionGroup);
- gtk_widget_set_hexpand(GTK_WIDGET(pMenuBarWidget), true);
- gtk_grid_attach(GTK_GRID(mpMenuBarWidget), pMenuBarWidget, 0, 0, 1, 1);
- g_signal_connect(G_OBJECT(pMenuBarWidget), "deactivate", G_CALLBACK(ReturnFocus), mpFrame->getWindow());
+ mpMenuBarWidget = gtk_menu_bar_new_from_model(mpMenuModel);
+ gtk_widget_insert_action_group(mpMenuBarWidget, "win", mpActionGroup);
+ gtk_widget_set_hexpand(GTK_WIDGET(mpMenuBarWidget), true);
+ gtk_grid_attach(GTK_GRID(mpMenuBarContainerWidget), mpMenuBarWidget, 0, 0, 1, 1);
+ g_signal_connect(G_OBJECT(mpMenuBarWidget), "deactivate", G_CALLBACK(MenuBarReturnFocus), this);
+ g_signal_connect(G_OBJECT(mpMenuBarWidget), "key-press-event", G_CALLBACK(MenuBarSignalKey), this);
- gtk_widget_show_all(mpMenuBarWidget);
+ gtk_widget_show_all(mpMenuBarContainerWidget);
#else
- (void)mpMenuBarWidget;
+ (void)mpMenuBarContainerWidget;
#endif
}
void GtkSalMenu::DestroyMenuBarWidget()
{
#if GTK_CHECK_VERSION(3,0,0)
- if (mpMenuBarWidget)
+ if (mpMenuBarContainerWidget)
{
- gtk_widget_destroy(mpMenuBarWidget);
- mpMenuBarWidget = nullptr;
+ gtk_widget_destroy(mpMenuBarContainerWidget);
+ mpMenuBarContainerWidget = nullptr;
}
#else
- (void)mpMenuBarWidget;
+ (void)mpMenuBarContainerWidget;
#endif
}
commit fac124afd23b23c648900d14c41881dc246f5e0e
Author: Caolán McNamara <caolanm at redhat.com>
Date: Tue May 10 14:56:54 2016 +0100
make this cunning more explicit
Change-Id: Ie461646e076da4aa4b144c68e0e08c0424474ad8
diff --git a/vcl/inc/salmenu.hxx b/vcl/inc/salmenu.hxx
index 0145547..6457d9a 100644
--- a/vcl/inc/salmenu.hxx
+++ b/vcl/inc/salmenu.hxx
@@ -80,6 +80,8 @@ public:
virtual void RemoveMenuBarButton( sal_uInt16 nId );
virtual void Update() {}
+ virtual bool CanGetFocus() const { return false; }
+
// TODO: implement show/hide for the Win/Mac VCL native backends
virtual void ShowItem( unsigned nPos, bool bShow ) { EnableItem( nPos, bShow ); }
diff --git a/vcl/source/window/menubarwindow.cxx b/vcl/source/window/menubarwindow.cxx
index 4b72e0b..ac84120 100644
--- a/vcl/source/window/menubarwindow.cxx
+++ b/vcl/source/window/menubarwindow.cxx
@@ -1180,10 +1180,13 @@ bool MenuBarWindow::HandleMenuButtonEvent( sal_uInt16 i_nButtonId )
bool MenuBarWindow::CanGetFocus() const
{
- /* #i83908# do not use the menubar if it is native and invisible
+ /* #i83908# do not use the menubar if it is native or invisible
this relies on MenuBar::ImplCreate setting the height of the menubar
to 0 in this case
*/
+ SalMenu *pNativeMenu = pMenu ? pMenu->ImplGetSalMenu() : nullptr;
+ if (pNativeMenu && pNativeMenu->VisibleMenuBar())
+ return pNativeMenu->CanGetFocus();
return GetSizePixel().Height() > 0;
}
commit ab30f3367686f37c18a5c11e3621e29e37b11409
Author: Caolán McNamara <caolanm at redhat.com>
Date: Wed May 11 10:41:31 2016 +0100
gtk[3]: the frame argument is now unused
Change-Id: Ib9989545495a8682d7cac97c02ab73d7c622aecf
diff --git a/vcl/inc/unx/gtk/gloactiongroup.h b/vcl/inc/unx/gtk/gloactiongroup.h
index 4fbab01..97d9db8 100644
--- a/vcl/inc/unx/gtk/gloactiongroup.h
+++ b/vcl/inc/unx/gtk/gloactiongroup.h
@@ -42,7 +42,7 @@ struct GLOActionGroupClass
GType g_lo_action_group_get_type (void) G_GNUC_CONST;
-GLOActionGroup * g_lo_action_group_new (gpointer frame);
+GLOActionGroup * g_lo_action_group_new (void);
void g_lo_action_group_set_top_menu (GLOActionGroup *group,
gpointer top_menu);
diff --git a/vcl/unx/gtk/gloactiongroup.cxx b/vcl/unx/gtk/gloactiongroup.cxx
index 00b0ccc..fe946f0 100644
--- a/vcl/unx/gtk/gloactiongroup.cxx
+++ b/vcl/unx/gtk/gloactiongroup.cxx
@@ -100,7 +100,6 @@ g_lo_action_class_init (GLOActionClass *klass)
struct GLOActionGroupPrivate
{
GHashTable *table; /* string -> GLOAction */
- GtkSalFrame *frame; /* Frame to which GActionGroup is associated. */
};
static void g_lo_action_group_iface_init (GActionGroupInterface *);
@@ -318,7 +317,6 @@ g_lo_action_group_init (GLOActionGroup *group)
GLOActionGroupPrivate);
group->priv->table = g_hash_table_new_full (g_str_hash, g_str_equal,
g_free, g_object_unref);
- group->priv->frame = nullptr;
}
static void
@@ -341,11 +339,9 @@ g_lo_action_group_iface_init (GActionGroupInterface *iface)
}
GLOActionGroup *
-g_lo_action_group_new (gpointer frame)
+g_lo_action_group_new()
{
GLOActionGroup* group = G_LO_ACTION_GROUP (g_object_new (G_TYPE_LO_ACTION_GROUP, nullptr));
- group->priv->frame = static_cast< GtkSalFrame* > (frame);
-
return group;
}
diff --git a/vcl/unx/gtk/gtksalframe.cxx b/vcl/unx/gtk/gtksalframe.cxx
index 7e118f0..83e8836 100644
--- a/vcl/unx/gtk/gtksalframe.cxx
+++ b/vcl/unx/gtk/gtksalframe.cxx
@@ -583,7 +583,7 @@ gboolean ensure_dbus_setup( gpointer data )
// Create menu model and action group attached to this frame.
GMenuModel* pMenuModel = G_MENU_MODEL( g_lo_menu_new() );
- GActionGroup* pActionGroup = reinterpret_cast<GActionGroup*>(g_lo_action_group_new( static_cast< gpointer >( pSalFrame ) ));
+ GActionGroup* pActionGroup = reinterpret_cast<GActionGroup*>(g_lo_action_group_new());
// Generate menu paths.
::Window windowId = GDK_WINDOW_XID( gdkWindow );
diff --git a/vcl/unx/gtk/gtksalmenu.cxx b/vcl/unx/gtk/gtksalmenu.cxx
index b6deecf..3f1a7fb 100644
--- a/vcl/unx/gtk/gtksalmenu.cxx
+++ b/vcl/unx/gtk/gtksalmenu.cxx
@@ -368,7 +368,7 @@ bool GtkSalMenu::ShowNativePopupMenu(FloatingWindow* pWin, const Rectangle& rRec
Point aPos = FloatingWindow::ImplCalcPos(pWin, rRect, nFlags, nArrangeIndex);
aPos = FloatingWindow::ImplConvertToAbsPos(xParent, aPos);
- GLOActionGroup* pActionGroup = g_lo_action_group_new(static_cast<gpointer>(mpFrame));
+ GLOActionGroup* pActionGroup = g_lo_action_group_new();
mpActionGroup = G_ACTION_GROUP(pActionGroup);
mpMenuModel = G_MENU_MODEL(g_lo_menu_new());
// Generate the main menu structure, populates mpMenuModel
diff --git a/vcl/unx/gtk3/gtk3gtkframe.cxx b/vcl/unx/gtk3/gtk3gtkframe.cxx
index ada90e7..36754f9 100644
--- a/vcl/unx/gtk3/gtk3gtkframe.cxx
+++ b/vcl/unx/gtk3/gtk3gtkframe.cxx
@@ -587,7 +587,7 @@ gboolean ensure_dbus_setup( gpointer data )
// Create menu model and action group attached to this frame.
GMenuModel* pMenuModel = G_MENU_MODEL( g_lo_menu_new() );
- GActionGroup* pActionGroup = reinterpret_cast<GActionGroup*>(g_lo_action_group_new( static_cast< gpointer >( pSalFrame ) ));
+ GActionGroup* pActionGroup = reinterpret_cast<GActionGroup*>(g_lo_action_group_new());
// Generate menu paths.
sal_uIntPtr windowId = pSalFrame->GetNativeWindowHandle(pSalFrame->getWindow());
More information about the Libreoffice-commits
mailing list