initial commit
This commit is contained in:
commit
ab90291f93
|
|
@ -0,0 +1,63 @@
|
|||
/compile_commands.json
|
||||
/sleeptimer
|
||||
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/c
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=c
|
||||
|
||||
### C ###
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.elf
|
||||
|
||||
# Linker output
|
||||
*.ilk
|
||||
*.map
|
||||
*.exp
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.a
|
||||
*.la
|
||||
*.lo
|
||||
|
||||
# Shared objects (inc. Windows DLLs)
|
||||
*.dll
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
*.su
|
||||
*.idb
|
||||
*.pdb
|
||||
|
||||
# Kernel Module Compile Results
|
||||
*.mod*
|
||||
*.cmd
|
||||
.tmp_versions/
|
||||
modules.order
|
||||
Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/c
|
||||
|
||||
/.cache
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
PROGRAM = sleeptimer
|
||||
|
||||
LDFLAGS = $(shell pkg-config --libs dbus-1 x11 xscrnsaver)
|
||||
CFLAGS = --std=gnu17 -Wall -Werror -Wextra -Wpedantic -g $(shell pkg-config --cflags dbus-1 x11 xscrnsaver)
|
||||
|
||||
objs = idle.o main.o dbus_wrapper.o suspend.o echo.o sleeptimer.o duration.o actions.o
|
||||
|
||||
sleeptimer: $(objs)
|
||||
$(CC) $(CFLAGS) $(LDFLAGS) -o $(PROGRAM) $(objs)
|
||||
|
||||
$(objs):
|
||||
|
||||
clean:
|
||||
rm $(PROGRAM) $(objs)
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "echo.h"
|
||||
#include "stdio.h"
|
||||
#include "suspend.h"
|
||||
|
||||
#include "actions.h"
|
||||
|
||||
const char *ACTION_ECHO = "echo";
|
||||
const char *ACTION_SUSPEND = "suspend";
|
||||
|
||||
enum Action parseAction(const char *action) {
|
||||
enum Action a = ActionSuspend;
|
||||
if (strcmp(action, ACTION_ECHO) == 0) {
|
||||
a = ActionEcho;
|
||||
} else if (strcmp(action, ACTION_SUSPEND) == 0) {
|
||||
a = ActionSuspend;
|
||||
} else {
|
||||
a = ActionUnknown;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
actionCallback getActionCallback(enum Action action) {
|
||||
actionCallback callback = suspend;
|
||||
switch (action) {
|
||||
case ActionSuspend:
|
||||
callback = suspend;
|
||||
break;
|
||||
case ActionEcho:
|
||||
callback = echo;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Unknown method\n");
|
||||
return NULL;
|
||||
}
|
||||
return callback;
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#ifndef _ACTIONS_H
|
||||
#define _ACTIONS_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef bool (*actionCallback)(void);
|
||||
enum Action { ActionUnknown, ActionSuspend, ActionEcho };
|
||||
actionCallback getActionCallback(enum Action action);
|
||||
enum Action parseAction(const char *action);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "dbus_wrapper.h"
|
||||
|
||||
DBusError dbusError;
|
||||
|
||||
DBusConnection *conn;
|
||||
|
||||
void handleDbusError(DBusError *err, const char *message) {
|
||||
if (dbus_error_is_set(err)) {
|
||||
fprintf(stderr, "DBus Error - %s - %s\n", message, err->message);
|
||||
dbus_error_free(err);
|
||||
}
|
||||
}
|
||||
|
||||
DBusConnection *dbusConnect(void) {
|
||||
dbus_error_init(&dbusError);
|
||||
|
||||
if (NULL == conn) {
|
||||
return conn;
|
||||
}
|
||||
|
||||
conn = dbus_bus_get(DBUS_BUS_SYSTEM, &dbusError);
|
||||
if (dbus_error_is_set(&dbusError)) {
|
||||
handleDbusError(&dbusError, "Could not connect");
|
||||
dbus_error_free(&dbusError);
|
||||
}
|
||||
if (NULL == conn) {
|
||||
return NULL;
|
||||
}
|
||||
return conn;
|
||||
}
|
||||
|
||||
bool dbusCallMethod(DBusConnection *conn, const char *bus_name,
|
||||
const char *path, const char *iface, const char *method) {
|
||||
DBusMessage *msg;
|
||||
DBusMessageIter args;
|
||||
|
||||
msg = dbus_message_new_method_call(bus_name, path, iface, method);
|
||||
if (NULL == msg) {
|
||||
handleDbusError(&dbusError, "Could not initialize message");
|
||||
return false;
|
||||
}
|
||||
|
||||
// append arguments
|
||||
dbus_message_iter_init_append(msg, &args);
|
||||
int val = 0;
|
||||
if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_BOOLEAN, &val)) {
|
||||
handleDbusError(&dbusError, "Could not append argument to method call");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!dbus_connection_send_with_reply_and_block(
|
||||
conn, msg, -1, &dbusError)) { // -1 is default timeout
|
||||
handleDbusError(&dbusError, "Could not send message");
|
||||
dbus_message_unref(msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
dbus_connection_flush(conn);
|
||||
|
||||
// free message
|
||||
dbus_message_unref(msg);
|
||||
|
||||
dbus_connection_close(conn);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef _DBUS_WRAPPER_H
|
||||
#define _DBUS_WRAPPER_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <dbus/dbus.h>
|
||||
|
||||
void handleDbusError(DBusError *err, const char *message);
|
||||
DBusConnection *dbusConnect(void);
|
||||
bool dbusCallMethod(DBusConnection *conn, const char *bus_name, const char *path,
|
||||
const char *iface, const char *method);
|
||||
|
||||
#endif // !_DBUS_WRAPPER_H
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
#include "duration.h"
|
||||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
#include <stdio.h>
|
||||
|
||||
enum DurationParserState {
|
||||
DURATION_PARSER_STATE_INITIAL,
|
||||
DURATION_PARSER_STATE_NUMBER,
|
||||
DURATION_PARSER_STATE_SECOND,
|
||||
DURATION_PARSER_STATE_MINUTE,
|
||||
DURATION_PARSER_STATE_HOUR,
|
||||
DURATION_PARSER_STATE_EOS,
|
||||
};
|
||||
|
||||
Duration parseDuration(const char *duration) {
|
||||
enum DurationParserState state = DURATION_PARSER_STATE_INITIAL;
|
||||
Duration d;
|
||||
d.seconds = 0;
|
||||
d.hours = 0;
|
||||
d.minutes = 0;
|
||||
char numBuf[32] = "0";
|
||||
for (const char *c = duration; *c; c++) {
|
||||
if (state == DURATION_PARSER_STATE_INITIAL) {
|
||||
if (*c >= '0' && *c <= '9') {
|
||||
state = DURATION_PARSER_STATE_NUMBER;
|
||||
} else if (*c == 's' || *c == 'S') {
|
||||
state = DURATION_PARSER_STATE_SECOND;
|
||||
} else if (*c == 'm' || *c == 'M') {
|
||||
state = DURATION_PARSER_STATE_MINUTE;
|
||||
} else if (*c == 'h' || *c == 'H') {
|
||||
state = DURATION_PARSER_STATE_HOUR;
|
||||
}
|
||||
}
|
||||
if (state == DURATION_PARSER_STATE_NUMBER) {
|
||||
const char *start = c;
|
||||
while (*c >= '0' && *c <= '9') {
|
||||
numBuf[c - start] = *c;
|
||||
c++;
|
||||
}
|
||||
c--;
|
||||
state = DURATION_PARSER_STATE_INITIAL;
|
||||
} else if (state == DURATION_PARSER_STATE_SECOND) {
|
||||
d.seconds = atoi(numBuf);
|
||||
strncpy(numBuf, "0", 32);
|
||||
state = DURATION_PARSER_STATE_INITIAL;
|
||||
} else if (state == DURATION_PARSER_STATE_MINUTE) {
|
||||
d.minutes = atoi(numBuf);
|
||||
strncpy(numBuf, "0", 32);
|
||||
state = DURATION_PARSER_STATE_INITIAL;
|
||||
} else if (state == DURATION_PARSER_STATE_HOUR) {
|
||||
d.hours = atoi(numBuf);
|
||||
strncpy(numBuf, "0", 32);
|
||||
state = DURATION_PARSER_STATE_INITIAL;
|
||||
}
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
unsigned long durationToSeconds(const Duration *d) {
|
||||
return d->hours * 3600 + d->minutes * 60 + d->seconds;
|
||||
}
|
||||
|
||||
Duration secondsToDuration(unsigned long seconds) {
|
||||
Duration d;
|
||||
d.hours = seconds / 3600;
|
||||
d.minutes = (seconds % 3600) / 60;
|
||||
d.seconds = seconds % 60;
|
||||
return d;
|
||||
}
|
||||
|
||||
char* formatDuration(const Duration *d) {
|
||||
char buf[32];
|
||||
sprintf(buf, "%02lu:%02lu:%02lu", d->hours, d->minutes, d->seconds);
|
||||
return strdup(buf);
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef _DURATION_H
|
||||
#define _DURATION_H
|
||||
typedef struct {
|
||||
unsigned long seconds;
|
||||
unsigned long minutes;
|
||||
unsigned long hours;
|
||||
} Duration;
|
||||
|
||||
Duration parseDuration(const char *duration);
|
||||
unsigned long durationToSeconds(const Duration *duration);
|
||||
Duration secondsToDuration(unsigned long seconds);
|
||||
char* formatDuration(const Duration *duration);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
bool echo(void) {
|
||||
printf("Timer has ran out!\n");
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
#ifndef _ECHO_H
|
||||
#define _ECHO_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
bool echo(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": [
|
||||
"systems"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1710146030,
|
||||
"narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1712791164,
|
||||
"narHash": "sha256-3sbWO1mbpWsLepZGbWaMovSO7ndZeFqDSdX0hZ9nVyw=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "1042fd8b148a9105f3c0aca3a6177fd1d9360ba5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nixos",
|
||||
"ref": "nixos-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs",
|
||||
"systems": "systems"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1680978846,
|
||||
"narHash": "sha256-Gtqg8b/v49BFDpDetjclCYXm8mAnTrUzR0JnE2nv5aw=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "x86_64-linux",
|
||||
"rev": "2ecfcac5e15790ba6ce360ceccddb15ad16d08a8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "x86_64-linux",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||
systems.url = "github:nix-systems/x86_64-linux";
|
||||
flake-utils = {
|
||||
url = "github:numtide/flake-utils";
|
||||
inputs.systems.follows = "systems";
|
||||
};
|
||||
};
|
||||
outputs = {
|
||||
nixpkgs,
|
||||
flake-utils,
|
||||
...
|
||||
}: let
|
||||
drv = {
|
||||
stdenv,
|
||||
lib,
|
||||
libX11,
|
||||
libXScrnSaver,
|
||||
dbus,
|
||||
pkg-config,
|
||||
...
|
||||
}:
|
||||
stdenv.mkDerivation {
|
||||
pname = "sleeptimer";
|
||||
version = "0.0.1";
|
||||
src = lib.cleanSource ./.;
|
||||
nativeBuildInputs = [pkg-config];
|
||||
buildInputs = [libX11 libXScrnSaver dbus.dev];
|
||||
installPhase = ''
|
||||
mkdir -p $out/bin
|
||||
cp sleeptimer $out/bin
|
||||
'';
|
||||
};
|
||||
in
|
||||
flake-utils.lib.eachDefaultSystem (system: let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
};
|
||||
llvm = pkgs.llvmPackages_latest;
|
||||
package = pkgs.callPackage drv {inherit (llvm) stdenv;};
|
||||
in {
|
||||
devShells.default = pkgs.mkShell.override {inherit (llvm) stdenv;} {
|
||||
inputsFrom = [package];
|
||||
packages = with pkgs; [
|
||||
bear
|
||||
clang-tools
|
||||
zlib
|
||||
lzma
|
||||
icu74
|
||||
];
|
||||
};
|
||||
packages = {
|
||||
default = package;
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/scrnsaver.h>
|
||||
|
||||
/* Get the idle time from the X Screen Saver extionsion.
|
||||
*
|
||||
* Returns:
|
||||
* long: Idle time in milliseconds
|
||||
*/
|
||||
Display *xorgDisplay;
|
||||
XScreenSaverInfo *xorgScreensaverInfo;
|
||||
|
||||
unsigned long getIdleTime(void) {
|
||||
unsigned long idle = 0;
|
||||
if (NULL == xorgDisplay) {
|
||||
xorgDisplay = XOpenDisplay(NULL);
|
||||
}
|
||||
|
||||
if (!xorgDisplay) {
|
||||
return idle;
|
||||
}
|
||||
|
||||
if (NULL == xorgScreensaverInfo) {
|
||||
xorgScreensaverInfo = XScreenSaverAllocInfo();
|
||||
}
|
||||
XScreenSaverQueryInfo(xorgDisplay, DefaultRootWindow(xorgDisplay), xorgScreensaverInfo);
|
||||
|
||||
idle = xorgScreensaverInfo->idle;
|
||||
|
||||
return idle;
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef _IDLE_H
|
||||
#define _IDLE_H
|
||||
|
||||
long getIdleTime(void);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "actions.h"
|
||||
#include "duration.h"
|
||||
#include "sleeptimer.h"
|
||||
#include "stdio.h"
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
time_t start = time(NULL);
|
||||
|
||||
Duration duration = {.minutes = 30};
|
||||
if (argc >= 2) {
|
||||
duration = parseDuration(argv[1]);
|
||||
}
|
||||
|
||||
enum Action action = ActionEcho;
|
||||
if (argc >= 3) {
|
||||
action = parseAction(argv[2]);
|
||||
}
|
||||
|
||||
printf("Sleep timer set for \"%s\"\n", formatDuration(&duration));
|
||||
|
||||
unsigned long seconds = durationToSeconds(&duration);
|
||||
actionCallback callback = getActionCallback(action);
|
||||
if (!sleeptimer(seconds, callback)) {
|
||||
return 1;
|
||||
}
|
||||
time_t end = time(NULL);
|
||||
Duration runtime = secondsToDuration(end - start);
|
||||
printf("Program ran for \"%s\"\n", formatDuration(&runtime));
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#include "actions.h"
|
||||
#include "idle.h"
|
||||
#include <stdbool.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
bool sleeptimer(unsigned long seconds, actionCallback callback) {
|
||||
unsigned long millis = seconds * 1000;
|
||||
unsigned long idleTime = getIdleTime();
|
||||
|
||||
struct timespec sleepTime = {.tv_sec = 0, .tv_nsec = 100 * 1000000};
|
||||
while (idleTime < millis) {
|
||||
idleTime = getIdleTime();
|
||||
nanosleep(&sleepTime, NULL);
|
||||
}
|
||||
|
||||
if (!(*callback)()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
#ifndef __SLEEPTIMER_H
|
||||
#define __SLEEPTIMER_H
|
||||
|
||||
#include "actions.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
bool sleeptimer(unsigned long seconds, actionCallback callback);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
#include "dbus_wrapper.h"
|
||||
|
||||
bool suspend(void) {
|
||||
const char *bus_name = "org.freedesktop.login1";
|
||||
const char *path = "/org/freedesktop/login1";
|
||||
const char *iface = "org.freedesktop.login1.Manager";
|
||||
const char *method = "Suspend";
|
||||
|
||||
DBusConnection *conn = dbusConnect();
|
||||
if (NULL == conn) {
|
||||
return false;
|
||||
}
|
||||
|
||||
dbusCallMethod(conn, bus_name, path, iface, method);
|
||||
return true;
|
||||
}
|
||||
Loading…
Reference in New Issue