all repos — openbox @ 881076d2a8634af4420496c16ff3699cfa3a573c

openbox fork - make it a bit more like ryudo

Add queries to If actions

This allows the If action to run queries against a client other than
the target of the actions being run, for example to check state on
the focused window while performing actions on another window during
focus cycling.

The syntax looks like

<action name="If">
  <query target="default">
    <title>FooBar</title>
    <maximized>yes</maximized>
  </query>
  <query target="focus">
    <desktop>3</desktop>
  </query>
  <then>
   <action name="NextDesktop"/>
  </then>
</action>

The above checks the client window that the actions will run on to
verify that its title is "FooBar" and that it is maximized. If that
is true, it also checks that the currently focused client window is
on desktop 3. If that is true also, then it runs the NextDesktop
action.

The target="" option can be set to "default" which uses the client
window that the actions will run on, or it can be "focus" which uses
the client window that is currently focused.

The <query> tag is optional, and the conditions inside the query can
be placed directly inside the If <action> tag, as they were before
this change. In that case, a default <query> tag is assumed with
target="default" which matches the previous behaviour.

Multiple <query> tags can be present, and they must all be true in
order to run the actions in <then>. If any one is false, the actions
in <else> will be run instead.
Dana Jansens danakj@orodu.net
commit

881076d2a8634af4420496c16ff3699cfa3a573c

parent

98c5205b9ef8ee9f11bc8912ad8b09f756036e77

1 files changed, 207 insertions(+), 67 deletions(-)

jump to
M openbox/actions/if.copenbox/actions/if.c

@@ -1,3 +1,22 @@

+/* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*- + + if.c for the Openbox window manager + Copyright (c) 2007 Mikael Magnusson + Copyright (c) 2007 Dana Jansens + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + See the COPYING file for a copy of the GNU General Public License. +*/ + #include "openbox/actions.h" #include "openbox/misc.h" #include "openbox/client.h"

@@ -6,7 +25,13 @@ #include "openbox/screen.h"

#include "openbox/focus.h" #include <glib.h> +typedef enum { + QUERY_TARGET_IS_ACTION_TARGET, + QUERY_TARGET_IS_FOCUS_TARGET, +} QueryTarget; + typedef struct { + QueryTarget target; gboolean shaded_on; gboolean shaded_off; gboolean maxvert_on;

@@ -33,6 +58,10 @@ guint client_monitor;

GPatternSpec *matchtitle; GRegex *regextitle; gchar *exacttitle; +} Query; + +typedef struct { + GArray* queries; GSList *thenacts; GSList *elseacts; } Options;

