362 lines
7.5 KiB
C++
362 lines
7.5 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"
|
|
}
|
|
|
|
#define DMENU_ARGS "-b", "-f", "-i", "-l", "30", "-fn", "monospace:size=14"
|
|
|
|
using namespace std;
|
|
using namespace std::chrono;
|
|
using namespace std::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 browser(BROWSER);
|
|
|
|
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 vol_out = $({"wpctl", "get-volume", "@DEFAULT_AUDIO_SINK@"});
|
|
size_t vol_begin = vol_out.find(' ');
|
|
|
|
if(vol_begin != string::npos)
|
|
{
|
|
bool is_muted = vol_out.find("[MUTED]") != string::npos;
|
|
new_stat += is_muted ? "🔇" : "🔉";
|
|
|
|
size_t first_digit = vol_begin + 1;
|
|
size_t vol_end = vol_out.find(' ', first_digit);
|
|
|
|
if(vol_end == string::npos)
|
|
vol_end = vol_out.size() + 1;
|
|
|
|
float vol = stof( vol_out.substr(first_digit, vol_end - first_digit) );
|
|
|
|
new_stat += to_string(int(vol * 100)) + "% ";
|
|
}
|
|
|
|
// 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()); // todo: write directly to status
|
|
}
|
|
|
|
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 to_clip("xclip", "-selection", "clipboard", "-t", "image/png");
|
|
scrot | tee | to_clip; // todo: cppipe < string
|
|
}
|
|
|
|
void vene_clip_history(const Arg*)
|
|
{
|
|
// Select a history entry and put to clip
|
|
Cmd clipmenu("clipmenu", DMENU_ARGS);
|
|
|
|
// Paste
|
|
Cmd xdotool("xdotool", "key", "--delay", "0", "--clearmodifiers", "shift+Insert");
|
|
|
|
clipmenu && 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
|
|
{
|
|
detach(browser);
|
|
}
|
|
}
|
|
|
|
void vene_webbookmark() // todo: cppipe exceptions
|
|
{
|
|
Cmd dmenu( "dmenu", DMENU_ARGS);
|
|
|
|
string bm_root = HOME + "/sync/bookmarks/web/"s;
|
|
|
|
Cmd list_dirs ("ls", bm_root.c_str());
|
|
|
|
while(true)
|
|
{
|
|
// Choose bookmark directory
|
|
string dir = $(list_dirs | dmenu);
|
|
if( dir.empty() )
|
|
return;
|
|
|
|
string bm_dir = bm_root + dir;
|
|
|
|
// Read content of bookmarks file and choose
|
|
string entry = $(dmenu < bm_dir.c_str());
|
|
|
|
// Extract link
|
|
size_t link_begin = entry.find('-');
|
|
if(link_begin != string::npos)
|
|
{
|
|
Cmd open_bookmark = browser + (entry.c_str() + link_begin + 1); // skip -
|
|
detach(open_bookmark);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void vene_inc_vol(const Arg*)
|
|
{
|
|
Cmd inc_vol("wpctl", "set-volume", "@DEFAULT_AUDIO_SINK@", "3%+");
|
|
child = detach(inc_vol);
|
|
has_child = true;
|
|
}
|
|
|
|
void vene_dec_vol(const Arg*)
|
|
{
|
|
Cmd dec_vol("wpctl", "set-volume", "@DEFAULT_AUDIO_SINK@", "3%-");
|
|
child = detach(dec_vol);
|
|
has_child = true;
|
|
}
|
|
|
|
void vene_toggle_vol(const Arg*)
|
|
{
|
|
Cmd toggle_vol("wpctl", "set-mute", "@DEFAULT_AUDIO_SINK@", "toggle");
|
|
child = detach(toggle_vol);
|
|
has_child = true;
|
|
}
|
|
|
|
void vene_toggle_mic(const Arg*)
|
|
{
|
|
Cmd toggle_mic("wpctl", "set-mute", "@DEFAULT_AUDIO_SOURCE@", "toggle");
|
|
child = detach(toggle_mic);
|
|
has_child = true;
|
|
}
|
|
|
|
void vene_zzz(const Arg*)
|
|
{
|
|
ofstream("/sys/power/state") << "mem";
|
|
}
|
|
}
|