344 lines
7.1 KiB
C++
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;
|
|
}
|
|
}
|