Added daemon mode, a help and version. Added a README.
This commit is contained in:
parent
90a5e4f510
commit
65b7a0e28d
3 changed files with 149 additions and 49 deletions
2
LICENSE
2
LICENSE
|
|
@ -1,4 +1,4 @@
|
||||||
Copyright 2024 Johannes Findeisen
|
Copyright 2025 Johannes Findeisen
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
|
|
|
||||||
46
README.md
Normal file
46
README.md
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
# Xtea
|
||||||
|
|
||||||
|
Xtea is a program that executes a given command or program after a given time if no X11 keybord or mouse input happend in the given time.
|
||||||
|
|
||||||
|
## Building checkpw
|
||||||
|
|
||||||
|
```
|
||||||
|
git clone https://git.xw3.org/hanez/Xtea.git
|
||||||
|
cd Xtea
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo make install
|
||||||
|
```
|
||||||
|
|
||||||
|
Xtea is installed to /usr/bin/.
|
||||||
|
|
||||||
|
## Uninstall
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo make uninstall
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
Xtea -h
|
||||||
|
Usage: Xtea [-d] [-v] [-h] <seconds> <program> [arguments...]
|
||||||
|
|
||||||
|
Options:
|
||||||
|
-d Run in daemon mode. Restart the program after inactivity.
|
||||||
|
-v Show the program version and exit.
|
||||||
|
-h Show this help message and exit.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
<seconds> Time (in seconds) to wait after inactivity before running the program.
|
||||||
|
<program> Program to execute after the specified delay.
|
||||||
|
[arguments...] Optional arguments to pass to the program.
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
Xtea 5 ls -ls Execute 'ls -l' after 5 seconds of inactivity.
|
||||||
|
Xtea -d 10 echo 'Hello' Run 'echo Hello' in daemon mode after 10 seconds of inactivity.
|
||||||
|
```
|
||||||
154
Xtea.c
154
Xtea.c
|
|
@ -1,40 +1,83 @@
|
||||||
/**
|
/**
|
||||||
* Xtimer is a program that executes a given command or program after a given
|
* Xtea is a program that executes a given command or program after a given
|
||||||
* time if no X11 keybord or mouse input happend in the given time.
|
* time if no X11 keybord or mouse input happend in the given time.
|
||||||
*
|
*
|
||||||
* Author: Johannes Findeisen <you@hanez.org> - 2025
|
* Author: Johannes Findeisen <you@hanez.org> - 2025
|
||||||
* License: Apache-2.0 (see LICENSE)
|
* License: Apache-2.0 (see LICENSE)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <limits.h> // For INT_MAX and INT_MIN
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <X11/Xlib.h>
|
|
||||||
#include <X11/extensions/XInput2.h>
|
#include <X11/extensions/XInput2.h>
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
|
#define VERSION "0.1.0"
|
||||||
|
|
||||||
|
void print_help(const char *program_name)
|
||||||
|
{
|
||||||
|
printf("Usage: %s [-d] [-v] [-h] <seconds> <program> [arguments...]\n", program_name);
|
||||||
|
printf("\n");
|
||||||
|
printf("Options:\n");
|
||||||
|
printf(" -d Run in daemon mode. Restart the program after inactivity.\n");
|
||||||
|
printf(" -v Show the program version and exit.\n");
|
||||||
|
printf(" -h Show this help message and exit.\n");
|
||||||
|
printf("\n");
|
||||||
|
printf("Arguments:\n");
|
||||||
|
printf(" <seconds> Time (in seconds) to wait after inactivity before running the program.\n");
|
||||||
|
printf(" <program> Program to execute after the specified delay.\n");
|
||||||
|
printf(" [arguments...] Optional arguments to pass to the program.\n");
|
||||||
|
printf("\n");
|
||||||
|
printf("Examples:\n");
|
||||||
|
printf(" %s 5 ls -ls Execute 'ls -l' after 5 seconds of inactivity.\n", program_name);
|
||||||
|
printf(" %s -d 10 echo 'Hello' Run 'echo Hello' in daemon mode after 10 seconds of inactivity.\n", program_name);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
if (argc < 3) {
|
if (argc < 2) {
|
||||||
fprintf(stderr, "Usage: %s <seconds> <program> [arguments...]\n",
|
print_help(argv[0]);
|
||||||
argv[0]);
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for version or help flags
|
||||||
|
if (strcmp(argv[1], "-v") == 0) {
|
||||||
|
printf("%s: %s\n", argv[0], VERSION);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(argv[1], "-h") == 0) {
|
||||||
|
print_help(argv[0]);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for daemon mode
|
||||||
|
int daemon_mode = 0;
|
||||||
|
int arg_offset = 1;
|
||||||
|
|
||||||
|
if (strcmp(argv[1], "-d") == 0) {
|
||||||
|
daemon_mode = 1;
|
||||||
|
arg_offset = 2; // Adjust argument offset for parsing other parameters
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc < arg_offset + 2) {
|
||||||
|
print_help(argv[0]);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate the first parameter (wait time)
|
// Validate the first parameter (wait time)
|
||||||
char *endptr;
|
char *endptr;
|
||||||
long wait_time = strtol(argv[1], &endptr, 10);
|
long wait_time = strtol(argv[arg_offset], &endptr, 10);
|
||||||
|
|
||||||
// Check for valid integer input
|
|
||||||
if (*endptr != '\0' || wait_time <= 0 || wait_time > INT_MAX) {
|
if (*endptr != '\0' || wait_time <= 0 || wait_time > INT_MAX) {
|
||||||
fprintf(stderr,
|
fprintf(stderr, "Error: First argument must be a positive integer within the range 1 to %d.\n", INT_MAX);
|
||||||
"Error: First argument must be a positive integer within the range 1 to %d.\n",
|
|
||||||
INT_MAX);
|
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Safely cast the wait_time to an int (it's safe after the above check)
|
// Safely cast the wait_time to an int
|
||||||
int wait_time_seconds = (int)wait_time;
|
int wait_time_seconds = (int)wait_time;
|
||||||
|
|
||||||
// Initialize X11 display
|
// Initialize X11 display
|
||||||
|
|
@ -47,8 +90,7 @@ INT_MAX);
|
||||||
// Check for XInput2 support
|
// Check for XInput2 support
|
||||||
int opcode, event, error;
|
int opcode, event, error;
|
||||||
if (!XQueryExtension(display, "XInputExtension", &opcode, &event, &error)) {
|
if (!XQueryExtension(display, "XInputExtension", &opcode, &event, &error)) {
|
||||||
fprintf(stderr,
|
fprintf(stderr, "Error: X Input Extension is not supported on this display.\n");
|
||||||
"Error: X Input Extension is not supported on this display.\n");
|
|
||||||
XCloseDisplay(display);
|
XCloseDisplay(display);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
@ -73,49 +115,61 @@ INT_MAX);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timer logic with input monitoring
|
do {
|
||||||
time_t start_time, current_time;
|
// Timer logic with input monitoring
|
||||||
start_time = time(NULL);
|
time_t start_time, current_time;
|
||||||
|
start_time = time(NULL);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
current_time = time(NULL);
|
current_time = time(NULL);
|
||||||
|
|
||||||
// Check if the timer has expired
|
// Check if the timer has expired
|
||||||
if (current_time - start_time >= wait_time_seconds) {
|
if (current_time - start_time >= wait_time_seconds) {
|
||||||
break;
|
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for input events
|
||||||
|
while (XPending(display) > 0) {
|
||||||
|
XEvent event;
|
||||||
|
XNextEvent(display, &event);
|
||||||
|
|
||||||
|
if (event.xcookie.type == GenericEvent &&
|
||||||
|
event.xcookie.extension == opcode &&
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sleep briefly to reduce CPU usage
|
// Execute the program with optional arguments
|
||||||
usleep(10000); // 10 milliseconds
|
pid_t pid = fork();
|
||||||
}
|
if (pid == 0) {
|
||||||
|
execvp(argv[arg_offset + 1], &argv[arg_offset + 1]);
|
||||||
|
|
||||||
|
// If execvp returns, an error occurred
|
||||||
|
perror("Error executing program");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
} else if (pid < 0) {
|
||||||
|
perror("Error forking to execute program");
|
||||||
|
} else {
|
||||||
|
// Wait for the child process to finish
|
||||||
|
waitpid(pid, NULL, 0);
|
||||||
|
}
|
||||||
|
} while (daemon_mode);
|
||||||
|
|
||||||
// Close the X display
|
// Close the X display
|
||||||
XCloseDisplay(display);
|
XCloseDisplay(display);
|
||||||
|
|
||||||
// Execute the program with optional arguments
|
return EXIT_SUCCESS;
|
||||||
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