Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
menu-bar: transfer focus correctly on alt-F1
The background is in https://gitlab.gnome.org/GNOME/gtk/issues/85 . One of
the conclusions, in https://gitlab.gnome.org/GNOME/gtk/issues/85#note_264804
, is that mate-panel needs to properly transfer focus on alt-F1 keyboard
shortcut.

It used to work only by luck before, only because gtk used to
deactivate itself during a keyboard grab. But as discussed in
https://gitlab.gnome.org/GNOME/gtk/issues/85 that behavior poses
accessibility feedback issues, is not coherent, and keyboard grab
feedback will not be available in wayland anyway. Thus @ebassi saying
in https://gitlab.gnome.org/GNOME/gtk/issues/85#note_264804 that not
transferring focus properly is the actual bug.

This change explictly switches to the menu bar after saving which X Window
had the focus, and on menu bar deactivation restores focus to that X Window.

Fixes #851

This a backport of commit f0f4c5e.
  • Loading branch information
sthibaul authored and cwendling committed Oct 17, 2018
1 parent d9dcf9c commit cdaf08f
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 0 deletions.
22 changes: 22 additions & 0 deletions mate-panel/panel-menu-bar.c
Expand Up @@ -28,6 +28,9 @@

#include "panel-menu-bar.h"

#include <X11/Xlib.h>
#include <gdk/gdkx.h>

#include <string.h>
#include <glib/gi18n.h>

Expand Down Expand Up @@ -65,6 +68,8 @@ struct _PanelMenuBarPrivate {
GSettings* settings;

PanelOrientation orientation;

Window interrupted_window;
};

