Compare commits
5 Commits
c204736762
...
6a3c8a3edf
Author | SHA1 | Date | |
---|---|---|---|
6a3c8a3edf | |||
c3ef4493d6 | |||
|
71f57072c5 | ||
|
3ef750ae21 | ||
|
ad4ec36365 |
24
.clang-format
Normal file
24
.clang-format
Normal file
@ -0,0 +1,24 @@
|
||||
---
|
||||
AccessModifierOffset: -4
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
BasedOnStyle: LLVM
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: 'false'
|
||||
ConstructorInitializerIndentWidth: 8
|
||||
Cpp11BracedListStyle: 'false'
|
||||
IndentWidth: '4'
|
||||
Language: Cpp
|
||||
PointerAlignment: Right
|
||||
SortIncludes: 'false'
|
||||
SpaceBeforeAssignmentOperators: 'true'
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: 'false'
|
||||
SpacesInAngles: 'false'
|
||||
SpacesInCStyleCastParentheses: 'false'
|
||||
SpacesInContainerLiterals: 'false'
|
||||
SpacesInParentheses: 'false'
|
||||
SpacesInSquareBrackets: 'false'
|
||||
Standard: Cpp11
|
||||
TabWidth: '4'
|
||||
UseTab: Never
|
||||
|
||||
...
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
*.o
|
||||
river-shifttags
|
||||
xdg-shell.h
|
||||
xdg-shell.c
|
||||
river-status-unstable-v1.h
|
||||
|
33
README.md
33
README.md
@ -1,4 +1,31 @@
|
||||
# river-shifttag
|
||||
# river-shifttags
|
||||
|
||||
A tool for the river Wayland compositor that will calculate the
|
||||
rotated tags from the currently focused tags.
|
||||
A small utility for the river Wayland compositor to rotate the focused tags.
|
||||
|
||||
# Installation
|
||||
|
||||
```
|
||||
$ make
|
||||
# make install
|
||||
```
|
||||
|
||||
# Usage
|
||||
|
||||
To rotate the currently focused once to the right
|
||||
```
|
||||
river-shifttags
|
||||
```
|
||||
|
||||
To rotate the currently focused once to the left
|
||||
```
|
||||
river-shifttags --shifts -1
|
||||
```
|
||||
|
||||
To rotate a different number of tags
|
||||
```
|
||||
river-shifttags --num-tags 16
|
||||
```
|
||||
|
||||
# License
|
||||
|
||||
GPLv3
|
||||
|
@ -7,218 +7,225 @@
|
||||
#include "river-status-unstable-v1.h"
|
||||
#include "river-control-unstable-v1.h"
|
||||
|
||||
#define INT_SIZE sizeof (int) // Size of int in bytes
|
||||
#define INT_BITS INT_SIZE * 8 - 1 // Size of int in bits - 1
|
||||
const char usage[] =
|
||||
"Usage: river-shiftview [OPTIONS]\n"
|
||||
" --shift VALUE value by which to rotate selected tag.\n"
|
||||
" --num-tags VALUE number of tags to rotate\n"
|
||||
" --start VALUE First tag to rotate from.\n"
|
||||
" --help print this message and exit.\n"
|
||||
"\n"
|
||||
"\n";
|
||||
|
||||
int _shift = 1;
|
||||
int _num_tags = 9;
|
||||
int _start_tag = 1;
|
||||
size_t outputs_size = 0;
|
||||
|
||||
int ret = EXIT_SUCCESS;
|
||||
|
||||
struct output {
|
||||
struct wl_output *output;
|
||||
size_t index;
|
||||
};
|
||||
|
||||
struct wl_display *wl_display = NULL;
|
||||
struct wl_output *wl_output = NULL;
|
||||
struct output *wl_outputs = NULL;
|
||||
struct wl_seat *seat = NULL;
|
||||
|
||||
struct zriver_status_manager_v1 *river_status_manager = NULL;
|
||||
struct zriver_control_v1 *river_controller = NULL;
|
||||
|
||||
struct zriver_output_status_v1 *river_output_status = NULL;
|
||||
struct zriver_output_status_v1 **river_output_statuses = NULL;
|
||||
|
||||
int shifts = 1;
|
||||
int num_tags = 9;
|
||||
int start_tag = 0;
|
||||
unsigned int *new_tags = NULL;
|
||||
size_t focused_output = 0;
|
||||
|
||||
unsigned int new_tags = 0;
|
||||
|
||||
const char usage[] =
|
||||
"Usage: river-shiftview [OPTIONS]\n"
|
||||
" --shifts VALUE value by which to rotate selected tag.\n"
|
||||
" --num-tags VALUE number of tags to rotate\n"
|
||||
" --start VALUE First tag to rotate from.\n"
|
||||
" --help print this message and exit.\n"
|
||||
"\n"
|
||||
"\n";
|
||||
|
||||
void
|
||||
rotate (
|
||||
unsigned int tagmask,
|
||||
int rotations,
|
||||
int start_tag,
|
||||
int num_tags)
|
||||
{
|
||||
|
||||
rotations %= (int)INT_BITS;
|
||||
|
||||
const unsigned int mask = ~(~(0U) << num_tags) << start_tag;
|
||||
unsigned int to_rotate = (tagmask & mask) >> start_tag;
|
||||
|
||||
if (rotations < 1)
|
||||
{
|
||||
rotations = -rotations;
|
||||
new_tags = (mask
|
||||
& ((to_rotate >> rotations)
|
||||
| (to_rotate << (num_tags - rotations)) << start_tag))
|
||||
+ (~mask & tagmask);
|
||||
void rotate(unsigned int tagmask, size_t index, int shift, int start_tag,
|
||||
int num_tags) {
|
||||
// if multiple tags, chose the lowest one
|
||||
int current_tag = 1;
|
||||
while (!(tagmask & 1)) {
|
||||
tagmask = tagmask >> 1;
|
||||
current_tag += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_tags = (mask
|
||||
& ((to_rotate << rotations)
|
||||
| (to_rotate >> (num_tags - rotations)) << start_tag))
|
||||
+ (~mask & tagmask);
|
||||
|
||||
int new_tag = current_tag + shift;
|
||||
while (new_tag > num_tags) {
|
||||
new_tag = start_tag + (new_tag - num_tags) -
|
||||
1; // -1 because new_tag - num_tags is always at least 1 and
|
||||
// if we overflow, we want to START at start_tag
|
||||
}
|
||||
while (new_tag < start_tag) {
|
||||
new_tag = num_tags + (new_tag - start_tag) +
|
||||
1; // +1 because num_tags is INCLUSIVE and new_tag - start_tag
|
||||
// is always at least 1
|
||||
}
|
||||
new_tags[index] = 1 << (new_tag - 1);
|
||||
}
|
||||
|
||||
static void print_tagmask(void *data,
|
||||
struct zriver_output_status_v1 *output_status_v1,
|
||||
unsigned int tagmask) {
|
||||
rotate(tagmask, (size_t)data, _shift, _start_tag, _num_tags);
|
||||
}
|
||||
|
||||
static void
|
||||
print_tagmask (
|
||||
void *data,
|
||||
struct zriver_output_status_v1 *output_status_v1,
|
||||
unsigned int tagmask)
|
||||
{
|
||||
rotate (tagmask, shifts, start_tag, num_tags);
|
||||
}
|
||||
river_status_handle_view_tags(void *data,
|
||||
struct zriver_output_status_v1 *river_status,
|
||||
struct wl_array *tags) {}
|
||||
|
||||
static void
|
||||
river_status_handle_view_tags (
|
||||
void *data,
|
||||
struct zriver_output_status_v1 *river_status,
|
||||
struct wl_array *tags)
|
||||
{ }
|
||||
static void river_status_handle_urgent_tags(
|
||||
void *data, struct zriver_output_status_v1 *river_status, uint32_t tags) {}
|
||||
|
||||
static void
|
||||
river_status_handle_urgent_tags (
|
||||
void *data,
|
||||
struct zriver_output_status_v1 *river_status,
|
||||
uint32_t tags)
|
||||
{ }
|
||||
|
||||
static const struct zriver_output_status_v1_listener output_status_listener = {
|
||||
.focused_tags = print_tagmask,
|
||||
.view_tags = river_status_handle_view_tags,
|
||||
.urgent_tags = river_status_handle_urgent_tags,
|
||||
static const struct zriver_output_status_v1_listener tag_status_listener = {
|
||||
.focused_tags = print_tagmask,
|
||||
.view_tags = river_status_handle_view_tags,
|
||||
.urgent_tags = river_status_handle_urgent_tags,
|
||||
};
|
||||
|
||||
static void
|
||||
global_registry_handler (
|
||||
void *data,
|
||||
struct wl_registry *registry,
|
||||
uint32_t id,
|
||||
const char *interface,
|
||||
uint32_t version)
|
||||
{
|
||||
if (strcmp (interface, "wl_output") == 0)
|
||||
{
|
||||
wl_output = wl_registry_bind (registry, id, &wl_output_interface, 1);
|
||||
}
|
||||
else if ( strcmp( interface, "wl_seat" ) == 0 )
|
||||
{
|
||||
seat = wl_registry_bind(registry, id, &wl_seat_interface, 3);
|
||||
}
|
||||
else if (strcmp (interface, zriver_status_manager_v1_interface.name) == 0)
|
||||
{
|
||||
river_status_manager = wl_registry_bind (
|
||||
registry, id, &zriver_status_manager_v1_interface, 2);
|
||||
}
|
||||
else if (strcmp (interface, zriver_control_v1_interface.name) == 0)
|
||||
{
|
||||
river_controller = wl_registry_bind(
|
||||
registry, id, &zriver_control_v1_interface, 1);
|
||||
void get_focused_output(void *data,
|
||||
struct zriver_seat_status_v1 *zriver_seat_status_v1,
|
||||
struct wl_output *output) {
|
||||
for (size_t i = 0; i < outputs_size; i++) {
|
||||
if (wl_outputs[i].output == output) {
|
||||
focused_output = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
global_registry_remover (
|
||||
void *data,
|
||||
struct wl_registry *registry,
|
||||
uint32_t id)
|
||||
{ }
|
||||
void unfocused_output_empty(void *data,
|
||||
struct zriver_seat_status_v1 *zriver_seat_status_v1,
|
||||
struct wl_output *output) {}
|
||||
|
||||
static const struct wl_registry_listener registry_listener
|
||||
= { global_registry_handler, global_registry_remover };
|
||||
void focused_view_empty(void *data,
|
||||
struct zriver_seat_status_v1 *zriver_seat_status_v1,
|
||||
const char *title) {}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
enum
|
||||
{
|
||||
HELP,
|
||||
SHIFT_VALUE,
|
||||
START_TAG,
|
||||
NUM_TAGS
|
||||
};
|
||||
static struct option opts[] = {
|
||||
{ "help", no_argument, NULL, HELP },
|
||||
{ "shifts", required_argument, NULL, SHIFT_VALUE },
|
||||
{ "num-tags", required_argument, NULL, NUM_TAGS },
|
||||
{ "start", required_argument, NULL, START_TAG },
|
||||
{ NULL, 0, NULL, 0 },
|
||||
};
|
||||
static const struct zriver_seat_status_v1_listener output_status_listener = {
|
||||
.focused_output = get_focused_output,
|
||||
.unfocused_output = unfocused_output_empty,
|
||||
.focused_view = focused_view_empty,
|
||||
};
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt_long (argc, argv, "h", opts, NULL)) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
static void global_registry_handler(void *data, struct wl_registry *registry,
|
||||
uint32_t id, const char *interface,
|
||||
uint32_t version) {
|
||||
if (strcmp(interface, "wl_output") == 0) {
|
||||
outputs_size++;
|
||||
wl_outputs = realloc(wl_outputs, outputs_size * sizeof(struct output));
|
||||
if (wl_outputs == NULL) {
|
||||
fputs("REALLOC ERROR", stderr);
|
||||
exit(1);
|
||||
}
|
||||
wl_outputs[outputs_size - 1].output =
|
||||
wl_registry_bind(registry, id, &wl_output_interface, 1);
|
||||
wl_outputs[outputs_size - 1].index = outputs_size - 1;
|
||||
} else if (strcmp(interface, "wl_seat") == 0) {
|
||||
seat = wl_registry_bind(registry, id, &wl_seat_interface, 3);
|
||||
} else if (strcmp(interface, zriver_status_manager_v1_interface.name) ==
|
||||
0) {
|
||||
river_status_manager = wl_registry_bind(
|
||||
registry, id, &zriver_status_manager_v1_interface, 2);
|
||||
} else if (strcmp(interface, zriver_control_v1_interface.name) == 0) {
|
||||
river_controller =
|
||||
wl_registry_bind(registry, id, &zriver_control_v1_interface, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void global_registry_remover(void *data, struct wl_registry *registry,
|
||||
uint32_t id) {}
|
||||
|
||||
static const struct wl_registry_listener registry_listener = {
|
||||
global_registry_handler, global_registry_remover
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
enum { HELP, SHIFT_VALUE, START_TAG, NUM_TAGS };
|
||||
static struct option opts[] = {
|
||||
{ "help", no_argument, NULL, HELP },
|
||||
{ "shift", required_argument, NULL, SHIFT_VALUE },
|
||||
{ "num-tags", required_argument, NULL, NUM_TAGS },
|
||||
{ "start", required_argument, NULL, START_TAG },
|
||||
{ NULL, 0, NULL, 0 },
|
||||
};
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt_long(argc, argv, "h", opts, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case HELP:
|
||||
fputs (usage, stderr);
|
||||
return EXIT_SUCCESS;
|
||||
fputs(usage, stderr);
|
||||
return EXIT_SUCCESS;
|
||||
case SHIFT_VALUE:
|
||||
shifts = atoi (optarg);
|
||||
break;
|
||||
_shift = atoi(optarg);
|
||||
break;
|
||||
case START_TAG:
|
||||
start_tag = atoi (optarg);
|
||||
break;
|
||||
_start_tag = atoi(optarg);
|
||||
break;
|
||||
case NUM_TAGS:
|
||||
num_tags = atoi (optarg);
|
||||
break;
|
||||
_num_tags = atoi(optarg);
|
||||
break;
|
||||
default:
|
||||
return EXIT_FAILURE;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
const char *display_name = getenv ("WAYLAND_DISPLAY");
|
||||
if (display_name == NULL)
|
||||
{
|
||||
fputs ("ERROR: WAYLAND_DISPLAY is not set.\n", stderr);
|
||||
return EXIT_FAILURE;
|
||||
const char *display_name = getenv("WAYLAND_DISPLAY");
|
||||
if (display_name == NULL) {
|
||||
fputs("ERROR: WAYLAND_DISPLAY is not set.\n", stderr);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
wl_display = wl_display_connect (display_name);
|
||||
if (wl_display == NULL)
|
||||
{
|
||||
fputs ("ERROR: Can not connect to wayland display.\n", stderr);
|
||||
return EXIT_FAILURE;
|
||||
wl_display = wl_display_connect(display_name);
|
||||
if (wl_display == NULL) {
|
||||
fputs("ERROR: Can not connect to wayland display.\n", stderr);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
struct wl_registry *registry = wl_display_get_registry (wl_display);
|
||||
wl_registry_add_listener (registry, ®istry_listener, NULL);
|
||||
struct wl_registry *registry = wl_display_get_registry(wl_display);
|
||||
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
||||
|
||||
wl_display_roundtrip (wl_display);
|
||||
wl_display_roundtrip(wl_display);
|
||||
|
||||
river_output_status = zriver_status_manager_v1_get_river_output_status (
|
||||
river_status_manager, wl_output);
|
||||
river_output_statuses =
|
||||
malloc(outputs_size * sizeof(struct zriver_output_status_v1 *));
|
||||
new_tags = malloc(outputs_size * sizeof(int *));
|
||||
|
||||
zriver_output_status_v1_add_listener (river_output_status,
|
||||
&output_status_listener, NULL);
|
||||
struct zriver_seat_status_v1 *seat_status_manager =
|
||||
zriver_status_manager_v1_get_river_seat_status(river_status_manager,
|
||||
seat);
|
||||
zriver_seat_status_v1_add_listener(seat_status_manager,
|
||||
&output_status_listener, NULL);
|
||||
|
||||
/* Wait till new_tags is populated */
|
||||
wl_display_roundtrip (wl_display);
|
||||
for (size_t i = 0; i < outputs_size; i++) {
|
||||
river_output_statuses[i] =
|
||||
zriver_status_manager_v1_get_river_output_status(
|
||||
river_status_manager, wl_outputs[i].output);
|
||||
|
||||
/* Set the new focused tags */
|
||||
zriver_control_v1_add_argument(
|
||||
river_controller,
|
||||
"set-focused-tags"
|
||||
);
|
||||
zriver_output_status_v1_add_listener(river_output_statuses[i],
|
||||
&tag_status_listener, (void *)i);
|
||||
new_tags[i] = 0;
|
||||
}
|
||||
|
||||
char* tags_str = malloc( (size_t)snprintf( NULL, 0, "%d", new_tags ));
|
||||
sprintf(tags_str, "%d", new_tags);
|
||||
/* Wait till new_tags is populated */
|
||||
wl_display_roundtrip(wl_display);
|
||||
|
||||
zriver_control_v1_add_argument(
|
||||
river_controller, tags_str);
|
||||
/* Set the new focused tags */
|
||||
zriver_control_v1_add_argument(river_controller, "set-focused-tags");
|
||||
|
||||
zriver_control_v1_run_command (
|
||||
river_controller, seat);
|
||||
char *tags_str =
|
||||
malloc((size_t)snprintf(NULL, 0, "%d", new_tags[focused_output]));
|
||||
sprintf(tags_str, "%d", new_tags[focused_output]);
|
||||
|
||||
zriver_control_v1_destroy(river_controller);
|
||||
wl_display_roundtrip (wl_display);
|
||||
zriver_control_v1_add_argument(river_controller, tags_str);
|
||||
|
||||
return ret;
|
||||
zriver_control_v1_run_command(river_controller, seat);
|
||||
|
||||
zriver_control_v1_destroy(river_controller);
|
||||
wl_display_roundtrip(wl_display);
|
||||
|
||||
free(wl_outputs);
|
||||
free(river_output_statuses);
|
||||
free(new_tags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user