diff options
author | Tom Smeding <tom@tomsmeding.com> | 2022-02-27 10:05:38 +0100 |
---|---|---|
committer | Tom Smeding <tom@tomsmeding.com> | 2022-02-27 10:05:38 +0100 |
commit | 4be4ac3e289fe4c555877841fa76d7b514625e1f (patch) | |
tree | e35cba9b9a279afe38075f0878a2ec0ce5ad008b | |
parent | 6412e6fd0f9f306b6b488191623c3ad0c6ea553c (diff) |
ddcutil support
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | brightness.c | 76 | ||||
-rw-r--r-- | brightness.cpp | 236 |
4 files changed, 241 insertions, 80 deletions
@@ -1 +1,2 @@ +.ccls-cache/ brightness @@ -1,5 +1,5 @@ -CC = gcc -CFLAGS = -Wall -Wextra -O2 -std=c11 -fwrapv +CXX = g++ +CXXFLAGS = -Wall -Wextra -O2 -std=c++11 INSTALL_DIR = $(HOME)/prefix/bin BIN = brightness @@ -16,5 +16,5 @@ install: sudo chmod +s $(INSTALL_DIR)/brightness -$(BIN): brightness.c $(wildcard *.h) - $(CC) $(CFLAGS) $(filter %.c,$^) -o $@ +$(BIN): brightness.cpp $(wildcard *.h) + $(CXX) $(CXXFLAGS) $(filter %.cpp,$^) -o $@ diff --git a/brightness.c b/brightness.c deleted file mode 100644 index feee058..0000000 --- a/brightness.c +++ /dev/null @@ -1,76 +0,0 @@ -// By Tom Smeding (2016) -// modified for new laptop (2017) - -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <string.h> -#include <unistd.h> -#include <sys/types.h> - -#define INCREMENT 100 - -__attribute__((noreturn)) -__attribute__((format (printf, 1, 2))) -void die(const char *format,...){ - va_list ap; - va_start(ap,format); - vprintf(format,ap); - va_end(ap); - putchar('\n'); - exit(1); -} - -int get_max_brightness(void){ - FILE *f=fopen("/sys/class/backlight/intel_backlight/max_brightness","r"); - if(!f)die("Could not open max_brightness file"); - int n; - fscanf(f,"%d",&n); - fclose(f); - return n; -} - -int get_brightness(void){ - FILE *f=fopen("/sys/class/backlight/intel_backlight/brightness","r"); - if(!f)die("Could not open brightness file"); - int n; - fscanf(f,"%d",&n); - fclose(f); - return n; -} - -void set_brightness(int n){ - FILE *f=fopen("/sys/class/backlight/intel_backlight/brightness","w"); - if(!f)die("Could not open brightness file"); - fprintf(f,"%d",n); - fflush(f); - fclose(f); -} - -int main(int argc,char **argv){ - uid_t uid=geteuid(); - if(uid!=0){ - printf("brightness will only work with root.\n"); - return 1; - } - - if(argc==1){ - printf("max: %d\n",get_max_brightness()); - printf("current: %d\n",get_brightness()); - } else if(argc==2){ - int n; - if(strcmp(argv[1],"-")==0){ - n=get_brightness()-INCREMENT; - if(n<0)n=0; - } else if(strcmp(argv[1],"+")==0){ - n=get_brightness()+INCREMENT; - int mx=get_max_brightness(); - if(n>mx)n=mx; - } else { - char *endp; - n=strtol(argv[1],&endp,10); - if(argv[1][0]=='\0'||*endp!='\0')die("Invalid number '%s'",argv[1]); - } - set_brightness(n); - } -} diff --git a/brightness.cpp b/brightness.cpp new file mode 100644 index 0000000..c06427d --- /dev/null +++ b/brightness.cpp @@ -0,0 +1,236 @@ +// By Tom Smeding (2016) +// modified for new laptop (2017) +// modified for ddcutil support (2022) + +#include <iostream> +#include <fstream> +#include <sstream> +#include <string> +#include <vector> +#include <cstdlib> +#include <cstdarg> +#include <cstring> +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/wait.h> + +std::string read_process(const char *procname, const std::vector<const char*> &args) { + int pi[2]; + int ret = pipe(pi); + if (ret != 0) { + perror("pipe"); + exit(1); + } + + pid_t pid = fork(); + if (pid < 0) { + perror("fork"); + exit(1); + } + if (pid == 0) { + dup2(pi[1], 1); + close(pi[0]); + close(pi[1]); + char **argv = new char*[args.size() + 2]; + argv[0] = strdup(procname); + for (size_t i = 0; i < args.size(); i++) { + argv[i + 1] = strdup(args[i]); + } + argv[args.size() + 1] = nullptr; + fprintf(stderr, "procname = <%s>\n", procname); + for (size_t i = 0; i < args.size() + 2; i++) { + fprintf(stderr, "argv[%zu] = <%s>\n", i, argv[i]); + } + execvp(procname, argv); + perror("execvp"); + exit(1); + } + + close(pi[1]); + std::string output; + while (true) { + output.resize(output.size() + 1024); + ssize_t nr = read(pi[0], &output[output.size() - 1024], 1024); + if (nr < 0) { + if (errno == EINTR) continue; + perror("read"); + exit(1); + } + if (nr == 0) break; + output.resize(output.size() - 1024 + nr); + } + close(pi[0]); + + while (true) { + int status; + int ret = waitpid(pid, &status, 0); + if (ret < 0) { + if (errno == EINTR) continue; + perror("waitpid"); + exit(1); + } + if (WIFEXITED(status)) break; + } + + return output; +} + +struct Backlight { + virtual ~Backlight() {} + + virtual int increment() const = 0; + + virtual bool suitable() = 0; + virtual int get_max_brightness() = 0; + virtual int get_brightness() = 0; + virtual void set_brightness(int n) = 0; + virtual void add_brightness(int n) { + n = get_brightness() + n; + if (n < 0) n = 0; + int maxval = get_max_brightness(); + if (n > maxval) n = maxval; + set_brightness(n); + } + virtual int convert_absolute_brightness(int n) = 0; // to percentage +}; + +struct IntelBacklight : public Backlight { +private: + int read_int_file(const char *fname) { + std::ifstream f{fname}; + if (!f) { + std::cerr << "Could not open brightness file" << std::endl; + exit(1); + } + int n; + f >> n; + return n; + } + +public: + int increment() const { return 100; } + + bool suitable() { + struct stat st; + int ret = stat("/sys/class/backlight/intel_backlight", &st); + return ret == 0; + } + + int get_max_brightness() { + return read_int_file("/sys/class/backlight/intel_backlight/max_brightness"); + } + + int get_brightness() { + return read_int_file("/sys/class/backlight/intel_backlight/brightness"); + } + + void set_brightness(int n) { + std::ofstream f{"/sys/class/backlight/intel_backlight/brightness"}; + if (!f) { + std::cerr << "Could not open brightness file" << std::endl; + exit(1); + } + f << n; + } + + int convert_absolute_brightness(int n) { + return n * 10; + } +}; + +struct DDCBacklight : public Backlight { +private: + bool have_read = false; + int brvalue, brmaxvalue; + + void read_current() { + std::string output = read_process("ddcutil", {"getvcp", "-t", "10"}); + std::istringstream ss{output}; + std::string word; + ss >> word; + if (word != "VCP") goto format_err; + ss >> word; + if (word != "10") goto format_err; + ss >> word; + if (word != "C") goto format_err; + ss >> brvalue; + ss >> brmaxvalue; + if (!ss) goto format_err; + have_read = true; + return; + + format_err: + std::cerr << "Invalid format from ddcutil" << std::endl; + exit(1); + } + +public: + int increment() const { return 10; } + + bool suitable() { + struct stat st; + int ret = stat("/usr/bin/ddcutil", &st); + return ret == 0; + } + + int get_brightness() { + if (!have_read) read_current(); + return brvalue; + } + + int get_max_brightness() { + if (!have_read) read_current(); + return brmaxvalue; + } + + void set_brightness(int n) { + std::string argstr = std::to_string(n); + read_process("ddcutil", {"setvcp", "10", argstr.data()}); + } + + void add_brightness(int n) { + if (n == 0) return; + std::string absargstr = std::to_string(abs(n)); + read_process("ddcutil", {"setvcp", "10", n > 0 ? "+" : "-", absargstr.data()}); + } + + int convert_absolute_brightness(int n) { + return n; + } +}; + +int main(int argc,char **argv){ + uid_t uid = geteuid(); + if (uid != 0) { + std::cerr << "brightness will only work with root." << std::endl; + return 1; + } + + std::vector<Backlight*> instances{new IntelBacklight{}, new DDCBacklight{}}; + Backlight *backlight = nullptr; + for (Backlight *b : instances) if (b->suitable()) { backlight = b; break; } + if (!backlight) { + std::cerr << "No idea how to control your monitor, sorry" << std::endl; + return 1; + } + + if (argc == 1) { + std::cout << "max: " << backlight->get_max_brightness() << std::endl; + std::cout << "current: " << backlight->get_brightness() << std::endl; + } else if (argc == 2) { + if (strcmp(argv[1], "-") == 0) { + backlight->add_brightness(-backlight->increment()); + } else if (strcmp(argv[1], "+") == 0) { + backlight->add_brightness(backlight->increment()); + } else { + char *endp; + int n = strtol(argv[1], &endp, 10); + if (argv[1][0] == '\0' || *endp != '\0') { + std::cerr << "Invalid number '" << argv[1] << "'" << std::endl; + } + backlight->set_brightness(backlight->convert_absolute_brightness(n)); + } + } +} |