Files
dwm/vene.cpp
T
2026-07-30 11:54:49 +03:00

344 lines
7.1 KiB
C++

#include <time.h>
#include <cstring>
#include <cstdlib>
#include <fstream>
#include <string>
#include <chrono>
#include <filesystem>
#include <cppipe/commands.hpp>
#include <X11/X.h>
// #include "vene.h"
#include "vene_env.h"
extern "C"
{
#include "slstatus/slstatus.h"
}
using namespace std;
using namespace std::chrono;
using namespace std::chrono_literals;
namespace fs = std::filesystem;
char* HOME;
char SCREEN_CAPS_DIR[64];
namespace
{
time_point<system_clock> next_update;
bool has_child;
Proc child;
Cmd amixer("amixer");
Cmd low_battery_notify("notify-send", "--urgency=critical", "Battery Low");
}
extern "C"
{
// from dwm
struct Monitor;
typedef struct {
const char *symbol;
void (*arrange)(Monitor *);
} Layout;
struct Client {
char name[256];
float mina, maxa;
int x, y, w, h;
int oldx, oldy, oldw, oldh;
int basew, baseh, incw, inch, maxw, maxh, minw, minh, hintsvalid;
int bw, oldbw;
unsigned int tags;
int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
Client *next;
Client *snext;
Monitor *mon;
Window win;
};
struct Monitor {
char ltsymbol[16];
float mfact;
int nmaster;
int num;
int by; /* bar geometry */
int mx, my, mw, mh; /* screen size */
int wx, wy, ww, wh; /* window area */
unsigned int seltags;
unsigned int sellt;
unsigned int tagset[2];
int showbar;
int topbar;
Client *clients;
Client *sel;
Client *stack;
Monitor *next;
Window barwin;
const Layout *lt[2];
};
typedef union {
int i;
unsigned int ui;
float f;
const void *v;
} Arg;
extern Monitor *selmon;
void updatestatus();
void view(const Arg* arg);
// end
void vene_setup()
{
// Init vars
HOME = getenv("HOME");
strcpy(SCREEN_CAPS_DIR, HOME);
strcat(SCREEN_CAPS_DIR, "/screenshots/ss.png");
// strcpy(BOOKMARK_DIR, HOME);
// strcat(BOOKMARK_DIR, "/notes/bookmarks/web");
}
void vene_updatestatus(char status[])
{
using std::string;
static string new_stat;
new_stat.clear();
try
{
// Net
#if defined(__linux__)
for(const auto& dir_entry: fs::directory_iterator("/sys/class/net"))
{
string interface_state;
string interface = dir_entry.path().filename();
switch(interface[0])
{
case 'e': // if the name begins with 'e' its ethernet
ifstream(dir_entry.path() / "operstate") >> interface_state;
if(interface_state == "up")
new_stat += "🌐 ";
break;
case 'w': // 'w' means wifi
if(const char* ssid = wifi_essid(interface.c_str()); ssid) // Connected
{
// State
new_stat += "🛜";
new_stat += ssid;
new_stat += ' ';
// Quality percent
if(const char* perc = wifi_perc(interface.c_str()); perc)
{
new_stat += perc;
new_stat += "% ";
}
}
else // Disconnected
{
string wifi_state;
ifstream(dir_entry.path() / "flags") >> wifi_state;
if( wifi_state == "0x1003")
new_stat += "📡 ";
}
break;
}
}
#else
if(const char* ssid = wifi_essid("iwn0"); ssid)
{
new_stat += "🛜";
new_stat += ssid;
new_stat += ' ';
if(const char* perc = wifi_perc("iwn0"); perc)
{
new_stat += perc;
new_stat += "% ";
}
}
#endif
// Battery
string charge;
ifstream("/sys/class/power_supply/BAT0/capacity") >> charge;
if( !charge.empty() ) // If we have a charge we have a battery
{
string state;
ifstream("/sys/class/power_supply/BAT0/status") >> state;
const char* remaining = "";
if(state == "Discharging")
{
new_stat += "🔋";
remaining = battery_remaining("BAT0");
// Low battery warning
if(remaining && atoi(charge.c_str()) < 15)
run(low_battery_notify); // todo: use lib notify
}
else
new_stat += "🔌";
new_stat += charge;
new_stat += "% ";
new_stat += remaining;
new_stat += ' ';
}
}
catch(...){ cerr << "EXCEPT\n"; }
// Volume
string amix_out = $(amixer + "get" + AUDIO_DEV);
size_t vol_bracket = amix_out.find('[');
if(vol_bracket != string::npos)
{
bool is_muted = amix_out.find("[on]") == string::npos;
new_stat += is_muted ? "🔇" : "🔉";
size_t first_digit = vol_bracket + 1;
size_t close_bracket = amix_out.find(']', first_digit);
new_stat.append(amix_out, first_digit, close_bracket - first_digit);
new_stat += ' ';
}
// Time
time_t rawtime;
struct tm * timeinfo;
time ( &rawtime );
timeinfo = localtime ( &rawtime );
new_stat += (timeinfo->tm_hour/10) + '0';
new_stat += (timeinfo->tm_hour%10) + '0';
new_stat += ':';
new_stat += (timeinfo->tm_min/10) + '0';
new_stat += (timeinfo->tm_min%10) + '0';
strcpy(status, new_stat.c_str());
}
void vene_run() // update status bar every 5 sec
{
time_point<system_clock> now = system_clock::now();
if(has_child && check_exited(child))
{
// Clean up all zombies
while (waitpid(-1, nullptr, WNOHANG) > 0);
has_child = false;
updatestatus();
next_update = now + 10s;
}
else if(!has_child && now > next_update)
{
// Clean up all zombies
while (waitpid(-1, nullptr, WNOHANG) > 0);
updatestatus();
next_update = now + 10s;
}
}
void vene_screenshot(const Arg*)
{
Cmd scrot("scrot", "-s", "-");
Cmd tee("tee", SCREEN_CAPS_DIR);
Cmd xclip("xclip", "-selection", "clipboard", "-t", "image/png");
scrot | tee | xclip; // todo: cppipe < string
}
void vene_paste_sel(const Arg*)
{
Cmd xclip("xclip", "-selection", "primary", "-o");
Cmd xdotool("xdotool", "click", "--delay", "0", "--clearmodifiers", "2");
xclip | xdotool;
}
void vene_browser(const Arg* browser_tag)
{
bool browser_tag_used = false;
for(Client* c = selmon->clients; c; c = c->next)
if(c->tags & browser_tag->ui)
{
browser_tag_used = true;
break;
}
if( browser_tag_used ) // browser tag is used, view it
{
view(browser_tag);
}
else // start browser
{
Cmd("apulse", BROWSER).detach();
}
}
void vene_webbookmark() // todo: cppipe exceptions
{
Cmd dmenu( "dmenu", "-b", "-f", "-i", "-l", "30", "-fn", "monospace:size=14");
string bm_root (HOME);
bm_root += "/sync/bookmarks/web/";
Cmd list_dirs ("ls");
list_dirs += bm_root.c_str();
while(true)
{
// Choose bookmark directory
string dir = $(list_dirs | dmenu);
if( dir.empty() )
return;
string bm_dir = bm_root + dir;
// Choose bookmark
string link = $(dmenu < bm_dir.c_str());
size_t link_begin = link.find('-');
if(link_begin != string::npos)
{
// Extract link
Cmd open_bookmark("apulse", BROWSER);
link = link.substr(link_begin+1);
open_bookmark += link.c_str();
open_bookmark.detach();
break;
}
}
}
void vene_inc_vol(const Arg*)
{
Cmd inc_vol(amixer + "-q" + "set" + AUDIO_DEV + "3%+");
child = inc_vol.detach();
has_child = true;
}
void vene_dec_vol(const Arg*)
{
Cmd dec_vol(amixer + "-q" + "set" + AUDIO_DEV + "3%-");
child = dec_vol.detach();
has_child = true;
}
void vene_toggle_vol(const Arg*)
{
Cmd toggle_vol(amixer + "-q" + "set" + AUDIO_DEV + "toggle");
child = toggle_vol.detach();
has_child = true;
}
}