text: /*
  Copyright(c) Dorin Duminica. All rights reserved.
  Redistribution and use in source and binary forms, with or without 
  modification, are permitted provided that the following conditions are met:
    1. Redistributions of source code must retain the above copyright notice, 
  	 this list of conditions and the following disclaimer.
    2. Redistributions in binary form must reproduce the above copyright notice,
  	 this list of conditions and the following disclaimer in the documentation
  	 and/or other materials provided with the distribution.
    3. Neither the name of the copyright holder nor the names of its 
  	 contributors may be used to endorse or promote products derived from this
  	 software without specific prior written permission.
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 
  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
  
  #include "events.h"
  #include "utils.h"
  #include "prints.h"
  
  #include <math.h>
  #include <time.h>
  #include <poll.h>
  #include <signal.h>
  
  #include <libinput.h>
  
  #include "defs.h"
  
  static volatile sig_atomic_t stop = 0;
  static uint32_t dispatch_counter = 0;
  
  void
  touchpad_swipe_reset(touchpad_swipe_t *swipe)
  {
      swipe->pos1->x = 0;
      swipe->pos1->y = 0;
      swipe->pos2->x = 0;
      swipe->pos2->y = 0;
      swipe->fingers = 0;
      swipe->dir_counts[swipeUp] = 0;
      swipe->dir_counts[swipeDown] = 0;
      swipe->dir_counts[swipeLeft] = 0;
      swipe->dir_counts[swipeRight] = 0;
  }
  
  touchpad_swipe_t *
  new_touchpad_swipe_t()
  {
      touchpad_swipe_t *swipe = malloc(sztouchpad_swipe_t);
  
      swipe->pos1 = new_touchpad_position(0, 0);
      swipe->pos2 = new_touchpad_position(0, 0);
      touchpad_swipe_reset(swipe);
  
      return swipe;
  }
  
  void
  free_touchpad_swipe_t(touchpad_swipe_t *swipe)
  {
      if (!swipe) return;
      if (swipe->pos1)
          free(swipe->pos1);
      if (swipe->pos2)
          free(swipe->pos2);
      free(swipe);
  }
  
  touchpad_pinch_t *
  new_touchpad_pinch_t()
  {
  	touchpad_pinch_t *pinch = malloc(sztouchpad_pinch_t);
  	touchpad_pinch_reset(pinch);
  	return pinch;
  }
  
  void
  touchpad_pinch_reset(touchpad_pinch_t *pinch)
  {
  	pinch->scale_begin = 0.0f;
  	pinch->scale_end = 0.0f;
  	pinch->angle_begin = 0.0f;
  	pinch->angle_end = 0.0f;
  	pinch->fingers = 0;
  	pinch->samples = 0;
  }
  
  void
  free_touchpad_pinch_t(touchpad_pinch_t *pinch)
  {
  	if (!pinch) return;
  	free(pinch);
  }
  
  touchpad_event_ctx_t *
  new_touchpad_event_ctx_t()
  {
      touchpad_event_ctx_t *ctx = malloc(sztouchpad_event_ctx_t);
      ctx->swipe = new_touchpad_swipe_t();
  	ctx->pinch = new_touchpad_pinch_t();
      return ctx;
  }
  
  void
  free_touchpad_event_ctx_t(touchpad_event_ctx_t *ctx)
  {
      if (!ctx) return;
      free_touchpad_swipe_t(ctx->swipe);
  	free_touchpad_pinch_t(ctx->pinch);
      free(ctx);
  }
  
  void
  tools_dispatch(struct libinput *libinput)
  {
  	dispatch_counter++;
  	libinput_dispatch(libinput);
  }
  
  touchpad_position_t *
  new_touchpad_position(double x, double y)
  {
      touchpad_position_t *pos = malloc(sztouchpad_position);
      pos->x = x;
      pos->y = y;
      return pos;
  }
  
  char
  swipe_direction_short(swipe_direction_t direction)
  {
      char dmap[4] = {'U', 'D', 'L', 'R'};
      return dmap[direction];
  }
  
  double
  get_distance(touchpad_position_t *left, touchpad_position_t *right)
  {
      double v = powf(((double)right->x) - ((double)left->x), 2) +
          powf(((double)right->y) - ((double)left->y), 2);
      return sqrt(v);
  }
  
  swipe_direction_t
  get_swipe_direction(touchpad_position_t *left, touchpad_position_t *right)
  {
      swipe_direction_t direction = swipeUp;
  
      if (abs(right->x - left->x) > abs(1.05f * (double)(right->y - left->y)))
      {
          direction = right->x > left->x ? swipeRight : swipeLeft;
      } else if (right->y > left->y)
      {
          direction = swipeDown;
      }
  
      return direction;
  }
  
  int
  handle_and_print_events(struct libinput *li, touchpad_event_ctx_t *ctx)
  {
  	int rc = -1;
  	struct libinput_event *ev;
  
  	tools_dispatch(li);
  	while ((ev = libinput_get_event(li))) {
  		print_event_header(ev);
  
  		switch (libinput_event_get_type(ev)) {
  		case LIBINPUT_EVENT_NONE:
  			abort();
  		case LIBINPUT_EVENT_DEVICE_ADDED:
  		case LIBINPUT_EVENT_DEVICE_REMOVED:
  		case LIBINPUT_EVENT_KEYBOARD_KEY:
  			break;
  		case LIBINPUT_EVENT_POINTER_MOTION:
  			print_motion_event(ev);
  			break;
  		case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
  			print_absmotion_event(ev);
  			break;
  		case LIBINPUT_EVENT_POINTER_BUTTON:
  			print_pointer_button_event(ev);
  			break;
  		case LIBINPUT_EVENT_POINTER_AXIS:
  			print_pointer_axis_event(ev);
  			break;
  		case LIBINPUT_EVENT_TOUCH_DOWN:
  		case LIBINPUT_EVENT_TOUCH_MOTION:
  		case LIBINPUT_EVENT_TOUCH_UP:
  		case LIBINPUT_EVENT_TOUCH_CANCEL:
  		case LIBINPUT_EVENT_TOUCH_FRAME:
  			print_touch_event(ev);
  			break;
  		case LIBINPUT_EVENT_GESTURE_SWIPE_BEGIN:
              touchpad_swipe_reset(ctx->swipe);
  			print_gesture_event_without_coords(ev, ctx->swipe);
  			break;
  		case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE:
  			print_gesture_event_with_coords(ev, ctx->swipe);
  			break;
  		case LIBINPUT_EVENT_GESTURE_SWIPE_END:
  			print_gesture_event_swipe_end(ev, ctx->swipe);
  			break;
  		case LIBINPUT_EVENT_GESTURE_PINCH_BEGIN:
  			touchpad_pinch_reset(ctx->pinch);
  			print_gesture_event_without_coords(ev, ctx->swipe);
  			break;
  		case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE:
  			print_gesture_event_pinch_update(ev, ctx->pinch);
  			break;
  		case LIBINPUT_EVENT_GESTURE_PINCH_END:
  			print_gesture_event_pinch_end(ev, ctx->pinch);
  			break;
  		case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
  		case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY:
  		case LIBINPUT_EVENT_TABLET_TOOL_TIP:
  		case LIBINPUT_EVENT_TABLET_TOOL_BUTTON:
  		case LIBINPUT_EVENT_TABLET_PAD_BUTTON:
  		case LIBINPUT_EVENT_TABLET_PAD_RING:
  		case LIBINPUT_EVENT_TABLET_PAD_STRIP:
  		// case LIBINPUT_EVENT_TABLET_PAD_KEY:
  		case LIBINPUT_EVENT_SWITCH_TOGGLE:
              break;
  		}
  
  		libinput_event_destroy(ev);
  		rc = 0;
  
  		fflush(stdout);
  	}
  	return rc;
  }
  
  void
  main_event_loop(struct libinput *li) {
      touchpad_event_ctx_t *ctx = new_touchpad_event_ctx_t();
  
      struct pollfd fds;
  
  	fds.fd = libinput_get_fd(li);
  	fds.events = POLLIN;
  	fds.revents = 0;
  
      /* Handle already-pending device added events */
  	if (handle_and_print_events(li, ctx))
  		perrorf("Expected device added events on startup but got none. "
  				"Maybe you don't have the right permissions?\n");
  
  	/* time offset starts with our first received event */
  	if (poll(&fds, 1, -1) > -1) {
  		struct timespec tp;
  		clock_gettime(CLOCK_MONOTONIC, &tp);
  		start_time = tp.tv_sec * 1000 + tp.tv_nsec / 1000000;
  		do {
  			handle_and_print_events(li, ctx);
  		} while (!stop && poll(&fds, 1, -1) > -1);
  	}
  
      printf("\n");
  
      free_touchpad_event_ctx_t(ctx);
  }
  
  
  