enum {
Expand All @@ -83,6 +88,15 @@ static gboolean panel_menu_bar_reinit_tooltip(GtkWidget* widget, PanelMenuBar* m
return FALSE;
}

static gboolean panel_menu_bar_deactivate (GtkWidget* widget, PanelMenuBar* menubar)
{
GtkWidget *toplevel = gtk_widget_get_toplevel (widget);
panel_util_set_current_active_window (toplevel, menubar->priv->interrupted_window);
menubar->priv->interrupted_window = None;

return FALSE;
}

static gboolean panel_menu_bar_hide_tooltip_and_focus(GtkWidget* widget, PanelMenuBar* menubar)
{
/* remove focus that would be drawn on the currently focused child of
Expand All @@ -108,6 +122,7 @@ static void panel_menu_bar_setup_tooltip(PanelMenuBar* menubar)

/* Reset tooltip when the menu bar is not used */
g_signal_connect(GTK_MENU_SHELL (menubar), "deactivate", G_CALLBACK (panel_menu_bar_reinit_tooltip), menubar);
g_signal_connect(GTK_MENU_SHELL (menubar), "deactivate", G_CALLBACK (panel_menu_bar_deactivate), menubar);
}

static void panel_menu_bar_update_visibility (GSettings* settings, gchar* key, PanelMenuBar* menubar)
Expand Down Expand Up @@ -411,11 +426,18 @@ void panel_menu_bar_popup_menu(PanelMenuBar* menubar, guint32 activate_time)
{
GtkMenu* menu;
GtkMenuShell* menu_shell;
GtkWidget* toplevel;
GdkWindow* window;

g_return_if_fail(PANEL_IS_MENU_BAR(menubar));

menu = GTK_MENU(menubar->priv->applications_menu);

toplevel = gtk_widget_get_toplevel (GTK_WIDGET (menubar));
menubar->priv->interrupted_window = panel_util_get_current_active_window (toplevel);
window = gtk_widget_get_window (toplevel);
panel_util_set_current_active_window (toplevel, GDK_WINDOW_XID(window));

/*
* We need to call _gtk_menu_shell_activate() here as is done in
* window_key_press_handler in gtkmenubar.c which pops up menu
Expand Down
22 changes: 22 additions & 0 deletions mate-panel/panel-menu-button.c
Expand Up @@ -26,9 +26,12 @@

#include "panel-menu-button.h"

#include <X11/Xlib.h>

#include <string.h>
#include <glib/gi18n.h>
#include <gio/gio.h>
#include <gdk/gdkx.h>

#include <matemenu-tree.h>

Expand Down Expand Up @@ -92,6 +95,8 @@ struct _PanelMenuButtonPrivate {
char *custom_icon;
char *tooltip;

Window interrupted_window;

MenuPathRoot path_root;
guint use_menu_path : 1;
guint use_custom_icon : 1;
Expand Down Expand Up @@ -424,12 +429,23 @@ panel_menu_button_recreate_menu (PanelMenuButton *button)
button->priv->menu = NULL;
}

static gboolean panel_menu_button_menu_deactivate (GtkWidget* widget, PanelMenuButton* button)
{
GtkWidget *toplevel = gtk_widget_get_toplevel(widget);
panel_util_set_current_active_window(toplevel, button->priv->interrupted_window);
button->priv->interrupted_window = None;

return FALSE;
}

void
panel_menu_button_popup_menu (PanelMenuButton *button,
guint n_button,
guint32 activate_time)
{
GdkScreen *screen;
GtkWidget *toplevel;
GdkWindow *window;

g_return_if_fail (PANEL_IS_MENU_BUTTON (button));

Expand All @@ -449,6 +465,12 @@ panel_menu_button_popup_menu (PanelMenuButton *button,
GTK_WIDGET (button),
n_button,
activate_time);

g_signal_connect(GTK_MENU_SHELL (button->priv->menu), "deactivate", G_CALLBACK (panel_menu_button_menu_deactivate), button);
toplevel = gtk_widget_get_toplevel(GTK_WIDGET(button->priv->toplevel));
button->priv->interrupted_window = panel_util_get_current_active_window (toplevel);
window = gtk_widget_get_window (toplevel);
panel_util_set_current_active_window (toplevel, GDK_WINDOW_XID(window));
}

static void
Expand Down
92 changes: 92 additions & 0 deletions mate-panel/panel-util.c
Expand Up @@ -23,11 +23,15 @@
#include <unistd.h>
#include <sys/types.h>

#include <X11/Xlib.h>
#include <X11/Xatom.h>

#include <glib.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
#include <gio/gio.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gdk/gdkx.h>

#define MATE_DESKTOP_USE_UNSTABLE_API
#include <libmate-desktop/mate-desktop-utils.h>
Expand All @@ -47,6 +51,8 @@
#include "panel-icon-names.h"
#include "panel-lockdown.h"

static Atom _net_active_window = None;

char *
panel_util_make_exec_uri_for_desktop (const char *exec)
{
Expand Down Expand Up @@ -1239,3 +1245,89 @@ panel_util_get_file_optional_homedir (const char *location)

return file;
}

static void panel_menu_bar_get_net_active_window(Display *xdisplay)
{
if (_net_active_window == None)
_net_active_window = XInternAtom (xdisplay,
"_NET_ACTIVE_WINDOW",
False);
}

Window panel_util_get_current_active_window (GtkWidget *toplevel)
{
GdkScreen *screen;
GdkDisplay *display;
GdkWindow *root;
Display *xdisplay;
Window xroot;

Window res = None;

Atom return_type;
int return_format;
unsigned long n;
unsigned long bytes;
unsigned char *prop = NULL;

screen = gtk_window_get_screen (GTK_WINDOW(toplevel));
display = gdk_screen_get_display (screen);
root = gdk_screen_get_root_window (screen);

xdisplay = GDK_DISPLAY_XDISPLAY (display);
xroot = GDK_WINDOW_XID (root);

panel_menu_bar_get_net_active_window (xdisplay);
if (_net_active_window != None
&& XGetWindowProperty (xdisplay, xroot, _net_active_window, 0, 1,
False, XA_WINDOW, &return_type, &return_format,
&n, &bytes, &prop) == Success)
{
if ((return_type == XA_WINDOW) && (return_format == 32) &&
(n == 1) && (prop)) {
res = *(Window *)prop;
}

if (prop)
XFree (prop);

}
return res;
}

void panel_util_set_current_active_window (GtkWidget *toplevel, Window window)
{
GdkScreen *screen;
GdkDisplay *display;
GdkWindow *root;
Display *xdisplay;
Window xroot;
XEvent xev;

screen = gtk_window_get_screen (GTK_WINDOW(toplevel));
display = gdk_screen_get_display (screen);
root = gdk_screen_get_root_window (screen);

xdisplay = GDK_DISPLAY_XDISPLAY (display);
xroot = GDK_WINDOW_XID (root);

panel_menu_bar_get_net_active_window (xdisplay);
if (_net_active_window == None)
return;

xev.xclient.type = ClientMessage;
xev.xclient.serial = 0;
xev.xclient.send_event = True;
xev.xclient.window = window;
xev.xclient.message_type = _net_active_window;
xev.xclient.format = 32;
xev.xclient.data.l[0] = 2; /* requestor type; we're not an app */
xev.xclient.data.l[1] = CurrentTime;
xev.xclient.data.l[2] = None; /* our currently active window */
xev.xclient.data.l[3] = 0;
xev.xclient.data.l[4] = 0;

XSendEvent (xdisplay, xroot, False,
SubstructureRedirectMask | SubstructureNotifyMask,
&xev);
}
5 changes: 5 additions & 0 deletions mate-panel/panel-util.h
Expand Up @@ -3,6 +3,7 @@

#include <gio/gio.h>
#include <gtk/gtk.h>
#include <X11/Xlib.h>

#ifdef __cplusplus
extern "C" {
Expand Down Expand Up @@ -66,6 +67,10 @@ void panel_util_set_tooltip_text (GtkWidget *widget,

GFile *panel_util_get_file_optional_homedir (const char *location);

Window panel_util_get_current_active_window (GtkWidget *toplevel);

void panel_util_set_current_active_window (GtkWidget *toplevel,
Window window);
#ifdef __cplusplus
}
#endif
Expand Down

0 comments on commit cdaf08f

Please sign in to comment.