@@ -61,37 +90,37 @@ *off = TRUE;

} } -static gpointer setup_func(xmlNodePtr node) -{ - xmlNodePtr n; - Options *o; +static void setup_query(Options* o, xmlNodePtr node, QueryTarget target) { + Query *q = g_slice_new0(Query); + g_array_append_val(o->queries, q); - o = g_slice_new0(Options); + q->target = target; - set_bool(node, "shaded", &o->shaded_on, &o->shaded_off); - set_bool(node, "maximized", &o->maxfull_on, &o->maxfull_off); - set_bool(node, "maximizedhorizontal", &o->maxhorz_on, &o->maxhorz_off); - set_bool(node, "maximizedvertical", &o->maxvert_on, &o->maxvert_off); - set_bool(node, "iconified", &o->iconic_on, &o->iconic_off); - set_bool(node, "focused", &o->focused, &o->unfocused); - set_bool(node, "urgent", &o->urgent_on, &o->urgent_off); - set_bool(node, "undecorated", &o->decor_off, &o->decor_on); - set_bool(node, "omnipresent", &o->omnipresent_on, &o->omnipresent_off); + set_bool(node, "shaded", &q->shaded_on, &q->shaded_off); + set_bool(node, "maximized", &q->maxfull_on, &q->maxfull_off); + set_bool(node, "maximizedhorizontal", &q->maxhorz_on, &q->maxhorz_off); + set_bool(node, "maximizedvertical", &q->maxvert_on, &q->maxvert_off); + set_bool(node, "iconified", &q->iconic_on, &q->iconic_off); + set_bool(node, "focused", &q->focused, &q->unfocused); + set_bool(node, "urgent", &q->urgent_on, &q->urgent_off); + set_bool(node, "undecorated", &q->decor_off, &q->decor_on); + set_bool(node, "omnipresent", &q->omnipresent_on, &q->omnipresent_off); + xmlNodePtr n; if ((n = obt_xml_find_node(node, "desktop"))) { gchar *s; if ((s = obt_xml_node_string(n))) { if (!g_ascii_strcasecmp(s, "current")) - o->desktop_current = TRUE; + q->desktop_current = TRUE; if (!g_ascii_strcasecmp(s, "other")) - o->desktop_other = TRUE; + q->desktop_other = TRUE; else - o->desktop_number = atoi(s); + q->desktop_number = atoi(s); g_free(s); } } if ((n = obt_xml_find_node(node, "activedesktop"))) { - o->screendesktop_number = obt_xml_node_int(n); + q->screendesktop_number = obt_xml_node_int(n); } if ((n = obt_xml_find_node(node, "title"))) { gchar *s, *type = NULL;

@@ -99,19 +128,31 @@ if ((s = obt_xml_node_string(n))) {

if (!obt_xml_attr_string(n, "type", &type) || !g_ascii_strcasecmp(type, "pattern")) { - o->matchtitle = g_pattern_spec_new(s); + q->matchtitle = g_pattern_spec_new(s); } else if (type && !g_ascii_strcasecmp(type, "regex")) { - o->regextitle = g_regex_new(s, 0, 0, NULL); + q->regextitle = g_regex_new(s, 0, 0, NULL); } else if (type && !g_ascii_strcasecmp(type, "exact")) { - o->exacttitle = g_strdup(s); + q->exacttitle = g_strdup(s); } g_free(s); } } if ((n = obt_xml_find_node(node, "monitor"))) { - o->client_monitor = obt_xml_node_int(n); + q->client_monitor = obt_xml_node_int(n); } +} + +static gpointer setup_func(xmlNodePtr node) +{ + Options *o = g_slice_new0(Options); + gboolean zero_terminated = FALSE; + gboolean clear_to_zero_on_alloc = FALSE; + o->queries = g_array_new(zero_terminated, + clear_to_zero_on_alloc, + sizeof(Query*)); + + xmlNodePtr n; if ((n = obt_xml_find_node(node, "then"))) { xmlNodePtr m;

@@ -133,6 +174,25 @@ m = obt_xml_find_node(m->next, "action");

} } + xmlNodePtr query_node = obt_xml_find_node(node, "query"); + if (!query_node) { + /* The default query if none is specified. It uses the conditions + found in the action's node. */ + setup_query(o, + node, + QUERY_TARGET_IS_ACTION_TARGET); + } else { + while (query_node) { + QueryTarget query_target = QUERY_TARGET_IS_ACTION_TARGET; + if (obt_xml_attr_contains(query_node, "target", "focus")) + query_target = QUERY_TARGET_IS_FOCUS_TARGET; + + setup_query(o, query_node->children, query_target); + + query_node = obt_xml_find_node(query_node->next, "query"); + } + } + return o; }

@@ -140,6 +200,20 @@ static void free_func(gpointer options)

