Skip to content

Commit

Permalink
blank-screens: rewrite with dynamic blanking support
Browse files Browse the repository at this point in the history
  • Loading branch information
XPhyro committed Aug 20, 2024
1 parent 1d99bb2 commit a0e5af1
Show file tree
Hide file tree
Showing 10 changed files with 672 additions and 529 deletions.
1 change: 1 addition & 0 deletions src/cpp/project/blank-screens/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
blank-screens
34 changes: 34 additions & 0 deletions src/cpp/project/blank-screens/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
VPATH = src

CXX := g++

warnings = -Wall -Wextra -Werror \
-Wswitch-default -Wfloat-equal \
-Wdisabled-optimization -Wsign-promo
libs = -lX11 -lXrandr

ifdef includeprefix
include = -I$(includeprefix)
else
include =
endif

CXXFLAGS = $(warnings) -O3 -DNDEBUG -std=c++2c -pedantic -fpermissive $(include)
LDFLAGS = $(libs)

EXE = blank-screens

SRC = $(shell find src -name "*.cpp")
OBJ_ = $(SRC:src/%=%)
OBJ = $(OBJ_:.cpp=.o)

$(EXE): $(OBJ)
$(CXX) $(LDFLAGS) $^ -o $(EXE)

$(OBJ): %.o: %.cpp
$(CXX) -c $(CXXFLAGS) $< -o $@

clean:
rm -f -- $(OBJ) $(EXE)

.PHONY: run clean
108 changes: 108 additions & 0 deletions src/cpp/project/blank-screens/src/blind.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#include "blind.hpp"

#include <algorithm>

#include <X11/Xatom.h>

#include <xph/exec_info.hpp>

bs::blind::blind(std::shared_ptr<bs::cli> cli,
std::string_view monitor,
Display* display,
int default_screen,
Window root_window,
XRRCrtcInfo* crtc_info)
: m_monitor(monitor)
, m_cli(cli)
, m_display(display)
{
m_window = XCreateSimpleWindow(display,
root_window,
crtc_info->x,
crtc_info->y,
crtc_info->width,
crtc_info->height,
0,
0,
0);

auto* class_hint = XAllocClassHint();
static std::string class_name(xph::exec_name);
class_hint->res_name = class_name.data();
class_hint->res_class = class_name.data();
XSetClassHint(display, m_window, class_hint);

XSetWindowAttributes window_attributes;
window_attributes.override_redirect = True;

const auto wm_state = XInternAtom(display, "_NET_WM_STATE", False);
const auto wm_state_above = XInternAtom(display, "_NET_WM_STATE_ABOVE", False);
const auto wm_window_type = XInternAtom(display, "_NET_WM_WINDOW_TYPE", False);
const auto wm_window_type_dock = XInternAtom(display, "_NET_WM_WINDOW_TYPE_DOCK", False);
XChangeProperty(display,
m_window,
wm_state,
XA_ATOM,
32,
PropModeAppend,
reinterpret_cast<const unsigned char*>(&wm_state_above),
1);
XChangeProperty(display,
m_window,
wm_window_type,
XA_ATOM,
32,
PropModeReplace,
reinterpret_cast<const unsigned char*>(&wm_window_type),
1);
XChangeProperty(display,
m_window,
wm_window_type_dock,
XA_ATOM,
32,
PropModeReplace,
reinterpret_cast<const unsigned char*>(&wm_window_type_dock),
1);

XChangeWindowAttributes(display, m_window, CWOverrideRedirect, &window_attributes);

XMapWindow(display, m_window);
XRaiseWindow(display, m_window);
XFlush(display);

set_alpha(cli->alpha());

XSetWindowBackground(display, m_window, BlackPixel(display, default_screen));
XClearWindow(display, m_window);
XFlush(display);
}

bs::blind::~blind(void)
{
XDestroyWindow(m_display, m_window);
XFlush(m_display);
}

void bs::blind::set_alpha(double alpha)
{
alpha = std::clamp(alpha, m_cli->min_alpha(), m_cli->max_alpha());

unsigned long opacity;
if (alpha > 1 - m_cli->snap_threshold())
opacity = 0xFFFFFFFFul;
else if (alpha < m_cli->snap_threshold())
opacity = 0x00000000ul;
else
opacity = 0xFFFFFFFFul * alpha;

const auto opacity_atom = XInternAtom(m_display, "_NET_WM_WINDOW_OPACITY", False);
XChangeProperty(m_display,
m_window,
opacity_atom,
XA_CARDINAL,
32,
PropModeReplace,
reinterpret_cast<unsigned char*>(&opacity),
1L);
XFlush(m_display);
}
32 changes: 32 additions & 0 deletions src/cpp/project/blank-screens/src/blind.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#ifndef HEADER_SCRIPTS_CXX_BS_BLIND_
#define HEADER_SCRIPTS_CXX_BS_BLIND_

#include <X11/extensions/Xrandr.h>

#include "cli.hpp"

namespace bs {
class blind {
public:
std::string_view m_monitor;

private:
std::shared_ptr<cli> m_cli;
Window m_window;
Display* m_display;

public:
blind(void) = delete;
~blind(void);
blind(std::shared_ptr<cli> cli,
std::string_view monitor,
Display* display,
int default_screen,
Window root_window,
XRRCrtcInfo* crtc_info);

void set_alpha(double alpha);
};
} // namespace bs

#endif /* ifndef HEADER_SCRIPTS_CXX_BS_BLIND_ */
116 changes: 116 additions & 0 deletions src/cpp/project/blank-screens/src/cli.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#include "cli.hpp"

#include <algorithm>
#include <iostream>
#include <limits>
#include <vector>

#include <cstdlib>

#include <lyra/lyra.hpp>

