init
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
**smsg** - send ipc messages to swindle (forked from [this repository](https://codeberg.org/notchoc/dwlmsg))
|
||||
|
||||
```
|
||||
usage: smsg [-OTLPF]
|
||||
smsg [-o <output>] -s [-t <tags>] [-l <layout>] [-c <tags>]
|
||||
smsg [-o <output>] (-g | -w) [-FOotlcvmf]
|
||||
```
|
||||
|
||||
```
|
||||
options:
|
||||
-g get
|
||||
-s set
|
||||
-w watch
|
||||
-O get all outputs
|
||||
-T get number of tags
|
||||
-L get all available layouts
|
||||
-P get compositor pid
|
||||
-F get focused output
|
||||
-o select output
|
||||
-t get/set selected tags (set with [+-^.], overwrite with ! prefix)
|
||||
-l get/set current layout
|
||||
-c get title and appid of focused client
|
||||
-v get visibility of statusbar
|
||||
-m get fullscreen status
|
||||
-f get floating status
|
||||
```
|
||||
|
||||
```
|
||||
examples:
|
||||
# act like dwl stdout
|
||||
smsg -w
|
||||
# watch focused client appid and title
|
||||
smsg -w -c
|
||||
# get currently focused output
|
||||
smsg -F
|
||||
# watch for focused output changes
|
||||
smsg -w -F
|
||||
# get all available outputs
|
||||
smsg -O
|
||||
# watch available outputs
|
||||
smsg -w -O
|
||||
# select tag 1, deselect tag 2, toggle tag 4 on output eDP-1
|
||||
smsg -o eDP-1 -s -t +-.^
|
||||
# toggle tag 3, overwriting current tagset (yes, zero-indexed)
|
||||
smsg -t !2^
|
||||
# select tag 8 on current output
|
||||
smsg -s -t 7
|
||||
# deselect tag 8 on current output
|
||||
smsg -s -t 7-
|
||||
# switch to first layout (order given by smsg -L)
|
||||
smsg -l 0
|
||||
# switch to floating layout
|
||||
smsg -l '><>'
|
||||
```
|
||||
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
#ifndef ARG_H__
|
||||
#define ARG_H__
|
||||
|
||||
extern char *argv0;
|
||||
|
||||
#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\
|
||||
argv[0] && argv[0][0] == '-'\
|
||||
&& argv[0][1];\
|
||||
argc--, argv++) {\
|
||||
char argc_;\
|
||||
char **argv_;\
|
||||
int brk_;\
|
||||
if (argv[0][1] == '-' && argv[0][2] == '\0') {\
|
||||
argv++;\
|
||||
argc--;\
|
||||
break;\
|
||||
}\
|
||||
for (brk_ = 0, argv[0]++, argv_ = argv;\
|
||||
argv[0][0] && !brk_;\
|
||||
argv[0]++) {\
|
||||
if (argv_ != argv)\
|
||||
break;\
|
||||
argc_ = argv[0][0];\
|
||||
switch (argc_)
|
||||
|
||||
#define ARGNUM case '0':\
|
||||
case '1':\
|
||||
case '2':\
|
||||
case '3':\
|
||||
case '4':\
|
||||
case '5':\
|
||||
case '6':\
|
||||
case '7':\
|
||||
case '8':\
|
||||
case '9'
|
||||
|
||||
#define ARGEND }\
|
||||
}
|
||||
|
||||
#define ARGC() argc_
|
||||
|
||||
#define ARGNUMF() (brk_ = 1, estrtonum(argv[0], 0, INT_MAX))
|
||||
|
||||
#define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\
|
||||
((x), abort(), (char *)0) :\
|
||||
(brk_ = 1, (argv[0][1] != '\0')?\
|
||||
(&argv[0][1]) :\
|
||||
(argc--, argv++, argv[0])))
|
||||
|
||||
#define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\
|
||||
(char *)0 :\
|
||||
(brk_ = 1, (argv[0][1] != '\0')?\
|
||||
(&argv[0][1]) :\
|
||||
(argc--, argv++, argv[0])))
|
||||
|
||||
#define LNGARG() &argv[0][0]
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,181 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
This is largely ripped from somebar's ipc patchset; just with some personal modifications.
|
||||
I would probably just submit raphi's patchset but I don't think that would be polite.
|
||||
-->
|
||||
<protocol name="dwl_ipc_unstable_v2">
|
||||
<description summary="inter-proccess-communication about dwl's state">
|
||||
This protocol allows clients to update and get updates from dwl.
|
||||
|
||||
Warning! The protocol described in this file is experimental and
|
||||
backward incompatible changes may be made. Backward compatible
|
||||
changes may be added together with the corresponding interface
|
||||
version bump.
|
||||
Backward incompatible changes are done by bumping the version
|
||||
number in the protocol and interface names and resetting the
|
||||
interface version. Once the protocol is to be declared stable,
|
||||
the 'z' prefix and the version number in the protocol and
|
||||
interface names are removed and the interface version number is
|
||||
reset.
|
||||
</description>
|
||||
|
||||
<interface name="zdwl_ipc_manager_v2" version="2">
|
||||
<description summary="manage dwl state">
|
||||
This interface is exposed as a global in wl_registry.
|
||||
|
||||
Clients can use this interface to get a dwl_ipc_output.
|
||||
After binding the client will recieve the dwl_ipc_manager.tags and dwl_ipc_manager.layout events.
|
||||
The dwl_ipc_manager.tags and dwl_ipc_manager.layout events expose tags and layouts to the client.
|
||||
</description>
|
||||
|
||||
<request name="release" type="destructor">
|
||||
<description summary="release dwl_ipc_manager">
|
||||
Indicates that the client will not the dwl_ipc_manager object anymore.
|
||||
Objects created through this instance are not affected.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<request name="get_output">
|
||||
<description summary="get a dwl_ipc_outout for a wl_output">
|
||||
Get a dwl_ipc_outout for the specified wl_output.
|
||||
</description>
|
||||
<arg name="id" type="new_id" interface="zdwl_ipc_output_v2"/>
|
||||
<arg name="output" type="object" interface="wl_output"/>
|
||||
</request>
|
||||
|
||||
<event name="tags">
|
||||
<description summary="Announces tag amount">
|
||||
This event is sent after binding.
|
||||
A roundtrip after binding guarantees the client recieved all tags.
|
||||
</description>
|
||||
<arg name="amount" type="uint"/>
|
||||
</event>
|
||||
|
||||
<event name="layout">
|
||||
<description summary="Announces a layout">
|
||||
This event is sent after binding.
|
||||
A roundtrip after binding guarantees the client recieved all layouts.
|
||||
</description>
|
||||
<arg name="name" type="string"/>
|
||||
</event>
|
||||
</interface>
|
||||
|
||||
<interface name="zdwl_ipc_output_v2" version="2">
|
||||
<description summary="control dwl output">
|
||||
Observe and control a dwl output.
|
||||
|
||||
Events are double-buffered:
|
||||
Clients should cache events and redraw when a dwl_ipc_output.frame event is sent.
|
||||
|
||||
Request are not double-buffered:
|
||||
The compositor will update immediately upon request.
|
||||
</description>
|
||||
|
||||
<enum name="tag_state">
|
||||
<entry name="none" value="0" summary="no state"/>
|
||||
<entry name="active" value="1" summary="tag is active"/>
|
||||
<entry name="urgent" value="2" summary="tag has at least one urgent client"/>
|
||||
</enum>
|
||||
|
||||
<request name="release" type="destructor">
|
||||
<description summary="release dwl_ipc_outout">
|
||||
Indicates to that the client no longer needs this dwl_ipc_output.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<event name="toggle_visibility">
|
||||
<description summary="Toggle client visibilty">
|
||||
Indicates the client should hide or show themselves.
|
||||
If the client is visible then hide, if hidden then show.
|
||||
</description>
|
||||
</event>
|
||||
|
||||
<event name="active">
|
||||
<description summary="Update the selected output.">
|
||||
Indicates if the output is active. Zero is invalid, nonzero is valid.
|
||||
</description>
|
||||
<arg name="active" type="uint"/>
|
||||
</event>
|
||||
|
||||
<event name="tag">
|
||||
<description summary="Update the state of a tag.">
|
||||
Indicates that a tag has been updated.
|
||||
</description>
|
||||
<arg name="tag" type="uint" summary="Index of the tag"/>
|
||||
<arg name="state" type="uint" enum="tag_state" summary="The state of the tag."/>
|
||||
<arg name="clients" type="uint" summary="The number of clients in the tag."/>
|
||||
<arg name="focused" type="uint" summary="If there is a focused client. Nonzero being valid, zero being invalid."/>
|
||||
</event>
|
||||
|
||||
<event name="layout">
|
||||
<description summary="Update the layout.">
|
||||
Indicates a new layout is selected.
|
||||
</description>
|
||||
<arg name="layout" type="uint" summary="Index of the layout."/>
|
||||
</event>
|
||||
|
||||
<event name="title">
|
||||
<description summary="Update the title.">
|
||||
Indicates the title has changed.
|
||||
</description>
|
||||
<arg name="title" type="string" summary="The new title name."/>
|
||||
</event>
|
||||
|
||||
<event name="appid" since="1">
|
||||
<description summary="Update the appid.">
|
||||
Indicates the appid has changed.
|
||||
</description>
|
||||
<arg name="appid" type="string" summary="The new appid."/>
|
||||
</event>
|
||||
|
||||
<event name="layout_symbol" since="1">
|
||||
<description summary="Update the current layout symbol">
|
||||
Indicates the layout has changed. Since layout symbols are dynamic.
|
||||
As opposed to the zdwl_ipc_manager.layout event, this should take precendence when displaying.
|
||||
You can ignore the zdwl_ipc_output.layout event.
|
||||
</description>
|
||||
<arg name="layout" type="string" summary="The new layout"/>
|
||||
</event>
|
||||
|
||||
<event name="frame">
|
||||
<description summary="The update sequence is done.">
|
||||
Indicates that a sequence of status updates have finished and the client should redraw.
|
||||
</description>
|
||||
</event>
|
||||
|
||||
<request name="set_tags">
|
||||
<description summary="Set the active tags of this output"/>
|
||||
<arg name="tagmask" type="uint" summary="bitmask of the tags that should be set."/>
|
||||
<arg name="toggle_tagset" type="uint" summary="toggle the selected tagset, zero for invalid, nonzero for valid."/>
|
||||
</request>
|
||||
|
||||
<request name="set_client_tags">
|
||||
<description summary="Set the tags of the focused client.">
|
||||
The tags are updated as follows:
|
||||
new_tags = (current_tags AND and_tags) XOR xor_tags
|
||||
</description>
|
||||
<arg name="and_tags" type="uint"/>
|
||||
<arg name="xor_tags" type="uint"/>
|
||||
</request>
|
||||
|
||||
<request name="set_layout">
|
||||
<description summary="Set the layout of this output"/>
|
||||
<arg name="index" type="uint" summary="index of a layout recieved by dwl_ipc_manager.layout"/>
|
||||
</request>
|
||||
|
||||
<!-- Version 2 -->
|
||||
<event name="fullscreen" since="2">
|
||||
<description summary="Update fullscreen status">
|
||||
Indicates if the selected client on this output is fullscreen.
|
||||
</description>
|
||||
<arg name="is_fullscreen" type="uint" summary="If the selected client is fullscreen. Nonzero is valid, zero invalid"/>
|
||||
</event>
|
||||
|
||||
<event name="floating" since="2">
|
||||
<description summary="Update the floating status">
|
||||
Indicates if the selected client on this output is floating.
|
||||
</description>
|
||||
<arg name="is_floating" type="uint" summary="If the selected client is floating. Nonzero is valid, zero invalid"/>
|
||||
</event>
|
||||
</interface>
|
||||
</protocol>
|
||||
+516
@@ -0,0 +1,516 @@
|
||||
#define _GNU_SOURCE
|
||||
#include "arg.h"
|
||||
#include <poll.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <wayland-client.h>
|
||||
#include <wayland-util.h>
|
||||
#include "dwl-ipc-unstable-v2-protocol.h"
|
||||
|
||||
#define die(fmt, ...) do { fprintf(stderr, fmt "\n", ##__VA_ARGS__); exit(EXIT_FAILURE); } while (0)
|
||||
|
||||
char *argv0;
|
||||
|
||||
static enum {
|
||||
NONE = 0,
|
||||
SET = 1<<0,
|
||||
GET = 1<<1,
|
||||
WATCH = 1<<2 | GET,
|
||||
} mode = NONE;
|
||||
|
||||
static int Oflag;
|
||||
static int Tflag;
|
||||
static int Lflag;
|
||||
static int Pflag;
|
||||
static int Fflag;
|
||||
static int oflag;
|
||||
static int tflag;
|
||||
static int lflag;
|
||||
static int cflag;
|
||||
static int vflag;
|
||||
static int mflag;
|
||||
static int fflag;
|
||||
|
||||
static uint32_t occ, seltags, sel, urg;
|
||||
|
||||
static char *output_name;
|
||||
static char *focused_output;
|
||||
static uint32_t tagcount;
|
||||
static char *tagset;
|
||||
static char *layout_name;
|
||||
static size_t layoutcount, layout_idx;
|
||||
static char *client_tags;
|
||||
|
||||
struct output {
|
||||
char *output_name;
|
||||
uint32_t name;
|
||||
};
|
||||
static size_t outputs_buflen = 4;
|
||||
static struct output *outputs;
|
||||
static size_t outputcount;
|
||||
|
||||
static struct wl_display *display;
|
||||
static struct wl_registry *registry;
|
||||
static struct zdwl_ipc_manager_v2 *dwl_ipc_manager;
|
||||
|
||||
static void
|
||||
dwl_ipc_tags(void *data, struct zdwl_ipc_manager_v2 *dwl_ipc_manager, uint32_t count)
|
||||
{
|
||||
tagcount = count;
|
||||
if (Tflag && mode & GET) printf("%d\n", tagcount);
|
||||
}
|
||||
|
||||
static void
|
||||
dwl_ipc_layout(void *data, struct zdwl_ipc_manager_v2 *dwl_ipc_manager, const char *name)
|
||||
{
|
||||
if (lflag && mode & SET && strcmp(layout_name, name) == 0)
|
||||
layout_idx = layoutcount;
|
||||
if (Lflag && mode & GET) printf("%s\n", name);
|
||||
layoutcount++;
|
||||
}
|
||||
|
||||
static const struct zdwl_ipc_manager_v2_listener dwl_ipc_listener = {
|
||||
.tags = dwl_ipc_tags,
|
||||
.layout = dwl_ipc_layout
|
||||
};
|
||||
|
||||
static void
|
||||
dwl_ipc_output_toggle_visibility(void *data, struct zdwl_ipc_output_v2 *dwl_ipc_output)
|
||||
{
|
||||
if (!vflag) return;
|
||||
char *oname = data;
|
||||
if (oname) printf("%s ", oname);
|
||||
printf("toggle\n");
|
||||
}
|
||||
|
||||
static void
|
||||
dwl_ipc_output_active(void *data, struct zdwl_ipc_output_v2 *dwl_ipc_output,
|
||||
uint32_t active)
|
||||
{
|
||||
if (active && (!output_name || !*output_name))
|
||||
output_name = strdup(data);
|
||||
if (active) {
|
||||
free(focused_output);
|
||||
focused_output = data ? strdup(data) : NULL;
|
||||
}
|
||||
if (!oflag) return;
|
||||
char *oname = data;
|
||||
if (oname) printf("%s ", oname);
|
||||
printf("selmon %u\n", !!active);
|
||||
}
|
||||
|
||||
static void
|
||||
dwl_ipc_output_tag(void *data, struct zdwl_ipc_output_v2 *dwl_ipc_output,
|
||||
uint32_t tag, uint32_t state, uint32_t clients, uint32_t focused)
|
||||
{
|
||||
if (!tflag) return;
|
||||
if (state != ZDWL_IPC_OUTPUT_V2_TAG_STATE_NONE) seltags |= 1<<tag;
|
||||
if (state == ZDWL_IPC_OUTPUT_V2_TAG_STATE_ACTIVE) urg |= 1<<tag;
|
||||
if (clients > 0) occ |= 1<<tag;
|
||||
if (!(mode & GET)) return;
|
||||
if (data) printf("%s ", (char *)data);
|
||||
printf("tag %u %u %u %u\n", tag, state, clients, focused);
|
||||
}
|
||||
|
||||
static void
|
||||
dwl_ipc_output_layout(void *data, struct zdwl_ipc_output_v2 *dwl_ipc_output,
|
||||
uint32_t layout)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
dwl_ipc_output_layout_symbol(void *data, struct zdwl_ipc_output_v2 *dwl_ipc_output,
|
||||
const char *layout)
|
||||
{
|
||||
if (!(lflag && mode & GET)) return;
|
||||
if (data) printf("%s ", (char *)data);
|
||||
printf("layout %s\n", layout);
|
||||
}
|
||||
|
||||
static void
|
||||
dwl_ipc_output_title(void *data, struct zdwl_ipc_output_v2 *dwl_ipc_output,
|
||||
const char *title)
|
||||
{
|
||||
if (!(cflag && mode & GET)) return;
|
||||
if (data) printf("%s ", (char *)data);
|
||||
printf("title %s\n", title);
|
||||
}
|
||||
|
||||
static void
|
||||
dwl_ipc_output_appid(void *data, struct zdwl_ipc_output_v2 *dwl_ipc_output,
|
||||
const char *appid)
|
||||
{
|
||||
if (!(cflag && mode & GET)) return;
|
||||
if (data) printf("%s ", (char *)data);
|
||||
printf("appid %s\n", appid);
|
||||
}
|
||||
|
||||
static void
|
||||
dwl_ipc_output_fullscreen(void *data, struct zdwl_ipc_output_v2 *dwl_ipc_output,
|
||||
uint32_t is_fullscreen)
|
||||
{
|
||||
if (!mflag) return;
|
||||
if (data) printf("%s ", (char *)data);
|
||||
printf("fullscreen %u\n", is_fullscreen);
|
||||
}
|
||||
|
||||
static void
|
||||
dwl_ipc_output_floating(void *data, struct zdwl_ipc_output_v2 *dwl_ipc_output,
|
||||
uint32_t is_floating)
|
||||
{
|
||||
if (!fflag) return;
|
||||
if (data) printf("%s ", (char *)data);
|
||||
printf("floating %u\n", is_floating);
|
||||
}
|
||||
|
||||
static void
|
||||
dwl_ipc_output_frame(void *data, struct zdwl_ipc_output_v2 *dwl_ipc_output)
|
||||
{
|
||||
if (mode & SET) {
|
||||
if (data && !(output_name && strcmp(output_name, (char *)data) == 0)) return;
|
||||
if (lflag) {
|
||||
if (layout_idx == 0) {
|
||||
for (char *c = layout_name; *c; c++) {
|
||||
if (*c < '0' || *c > '9')
|
||||
die("bad layout %s", layout_name);
|
||||
layout_idx = *c-'0' + layout_idx*10;
|
||||
}
|
||||
}
|
||||
if (layout_idx >= layoutcount)
|
||||
die("bad layout %s", layout_name);
|
||||
zdwl_ipc_output_v2_set_layout(dwl_ipc_output, layout_idx);
|
||||
}
|
||||
if (tflag) {
|
||||
uint32_t mask = seltags;
|
||||
char *t = tagset;
|
||||
uint32_t i = 0;
|
||||
int toggle = 1;
|
||||
|
||||
if (*t == '!') {
|
||||
toggle = 0;
|
||||
t++;
|
||||
}
|
||||
|
||||
for (; *t && *t >= '0' && *t <= '9'; t++)
|
||||
i = *t-'0' + i*10;
|
||||
|
||||
if (toggle && !*t) mask = 1<<i;
|
||||
|
||||
for (; *t; t++, i++) {
|
||||
switch (*t) {
|
||||
case '-':
|
||||
mask &= ~(1<<i);
|
||||
break;
|
||||
case '+':
|
||||
mask |= 1<<i;
|
||||
break;
|
||||
case '^':
|
||||
mask ^= 1<<i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i > tagcount) die("bad tagset %s", tagset);
|
||||
|
||||
zdwl_ipc_output_v2_set_tags(dwl_ipc_output, mask, toggle);
|
||||
}
|
||||
if (cflag) {
|
||||
uint32_t and = ~0, xor = 0;
|
||||
char *t = client_tags;
|
||||
uint32_t i = 0;
|
||||
|
||||
for (; *t && *t >= '0' && *t <= '9'; t++)
|
||||
i = *t-'0' + i*10;
|
||||
|
||||
if (!*t) {
|
||||
and = 0;
|
||||
xor = 1<<i;
|
||||
}
|
||||
|
||||
for (; *t; t++, i++) {
|
||||
switch (*t) {
|
||||
case '-':
|
||||
and &= ~(1<<i);
|
||||
break;
|
||||
case '+':
|
||||
and &= ~(1<<i);
|
||||
xor |= 1<<i;
|
||||
break;
|
||||
case '^':
|
||||
xor |= 1<<i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i > tagcount) die("bad client tagset %s", client_tags);
|
||||
|
||||
zdwl_ipc_output_v2_set_client_tags(dwl_ipc_output, and, xor);
|
||||
}
|
||||
wl_display_flush(display);
|
||||
exit(0);
|
||||
} else {
|
||||
if (Fflag && mode == WATCH && focused_output)
|
||||
printf("focusmon %s\n", focused_output);
|
||||
if (tflag) {
|
||||
if (data) printf("%s ", (char *)data);
|
||||
printf("tags %u %u %u %u\n", occ, seltags, sel, urg);
|
||||
occ = seltags = sel = urg = 0;
|
||||
}
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static const struct zdwl_ipc_output_v2_listener dwl_ipc_output_listener = {
|
||||
.toggle_visibility = dwl_ipc_output_toggle_visibility,
|
||||
.active = dwl_ipc_output_active,
|
||||
.tag = dwl_ipc_output_tag,
|
||||
.layout = dwl_ipc_output_layout,
|
||||
.title = dwl_ipc_output_title,
|
||||
.appid = dwl_ipc_output_appid,
|
||||
.layout_symbol = dwl_ipc_output_layout_symbol,
|
||||
.fullscreen = dwl_ipc_output_fullscreen,
|
||||
.floating = dwl_ipc_output_floating,
|
||||
.frame = dwl_ipc_output_frame,
|
||||
};
|
||||
|
||||
static void
|
||||
wl_output_name(void *data, struct wl_output *output, const char *name)
|
||||
{
|
||||
if (outputs) {
|
||||
struct output *o = (struct output *)data;
|
||||
o->output_name = strdup(name);
|
||||
printf("+ ");
|
||||
}
|
||||
if (Oflag) printf("%s\n", name);
|
||||
if (output_name && *output_name && strcmp(output_name, name) != 0) {
|
||||
wl_output_release(output);
|
||||
return;
|
||||
}
|
||||
if (dwl_ipc_manager) {
|
||||
struct zdwl_ipc_output_v2 *dwl_ipc_output =
|
||||
zdwl_ipc_manager_v2_get_output(dwl_ipc_manager, output);
|
||||
zdwl_ipc_output_v2_add_listener(dwl_ipc_output, &dwl_ipc_output_listener,
|
||||
output_name && *output_name ? NULL : strdup(name));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wl_output_geometry(void *data, struct wl_output *wl_output, int32_t x, int32_t y, int32_t w, int32_t h, int32_t subpixel, const char *make, const char *model, int32_t transform) {
|
||||
}
|
||||
|
||||
static void
|
||||
wl_output_mode(void *data, struct wl_output *wl_output, uint32_t flags, int32_t width, int32_t height, int32_t refresh)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
wl_output_done(void *data, struct wl_output *wl_output)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
wl_output_scale(void *data, struct wl_output *wl_output, int32_t factor)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
wl_output_description(void *data, struct wl_output *output, const char *description)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct wl_output_listener output_listener = {
|
||||
.geometry = wl_output_geometry,
|
||||
.mode = wl_output_mode,
|
||||
.done = wl_output_done,
|
||||
.scale = wl_output_scale,
|
||||
.name = wl_output_name,
|
||||
.description = wl_output_description,
|
||||
};
|
||||
|
||||
static void
|
||||
global_add(void *data, struct wl_registry *wl_registry,
|
||||
uint32_t name, const char *interface, uint32_t version)
|
||||
{
|
||||
if (strcmp(interface, wl_output_interface.name) == 0) {
|
||||
struct wl_output *o = wl_registry_bind(
|
||||
wl_registry, name, &wl_output_interface,
|
||||
WL_OUTPUT_NAME_SINCE_VERSION);
|
||||
wl_output_add_listener(o, &output_listener, outputs ? &outputs[outputcount] : NULL);
|
||||
if (!outputs) return;
|
||||
if (outputcount >= outputs_buflen) {
|
||||
outputs_buflen *= 2;
|
||||
outputs = reallocarray(outputs, outputs_buflen, sizeof(struct output));
|
||||
}
|
||||
outputs[outputcount].name = name;
|
||||
outputcount++;
|
||||
} else if (strcmp(interface, zdwl_ipc_manager_v2_interface.name) == 0) {
|
||||
dwl_ipc_manager = wl_registry_bind(wl_registry, name,
|
||||
&zdwl_ipc_manager_v2_interface, version < 2 ? version : 2);
|
||||
zdwl_ipc_manager_v2_add_listener(dwl_ipc_manager, &dwl_ipc_listener, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
global_remove(void *data, struct wl_registry *wl_registry, uint32_t name)
|
||||
{
|
||||
if (!outputs) return;
|
||||
for (size_t i = 0; i < outputcount; i++) {
|
||||
if (outputs[i].name == name) {
|
||||
printf("- %s\n", outputs[i].output_name);
|
||||
free(outputs[i].output_name);
|
||||
outputs[i] = outputs[--outputcount];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static const struct wl_registry_listener registry_listener = {
|
||||
.global = global_add,
|
||||
.global_remove = global_remove,
|
||||
};
|
||||
|
||||
static void
|
||||
usage(int code)
|
||||
{
|
||||
fprintf(code ? stderr : stdout,
|
||||
"usage:"
|
||||
"\t%1$s [-OTLPF]\n"
|
||||
"\t%1$s [-o <output>] -s [-t <tags>] [-l <layout>] [-c <tags>]\n"
|
||||
"\t%1$s [-o <output>] (-g | -w) [-FOotlcvmf]\n",
|
||||
argv0);
|
||||
exit(code);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
ARGBEGIN {
|
||||
case '?': case 'h':
|
||||
usage(0); break;
|
||||
case 's':
|
||||
if (mode != NONE) usage(1);
|
||||
mode = SET;
|
||||
break;
|
||||
case 'g':
|
||||
if (mode != NONE) usage(1);
|
||||
mode = GET;
|
||||
break;
|
||||
case 'w':
|
||||
if (mode != NONE) usage(1);
|
||||
mode = WATCH;
|
||||
break;
|
||||
case 'o':
|
||||
if (mode & SET)
|
||||
output_name = EARGF(usage(1));
|
||||
else if (mode & GET || !(output_name = ARGF()))
|
||||
oflag = 1;
|
||||
break;
|
||||
case 't':
|
||||
tflag = 1;
|
||||
if (mode & GET) break;
|
||||
mode = SET;
|
||||
tagset = EARGF(usage(1));
|
||||
break;
|
||||
case 'l':
|
||||
lflag = 1;
|
||||
if (mode & GET) break;
|
||||
mode = SET;
|
||||
layout_name = EARGF(usage(1));
|
||||
break;
|
||||
case 'c':
|
||||
cflag = 1;
|
||||
if (mode & GET) break;
|
||||
mode = SET;
|
||||
client_tags = EARGF(usage(1));
|
||||
break;
|
||||
case 'O':
|
||||
Oflag = 1;
|
||||
if (mode & SET) usage(1);
|
||||
if (mode & WATCH)
|
||||
outputs = malloc(outputs_buflen * sizeof(struct output));
|
||||
else
|
||||
mode = GET;
|
||||
break;
|
||||
case 'T':
|
||||
Tflag = 1;
|
||||
if (mode && mode != GET) usage(1);
|
||||
mode = GET;
|
||||
break;
|
||||
case 'L':
|
||||
Lflag = 1;
|
||||
if (mode && mode != GET) usage(1);
|
||||
mode = GET;
|
||||
break;
|
||||
case 'P':
|
||||
Pflag = 1;
|
||||
if (mode && mode != GET) usage(1);
|
||||
mode = GET;
|
||||
break;
|
||||
case 'F':
|
||||
Fflag = 1;
|
||||
if (mode && mode != GET) usage(1);
|
||||
mode = GET;
|
||||
break;
|
||||
case 'v':
|
||||
vflag = 1;
|
||||
if (mode & SET) usage(1);
|
||||
mode |= GET;
|
||||
break;
|
||||
case 'm':
|
||||
mflag = 1;
|
||||
if (mode & SET) usage(1);
|
||||
mode |= GET;
|
||||
break;
|
||||
case 'f':
|
||||
fflag = 1;
|
||||
if (mode & SET) usage(1);
|
||||
mode |= GET;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "%s: bad option: -%c\n", argv0, ARGC());
|
||||
usage(1);
|
||||
} ARGEND
|
||||
if (argc > 0) {
|
||||
fprintf(stderr, "%s: bad args:", argv0);
|
||||
for (; *argv; argv++)
|
||||
fprintf(stderr, " %s", argv[0]);
|
||||
fprintf(stderr, "\n");
|
||||
usage(1);
|
||||
}
|
||||
if (mode == NONE) usage(1);
|
||||
if (mode & GET && !(oflag || tflag || lflag || Oflag || Tflag || Lflag || Pflag || Fflag || cflag || vflag || mflag || fflag))
|
||||
oflag = tflag = lflag = cflag = vflag = mflag = fflag = Fflag = 1;
|
||||
|
||||
display = wl_display_connect(NULL);
|
||||
if (!display) die("bad display");
|
||||
|
||||
if (Pflag) {
|
||||
int fd = wl_display_get_fd(display);
|
||||
struct ucred ucred;
|
||||
socklen_t len = sizeof(struct ucred);
|
||||
if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1)
|
||||
die("bad getsockopt");
|
||||
printf("%d\n", ucred.pid);
|
||||
}
|
||||
|
||||
registry = wl_display_get_registry(display);
|
||||
if (!registry) die("bad registry");
|
||||
|
||||
wl_registry_add_listener(registry, ®istry_listener, NULL);
|
||||
|
||||
wl_display_dispatch(display);
|
||||
wl_display_roundtrip(display);
|
||||
|
||||
if (!dwl_ipc_manager && (mode & SET || tflag || lflag || Tflag || Lflag || cflag || vflag || mflag || fflag))
|
||||
die("bad dwl-ipc protocol");
|
||||
|
||||
wl_display_roundtrip(display);
|
||||
|
||||
if (Fflag && !(mode == WATCH) && focused_output)
|
||||
printf("focusmon %s\n", focused_output);
|
||||
|
||||
if (mode == WATCH)
|
||||
while (wl_display_dispatch(display) != -1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user