main.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. /*
  2. * Copyright (C) 2011 Michael Buesch <m@bues.ch>
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License
  6. * as published by the Free Software Foundation; either version 2
  7. * of the License, or (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. */
  14. #include <stdlib.h>
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <unistd.h>
  18. #include <signal.h>
  19. #include <errno.h>
  20. #include <sys/time.h>
  21. #include <X11/Xlib.h>
  22. #include <X11/extensions/XInput2.h>
  23. #define PFX "pwrtray-xevrep: "
  24. static pid_t report_pid;
  25. static int report_signal;
  26. static unsigned int grace_period_ms;
  27. static struct timeval next_report;
  28. int timeval_after(const struct timeval *a, const struct timeval *b)
  29. {
  30. if (a->tv_sec > b->tv_sec)
  31. return 1;
  32. if ((a->tv_sec == b->tv_sec) && (a->tv_usec > b->tv_usec))
  33. return 1;
  34. return 0;
  35. }
  36. void timeval_add_msec(struct timeval *tv, unsigned int msec)
  37. {
  38. unsigned int seconds, usec;
  39. seconds = msec / 1000;
  40. msec = msec % 1000;
  41. usec = msec * 1000;
  42. tv->tv_usec += usec;
  43. while (tv->tv_usec >= 1000000) {
  44. tv->tv_sec++;
  45. tv->tv_usec -= 1000000;
  46. }
  47. tv->tv_sec += seconds;
  48. }
  49. static void report_event(XIDeviceEvent *ev)
  50. {
  51. struct timeval now;
  52. int err;
  53. gettimeofday(&now, NULL);
  54. if (!timeval_after(&now, &next_report))
  55. return;
  56. next_report = now;
  57. timeval_add_msec(&next_report, grace_period_ms);
  58. err = kill(report_pid, report_signal);
  59. if (err) {
  60. fprintf(stderr, PFX
  61. "Failed to send signal %d to process %d: %s\n",
  62. report_signal, report_pid, strerror(errno));
  63. }
  64. }
  65. static void signal_handler(int signal)
  66. {
  67. printf(PFX "terminated\n");
  68. exit(0);
  69. }
  70. static int install_sighandler(int signal, void (*handler)(int))
  71. {
  72. struct sigaction act;
  73. memset(&act, 0, sizeof(act));
  74. sigemptyset(&act.sa_mask);
  75. act.sa_flags = 0;
  76. act.sa_handler = handler;
  77. return sigaction(signal, &act, NULL);
  78. }
  79. static void usage(void)
  80. {
  81. printf("Usage: pwrtray-xevrep PID SIGNAL GRACEPERIOD\n");
  82. }
  83. int main(int argc, char **argv)
  84. {
  85. Display *display;
  86. Window window;
  87. XIEventMask evmask;
  88. unsigned char evmask_bits[(XI_LASTEVENT + 8) / 8] = { 0, };
  89. int res, tmp0, tmp1, xi_opcode;
  90. int pid;
  91. sigset_t sigset;
  92. if (argc != 4) {
  93. usage();
  94. return 1;
  95. }
  96. if (sscanf(argv[1], "%d", &pid) != 1 ||
  97. sscanf(argv[2], "%d", &report_signal) != 1 ||
  98. sscanf(argv[3], "%u", &grace_period_ms) != 1) {
  99. usage();
  100. return 1;
  101. }
  102. report_pid = pid;
  103. display = XOpenDisplay(NULL);
  104. if (!display) {
  105. /* Fallback to the first display. */
  106. display = XOpenDisplay(":0");
  107. if (!display) {
  108. fprintf(stderr, PFX "Failed to open DISPLAY\n");
  109. return 1;
  110. }
  111. }
  112. window = DefaultRootWindow(display);
  113. res = XQueryExtension(display, "XInputExtension", &xi_opcode, &tmp0, &tmp1);
  114. if (!res) {
  115. fprintf(stderr, PFX "X Input extension not available.\n");
  116. return 1;
  117. }
  118. sigemptyset(&sigset);
  119. res = sigprocmask(SIG_SETMASK, &sigset, NULL);
  120. res |= install_sighandler(SIGINT, signal_handler);
  121. res |= install_sighandler(SIGTERM, signal_handler);
  122. if (res) {
  123. fprintf(stderr, PFX "Failed to setup signal handlers\n");
  124. return 1;
  125. }
  126. XISetMask(evmask_bits, XI_DeviceChanged);
  127. XISetMask(evmask_bits, XI_KeyPress);
  128. XISetMask(evmask_bits, XI_KeyRelease);
  129. XISetMask(evmask_bits, XI_RawButtonPress);
  130. XISetMask(evmask_bits, XI_RawButtonRelease);
  131. XISetMask(evmask_bits, XI_Motion);
  132. XISetMask(evmask_bits, XI_HierarchyChanged);
  133. XISetMask(evmask_bits, XI_PropertyEvent);
  134. memset(&evmask, 0, sizeof(evmask));
  135. evmask.deviceid = XIAllDevices;
  136. evmask.mask_len = sizeof(evmask_bits);
  137. evmask.mask = evmask_bits;
  138. res = XISelectEvents(display, window, &evmask, 1);
  139. if (res != Success) {
  140. fprintf(stderr, PFX "Failed to set event mask (%d)\n", res);
  141. return 1;
  142. }
  143. printf(PFX "Monitoring X11 input events...\n");
  144. while (1) {
  145. XEvent ev;
  146. XGenericEventCookie *cookie = &ev.xcookie;
  147. XNextEvent(display, &ev);
  148. if (XGetEventData(display, cookie) &&
  149. cookie->type == GenericEvent &&
  150. cookie->extension == xi_opcode) {
  151. XIDeviceEvent *event = cookie->data;
  152. report_event(event);
  153. }
  154. XFreeEventData(display, cookie);
  155. }
  156. }