+/* -*- 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"
#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;
GPatternSpec *matchtitle;
GRegex *regextitle;
gchar *exacttitle;
+} Query;
+
+typedef struct {
+ GArray* queries;
GSList *thenacts;
GSList *elseacts;
} Options;
}
}
-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;
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;
}
}
+ 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;
}
{
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);
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);
}
static gboolean run_func(ObActionsData *data, gpointer options)
{
Options *o = options;
+ ObClient *action_target = data->client;
+ gboolean is_true = TRUE;
+
+ 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;
- ObClient *c = data->client;
-
- 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)))
- {
+ 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;
}