can be caused by *<margin>* settings or exclusive layer-shell clients
such as panels.
+*<windowRules><windowRule wantAbsorbedModifierReleaseEvents="">* [yes|no|default]
+ *wantAbsorbedModifierReleaseEvents* allows clients to receive modifier
+ release events even if they are part of keybinds. Most clients should
+ not receive these, but some (for example blender) need it in some
+ situations.
+
+```
+<windowRules>
+ <windowRule identifier="blender" wantAbsorbedModifierReleaseEvents="yes"/>
+</windowRules>
+```
+
## MENU
```
set_property(content, ¤t_window_rule->ignore_configure_request);
} else if (!strcasecmp(nodename, "fixedPosition")) {
set_property(content, ¤t_window_rule->fixed_position);
+ } else if (!strcasecmp(nodename, "wantAbsorbedModifierReleaseEvents")) {
+ set_property(content, ¤t_window_rule->want_absorbed_modifier_release_events);
/* Actions */
} else if (!strcmp(nodename, "name.action")) {
#include "osd.h"
#include "regions.h"
#include "view.h"
+#include "window-rules.h"
#include "workspaces.h"
enum lab_key_handled {
}
static bool
-handle_key_release(struct server *server, uint32_t evdev_keycode)
+handle_key_release(struct server *server, uint32_t evdev_keycode,
+ bool is_modifier_key)
{
/*
* Release events for keys that were not bound should always be
end_cycling(server);
}
+ key_state_bound_key_remove(evdev_keycode);
+
+ /*
+ * There are some clients (for example blender) that want to see the
+ * modifier-release-event even if it was part of a keybinds. This is
+ * treated as a special case and can only be achieved by configuration.
+ *
+ * Most clients (including those using Qt and GTK) are setup to not see
+ * these modifier release events - and actually misbehave if they do.
+ * For example Firefox shows the menu bar if alt is pressed and then
+ * released, whereas if only pressed (because the release is absorbed)
+ * nothing happens. So, if Firefox saw bound modifier-release-events it
+ * would show the menu bar every time the window-switcher is used with
+ * alt-tab.
+ */
+ struct view *view = server->active_view;
+ if (is_modifier_key && view) {
+ if (window_rules_get_property(view, "wantAbsorbedModifierReleaseEvents")
+ == LAB_PROP_TRUE) {
+ return false;
+ }
+ }
+
/*
* If a press event was handled by a compositor binding, then do
* not forward the corresponding release event to clients.
*/
- key_state_bound_key_remove(evdev_keycode);
return true;
}
actions_run(NULL, server, &cur_keybind->actions, NULL);
return true;
} else {
- return handle_key_release(server, event->keycode);
+ return handle_key_release(server, event->keycode,
+ keyinfo.is_modifier);
}
}
&& !strcasecmp(property, "fixedPosition")) {
return rule->fixed_position;
}
+ if (rule->want_absorbed_modifier_release_events
+ && !strcasecmp(property,
+ "wantAbsorbedModifierReleaseEvents")) {
+ return rule->want_absorbed_modifier_release_events;
+ }
}
}
return LAB_PROP_UNSPECIFIED;