{ Options *o = options; + guint i; + for (i = 0; i < o->queries->len; ++i) { + Query *q = g_array_index(o->queries, Query*, i); + + if (q->matchtitle) + g_pattern_spec_free(q->matchtitle); + if (q->regextitle) + g_regex_unref(q->regextitle); + if (q->exacttitle) + g_free(q->exacttitle); + + g_slice_free(Query, q); + } + while (o->thenacts) { actions_act_unref(o->thenacts->data); o->thenacts = g_slist_delete_link(o->thenacts, o->thenacts);

@@ -148,13 +222,8 @@ while (o->elseacts) {

actions_act_unref(o->elseacts->data); o->elseacts = g_slist_delete_link(o->elseacts, o->elseacts); } - if (o->matchtitle) - g_pattern_spec_free(o->matchtitle); - if (o->regextitle) - g_regex_unref(o->regextitle); - if (o->exacttitle) - g_free(o->exacttitle); + g_array_unref(o->queries); g_slice_free(Options, o); }

@@ -162,52 +231,123 @@ /* Always return FALSE because its not interactive */

static gboolean run_func(ObActionsData *data, gpointer options) { Options *o = options; - GSList *acts; - ObClient *c = data->client; + ObClient *action_target = data->client; + gboolean is_true = TRUE; - if (c && - (!o->shaded_on || c->shaded) && - (!o->shaded_off || !c->shaded) && - (!o->iconic_on || c->iconic) && - (!o->iconic_off || !c->iconic) && - (!o->maxhorz_on || c->max_horz) && - (!o->maxhorz_off || !c->max_horz) && - (!o->maxvert_on || c->max_vert) && - (!o->maxvert_off || !c->max_vert) && - (!o->maxfull_on || (c->max_vert && c->max_horz)) && - (!o->maxfull_off || !(c->max_vert && c->max_horz)) && - (!o->focused || (c == focus_client)) && - (!o->unfocused || !(c == focus_client)) && - (!o->urgent_on || (c->urgent || c->demands_attention)) && - (!o->urgent_off || !(c->urgent || c->demands_attention)) && - (!o->decor_off || (c->undecorated || !(c->decorations & OB_FRAME_DECOR_TITLEBAR))) && - (!o->decor_on || (!c->undecorated && (c->decorations & OB_FRAME_DECOR_TITLEBAR))) && - (!o->omnipresent_on || (c->desktop == DESKTOP_ALL)) && - (!o->omnipresent_off || (c->desktop != DESKTOP_ALL)) && - (!o->desktop_current || ((c->desktop == screen_desktop) || - (c->desktop == DESKTOP_ALL))) && - (!o->desktop_other || ((c->desktop != screen_desktop) && - (c->desktop != DESKTOP_ALL))) && - (!o->desktop_number || ((c->desktop == o->desktop_number - 1) || - (c->desktop == DESKTOP_ALL))) && - (!o->screendesktop_number || screen_desktop == o->screendesktop_number - 1) && - (!o->matchtitle || - (g_pattern_match_string(o->matchtitle, c->original_title))) && - (!o->regextitle || - (g_regex_match(o->regextitle, c->original_title, 0, NULL))) && - (!o->exacttitle || - (!strcmp(o->exacttitle, c->original_title))) && - (!o->client_monitor || - (o->client_monitor == client_monitor(c) + 1))) - { - acts = o->thenacts; + guint i; + for (i = 0; i < o->queries->len; ++i) { + Query *q = g_array_index(o->queries, Query*, i); + ObClient *query_target = NULL; + + switch (q->target) { + case QUERY_TARGET_IS_ACTION_TARGET: + query_target = data->client; + break; + case QUERY_TARGET_IS_FOCUS_TARGET: + query_target = focus_client; + break; + } + + /* If there's no client to query, then false. */ + is_true &= query_target != NULL; + + if (q->shaded_on) + is_true &= query_target->shaded; + if (q->shaded_off) + is_true &= !query_target->shaded; + + if (q->iconic_on) + is_true &= query_target->iconic; + if (q->iconic_off) + is_true &= !query_target->iconic; + + if (q->maxhorz_on) + is_true &= query_target->max_horz; + if (q->maxhorz_off) + is_true &= !query_target->max_horz; + + if (q->maxvert_on) + is_true &= query_target->max_vert; + if (q->maxvert_off) + is_true &= !query_target->max_vert; + + gboolean is_max_full = + query_target->max_vert && query_target->max_horz; + if (q->maxfull_on) + is_true &= is_max_full; + if (q->maxfull_off) + is_true &= !is_max_full; + + if (q->focused) + is_true &= query_target == focus_client; + if (q->unfocused) + is_true &= query_target != focus_client; + + gboolean is_urgent = + query_target->urgent || query_target->demands_attention; + if (q->urgent_on) + is_true &= is_urgent; + if (q->urgent_off) + is_true &= !is_urgent; + + gboolean has_visible_title_bar = + !query_target->undecorated && + (query_target->decorations & OB_FRAME_DECOR_TITLEBAR); + if (q->decor_on) + is_true &= has_visible_title_bar; + if (q->decor_off) + is_true &= !has_visible_title_bar; + + if (q->omnipresent_on) + is_true &= query_target->desktop == DESKTOP_ALL; + if (q->omnipresent_off) + is_true &= query_target->desktop != DESKTOP_ALL; + + gboolean is_on_current_desktop = + query_target->desktop == screen_desktop || + query_target->desktop == DESKTOP_ALL; + if (q->desktop_current) + is_true &= is_on_current_desktop; + if (q->desktop_other) + is_true &= !is_on_current_desktop; + + if (q->desktop_number) { + gboolean is_on_desktop = + query_target->desktop == q->desktop_number - 1 || + query_target->desktop == DESKTOP_ALL; + is_true &= is_on_desktop; + } + + if (q->screendesktop_number) + is_true &= screen_desktop == q->screendesktop_number - 1; + + if (q->matchtitle) { + is_true &= g_pattern_match_string(q->matchtitle, + query_target->original_title); + } + if (q->regextitle) { + is_true &= g_regex_match(q->regextitle, + query_target->original_title, + 0, + NULL); + } + if (q->exacttitle) + is_true &= !strcmp(q->exacttitle, query_target->original_title); + + if (q->client_monitor) + is_true &= client_monitor(query_target) == q->client_monitor - 1; + } + + GSList *acts; + if (is_true) + acts = o->thenacts; else acts = o->elseacts; actions_run_acts(acts, data->uact, data->state, data->x, data->y, data->button, - data->context, data->client); + data->context, action_target); return FALSE; }