#include <xph/exec_info.hpp>

bs::cli::cli(int argc, char** argv)
{
bool show_help = false;
double fps = 240;
auto cli =
lyra::cli() | lyra::help(show_help).description("Blank monitors.") |
lyra::opt(m_alpha, "num")["-a"]["--alpha"]("set initial alpha of blinds") |
lyra::opt(m_fifo_path, "path")["-c"]["--command-fifo"]("listen for commands on fifo") |
lyra::opt(fps, "num")["-f"]["--fps"]("set frame rate of alpha interpolation") |
lyra::opt(m_max_alpha, "num")["-H"]["--high"]("set upper alpha bound") |
lyra::opt(m_min_alpha, "num")["-L"]["--low"]("set lower alpha bound") |
lyra::opt(m_lock_path, "path")["-l"]["--lock"]("set lock path") |
lyra::opt(m_ignore_primary)["-p"]["--ignore-primary"]("ignore primary monitor") |
lyra::opt(m_snap_threshold, "num")["-s"]["--snap"]("set alpha snap threshold") |
lyra::opt(m_lerp_factor, "num")["-t"]["--factor"]("set alpha linear interpolation factor") |
lyra::arg(m_monitors, "monitor")("initial monitor to blank")
.cardinality(0, std::numeric_limits<size_t>::max());

auto args = cli.parse({ argc, argv });

if (!args) {
std::cerr << args.message() << '\n';
std::cerr << "Try '" << xph::exec_path << " -h' for more information.\n";
std::exit(EXIT_FAILURE);
}

if (show_help) {
std::cout << cli << '\n';
std::exit(EXIT_SUCCESS);
}

m_frame_time = std::chrono::duration<double>{ 1.0 / fps };

std::sort(m_monitors.begin(), m_monitors.end());
m_monitors.erase(std::unique(m_monitors.begin(), m_monitors.end()), m_monitors.end());
}

double bs::cli::alpha(void) const noexcept
{
return m_alpha;
}

const std::string& bs::cli::fifo_path(void) const noexcept
{
return m_fifo_path;
}

const std::chrono::duration<double>& bs::cli::frame_time(void) const noexcept
{
return m_frame_time;
}

double bs::cli::max_alpha(void) const noexcept
{
return m_max_alpha;
}

double bs::cli::min_alpha(void) const noexcept
{
return m_min_alpha;
}

const std::string& bs::cli::lock_path(void) const noexcept
{
return m_lock_path;
}

bool bs::cli::ignore_primary(void) const noexcept
{
return m_ignore_primary;
}

double bs::cli::snap_threshold(void) const noexcept
{
return m_snap_threshold;
}

double bs::cli::lerp_factor(void) const noexcept
{
return m_lerp_factor;
}

const std::vector<std::string>& bs::cli::monitors(void) const noexcept
{
return m_monitors;
}

namespace bs {
std::ostream& operator<<(std::ostream& os, const bs::cli& cli)
{
os << "alpha: " << cli.alpha() << '\n';
os << "fifo path: " << cli.fifo_path() << '\n';
os << "frame time: " << cli.frame_time().count() << '\n';
os << "max alpha: " << cli.max_alpha() << '\n';
os << "min alpha: " << cli.min_alpha() << '\n';
os << "lock path: " << cli.lock_path() << '\n';
os << "ignore primary: " << std::boolalpha << cli.ignore_primary() << '\n';
os << "snap threshold: " << cli.snap_threshold() << '\n';
os << "lerp factor: " << cli.lerp_factor() << '\n';

return os;
}
} // namespace bs
51 changes: 51 additions & 0 deletions src/cpp/project/blank-screens/src/cli.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#ifndef HEADER_SCRIPTS_CXX_PAF_CLI_
#define HEADER_SCRIPTS_CXX_PAF_CLI_

#include <chrono>
#include <string>
#include <vector>

namespace bs {
class cli {
public:
static const constexpr double k_default_alpha = 1.0;
static const constexpr double k_default_frame_rate = 100.0;
static const constexpr double k_default_max_alpha = 1.0;
static const constexpr double k_default_min_alpha = 0.0;
static const constexpr double k_default_snap_threshold = 0.01;
static const constexpr double k_default_lerp_factor = 0.10;
static const constexpr char* const k_default_fifo_path = "/tmp/blank-screens/fifo";
static const constexpr char* const k_default_lock_path = "/tmp/blank-screens/";

private:
double m_alpha = k_default_alpha;
std::string m_fifo_path = k_default_fifo_path;
std::chrono::duration<double> m_frame_time{ 1.0 / k_default_frame_rate };
double m_max_alpha = k_default_max_alpha;
double m_min_alpha = k_default_min_alpha;
std::string m_lock_path = k_default_lock_path;
bool m_ignore_primary = false;
double m_snap_threshold = k_default_snap_threshold;
double m_lerp_factor = k_default_lerp_factor;
std::vector<std::string> m_monitors;

public:
cli(void) = delete;
cli(int argc, char** argv);

double alpha(void) const noexcept;
const std::string& fifo_path(void) const noexcept;
const std::chrono::duration<double>& frame_time(void) const noexcept;
double max_alpha(void) const noexcept;
double min_alpha(void) const noexcept;
const std::string& lock_path(void) const noexcept;
bool ignore_primary(void) const noexcept;
double snap_threshold(void) const noexcept;
double lerp_factor(void) const noexcept;
const std::vector<std::string>& monitors(void) const noexcept;

friend std::ostream& operator<<(std::ostream& os, const cli& cli);
};
} // namespace bs

#endif /* ifndef HEADER_SCRIPTS_CXX_PAF_CLI_ */
Loading

0 comments on commit a0e5af1

Please sign in to comment.