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 #include "all.h"
00015 
00016 /*
00017  * Initializes the Match data structure. This function is necessary because the
00018  * members representing boolean values (like dock) need to be initialized with
00019  * -1 instead of 0.
00020  *
00021  */
00022 void match_init(Match *match) {
00023     memset(match, 0, sizeof(Match));
00024     match->dock = -1;
00025 }
00026 
00027 /*
00028  * Check if a match is empty. This is necessary while parsing commands to see
00029  * whether the user specified a match at all.
00030  *
00031  */
00032 bool match_is_empty(Match *match) {
00033     /* we cannot simply use memcmp() because the structure is part of a
00034      * TAILQ and I don’t want to start with things like assuming that the
00035      * last member of a struct really is at the end in memory… */
00036     return (match->title == NULL &&
00037             match->mark == NULL &&
00038             match->application == NULL &&
00039             match->class == NULL &&
00040             match->instance == NULL &&
00041             match->role == 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 /* The DUPLICATE_REGEX macro creates a new regular expression from the
00056  * ->pattern of the old one. It therefore does use a little more memory then
00057  *  with a refcounting system, but it’s easier this way. */
00058 #define DUPLICATE_REGEX(field) do { \
00059     if (src->field != NULL) \
00060         dest->field = regex_new(src->field->pattern); \
00061 } while (0)
00062 
00063     DUPLICATE_REGEX(title);
00064     DUPLICATE_REGEX(mark);
00065     DUPLICATE_REGEX(application);
00066     DUPLICATE_REGEX(class);
00067     DUPLICATE_REGEX(instance);
00068     DUPLICATE_REGEX(role);
00069 }
00070 
00071 /*
00072  * Check if a match data structure matches the given window.
00073  *
00074  */
00075 bool match_matches_window(Match *match, i3Window *window) {
00076     LOG("Checking window 0x%08x (class %s)\n", window->id, window->class_class);
00077 
00078     if (match->class != NULL) {
00079         if (window->class_class != NULL &&
00080             regex_matches(match->class, window->class_class)) {
00081             LOG("window class matches (%s)\n", window->class_class);
00082         } else {
00083             return false;
00084         }
00085     }
00086 
00087     if (match->instance != NULL) {
00088         if (window->class_instance != NULL &&
00089             regex_matches(match->instance, window->class_instance)) {
00090             LOG("window instance matches (%s)\n", window->class_instance);
00091         } else {
00092             return false;
00093         }
00094     }
00095 
00096     if (match->id != XCB_NONE) {
00097         if (window->id == match->id) {
00098             LOG("match made by window id (%d)\n", window->id);
00099         } else {
00100             LOG("window id does not match\n");
00101             return false;
00102         }
00103     }
00104 
00105     if (match->title != NULL) {
00106         if (window->name_json != NULL &&
00107             regex_matches(match->title, window->name_json)) {
00108             LOG("title matches (%s)\n", window->name_json);
00109         } else {
00110             return false;
00111         }
00112     }
00113 
00114     if (match->role != NULL) {
00115         if (window->role != NULL &&
00116             regex_matches(match->role, window->role)) {
00117             LOG("window_role matches (%s)\n", window->role);
00118         } else {
00119             return false;
00120         }
00121     }
00122 
00123     if (match->dock != -1) {
00124         if ((window->dock == W_DOCK_TOP && match->dock == M_DOCK_TOP) ||
00125          (window->dock == W_DOCK_BOTTOM && match->dock == M_DOCK_BOTTOM) ||
00126          ((window->dock == W_DOCK_TOP || window->dock == W_DOCK_BOTTOM) &&
00127           match->dock == M_DOCK_ANY) ||
00128          (window->dock == W_NODOCK && match->dock == M_NODOCK)) {
00129             LOG("dock status matches\n");
00130         } else {
00131             LOG("dock status does not match\n");
00132             return false;
00133         }
00134     }
00135 
00136     /* We don’t check the mark because this function is not even called when
00137      * the mark would have matched - it is checked in cmdparse.y itself */
00138     if (match->mark != NULL) {
00139         LOG("mark does not match\n");
00140         return false;
00141     }
00142 
00143     return true;
00144 }
00145 
00146 /*
00147  * Frees the given match. It must not be used afterwards!
00148  *
00149  */
00150 void match_free(Match *match) {
00151     /* First step: free the regex fields / patterns */
00152     regex_free(match->title);
00153     regex_free(match->application);
00154     regex_free(match->class);
00155     regex_free(match->instance);
00156     regex_free(match->mark);
00157     regex_free(match->role);
00158 
00159     /* Second step: free the regex helper struct itself */
00160     FREE(match->title);
00161     FREE(match->application);
00162     FREE(match->class);
00163     FREE(match->instance);
00164     FREE(match->mark);
00165     FREE(match->role);
00166 }