mirror of
https://github.com/labwc/labwc.git
synced 2025-10-29 05:40:24 -04:00
Add labnag
Based on swaynag (https://github.com/swaywm/sway/tree/master/swaynag)
Copied at commit:
03483ff370
Contains the following modifiations:
- Some functional changes including:
- Disable exclusive-zone by default (Written-by: @Consolatis) and add
command line option -x|--exclusive-zone
- Add close timeout (Written-by: @Consolatis) and -t|--timeout option
- Use index of button (from right-to-left) for exit code
- Disable reading from config file and remove associated --type option
- Refactoring including:
- Use wlr_log() instead of the log.{c,h} functions
- Use wl_list instead of sway's list.c implementation
- In the pango wrapper functions, use glib's g_strdup_vprintf() rather
than the original stringop.c functions
- Align with labwc coding style to pass checkpatch.pl
- Re-licenced from MIT to GPL-2.0, and add Copyright notices for original
authors
v2
- Remove option -s|--dismiss-button and the default "X" button. To get
such a button, "-Z X :"
- Remove options -b and -z because there is no requirement to run
in a terminal.
- Remove *-no-terminal from options --button and --button-dismiss because
commands are now always run directly without a terminal.
v3
- Allow -B/-Z options without action-argument
- Invert button order of -B/-Z so that `labnag -m foo -Z x -Z y -Z z`
results in three buttons with "x" furthest to the left, and "z" on the
right (rather than the other way around).
- Use signalfd() to prevent race conditions on SIGTERM
v4
- Limit number of stdin lines to 200 to avoid hogging CPU
Co-Authored-by: tokyo4j
This commit is contained in:
parent
6fd14987dd
commit
c63d35c942
8 changed files with 1986 additions and 1 deletions
1652
clients/labnag.c
Normal file
1652
clients/labnag.c
Normal file
File diff suppressed because it is too large
Load diff
47
clients/meson.build
Normal file
47
clients/meson.build
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
wayland_client = dependency('wayland-client')
|
||||
wayland_cursor = dependency('wayland-cursor')
|
||||
|
||||
nag_sources = files(
|
||||
'labnag.c',
|
||||
'pool-buffer.c',
|
||||
)
|
||||
|
||||
wl_protocol_dir = wayland_protos.get_variable('pkgdatadir')
|
||||
|
||||
protocols = [
|
||||
wl_protocol_dir / 'stable/tablet/tablet-v2.xml',
|
||||
wl_protocol_dir / 'stable/xdg-shell/xdg-shell.xml',
|
||||
wl_protocol_dir / 'staging/cursor-shape/cursor-shape-v1.xml',
|
||||
'../protocols/wlr-layer-shell-unstable-v1.xml',
|
||||
]
|
||||
|
||||
foreach xml : protocols
|
||||
nag_sources += custom_target(
|
||||
xml.underscorify() + '_c',
|
||||
input: xml,
|
||||
output: '@BASENAME@-protocol.c',
|
||||
command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'],
|
||||
)
|
||||
nag_sources += custom_target(
|
||||
xml.underscorify() + '_client_h',
|
||||
input: xml,
|
||||
output: '@BASENAME@-client-protocol.h',
|
||||
command: [wayland_scanner, 'client-header', '@INPUT@', '@OUTPUT@'],
|
||||
)
|
||||
endforeach
|
||||
|
||||
executable(
|
||||
'labnag',
|
||||
nag_sources,
|
||||
dependencies: [
|
||||
cairo,
|
||||
pangocairo,
|
||||
glib,
|
||||
wayland_client,
|
||||
wayland_cursor,
|
||||
wlroots,
|
||||
server_protos,
|
||||
],
|
||||
install: true
|
||||
)
|
||||
|
||||
145
clients/pool-buffer.c
Normal file
145
clients/pool-buffer.c
Normal file
|
|
@ -0,0 +1,145 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Copied from https://github.com/swaywm/sway
|
||||
*
|
||||
* Copyright (C) 2016-2017 Drew DeVault
|
||||
*/
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <assert.h>
|
||||
#include <cairo.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <pango/pangocairo.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <wayland-client.h>
|
||||
#include "pool-buffer.h"
|
||||
|
||||
static int anonymous_shm_open(void)
|
||||
{
|
||||
int retries = 100;
|
||||
|
||||
do {
|
||||
// try a probably-unique name
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
pid_t pid = getpid();
|
||||
char name[50];
|
||||
snprintf(name, sizeof(name), "/labnag-%x-%x",
|
||||
(unsigned int)pid, (unsigned int)ts.tv_nsec);
|
||||
|
||||
// shm_open guarantees that O_CLOEXEC is set
|
||||
int fd = shm_open(name, O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||
if (fd >= 0) {
|
||||
shm_unlink(name);
|
||||
return fd;
|
||||
}
|
||||
|
||||
--retries;
|
||||
} while (retries > 0 && errno == EEXIST);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void buffer_release(void *data, struct wl_buffer *wl_buffer)
|
||||
{
|
||||
struct pool_buffer *buffer = data;
|
||||
buffer->busy = false;
|
||||
}
|
||||
|
||||
static const struct wl_buffer_listener buffer_listener = {
|
||||
.release = buffer_release
|
||||
};
|
||||
|
||||
static struct pool_buffer *create_buffer(struct wl_shm *shm,
|
||||
struct pool_buffer *buf, int32_t width, int32_t height,
|
||||
uint32_t format)
|
||||
{
|
||||
uint32_t stride = width * 4;
|
||||
size_t size = stride * height;
|
||||
|
||||
int fd = anonymous_shm_open();
|
||||
if (fd == -1) {
|
||||
return NULL;
|
||||
}
|
||||
if (ftruncate(fd, size) < 0) {
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
void *data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size);
|
||||
buf->buffer = wl_shm_pool_create_buffer(pool, 0,
|
||||
width, height, stride, format);
|
||||
wl_shm_pool_destroy(pool);
|
||||
close(fd);
|
||||
|
||||
buf->size = size;
|
||||
buf->width = width;
|
||||
buf->height = height;
|
||||
buf->data = data;
|
||||
buf->surface = cairo_image_surface_create_for_data(data,
|
||||
CAIRO_FORMAT_ARGB32, width, height, stride);
|
||||
buf->cairo = cairo_create(buf->surface);
|
||||
buf->pango = pango_cairo_create_context(buf->cairo);
|
||||
|
||||
wl_buffer_add_listener(buf->buffer, &buffer_listener, buf);
|
||||
return buf;
|
||||
}
|
||||
|
||||
void destroy_buffer(struct pool_buffer *buffer)
|
||||
{
|
||||
if (buffer->buffer) {
|
||||
wl_buffer_destroy(buffer->buffer);
|
||||
buffer->buffer = NULL;
|
||||
}
|
||||
if (buffer->cairo) {
|
||||
cairo_destroy(buffer->cairo);
|
||||
buffer->cairo = NULL;
|
||||
}
|
||||
if (buffer->surface) {
|
||||
cairo_surface_destroy(buffer->surface);
|
||||
buffer->surface = NULL;
|
||||
}
|
||||
if (buffer->pango) {
|
||||
g_object_unref(buffer->pango);
|
||||
buffer->pango = NULL;
|
||||
}
|
||||
if (buffer->data) {
|
||||
munmap(buffer->data, buffer->size);
|
||||
buffer->data = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
struct pool_buffer *get_next_buffer(struct wl_shm *shm,
|
||||
struct pool_buffer pool[static 2], uint32_t width, uint32_t height)
|
||||
{
|
||||
struct pool_buffer *buffer = NULL;
|
||||
|
||||
for (size_t i = 0; i < 2; ++i) {
|
||||
if (pool[i].busy) {
|
||||
continue;
|
||||
}
|
||||
buffer = &pool[i];
|
||||
}
|
||||
|
||||
if (!buffer) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (buffer->width != width || buffer->height != height) {
|
||||
destroy_buffer(buffer);
|
||||
}
|
||||
|
||||
if (!buffer->buffer) {
|
||||
if (!create_buffer(shm, buffer, width, height,
|
||||
WL_SHM_FORMAT_ARGB8888)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
buffer->busy = true;
|
||||
return buffer;
|
||||
}
|
||||
30
clients/pool-buffer.h
Normal file
30
clients/pool-buffer.h
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copied from https://github.com/swaywm/sway
|
||||
*
|
||||
* Copyright (C) 2016-2017 Drew DeVault
|
||||
*/
|
||||
#ifndef LAB_POOL_BUFFER_H
|
||||
#define LAB_POOL_BUFFER_H
|
||||
#include <cairo.h>
|
||||
#include <pango/pangocairo.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
struct pool_buffer {
|
||||
struct wl_buffer *buffer;
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *cairo;
|
||||
PangoContext *pango;
|
||||
uint32_t width, height;
|
||||
void *data;
|
||||
size_t size;
|
||||
bool busy;
|
||||
};
|
||||
|
||||
struct pool_buffer *get_next_buffer(struct wl_shm *shm,
|
||||
struct pool_buffer pool[static 2], uint32_t width, uint32_t height);
|
||||
void destroy_buffer(struct pool_buffer *buffer);
|
||||
|
||||
#endif /* LAB_POOL_BUFFER_H */
|
||||
109
docs/labnag.1.scd
Normal file
109
docs/labnag.1.scd
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
labnag(1)
|
||||
|
||||
# NAME
|
||||
|
||||
labnag - Show dialog with message and buttons
|
||||
|
||||
# SYNOPSIS
|
||||
|
||||
_labnag_ [options...]
|
||||
|
||||
# OPTIONS
|
||||
|
||||
*-B, --button* <text> [<action>]
|
||||
Create a button with the text _text_ that optionally executes _action_
|
||||
when pressed. Multiple buttons can be defined by providing the flag
|
||||
multiple times. Buttons will appear in the order they are provided from
|
||||
lef to right.
|
||||
|
||||
*-Z, --button-dismiss* <text> [<action>]
|
||||
Create a button with the text _text_ that optionally executes _action_
|
||||
when pressed, and dismisses labnag. Multiple buttons can be defined by
|
||||
providing the flag multiple times. Buttons will appear in the order
|
||||
they are provided from lef to right.
|
||||
|
||||
*-d, --debug*
|
||||
Enable debugging.
|
||||
|
||||
*-e, --edge* top|bottom
|
||||
Set the edge to use.
|
||||
|
||||
*-y, --layer* overlay|top|bottom|background
|
||||
Set the layer to use.
|
||||
|
||||
*-f, --font* <font>
|
||||
Set the font to use.
|
||||
|
||||
*-h, --help*
|
||||
Show help message and quit.
|
||||
|
||||
*-l, --detailed-message*
|
||||
Read a detailed message from stdin. A button to toggle details will be
|
||||
added. Details are shown in a scrollable multi-line text area.
|
||||
|
||||
*-L, --detailed-button* <text>
|
||||
Set the text for the button that toggles details. This has no effect if
|
||||
there is not a detailed message. The default is _Toggle details_.
|
||||
|
||||
*-m, --message* <msg>
|
||||
Set the message text.
|
||||
|
||||
*-o, --output* <output>
|
||||
Set the output to use. This should be the name of a _xdg\_output_.
|
||||
|
||||
*-t, --timeout*
|
||||
Set duration to close dialog. Default is 5 seconds.
|
||||
|
||||
*-x, --exclusive-zone*
|
||||
Use exclusive zone. Default is false.
|
||||
|
||||
*-v, --version*
|
||||
Show the version number and quit.
|
||||
|
||||
# APPEARANCE OPTIONS
|
||||
|
||||
*--background* <RRGGBB[AA]>
|
||||
Set the color of the background.
|
||||
|
||||
*--border* <RRGGBB[AA]>
|
||||
Set the color of the border.
|
||||
|
||||
*--border-bottom* <RRGGBB[AA]>
|
||||
Set the color of the bottom border.
|
||||
|
||||
*--button-background* <RRGGBB[AA]>
|
||||
Set the color for the background for buttons.
|
||||
|
||||
*--text* <RRGGBB[AA]>
|
||||
Set the text color.
|
||||
|
||||
*--button-text* <RRGGBB[AA]>
|
||||
Set the button text color.
|
||||
|
||||
*--border-bottom-size* <size>
|
||||
Set the thickness of the bottom border.
|
||||
|
||||
*--message-padding* <padding>
|
||||
Set the padding for the message.
|
||||
|
||||
*--details-background* <RRGGBB[AA]>
|
||||
Set the color for the background for details.
|
||||
|
||||
*--details-border-size* <size>
|
||||
Set the thickness for the details border.
|
||||
|
||||
*--button-border-size* <size>
|
||||
Set the thickness for the button border.
|
||||
|
||||
*--button-gap* <gap>
|
||||
Set the size of the gap between buttons.
|
||||
|
||||
*--button-dismiss-gap* <gap>
|
||||
Set the size of the gap between the dismiss button and another button.
|
||||
|
||||
*--button-margin-right* <margin>
|
||||
Set the margin from the right of the dismiss button to edge.
|
||||
|
||||
*--button-padding* <padding>
|
||||
Set the padding for the button text.
|
||||
|
||||
|
|
@ -7,6 +7,7 @@ if scdoc.found()
|
|||
'labwc-config.5',
|
||||
'labwc-menu.5',
|
||||
'labwc-theme.5',
|
||||
'labnag.1',
|
||||
]
|
||||
foreach manpage : manpages
|
||||
markdown = manpage + '.scd'
|
||||
|
|
|
|||
|
|
@ -180,6 +180,7 @@ endif
|
|||
subdir('include')
|
||||
subdir('src')
|
||||
subdir('docs')
|
||||
subdir('clients')
|
||||
|
||||
dep_cmocka = dependency('cmocka', required: get_option('test'))
|
||||
if dep_cmocka.found()
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ run_checks () {
|
|||
return $?
|
||||
fi
|
||||
|
||||
find src/ include/ \( -name "*.c" -o -name "*.h" \) -type f -print0 |
|
||||
find src/ include/ clients/ \( -name "*.c" -o -name "*.h" \) -type f -print0 |
|
||||
nice xargs -0 --max-args 1 --max-procs $(nproc) \
|
||||
scripts/checkpatch.pl --terse --no-tree --strict --file
|
||||
return $?
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue