Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Config option to replace screenshots with window geometries outlines #54

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
22 changes: 17 additions & 5 deletions src/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@ constexpr std::size_t keys_size = 10;
using color = const uint32_t;
using keys = std::array<std::string_view, keys_size>;

///
/// Whether to show desktop screenshots.
///
/// True: Display desktop screenshots.
/// Display desktop layouts if no screenshots are available.
/// False: Always display desktop layouts.
///
const bool dxp_do_screenshots = true;

///
/// Dimensions of the screenshots that will be displayed.
///
Expand Down Expand Up @@ -52,13 +61,16 @@ const bool dxp_center_y = false; ///< Center dxp on the monitor vertically

const uint16_t dxp_padding = 3; ///< Padding around the screenshots

color dxp_background = 0x444444; ///< Window background
color dxp_border_pres = 0xFFFFFF; ///< Desktop preselection
color dxp_border_nopres = 0x808080; ///< Desktop without preselection
color dxp_background = 0x444444; ///< Window background
color dxp_border_pres = 0xFFFFFF; ///< Desktop preselection
color dxp_border_nopres = 0x808080; ///< Desktop without preselection
color dxp_layout_background = 0x000214; ///< TODO(mmskv): Document
color dxp_layout_window_border = 0x2c0069; ///< TODO(mmskv): Document
color dxp_layout_window_background = 0x04001a; ///< TODO(mmskv): Document

const uint dxp_border_width = 0; ///< dxp window border
const uint16_t dxp_border_pres_width = 2; ///< Width of the preselection

const uint dxp_border_width = 0; ///< dxp window border
const uint dxp_desktop_layout_window_border_size = 2; ///< TODO(mmskv): Document

///
/// How often to take screenshots.
Expand Down
12 changes: 9 additions & 3 deletions src/daemon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,14 @@ dxp_daemon::dxp_daemon ()
dxp_socket_desktop p;

p.id = i;
p.active = false;
p.x = desktops[i].x;
p.y = desktops[i].y;
p.width = desktops[i].width;
p.height = desktops[i].height;
p.pixmap_len = desktops[i].pixmap_width * desktops[i].pixmap_height * 4U;
p.width = desktops[i].pixmap_width;
p.height = desktops[i].pixmap_height;
p.pixmap_width = desktops[i].pixmap_width;
p.pixmap_height = desktops[i].pixmap_height;

// Copying pixmap from desktops into socket pixmaps
p.pixmap = desktops[i].pixmap; // Should be as fast as memcpy
Expand All @@ -61,14 +66,15 @@ dxp_daemon::run ()
{
throw std::runtime_error (
"The amount of virtual desktops specified in the config does not "
"match the amount of your virtual deskops in your system.");
"match the amount of virtual deskops in your system.");
}

this->socket_desktops_lock.lock ();
this->desktops[current].save_screen ();

// Copying pixmap from desktops into socket pixmaps
this->socket_desktops[current].pixmap = this->desktops[current].pixmap;
this->socket_desktops[current].active = true;

this->socket_desktops_lock.unlock ();

Expand Down
69 changes: 29 additions & 40 deletions src/desktop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,10 @@ dxp_desktop::save_screen ()
// a low pass filter should be used on the source.
int radius = this->width / this->pixmap_width / 2;

box_blur_horizontal (this->image_ptr, this->width, this->height, radius);
box_blur_vertical (this->image_ptr, this->width, this->height, radius);
this->box_blur_horizontal (radius);
this->box_blur_vertical (radius);

nn_resize (this->image_ptr, this->pixmap.data (), this->width, this->height,
this->pixmap_width, this->pixmap_height);
this->nn_resize ();
}

