Initial commit.
This commit is contained in:
commit
09fbae8eab
3 changed files with 140 additions and 0 deletions
13
LICENSE
Normal file
13
LICENSE
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
Copyright 2024 Johannes Findeisen
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
6
Makefile
Normal file
6
Makefile
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
all:
|
||||
$(CC) -Wall -o xtimer xtimer.c -lX11 -lXi
|
||||
|
||||
clean:
|
||||
rm -f xtimer
|
||||
|
||||
121
xtimer.c
Normal file
121
xtimer.c
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
/**
|
||||
* xtimer is a program that executes a givin program after a given time if no
|
||||
* X11 keybord or mouse input happend in the given time.
|
||||
*
|
||||
* Author: Johannes Findeisen <you@hanez.org> - 2025
|
||||
* License: Apache-2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/XInput2.h>
|
||||
#include <time.h>
|
||||
#include <limits.h> // For INT_MAX and INT_MIN
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "Usage: %s <seconds> <program> [arguments...]\n",
|
||||
argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Validate the first parameter (wait time)
|
||||
char *endptr;
|
||||
long wait_time = strtol(argv[1], &endptr, 10);
|
||||
|
||||
// Check for valid integer input
|
||||
if (*endptr != '\0' || wait_time <= 0 || wait_time > INT_MAX) {
|
||||
fprintf(stderr,
|
||||
"Error: First argument must be a positive integer within the range 1 to %d.\n",
|
||||
INT_MAX);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Safely cast the wait_time to an int (it's safe after the above check)
|
||||
int wait_time_seconds = (int)wait_time;
|
||||
|
||||
// Initialize X11 display
|
||||
Display *display = XOpenDisplay(NULL);
|
||||
if (!display) {
|
||||
fprintf(stderr, "Error: Unable to open X display.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Check for XInput2 support
|
||||
int opcode, event, error;
|
||||
if (!XQueryExtension(display, "XInputExtension", &opcode, &event, &error)) {
|
||||
fprintf(stderr,
|
||||
"Error: X Input Extension is not supported on this display.\n");
|
||||
XCloseDisplay(display);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Select events to monitor (keyboard, mouse clicks, and motion)
|
||||
Window root = DefaultRootWindow(display);
|
||||
XIEventMask evmask;
|
||||
unsigned char mask[(XI_LASTEVENT + 7) / 8] = {0};
|
||||
evmask.deviceid = XIAllDevices;
|
||||
evmask.mask_len = sizeof(mask);
|
||||
evmask.mask = mask;
|
||||
|
||||
XISetMask(mask, XI_KeyPress);
|
||||
XISetMask(mask, XI_KeyRelease);
|
||||
XISetMask(mask, XI_ButtonPress);
|
||||
XISetMask(mask, XI_ButtonRelease);
|
||||
XISetMask(mask, XI_Motion); // Listen for mouse motion events
|
||||
|
||||
if (XISelectEvents(display, root, &evmask, 1) != Success) {
|
||||
fprintf(stderr, "Error: Unable to select input events.\n");
|
||||
XCloseDisplay(display);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Timer logic with input monitoring
|
||||
time_t start_time, current_time;
|
||||
start_time = time(NULL);
|
||||
|
||||
while (1) {
|
||||
current_time = time(NULL);
|
||||
|
||||
// Check if the timer has expired
|
||||
if (current_time - start_time >= wait_time_seconds) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Check for input events
|
||||
while (XPending(display) > 0) {
|
||||
XEvent event;
|
||||
XNextEvent(display, &event);
|
||||
|
||||
if (event.xcookie.type == GenericEvent &&
|
||||
event.xcookie.extension == opcode && // Use the opcode obtained earlier
|
||||
XGetEventData(display, &event.xcookie)) {
|
||||
XIDeviceEvent *xi_event = (XIDeviceEvent *)event.xcookie.data;
|
||||
if (xi_event->evtype == XI_KeyPress ||
|
||||
xi_event->evtype == XI_ButtonPress ||
|
||||
xi_event->evtype == XI_Motion) {
|
||||
// Reset the timer on input or mouse movement
|
||||
start_time = time(NULL);
|
||||
}
|
||||
XFreeEventData(display, &event.xcookie);
|
||||
}
|
||||
}
|
||||
|
||||
// Sleep briefly to reduce CPU usage
|
||||
usleep(10000); // 10 milliseconds
|
||||
}
|
||||
|
||||
// Close the X display
|
||||
XCloseDisplay(display);
|
||||
|
||||
// Execute the program with optional arguments
|
||||
execvp(argv[2], &argv[2]);
|
||||
|
||||
// If execvp returns, an error occurred
|
||||
perror("Error executing program");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue