mirror of
https://github.com/morgan9e/power-overlay
synced 2026-04-14 00:14:06 +09:00
init
This commit is contained in:
32
README.md
Normal file
32
README.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# power-overlay
|
||||
|
||||
because reading Intel RAPL requires root (and also is NOT safe to make it globally readable)
|
||||
|
||||
- esc/q to exit
|
||||
- +/- to change font size
|
||||
- up/down to change opacity
|
||||
- drag to move
|
||||
|
||||
<img width="250" alt="image" src="https://github.com/user-attachments/assets/5d390a20-6156-4857-acf4-bf7259e0adcf" />
|
||||
|
||||
### compile
|
||||
|
||||
```
|
||||
gcc main.c -o power-overlay `sdl2-config --cflags --libs` -lSDL2_gfx -lm
|
||||
```
|
||||
|
||||
### if you want to add a desktop file
|
||||
|
||||
power-overlay.sh
|
||||
```bash
|
||||
#!/bin/bash
|
||||
pkexec env DISPLAY=$DISPLAY XAUTHORITY=$XAUTHORITY /home/user/.local/bin/power-overlay
|
||||
```
|
||||
|
||||
power-overlay.desktop
|
||||
```
|
||||
[Desktop Entry]
|
||||
Name=power overlay
|
||||
Exec=power-overlay
|
||||
Type=Application
|
||||
```
|
||||
155
main.c
Normal file
155
main.c
Normal file
@@ -0,0 +1,155 @@
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL2_gfxPrimitives.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define ENERGY_PATH "/sys/class/powercap/intel-rapl:0/energy_uj"
|
||||
|
||||
static uint64_t read_energy_uj(const char *path) {
|
||||
FILE *f = fopen(path, "r");
|
||||
if (!f) return UINT64_MAX;
|
||||
unsigned long long val = 0ULL;
|
||||
if (fscanf(f, "%llu", &val) != 1) {
|
||||
fclose(f);
|
||||
return UINT64_MAX;
|
||||
}
|
||||
fclose(f);
|
||||
return (uint64_t)val;
|
||||
}
|
||||
|
||||
static double cur_time() {
|
||||
struct timespec ts; clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return (double)ts.tv_sec + (double)ts.tv_nsec / 1e9;
|
||||
}
|
||||
|
||||
int running = 1;
|
||||
double current_watts = 0.0;
|
||||
SDL_mutex *watt_lock;
|
||||
|
||||
int watt_reader(void *arg) {
|
||||
const char *path = (const char *)arg;
|
||||
uint64_t prev_uj = read_energy_uj(path);
|
||||
double prev_t = cur_time();
|
||||
while (running) {
|
||||
usleep(100000);
|
||||
uint64_t curr_uj = read_energy_uj(path);
|
||||
if (curr_uj == UINT64_MAX) continue;
|
||||
double curr_t = cur_time();
|
||||
double dJ = (double)((curr_uj >= prev_uj) ? (curr_uj - prev_uj) : 0ULL) / 1e6;
|
||||
double dt = curr_t - prev_t;
|
||||
double watts = (dt > 0) ? dJ / dt : 0.0;
|
||||
prev_uj = curr_uj;
|
||||
prev_t = curr_t;
|
||||
SDL_LockMutex(watt_lock);
|
||||
current_watts = watts;
|
||||
SDL_UnlockMutex(watt_lock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
const char *energy_path = (argc > 1) ? argv[1] : ENERGY_PATH;
|
||||
int refresh_ms = (argc > 2) ? atoi(argv[2]) : 1000;
|
||||
float window_opacity = 1.0f;
|
||||
|
||||
SDL_SetHint(SDL_HINT_X11_WINDOW_TYPE, "_NET_WM_WINDOW_TYPE_DOCK");
|
||||
SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0");
|
||||
|
||||
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_EVENTS) != 0) return 1;
|
||||
|
||||
SDL_Window *win = SDL_CreateWindow("overlay",
|
||||
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
||||
160, 36,
|
||||
SDL_WINDOW_BORDERLESS | SDL_WINDOW_ALWAYS_ON_TOP | SDL_WINDOW_ALLOW_HIGHDPI);
|
||||
|
||||
SDL_SetWindowAlwaysOnTop(win, SDL_TRUE);
|
||||
|
||||
SDL_Renderer *ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
|
||||
if (!ren) ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_SOFTWARE);
|
||||
|
||||
SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetWindowOpacity(win, window_opacity);
|
||||
|
||||
int fontScale = 2;
|
||||
const int pad = 8;
|
||||
|
||||
watt_lock = SDL_CreateMutex();
|
||||
SDL_Thread *reader = SDL_CreateThread(watt_reader, "reader", (void *)energy_path);
|
||||
|
||||
int dragging = 0, drag_off_x = 0, drag_off_y = 0;
|
||||
char text[64] = "--.-- W";
|
||||
uint32_t next_tick = SDL_GetTicks();
|
||||
|
||||
while (running) {
|
||||
SDL_Event e;
|
||||
while (SDL_PollEvent(&e)) {
|
||||
switch (e.type) {
|
||||
case SDL_QUIT: running = 0; break;
|
||||
case SDL_KEYDOWN:
|
||||
switch (e.key.keysym.sym) {
|
||||
case SDLK_ESCAPE: case SDLK_q: running = 0; break;
|
||||
case SDLK_UP: window_opacity += 0.05f; if (window_opacity > 1.0f) window_opacity = 1.0f; SDL_SetWindowOpacity(win, window_opacity); break;
|
||||
case SDLK_DOWN: window_opacity -= 0.05f; if (window_opacity < 0.2f) window_opacity = 0.2f; SDL_SetWindowOpacity(win, window_opacity); break;
|
||||
case SDLK_RIGHT: refresh_ms += 100; if (refresh_ms > 5000) refresh_ms = 5000; break;
|
||||
case SDLK_LEFT: refresh_ms -= 100; if (refresh_ms < 100) refresh_ms = 100; break;
|
||||
case SDLK_EQUALS: case SDLK_PLUS: fontScale++; if (fontScale>6) fontScale=6; break;
|
||||
case SDLK_MINUS: if (fontScale>1) fontScale--; break;
|
||||
}
|
||||
break;
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
if (e.button.button == SDL_BUTTON_LEFT) {
|
||||
dragging = 1;
|
||||
int wx, wy; SDL_GetWindowPosition(win, &wx, &wy);
|
||||
int mx, my; SDL_GetGlobalMouseState(&mx, &my);
|
||||
drag_off_x = mx - wx; drag_off_y = my - wy;
|
||||
}
|
||||
break;
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
if (e.button.button == SDL_BUTTON_LEFT) dragging = 0;
|
||||
break;
|
||||
case SDL_MOUSEMOTION:
|
||||
if (dragging) {
|
||||
int mx, my; SDL_GetGlobalMouseState(&mx, &my);
|
||||
SDL_SetWindowPosition(win, mx - drag_off_x, my - drag_off_y);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
uint32_t now = SDL_GetTicks();
|
||||
if ((int)(now - next_tick) >= 0) {
|
||||
SDL_LockMutex(watt_lock);
|
||||
double watts = current_watts;
|
||||
SDL_UnlockMutex(watt_lock);
|
||||
snprintf(text, sizeof(text), "%.2f W", watts);
|
||||
int baseW = (int)strlen(text) * 8;
|
||||
int baseH = 8;
|
||||
int w = baseW * fontScale + pad*2;
|
||||
int h = baseH * fontScale + pad*2;
|
||||
SDL_SetWindowSize(win, w, h);
|
||||
SDL_SetRenderDrawColor(ren, 0, 0, 0, 0);
|
||||
SDL_RenderClear(ren);
|
||||
SDL_Texture *tmp = SDL_CreateTexture(ren, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, baseW, baseH);
|
||||
SDL_SetTextureBlendMode(tmp, SDL_BLENDMODE_BLEND);
|
||||
SDL_SetRenderTarget(ren, tmp);
|
||||
SDL_SetRenderDrawColor(ren, 0,0,0,0); SDL_RenderClear(ren);
|
||||
stringRGBA(ren, 0, 0, text, 255, 255, 255, 255);
|
||||
SDL_SetRenderTarget(ren, NULL);
|
||||
SDL_Rect dst = { pad, pad, baseW*fontScale, baseH*fontScale };
|
||||
SDL_RenderCopy(ren, tmp, NULL, &dst);
|
||||
SDL_DestroyTexture(tmp);
|
||||
SDL_RenderPresent(ren);
|
||||
next_tick = now + (uint32_t)refresh_ms;
|
||||
}
|
||||
SDL_Delay(10);
|
||||
}
|
||||
running = 0;
|
||||
SDL_WaitThread(reader, NULL);
|
||||
SDL_DestroyMutex(watt_lock);
|
||||
SDL_DestroyRenderer(ren);
|
||||
SDL_DestroyWindow(win);
|
||||
SDL_Quit();
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user