sxhkd-rc

[fork] simple X hotkey daemon (but for the rc shell)
git clone https://hhvn.uk/sxhkd-rc
git clone git://hhvn.uk/sxhkd-rc
Log | Files | Refs | README | LICENSE

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 }