i3
src/match.c
Go to the documentation of this file.
00001 /*
00002  * vim:ts=4:sw=4:expandtab
00003  *
00004  * i3 - an improved dynamic tiling window manager
00005  * © 2009-2011 Michael Stapelberg and contributors (see also: LICENSE)
00006  *
00007  * A "match" is a data structure which acts like a mask or expression to match
00008  * certain windows or not. For example, when using commands, you can specify a
00009  * command like this: [title="*Firefox*"] kill. The title member of the match
00010  * data structure will then be filled and i3 will check each window using
00011  * match_matches_window() to find the windows affected by this command.
00012  *
00013  */
00014 
00015 #include "all.h"
00016 
00017 /*
00018  * Initializes the Match data structure. This function is necessary because the
00019  * members representing boolean values (like dock) need to be initialized with
00020  * -1 instead of 0.
00021  *
00022  */
00023 void match_init(Match *match) {
00024     memset(match, 0, sizeof(Match));
00025     match->dock = -1;
00026 }
00027 
00028 /*
00029  * Check if a match is empty. This is necessary while parsing commands to see
00030  * whether the user specified a match at all.
00031  *
00032  */
00033 bool match_is_empty(Match *match) {
00034     /* we cannot simply use memcmp() because the structure is part of a
00035      * TAILQ and I don’t want to start with things like assuming that the
00036      * last member of a struct really is at the end in memory… */
00037     return (match->title == NULL &&
00038             match->mark == NULL &&
00039             match->application == NULL &&
00040             match->class == NULL &&
00041             match->instance == NULL &&
00042             match->id == XCB_NONE &&
00043             match->con_id == NULL &&
00044             match->dock == -1 &&
00045             match->floating == M_ANY);
00046 }
00047 
00048 /*
00049  * Copies the data of a match from src to dest.
00050  *
00051  */
00052 void match_copy(Match *dest, Match *src) {
00053     memcpy(dest, src, sizeof(Match));
00054 
00055 #define STRDUP(field) do { \
00056     if (src->field != NULL) \
00057         dest->field = sstrdup(src->field); \
00058 } while (0)
00059 
00060     STRDUP(title);
00061     STRDUP(mark);
00062     STRDUP(application);
00063     STRDUP(class);
00064     STRDUP(instance);
00065 }
00066 
00067 /*
00068  * Check if a match data structure matches the given window.
00069  *
00070  */
00071 bool match_matches_window(Match *match, i3Window *window) {
00072     LOG("checking window %d (%s)\n", window->id, window->class_class);
00073 
00074     /* TODO: pcre, full matching, … */
00075     if (match->class != NULL) {
00076         if (window->class_class != NULL && strcasecmp(match->class, window->class_class) == 0) {
00077             LOG("window class matches (%s)\n", window->class_class);
00078         } else {
00079             LOG("window class does not match\n");
00080             return false;
00081         }
00082     }
00083 
00084     if (match->instance != NULL) {
00085         if (window->class_instance != NULL && strcasecmp(match->instance, window->class_instance) == 0) {
00086             LOG("window instance matches (%s)\n", window->class_instance);
00087         } else {
00088             LOG("window instance does not match\n");
00089             return false;
00090         }
00091     }
00092 
00093     if (match->id != XCB_NONE) {
00094         if (window->id == match->id) {
00095             LOG("match made by window id (%d)\n", window->id);
00096         } else {
00097             LOG("window id does not match\n");
00098             return false;
00099         }
00100     }
00101 
00102     /* TODO: pcre match */
00103     if (match->title != NULL) {
00104         if (window->name_json != NULL && strcasecmp(match->title, window->name_json) == 0) {
00105             LOG("title matches (%s)\n", window->name_json);
00106         } else {
00107             LOG("title does not match\n");
00108             return false;
00109         }
00110     }
00111 
00112     if (match->dock != -1) {
00113         LOG("match->dock = %d, window->dock = %d\n", match->dock, window->dock);
00114         if ((window->dock == W_DOCK_TOP && match->dock == M_DOCK_TOP) ||
00115          (window->dock == W_DOCK_BOTTOM && match->dock == M_DOCK_BOTTOM) ||
00116          ((window->dock == W_DOCK_TOP || window->dock == W_DOCK_BOTTOM) &&
00117           match->dock == M_DOCK_ANY) ||
00118          (window->dock == W_NODOCK && match->dock == M_NODOCK)) {
00119             LOG("dock status matches\n");
00120         } else {
00121             LOG("dock status does not match\n");
00122             return false;
00123         }
00124     }
00125 
00126     /* We don’t check the mark because this function is not even called when
00127      * the mark would have matched - it is checked in cmdparse.y itself */
00128     if (match->mark != NULL) {
00129         LOG("mark does not match\n");
00130         return false;
00131     }
00132 
00133     return true;
00134 }