mirror of
https://github.com/labwc/labwc.git
synced 2025-10-29 05:40:24 -04:00
Compare commits
3 commits
ebce406b11
...
5fdebedcd9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5fdebedcd9 | ||
|
|
5765586636 | ||
|
|
7028e65154 |
12 changed files with 242 additions and 7 deletions
|
|
@ -1370,7 +1370,7 @@ nag_parse_options(int argc, char **argv, struct nag *nag,
|
||||||
{"detailed-button", required_argument, NULL, 'L'},
|
{"detailed-button", required_argument, NULL, 'L'},
|
||||||
{"message", required_argument, NULL, 'm'},
|
{"message", required_argument, NULL, 'm'},
|
||||||
{"output", required_argument, NULL, 'o'},
|
{"output", required_argument, NULL, 'o'},
|
||||||
{"timeout", no_argument, NULL, 't'},
|
{"timeout", required_argument, NULL, 't'},
|
||||||
{"version", no_argument, NULL, 'v'},
|
{"version", no_argument, NULL, 'v'},
|
||||||
|
|
||||||
{"background", required_argument, NULL, TO_COLOR_BACKGROUND},
|
{"background", required_argument, NULL, TO_COLOR_BACKGROUND},
|
||||||
|
|
|
||||||
|
|
@ -179,6 +179,7 @@ this is for compatibility with Openbox.
|
||||||
<reuseOutputMode>no</reuseOutputMode>
|
<reuseOutputMode>no</reuseOutputMode>
|
||||||
<xwaylandPersistence>no</xwaylandPersistence>
|
<xwaylandPersistence>no</xwaylandPersistence>
|
||||||
<primarySelection>yes</primarySelection>
|
<primarySelection>yes</primarySelection>
|
||||||
|
<promptCommand>[see details below]</promptCommand>
|
||||||
</core>
|
</core>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -265,6 +266,53 @@ this is for compatibility with Openbox.
|
||||||
up/down) in Chromium and electron based clients without inadvertantly
|
up/down) in Chromium and electron based clients without inadvertantly
|
||||||
pasting the primary clipboard. Default is yes.
|
pasting the primary clipboard. Default is yes.
|
||||||
|
|
||||||
|
*<core><promptCommand>*
|
||||||
|
Set command to be invoked for an action prompt (*<action><prompt>*)
|
||||||
|
|
||||||
|
The following conversion specifiers are supported:
|
||||||
|
- *%m*: the *<prompt>* message option
|
||||||
|
- *%n*: "No" (in local language if translation is available)
|
||||||
|
- *%y*: "Yes" (in local language if translation is available)
|
||||||
|
- *%b*: osd.bg.color
|
||||||
|
- *%t*: osd.label.text.color
|
||||||
|
|
||||||
|
The default prompt command is:
|
||||||
|
|
||||||
|
```
|
||||||
|
labnag \\
|
||||||
|
--message '%m' \\
|
||||||
|
--button-dismiss '%n' \\
|
||||||
|
--button-dismiss '%y' \\
|
||||||
|
--background '%b' \\
|
||||||
|
--text '%t' \\
|
||||||
|
--border '%t' \\
|
||||||
|
--border-bottom '%t' \\
|
||||||
|
--button-background '%b' \\
|
||||||
|
--button-text '%t' \\
|
||||||
|
--border-bottom-size 1 \\
|
||||||
|
--button-border-size 3 \\
|
||||||
|
--timeout 0
|
||||||
|
```
|
||||||
|
|
||||||
|
Example 1: The prompt can be configured to use a different dialog client
|
||||||
|
|
||||||
|
```
|
||||||
|
<core>
|
||||||
|
<promptCommand>zenity --question --text="%m"</promptCommand>
|
||||||
|
</core>
|
||||||
|
```
|
||||||
|
|
||||||
|
Example 2: A more complex zenity command could be used:
|
||||||
|
|
||||||
|
```
|
||||||
|
zenity \\
|
||||||
|
--question \\
|
||||||
|
--title="" \\
|
||||||
|
--text="%m" \\
|
||||||
|
--ok-label="%y" \\
|
||||||
|
--cancel-label="%n"
|
||||||
|
```
|
||||||
|
|
||||||
## PLACEMENT
|
## PLACEMENT
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,10 @@
|
||||||
<reuseOutputMode>no</reuseOutputMode>
|
<reuseOutputMode>no</reuseOutputMode>
|
||||||
<xwaylandPersistence>no</xwaylandPersistence>
|
<xwaylandPersistence>no</xwaylandPersistence>
|
||||||
<primarySelection>yes</primarySelection>
|
<primarySelection>yes</primarySelection>
|
||||||
|
<!--
|
||||||
|
# See labwc-config(5) for details
|
||||||
|
<promptCommand></promptCommand>
|
||||||
|
-->
|
||||||
</core>
|
</core>
|
||||||
|
|
||||||
<placement>
|
<placement>
|
||||||
|
|
|
||||||
12
include/action-prompt-command.h
Normal file
12
include/action-prompt-command.h
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
|
#ifndef LABWC_ACTION_PROMPT_COMMAND_H
|
||||||
|
#define LABWC_ACTION_PROMPT_COMMAND_H
|
||||||
|
|
||||||
|
struct buf;
|
||||||
|
struct action;
|
||||||
|
struct theme;
|
||||||
|
|
||||||
|
void action_prompt_command(struct buf *buf, const char *format,
|
||||||
|
struct action *action, struct theme *theme);
|
||||||
|
|
||||||
|
#endif /* LABWC_ACTION_PROMPT_COMMAND_H */
|
||||||
|
|
@ -23,6 +23,8 @@ struct action {
|
||||||
|
|
||||||
struct action *action_create(const char *action_name);
|
struct action *action_create(const char *action_name);
|
||||||
|
|
||||||
|
const char *action_get_str(struct action *action, const char *key,
|
||||||
|
const char *default_value);
|
||||||
bool action_is_valid(struct action *action);
|
bool action_is_valid(struct action *action);
|
||||||
bool action_is_show_menu(struct action *action);
|
bool action_is_show_menu(struct action *action);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,17 @@ void buf_expand_shell_variables(struct buf *s);
|
||||||
*/
|
*/
|
||||||
void buf_add_fmt(struct buf *s, const char *fmt, ...);
|
void buf_add_fmt(struct buf *s, const char *fmt, ...);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* buf_add_hex_color - add rgb color as hex string to C string buffer
|
||||||
|
* @s: buffer
|
||||||
|
* @color: rgb color to be added
|
||||||
|
*
|
||||||
|
* For example:
|
||||||
|
* - With the input 'red' (defined as red[4] = { 1.0f, 0.0f, 0.0f, 1.0f}) the
|
||||||
|
* string "#ff0000ff" will be written to the buffer.
|
||||||
|
*/
|
||||||
|
void buf_add_hex_color(struct buf *s, float color[4]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* buf_add - add data to C string buffer
|
* buf_add - add data to C string buffer
|
||||||
* @s: buffer
|
* @s: buffer
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,8 @@ struct rcxml {
|
||||||
enum lab_placement_policy placement_policy;
|
enum lab_placement_policy placement_policy;
|
||||||
bool xwayland_persistence;
|
bool xwayland_persistence;
|
||||||
bool primary_selection;
|
bool primary_selection;
|
||||||
|
char *prompt_command;
|
||||||
|
|
||||||
int placement_cascade_offset_x;
|
int placement_cascade_offset_x;
|
||||||
int placement_cascade_offset_y;
|
int placement_cascade_offset_y;
|
||||||
|
|
||||||
|
|
|
||||||
108
src/action-prompt-command.c
Normal file
108
src/action-prompt-command.c
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#include "action-prompt-command.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <wlr/util/log.h>
|
||||||
|
#include "action.h"
|
||||||
|
#include "common/buf.h"
|
||||||
|
#include "labwc.h" /* for gettext */
|
||||||
|
#include "theme.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
LAB_PROMPT_NONE = 0,
|
||||||
|
LAB_PROMPT_MESSAGE,
|
||||||
|
LAB_PROMPT_NO,
|
||||||
|
LAB_PROMPT_YES,
|
||||||
|
LAB_PROMPT_BG_COL,
|
||||||
|
LAB_PROMPT_TEXT_COL,
|
||||||
|
|
||||||
|
LAB_PROMPT_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void field_conversion_type(struct buf *buf, struct action *action,
|
||||||
|
struct theme *theme);
|
||||||
|
|
||||||
|
struct field_converter {
|
||||||
|
const char fmt_char;
|
||||||
|
field_conversion_type *fn;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* %m */
|
||||||
|
static void
|
||||||
|
set_message(struct buf *buf, struct action *action, struct theme *theme)
|
||||||
|
{
|
||||||
|
buf_add(buf, action_get_str(action, "message.prompt", "Choose wisely"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* %n */
|
||||||
|
static void
|
||||||
|
set_no(struct buf *buf, struct action *action, struct theme *theme)
|
||||||
|
{
|
||||||
|
buf_add(buf, _("No"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* %y */
|
||||||
|
static void
|
||||||
|
set_yes(struct buf *buf, struct action *action, struct theme *theme)
|
||||||
|
{
|
||||||
|
buf_add(buf, _("Yes"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* %b */
|
||||||
|
static void
|
||||||
|
set_bg_col(struct buf *buf, struct action *action, struct theme *theme)
|
||||||
|
{
|
||||||
|
buf_add_hex_color(buf, theme->osd_bg_color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* %t */
|
||||||
|
static void
|
||||||
|
set_text_col(struct buf *buf, struct action *action, struct theme *theme)
|
||||||
|
{
|
||||||
|
buf_add_hex_color(buf, theme->osd_label_text_color);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct field_converter field_converter[LAB_PROMPT_COUNT] = {
|
||||||
|
[LAB_PROMPT_MESSAGE] = { 'm', set_message },
|
||||||
|
[LAB_PROMPT_NO] = { 'n', set_no },
|
||||||
|
[LAB_PROMPT_YES] = { 'y', set_yes },
|
||||||
|
[LAB_PROMPT_BG_COL] = { 'b', set_bg_col },
|
||||||
|
[LAB_PROMPT_TEXT_COL] = { 't', set_text_col },
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
action_prompt_command(struct buf *buf, const char *format,
|
||||||
|
struct action *action, struct theme *theme)
|
||||||
|
{
|
||||||
|
if (!format) {
|
||||||
|
wlr_log(WLR_ERROR, "missing format");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const char *p = format; *p; p++) {
|
||||||
|
/*
|
||||||
|
* If we're not on a conversion specifier (like %m) then just
|
||||||
|
* keep adding it to the buffer
|
||||||
|
*/
|
||||||
|
if (*p != '%') {
|
||||||
|
buf_add_char(buf, *p);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process the %* conversion specifier */
|
||||||
|
++p;
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
for (unsigned char i = 0; i < LAB_PROMPT_COUNT; i++) {
|
||||||
|
if (*p == field_converter[i].fmt_char) {
|
||||||
|
field_converter[i].fn(buf, action, theme);
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
|
wlr_log(WLR_ERROR,
|
||||||
|
"invalid prompt command conversion specifier '%c'", *p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
14
src/action.c
14
src/action.c
|
|
@ -10,6 +10,7 @@
|
||||||
#include <wlr/types/wlr_scene.h>
|
#include <wlr/types/wlr_scene.h>
|
||||||
#include <wlr/util/log.h>
|
#include <wlr/util/log.h>
|
||||||
#include "action-prompt-codes.h"
|
#include "action-prompt-codes.h"
|
||||||
|
#include "action-prompt-command.h"
|
||||||
#include "common/buf.h"
|
#include "common/buf.h"
|
||||||
#include "common/macros.h"
|
#include "common/macros.h"
|
||||||
#include "common/list.h"
|
#include "common/list.h"
|
||||||
|
|
@ -281,7 +282,7 @@ action_get_arg(struct action *action, const char *key, enum action_arg_type type
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *
|
const char *
|
||||||
action_get_str(struct action *action, const char *key, const char *default_value)
|
action_get_str(struct action *action, const char *key, const char *default_value)
|
||||||
{
|
{
|
||||||
struct action_arg_str *arg = action_get_arg(action, key, LAB_ACTION_ARG_STR);
|
struct action_arg_str *arg = action_get_arg(action, key, LAB_ACTION_ARG_STR);
|
||||||
|
|
@ -833,12 +834,13 @@ handle_view_destroy(struct wl_listener *listener, void *data)
|
||||||
static void
|
static void
|
||||||
action_prompt_create(struct view *view, struct server *server, struct action *action)
|
action_prompt_create(struct view *view, struct server *server, struct action *action)
|
||||||
{
|
{
|
||||||
char *command = strdup_printf("labnag -m \"%s\" -Z \"%s\" -Z \"%s\"",
|
struct buf command = BUF_INIT;
|
||||||
action_get_str(action, "message.prompt", "Choose wisely"),
|
action_prompt_command(&command, rc.prompt_command, action, rc.theme);
|
||||||
_("No"), _("Yes"));
|
|
||||||
|
wlr_log(WLR_INFO, "prompt command: '%s'", command.data);
|
||||||
|
|
||||||
int pipe_fd;
|
int pipe_fd;
|
||||||
pid_t prompt_pid = spawn_piped(command, &pipe_fd);
|
pid_t prompt_pid = spawn_piped(command.data, &pipe_fd);
|
||||||
if (prompt_pid < 0) {
|
if (prompt_pid < 0) {
|
||||||
wlr_log(WLR_ERROR, "Failed to create action prompt");
|
wlr_log(WLR_ERROR, "Failed to create action prompt");
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
@ -862,7 +864,7 @@ action_prompt_create(struct view *view, struct server *server, struct action *ac
|
||||||
wl_list_insert(&prompts, &prompt->link);
|
wl_list_insert(&prompts, &prompt->link);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
free(command);
|
buf_reset(&command);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
||||||
|
|
@ -128,6 +128,30 @@ buf_add_fmt(struct buf *s, const char *fmt, ...)
|
||||||
s->data[s->len] = 0;
|
s->data[s->len] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
buf_add_hex_color(struct buf *s, float color[4])
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* In theme.c parse_hexstr() colors are pre-multiplied (by alpha) as
|
||||||
|
* expected by wlr_scene(). We therefore need to reverse that here.
|
||||||
|
*
|
||||||
|
* For details, see https://github.com/labwc/labwc/pull/1685
|
||||||
|
*/
|
||||||
|
float alpha = color[3];
|
||||||
|
|
||||||
|
/* Avoid division by zero */
|
||||||
|
if (alpha == 0.0f) {
|
||||||
|
buf_add(s, "#00000000");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf_add_fmt(s, "#%02x%02x%02x%02x",
|
||||||
|
(int)(color[0] / alpha * 255),
|
||||||
|
(int)(color[1] / alpha * 255),
|
||||||
|
(int)(color[2] / alpha * 255),
|
||||||
|
(int)(alpha * 255));
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
buf_add(struct buf *s, const char *data)
|
buf_add(struct buf *s, const char *data)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1102,6 +1102,10 @@ entry(xmlNode *node, char *nodename, char *content)
|
||||||
set_bool(content, &rc.xwayland_persistence);
|
set_bool(content, &rc.xwayland_persistence);
|
||||||
} else if (!strcasecmp(nodename, "primarySelection.core")) {
|
} else if (!strcasecmp(nodename, "primarySelection.core")) {
|
||||||
set_bool(content, &rc.primary_selection);
|
set_bool(content, &rc.primary_selection);
|
||||||
|
|
||||||
|
} else if (!strcasecmp(nodename, "promptCommand.core")) {
|
||||||
|
xstrdup_replace(rc.prompt_command, content);
|
||||||
|
|
||||||
} else if (!strcmp(nodename, "policy.placement")) {
|
} else if (!strcmp(nodename, "policy.placement")) {
|
||||||
enum lab_placement_policy policy = view_placement_parse(content);
|
enum lab_placement_policy policy = view_placement_parse(content);
|
||||||
if (policy != LAB_PLACE_INVALID) {
|
if (policy != LAB_PLACE_INVALID) {
|
||||||
|
|
@ -1624,6 +1628,22 @@ post_processing(void)
|
||||||
load_default_mouse_bindings();
|
load_default_mouse_bindings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!rc.prompt_command) {
|
||||||
|
rc.prompt_command =
|
||||||
|
xstrdup("labnag "
|
||||||
|
"--message '%m' "
|
||||||
|
"--button-dismiss '%n' "
|
||||||
|
"--button-dismiss '%y' "
|
||||||
|
"--background '%b' "
|
||||||
|
"--text '%t' "
|
||||||
|
"--border '%t' "
|
||||||
|
"--border-bottom '%t' "
|
||||||
|
"--button-background '%b' "
|
||||||
|
"--button-text '%t' "
|
||||||
|
"--border-bottom-size 1 "
|
||||||
|
"--button-border-size 3 "
|
||||||
|
"--timeout 0");
|
||||||
|
}
|
||||||
if (!rc.fallback_app_icon_name) {
|
if (!rc.fallback_app_icon_name) {
|
||||||
rc.fallback_app_icon_name = xstrdup("labwc");
|
rc.fallback_app_icon_name = xstrdup("labwc");
|
||||||
}
|
}
|
||||||
|
|
@ -1886,6 +1906,7 @@ rcxml_finish(void)
|
||||||
zfree(rc.font_menuheader.name);
|
zfree(rc.font_menuheader.name);
|
||||||
zfree(rc.font_menuitem.name);
|
zfree(rc.font_menuitem.name);
|
||||||
zfree(rc.font_osd.name);
|
zfree(rc.font_osd.name);
|
||||||
|
zfree(rc.prompt_command);
|
||||||
zfree(rc.theme_name);
|
zfree(rc.theme_name);
|
||||||
zfree(rc.icon_theme_name);
|
zfree(rc.icon_theme_name);
|
||||||
zfree(rc.fallback_app_icon_name);
|
zfree(rc.fallback_app_icon_name);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
labwc_sources = files(
|
labwc_sources = files(
|
||||||
'action.c',
|
'action.c',
|
||||||
|
'action-prompt-command.c',
|
||||||
'buffer.c',
|
'buffer.c',
|
||||||
'debug.c',
|
'debug.c',
|
||||||
'desktop.c',
|
'desktop.c',
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue