i3
|
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 }