types.c (7516B)
1 /* Copyright (c) 2013, Bastien Dejean 2 * All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are met: 6 * 7 * 1. Redistributions of source code must retain the above copyright notice, this 8 * list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright notice, 10 * this list of conditions and the following disclaimer in the documentation 11 * and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 */ 24 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <string.h> 28 #include <stdbool.h> 29 #include <unistd.h> 30 #include "parse.h" 31 #include "grab.h" 32 33 hotkey_t *find_hotkey(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, uint8_t event_type, bool *replay_event) 34 { 35 int num_active = 0; 36 int num_locked = 0; 37 hotkey_t *result = NULL; 38 39 for (hotkey_t *hk = hotkeys_head; hk != NULL; hk = hk->next) { 40 chain_t *c = hk->chain; 41 if ((chained && c->state == c->head) || (locked && c->state != c->tail)) 42 continue; 43 if (match_chord(c->state, event_type, keysym, button, modfield)) { 44 if (status_fifo != NULL && num_active == 0) { 45 if (!chained) { 46 snprintf(progress, sizeof(progress), "%s", c->state->repr); 47 } else { 48 strncat(progress, ";", sizeof(progress) - strlen(progress) - 1); 49 strncat(progress, c->state->repr, sizeof(progress) - strlen(progress) - 1); 50 } 51 put_status(HOTKEY_PREFIX, progress); 52 } 53 if (replay_event != NULL && c->state->replay_event) 54 *replay_event = true; 55 if (c->state->lock_chain) { 56 num_locked += 1; 57 if (timeout > 0) 58 alarm(0); 59 } 60 if (c->state == c->tail) { 61 if (hk->cycle != NULL) { 62 unsigned char delay = hk->cycle->delay; 63 hk->cycle->delay = (delay == 0 ? hk->cycle->period - 1 : delay - 1); 64 if (delay == 0) 65 result = hk; 66 continue; 67 } 68 if (chained && !locked) 69 abort_chain(); 70 return hk; 71 } else { 72 c->state = c->state->next; 73 num_active++; 74 grab_chord(c->state); 75 } 76 } else if (chained) { 77 if (!locked && c->state->event_type == event_type) 78 c->state = c->head; 79 else 80 num_active++; 81 } 82 } 83 84 if (result != NULL) 85 return result; 86 87 if (num_locked > 0) { 88 locked = true; 89 } 90 91 if (!chained) { 92 if (num_active > 0) { 93 chained = true; 94 put_status(BEGIN_CHAIN_PREFIX, "Begin chain"); 95 grab_chord(abort_chord); 96 } 97 } else if (num_active == 0 || match_chord(abort_chord, event_type, keysym, button, modfield)) { 98 abort_chain(); 99 return find_hotkey(keysym, button, modfield, event_type, replay_event); 100 } 101 if (chained && !locked && timeout > 0) 102 alarm(timeout); 103 PRINTF("num active %i\n", num_active); 104 105 return NULL; 106 } 107 108 bool match_chord(chord_t *chord, uint8_t event_type, xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield) 109 { 110 for (chord_t *c = chord; c != NULL; c = c->more) 111 if (c->event_type == event_type && c->keysym == keysym && c->button == button && (c->modfield == XCB_MOD_MASK_ANY || c->modfield == modfield)) 112 return true; 113 return false; 114 } 115 116 chord_t *make_chord(xcb_keysym_t keysym, xcb_button_t button, uint16_t modfield, uint8_t event_type, bool replay_event, bool lock_chain) 117 { 118 chord_t *chord; 119 if (button == XCB_NONE) { 120 chord_t *prev = NULL; 121 chord_t *orig = NULL; 122 xcb_keycode_t *keycodes = keycodes_from_keysym(keysym); 123 if (keycodes != NULL) { 124 for (xcb_keycode_t *kc = keycodes; *kc != XCB_NO_SYMBOL; kc++) { 125 xcb_keysym_t natural_keysym = xcb_key_symbols_get_keysym(symbols, *kc, 0); 126 for (unsigned char col = 0; col < KEYSYMS_PER_KEYCODE; col++) { 127 xcb_keysym_t ks = xcb_key_symbols_get_keysym(symbols, *kc, col); 128 if (ks == keysym) { 129 uint16_t implicit_modfield = (col & 1 ? XCB_MOD_MASK_SHIFT : 0) | (col & 2 ? modfield_from_keysym(Mode_switch) : 0); 130 uint16_t explicit_modfield = modfield | implicit_modfield; 131 chord = malloc(sizeof(chord_t)); 132 bool unique = true; 133 for (chord_t *c = orig; unique && c != NULL; c = c->more) 134 if (c->modfield == explicit_modfield && c->keysym == natural_keysym) 135 unique = false; 136 if (!unique) { 137 free(chord); 138 break; 139 } 140 chord->keysym = natural_keysym; 141 chord->button = button; 142 chord->modfield = explicit_modfield; 143 chord->next = chord->more = NULL; 144 chord->event_type = event_type; 145 chord->replay_event = replay_event; 146 chord->lock_chain = lock_chain; 147 if (prev != NULL) 148 prev->more = chord; 149 else 150 orig = chord; 151 prev = chord; 152 PRINTF("key chord %u %u\n", natural_keysym, explicit_modfield); 153 break; 154 } 155 } 156 } 157 } else { 158 warn("No keycodes found for keysym %u.\n", keysym); 159 } 160 free(keycodes); 161 chord = orig; 162 } else { 163 chord = malloc(sizeof(chord_t)); 164 chord->keysym = keysym; 165 chord->button = button; 166 chord->modfield = modfield; 167 chord->event_type = event_type; 168 chord->replay_event = replay_event; 169 chord->lock_chain = lock_chain; 170 chord->next = chord->more = NULL; 171 PRINTF("button chord %u %u\n", button, modfield); 172 } 173 return chord; 174 } 175 176 void add_chord(chain_t *chain, chord_t *chord) 177 { 178 if (chain->head == NULL) { 179 chain->head = chain->tail = chain->state = chord; 180 } else { 181 chain->tail->next = chord; 182 chain->tail = chord; 183 } 184 } 185 186 chain_t *make_chain(void) 187 { 188 chain_t *chain = malloc(sizeof(chain_t)); 189 chain->head = chain->tail = chain->state = NULL; 190 return chain; 191 } 192 193 cycle_t *make_cycle(int delay, int period) 194 { 195 cycle_t *cycle = malloc(sizeof(cycle_t)); 196 cycle->delay = delay; 197 cycle->period = period; 198 return cycle; 199 } 200 201 hotkey_t *make_hotkey(chain_t *chain, char *command) 202 { 203 hotkey_t *hk = malloc(sizeof(hotkey_t)); 204 hk->chain = chain; 205 hk->sync = false; 206 if (command[0] == SYNCHRONOUS_CHAR) { 207 command = lgraph(command+1); 208 hk->sync = true; 209 } 210 snprintf(hk->command, sizeof(hk->command), "%s", command); 211 hk->cycle = NULL; 212 hk->next = hk->prev = NULL; 213 return hk; 214 } 215 216 void add_hotkey(hotkey_t *hk) 217 { 218 if (hotkeys_head == NULL) { 219 hotkeys_head = hotkeys_tail = hk; 220 } else { 221 hotkeys_tail->next = hk; 222 hk->prev = hotkeys_tail; 223 hotkeys_tail = hk; 224 } 225 } 226 227 void abort_chain(void) 228 { 229 PUTS("abort chain"); 230 put_status(END_CHAIN_PREFIX, "End chain"); 231 for (hotkey_t *hk = hotkeys_head; hk != NULL; hk = hk->next) 232 hk->chain->state = hk->chain->head; 233 chained = false; 234 locked = false; 235 if (timeout > 0) 236 alarm(0); 237 ungrab(); 238 grab(); 239 } 240 241 void destroy_chain(chain_t *chain) 242 { 243 chord_t *c = chain->head; 244 while (c != NULL) { 245 chord_t *n = c->next; 246 destroy_chord(c); 247 c = n; 248 } 249 free(chain); 250 } 251 252 void destroy_chord(chord_t *chord) 253 { 254 chord_t *c = chord->more; 255 while (c != NULL) { 256 chord_t *n = c->more; 257 free(c); 258 c = n; 259 } 260 free(chord); 261 }