/**
Expand All @@ -86,9 +85,9 @@ dxp_desktop::save_screen ()
* and here https://www.gamasutra.com/view/feature/3102
*/
void
box_blur_horizontal (uint8_t *image, int width, int height, uint radius)
dxp_desktop::box_blur_horizontal (uint radius)
{
auto *input32 = reinterpret_cast<uint32_t *> (image);
auto *input32 = reinterpret_cast<uint32_t *> (image_ptr);
class pixmap img (input32, width); // Adds operator[][]

constexpr uint32_t a_mask = 0xFF000000;
Expand Down Expand Up @@ -170,9 +169,9 @@ box_blur_horizontal (uint8_t *image, int width, int height, uint radius)
* Apply a vertical box filter (low pass) to the image.
*/
void
box_blur_vertical (uint8_t *image, int width, int height, uint radius)
dxp_desktop::box_blur_vertical (uint radius)
{
auto *input32 = reinterpret_cast<uint32_t *> (image);
auto *input32 = reinterpret_cast<uint32_t *> (image_ptr);
class pixmap img (input32, width);

constexpr uint32_t r_mask = 0x00FF0000;
Expand Down Expand Up @@ -242,15 +241,10 @@ box_blur_vertical (uint8_t *image, int width, int height, uint radius)
* https://stackoverflow.com/questions/28566290
*/
void
dxp_desktop::nn_resize (const uint8_t *__restrict input,
uint8_t *__restrict output,
int source_width, /* Source dimensions */
int source_height,
int target_width, /* Target dimensions */
int target_height)
dxp_desktop::nn_resize ()
{
const auto *input32 = reinterpret_cast<const uint32_t *> (input);
auto *output32 = reinterpret_cast<uint32_t *> (output);
const auto *input32 = reinterpret_cast<const uint32_t *> (image_ptr);
auto *output32 = reinterpret_cast<uint32_t *> (pixmap.data ());

//
// Bitshifts are used to preserve precision in x_ratio and y_ratio.
Expand All @@ -263,17 +257,17 @@ dxp_desktop::nn_resize (const uint8_t *__restrict input,
//
constexpr int k_precision_bytes = 16;

const int x_ratio = (source_width << k_precision_bytes) / target_width;
const int y_ratio = (source_height << k_precision_bytes) / target_height;
const int x_ratio = (width << k_precision_bytes) / pixmap_width;
const int y_ratio = (height << k_precision_bytes) / pixmap_height;

for (int y = 0; y < target_height; y++)
for (int y = 0; y < pixmap_height; y++)
{
int y_source = ((y * y_ratio) >> k_precision_bytes) * source_width;
int y_dest = y * target_width;
int y_source = ((y * y_ratio) >> k_precision_bytes) * width;
int y_dest = y * pixmap_width;

int x_source = 0;
const uint32_t *input32_line = input32 + y_source;
for (int x = 0; x < target_width; x++)
for (int x = 0; x < pixmap_width; x++)
{
x_source += x_ratio;
output32[y_dest + x] = input32_line[x_source >> k_precision_bytes];
Expand All @@ -287,40 +281,35 @@ dxp_desktop::nn_resize (const uint8_t *__restrict input,
* significantly better images. So this resize algorithm is not used.
*/
void
dxp_desktop::bilinear_resize (const uint8_t *__restrict input,
uint8_t *__restrict output,
int source_width, /* Source dimensions */
int source_height,
int target_width, /* Target dimensions */
int target_height)
dxp_desktop::bilinear_resize ()
{
const float x_ratio = float (source_width) / target_width;
const float y_ratio = float (source_height) / target_height;
const float x_ratio = float (width) / pixmap_width;
const float y_ratio = float (height) / pixmap_height;

for (int y_dst = 0; y_dst < target_height; y_dst++)
for (int y_dst = 0; y_dst < pixmap_height; y_dst++)
{
float y_src = y_dst * y_ratio;
int y = std::floor (y_src);
float dy = y_src - y;

for (int x_dst = 0; x_dst < target_width; x_dst++)
for (int x_dst = 0; x_dst < pixmap_width; x_dst++)
{
float x_src = x_dst * x_ratio;
int x = std::floor (x_src);
float dx = x_src - x;

int y_offset = y_dst * target_width;
int y_offset = y_dst * pixmap_width;

int y0_offset = y * source_width;
int y1_offset = y0_offset + source_width;
int y0_offset = y * width;
int y1_offset = y0_offset + width;

for (int ch = 0; ch < 4; ch++)
{
output[(x_dst + y_offset) * 4 + ch]
= (input[(x + y0_offset) * 4 + ch] * (1 - dx) * (1 - dy)
+ input[(x + y1_offset) * 4 + ch] * (1 - dx) * dy
+ input[(x + 1 + y0_offset) * 4 + ch] * dx * (1 - dy)
+ input[(x + 1 + y1_offset) * 4 + ch] * dx * dy);
pixmap[(x_dst + y_offset) * 4 + ch]
= (image_ptr[(x + y0_offset) * 4 + ch] * (1 - dx) * (1 - dy)
+ image_ptr[(x + y1_offset) * 4 + ch] * (1 - dx) * dy
+ image_ptr[(x + 1 + y0_offset) * 4 + ch] * dx * (1 - dy)
+ image_ptr[(x + 1 + y1_offset) * 4 + ch] * dx * dy);
}
}
}
Expand Down
34 changes: 11 additions & 23 deletions src/desktop.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,36 +66,24 @@ class dxp_desktop : public drawable
*/
void save_screen ();

/**
* Apply a horizontal box filter (low pass) to the image.
*/
void box_blur_horizontal (uint radius);
/**
* Apply a vertical box filter (low pass) to the image.
*/
void box_blur_vertical (uint radius);

/**
* Resize image to specified dimensions with nearest neighbour algorithm
*/
static void
nn_resize (const uint8_t *input, ///< Input RGBA 1D array pointer
uint8_t *output, ///< Output RGBA 1D array pointers
int source_width, /* Dimensions of unresized screenshot */
int source_height,
int target_width, /* Dimensions of screenshot after resize */
int target_height);
void nn_resize ();

/**
* Resize image to specified dimensions with bilinear interpolation algorithm
*/
static void
bilinear_resize (const uint8_t *input, ///< Input RGBA 1D array pointer
uint8_t *output, ///< Output RGBA 1D array pointers
int source_width, /* Dimensions of unresized screenshot */
int source_height,
int target_width, /* Dimensions of screenshot after resize */
int target_height);
void bilinear_resize ();
};

/**
* Apply a horizontal box filter (low pass) to the image.
*/
void box_blur_horizontal (uint8_t *image, int width, int height, uint radius);
/**
* Apply a vertical box filter (low pass) to the image.
*/
void box_blur_vertical (uint8_t *image, int width, int height, uint radius);

#endif /* ifndef DESKTOP_PIXMAP_HPP */
10 changes: 7 additions & 3 deletions src/dxp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,13 @@ main ()
{
try
{
// Get screenshots from socket
dxp_socket client;
auto v = client.get_desktops ();
// Get screenshots from socket or create them manually
std::vector<dxp_socket_desktop> v{};
if (dxp_do_screenshots)
{
dxp_socket client;
v = client.get_desktops ();
}

window w (v);

Expand Down
6 changes: 3 additions & 3 deletions src/socket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,14 +198,14 @@ dxp_socket::send_desktops_on_event (
"Failed to send number of desktops to dxp");

// Writes from second to `num+1` * 2 -- sending desktops
for (const auto &p : desktops)
for (const auto &d : desktops)
{
// Sending everything except raw pixmap
write_unix (data_fd, &p, offsetof (dxp_socket_desktop, pixmap),
write_unix (data_fd, &d, offsetof (dxp_socket_desktop, pixmap),
"Failed to send desktop data to dxp");

// Sending pixmap
write_unix (data_fd, p.pixmap.data (), p.pixmap_len,
write_unix (data_fd, d.pixmap.data (), d.pixmap_len,
"Failed to send raw desktop pixmap to dxp");
}
}
Expand Down
36 changes: 8 additions & 28 deletions src/socket.hpp
Original file line number Diff line number Diff line change
@@ -1,37 +1,17 @@
#ifndef DEXPO_SOCKET_HPP
#define DEXPO_SOCKET_HPP

#include <atomic> // for atomic
#include <cstdint> // for uint8_t, uint16_t, uint32_t
#include <mutex> // for mutex
#include <stdexcept> // for runtime_error
#include <string> // for string
#include <sys/types.h> // for uint
#include <vector> // for vector
#include "xcb_util.hpp" // for dxp_socket_desktop, dxp_event
#include <atomic> // for atomic
#include <cstdint> // for uint8_t, uint16_t, uint32_t
#include <mutex> // for mutex
#include <stdexcept> // for runtime_error
#include <string> // for string
#include <sys/types.h> // for uint
#include <vector> // for vector

constexpr const char *k_socket_path = "/tmp/dxp.socket";

/**
* Dekstop struct that will be transferred over socket
* Contains only necessary data
*/
struct dxp_socket_desktop
{
uint id; // _NET_CURRENT_DESKTOP
uint16_t width;
uint16_t height;
uint32_t pixmap_len;
std::vector<uint8_t> pixmap; ///< Pixmap in RBGA format
};

/**
* All commands that can be sent by client to daemon
*/
enum dxp_event
{
RequestDesktops = 1 // Request all pixmaps
};

class dxp_socket
{
public:
Expand Down
Loading