summaryrefslogtreecommitdiffstats
path: root/src/draglock.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/draglock.c')
-rw-r--r--src/draglock.c282
1 files changed, 282 insertions, 0 deletions
diff --git a/src/draglock.c b/src/draglock.c
new file mode 100644
index 0000000..e0a91d0
--- /dev/null
+++ b/src/draglock.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright © 2015 Red Hat, Inc.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software
+ * and its documentation for any purpose is hereby granted without
+ * fee, provided that the above copyright notice appear in all copies
+ * and that both that copyright notice and this permission notice
+ * appear in supporting documentation, and that the name of Red Hat
+ * not be used in advertising or publicity pertaining to distribution
+ * of the software without specific, written prior permission. Red
+ * Hat makes no representations about the suitability of this software
+ * for any purpose. It is provided "as is" without express or implied
+ * warranty.
+ *
+ * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
+ * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+ * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "draglock.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
+
+static int
+draglock_parse_config(struct draglock *dl, const char *config)
+{
+ int button = 0, target = 0;
+ const char *str = NULL;
+ char *end_str = NULL;
+ int pairs[DRAGLOCK_MAX_BUTTONS] = {0};
+
+ if (!config)
+ return 0;
+
+ /* empty string disables drag lock */
+ if (*config == '\0') {
+ dl->mode = DRAGLOCK_DISABLED;
+ return 0;
+ }
+
+ /* check for a single-number string first, config is "<int>" */
+ button = strtol(config, &end_str, 10);
+ if (*end_str == '\0') {
+ if (button < 0 || button >= DRAGLOCK_MAX_BUTTONS)
+ return 1;
+ /* we allow for button 0 so stacked xorg.conf.d snippets can
+ * disable the config again */
+ if (button == 0) {
+ dl->mode = DRAGLOCK_DISABLED;
+ return 0;
+ }
+
+ return draglock_set_meta(dl, button);
+ }
+
+ dl->mode = DRAGLOCK_DISABLED;
+
+ /* check for a set of button pairs, config is
+ * "<int> <int> <int> <int>..." */
+ str = config;
+ while (*str != '\0') {
+ button = strtol(str, &end_str, 10);
+ if (*end_str == '\0')
+ return 1;
+
+ str = end_str;
+ target = strtol(str, &end_str, 10);
+ if (end_str == str)
+ return 1;
+ if (button <= 0 || button >= DRAGLOCK_MAX_BUTTONS || target >= DRAGLOCK_MAX_BUTTONS)
+ return 1;
+
+ pairs[button] = target;
+ str = end_str;
+ }
+
+ return draglock_set_pairs(dl, pairs, ARRAY_SIZE(pairs));
+}
+
+int
+draglock_init_from_string(struct draglock *dl, const char *config)
+{
+ dl->mode = DRAGLOCK_DISABLED;
+
+ dl->meta_button = 0;
+ dl->meta_state = false;
+ memset(dl->lock_pair, 0, sizeof(dl->lock_pair));
+ memset(dl->lock_state, 0, sizeof(dl->lock_state));
+
+ return draglock_parse_config(dl, config);
+}
+
+enum draglock_mode
+draglock_get_mode(const struct draglock *dl)
+{
+ return dl->mode;
+}
+
+int
+draglock_get_meta(const struct draglock *dl)
+{
+ if (dl->mode == DRAGLOCK_META)
+ return dl->meta_button;
+ return 0;
+}
+
+size_t
+draglock_get_pairs(const struct draglock *dl, int *array, size_t nelem)
+{
+ unsigned int i;
+ size_t last = 0;
+
+ if (dl->mode != DRAGLOCK_PAIRS)
+ return 0;
+
+ /* size 1 array with the meta button */
+ if (dl->meta_button) {
+ *array = dl->meta_button;
+ return 1;
+ }
+
+ /* size N array with a[0] == 0, the rest ordered by button number */
+ memset(array, 0, nelem * sizeof(array[0]));
+ for (i = 0; i < nelem && i < ARRAY_SIZE(dl->lock_pair); i++) {
+ array[i] = dl->lock_pair[i];
+ if (array[i] != 0 && i > last)
+ last = i;
+ }
+ return last;
+}
+
+int
+draglock_set_meta(struct draglock *dl, int meta_button)
+{
+ if (meta_button < 0 || meta_button >= DRAGLOCK_MAX_BUTTONS)
+ return 1;
+
+ dl->meta_button = meta_button;
+ dl->mode = meta_button ? DRAGLOCK_META : DRAGLOCK_DISABLED;
+
+ return 0;
+}
+
+int
+draglock_set_pairs(struct draglock *dl, const int *array, size_t nelem)
+{
+ unsigned int i;
+
+ if (nelem == 0 || array[0] != 0)
+ return 1;
+
+ for (i = 0; i < nelem; i++) {
+ if (array[i] < 0 || array[i] >= DRAGLOCK_MAX_BUTTONS)
+ return 1;
+ }
+
+ dl->mode = DRAGLOCK_DISABLED;
+ for (i = 0; i < nelem; i++) {
+ dl->lock_pair[i] = array[i];
+ if (dl->lock_pair[i])
+ dl->mode = DRAGLOCK_PAIRS;
+ }
+
+ return 0;
+}
+
+static int
+draglock_filter_meta(struct draglock *dl, int *button, int *press)
+{
+ int b = *button,
+ is_press = *press;
+
+ if (b == dl->meta_button) {
+ if (is_press)
+ dl->meta_state = true;
+ *button = 0;
+ return 0;
+ }
+
+ switch (dl->lock_state[b]) {
+ case DRAGLOCK_BUTTON_STATE_NONE:
+ if (dl->meta_state && is_press) {
+ dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_DOWN_1;
+ dl->meta_state = false;
+ }
+ break;
+ case DRAGLOCK_BUTTON_STATE_DOWN_1:
+ if (!is_press) {
+ dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_UP_1;
+ b = 0;
+ }
+ break;
+ case DRAGLOCK_BUTTON_STATE_UP_1:
+ if (is_press) {
+ dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_DOWN_2;
+ b = 0;
+ }
+ break;
+ case DRAGLOCK_BUTTON_STATE_DOWN_2:
+ if (!is_press) {
+ dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_NONE;
+ }
+ break;
+ }
+
+ *button = b;
+
+ return 0;
+}
+
+static int
+draglock_filter_pair(struct draglock *dl, int *button, int *press)
+{
+ int b = *button,
+ is_press = *press;
+
+ if (dl->lock_pair[b] == 0)
+ return 0;
+
+ switch (dl->lock_state[b]) {
+ case DRAGLOCK_BUTTON_STATE_NONE:
+ if (is_press) {
+ dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_DOWN_1;
+ b = dl->lock_pair[b];
+ }
+ break;
+ case DRAGLOCK_BUTTON_STATE_DOWN_1:
+ if (!is_press) {
+ dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_UP_1;
+ b = 0;
+ }
+ break;
+ case DRAGLOCK_BUTTON_STATE_UP_1:
+ if (is_press) {
+ dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_DOWN_2;
+ b = 0;
+ }
+ break;
+ case DRAGLOCK_BUTTON_STATE_DOWN_2:
+ if (!is_press) {
+ dl->lock_state[b] = DRAGLOCK_BUTTON_STATE_NONE;
+ b = dl->lock_pair[b];
+ }
+ break;
+ }
+
+ *button = b;
+
+ return 0;
+}
+
+int
+draglock_filter_button(struct draglock *dl, int *button, int *is_press)
+{
+ if (*button == 0)
+ return 0;
+
+ switch(dl->mode) {
+ case DRAGLOCK_DISABLED:
+ return 0;
+ case DRAGLOCK_META:
+ return draglock_filter_meta(dl, button, is_press);
+ case DRAGLOCK_PAIRS:
+ return draglock_filter_pair(dl, button, is_press);
+ default:
+ abort();
+ break;
+ }
+
+ return 0;
+}