mirror of
https://github.com/labwc/labwc.git
synced 2025-10-29 05:40:24 -04:00
scaled-icon-buffer: add icon priority
Co-Authored-By: tokyo4j <hrak1529@gmail.com>
This commit is contained in:
parent
e72f862650
commit
acd2a23f1b
7 changed files with 118 additions and 38 deletions
|
|
@ -1178,7 +1178,7 @@ sandboxAppId="" type="" matchOnce="">*
|
||||||
|
|
||||||
*Properties*
|
*Properties*
|
||||||
|
|
||||||
Property values can be *yes*, *no* or *default*.
|
Most property values can be *yes*, *no* or *default*.
|
||||||
|
|
||||||
If a window matches criteria for multiple rules which set the same property,
|
If a window matches criteria for multiple rules which set the same property,
|
||||||
later config entries have higher priority. *default* can be useful in this
|
later config entries have higher priority. *default* can be useful in this
|
||||||
|
|
@ -1210,6 +1210,16 @@ situation.
|
||||||
can be caused by *<margin>* settings or exclusive layer-shell clients
|
can be caused by *<margin>* settings or exclusive layer-shell clients
|
||||||
such as panels.
|
such as panels.
|
||||||
|
|
||||||
|
*<windowRules><windowRule iconPriority="">* [client|server]
|
||||||
|
By default, labwc tries to find application icons based on their
|
||||||
|
app-id, either via .desktop file or by finding an icon with the same
|
||||||
|
name. If that fails labwc will then try to use client supplied icons,
|
||||||
|
accomplished with the xdg-toplevel-icon protocol for wayland native
|
||||||
|
applications or the \_NET_WM_ICON property for X11 applications.
|
||||||
|
|
||||||
|
This property allows prioritizing client supplied icons for specific
|
||||||
|
applications. Default is server.
|
||||||
|
|
||||||
## MENU
|
## MENU
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ struct scaled_icon_buffer {
|
||||||
struct view *view;
|
struct view *view;
|
||||||
char *view_app_id;
|
char *view_app_id;
|
||||||
char *view_icon_name;
|
char *view_icon_name;
|
||||||
|
bool view_icon_prefer_client;
|
||||||
struct wl_array view_icon_buffers;
|
struct wl_array view_icon_buffers;
|
||||||
struct {
|
struct {
|
||||||
struct wl_listener set_icon;
|
struct wl_listener set_icon;
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ struct window_rule {
|
||||||
enum property ignore_focus_request;
|
enum property ignore_focus_request;
|
||||||
enum property ignore_configure_request;
|
enum property ignore_configure_request;
|
||||||
enum property fixed_position;
|
enum property fixed_position;
|
||||||
|
enum property icon_prefer_client;
|
||||||
|
|
||||||
struct wl_list link; /* struct rcxml.window_rules */
|
struct wl_list link; /* struct rcxml.window_rules */
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
#include "img/img.h"
|
#include "img/img.h"
|
||||||
#include "node.h"
|
#include "node.h"
|
||||||
#include "view.h"
|
#include "view.h"
|
||||||
|
#include "window-rules.h"
|
||||||
|
|
||||||
#if HAVE_LIBSFDO
|
#if HAVE_LIBSFDO
|
||||||
|
|
||||||
|
|
@ -42,6 +43,57 @@ choose_best_icon_buffer(struct scaled_icon_buffer *self, int icon_size, double s
|
||||||
}
|
}
|
||||||
return best_buffer;
|
return best_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct lab_data_buffer *
|
||||||
|
img_to_buffer(struct lab_img *img, int width, int height, int scale)
|
||||||
|
{
|
||||||
|
struct lab_data_buffer *buffer = lab_img_render(img, width, height, scale);
|
||||||
|
lab_img_destroy(img);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load an icon from application-supplied icon name or buffers.
|
||||||
|
* Wayland apps can provide icon names and buffers via xdg-toplevel-icon protocol.
|
||||||
|
* X11 apps can provide icon buffers via _NET_WM_ICON property.
|
||||||
|
*/
|
||||||
|
static struct lab_data_buffer *
|
||||||
|
load_client_icon(struct scaled_icon_buffer *self, int icon_size, double scale)
|
||||||
|
{
|
||||||
|
struct lab_img *img = desktop_entry_load_icon(self->server,
|
||||||
|
self->view_icon_name, icon_size, scale);
|
||||||
|
if (img) {
|
||||||
|
wlr_log(WLR_DEBUG, "loaded icon from client icon name");
|
||||||
|
return img_to_buffer(img, self->width, self->height, scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct lab_data_buffer *buffer = choose_best_icon_buffer(self, icon_size, scale);
|
||||||
|
if (buffer) {
|
||||||
|
wlr_log(WLR_DEBUG, "loaded icon from client buffer");
|
||||||
|
return buffer_resize(buffer, self->width, self->height, scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Load an icon by a view's app_id. For example, if the app_id is 'firefox', then
|
||||||
|
* libsfdo will parse firefox.desktop to get the Icon name and then find that icon
|
||||||
|
* based on the icon theme specified in rc.xml.
|
||||||
|
*/
|
||||||
|
static struct lab_data_buffer *
|
||||||
|
load_server_icon(struct scaled_icon_buffer *self, int icon_size, double scale)
|
||||||
|
{
|
||||||
|
struct lab_img *img = desktop_entry_load_icon_from_app_id(self->server,
|
||||||
|
self->view_app_id, icon_size, scale);
|
||||||
|
if (img) {
|
||||||
|
wlr_log(WLR_DEBUG, "loaded icon by app_id");
|
||||||
|
return img_to_buffer(img, self->width, self->height, scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* HAVE_LIBSFDO */
|
#endif /* HAVE_LIBSFDO */
|
||||||
|
|
||||||
static struct lab_data_buffer *
|
static struct lab_data_buffer *
|
||||||
|
|
@ -51,50 +103,48 @@ _create_buffer(struct scaled_scene_buffer *scaled_buffer, double scale)
|
||||||
struct scaled_icon_buffer *self = scaled_buffer->data;
|
struct scaled_icon_buffer *self = scaled_buffer->data;
|
||||||
int icon_size = MIN(self->width, self->height);
|
int icon_size = MIN(self->width, self->height);
|
||||||
struct lab_img *img = NULL;
|
struct lab_img *img = NULL;
|
||||||
|
struct lab_data_buffer *buffer = NULL;
|
||||||
|
|
||||||
if (self->icon_name) {
|
if (self->icon_name) {
|
||||||
img = desktop_entry_load_icon(self->server,
|
/* generic icon (e.g. menu icons) */
|
||||||
self->icon_name, icon_size, scale);
|
img = desktop_entry_load_icon(self->server, self->icon_name,
|
||||||
} else if (self->view) {
|
icon_size, scale);
|
||||||
if (self->view_icon_name) {
|
if (img) {
|
||||||
wlr_log(WLR_DEBUG, "loading icon by name: %s",
|
wlr_log(WLR_DEBUG, "loaded icon by icon name");
|
||||||
self->view_icon_name);
|
return img_to_buffer(img, self->width, self->height, scale);
|
||||||
img = desktop_entry_load_icon(self->server,
|
|
||||||
self->view_icon_name, icon_size, scale);
|
|
||||||
}
|
}
|
||||||
if (!img) {
|
|
||||||
struct lab_data_buffer *buffer =
|
|
||||||
choose_best_icon_buffer(self, icon_size, scale);
|
|
||||||
if (buffer) {
|
|
||||||
wlr_log(WLR_DEBUG, "loading icon by buffer");
|
|
||||||
return buffer_resize(buffer,
|
|
||||||
self->width, self->height, scale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!img) {
|
|
||||||
wlr_log(WLR_DEBUG, "loading icon by app_id");
|
|
||||||
img = desktop_entry_load_icon_from_app_id(self->server,
|
|
||||||
self->view_app_id, icon_size, scale);
|
|
||||||
}
|
|
||||||
if (!img) {
|
|
||||||
wlr_log(WLR_DEBUG, "loading fallback icon");
|
|
||||||
img = desktop_entry_load_icon(self->server,
|
|
||||||
rc.fallback_app_icon_name, icon_size, scale);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!img) {
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct lab_data_buffer *buffer =
|
/* window icon */
|
||||||
lab_img_render(img, self->width, self->height, scale);
|
if (self->view_icon_prefer_client) {
|
||||||
lab_img_destroy(img);
|
buffer = load_client_icon(self, icon_size, scale);
|
||||||
|
if (buffer) {
|
||||||
return buffer;
|
return buffer;
|
||||||
#else
|
}
|
||||||
return NULL;
|
buffer = load_server_icon(self, icon_size, scale);
|
||||||
|
if (buffer) {
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
buffer = load_server_icon(self, icon_size, scale);
|
||||||
|
if (buffer) {
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
buffer = load_client_icon(self, icon_size, scale);
|
||||||
|
if (buffer) {
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* If both client and server icons are unavailable, use the fallback icon */
|
||||||
|
img = desktop_entry_load_icon(self->server, rc.fallback_app_icon_name,
|
||||||
|
icon_size, scale);
|
||||||
|
if (img) {
|
||||||
|
wlr_log(WLR_DEBUG, "loaded fallback icon");
|
||||||
|
return img_to_buffer(img, self->width, self->height, scale);
|
||||||
|
}
|
||||||
#endif /* HAVE_LIBSFDO */
|
#endif /* HAVE_LIBSFDO */
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -149,6 +199,7 @@ _equal(struct scaled_scene_buffer *scaled_buffer_a,
|
||||||
struct scaled_icon_buffer *b = scaled_buffer_b->data;
|
struct scaled_icon_buffer *b = scaled_buffer_b->data;
|
||||||
|
|
||||||
return str_equal(a->view_app_id, b->view_app_id)
|
return str_equal(a->view_app_id, b->view_app_id)
|
||||||
|
&& a->view_icon_prefer_client == b->view_icon_prefer_client
|
||||||
&& str_equal(a->view_icon_name, b->view_icon_name)
|
&& str_equal(a->view_icon_name, b->view_icon_name)
|
||||||
&& icon_buffers_equal(&a->view_icon_buffers, &b->view_icon_buffers)
|
&& icon_buffers_equal(&a->view_icon_buffers, &b->view_icon_buffers)
|
||||||
&& str_equal(a->icon_name, b->icon_name)
|
&& str_equal(a->icon_name, b->icon_name)
|
||||||
|
|
@ -189,6 +240,9 @@ handle_view_set_icon(struct wl_listener *listener, void *data)
|
||||||
struct scaled_icon_buffer *self =
|
struct scaled_icon_buffer *self =
|
||||||
wl_container_of(listener, self, on_view.set_icon);
|
wl_container_of(listener, self, on_view.set_icon);
|
||||||
|
|
||||||
|
self->view_icon_prefer_client = window_rules_get_property(
|
||||||
|
self->view, "iconPreferClient") == LAB_PROP_TRUE;
|
||||||
|
|
||||||
/* view_get_string_prop() never returns NULL */
|
/* view_get_string_prop() never returns NULL */
|
||||||
xstrdup_replace(self->view_app_id, view_get_string_prop(self->view, "app_id"));
|
xstrdup_replace(self->view_app_id, view_get_string_prop(self->view, "app_id"));
|
||||||
zfree(self->view_icon_name);
|
zfree(self->view_icon_name);
|
||||||
|
|
|
||||||
|
|
@ -328,6 +328,15 @@ fill_window_rule(char *nodename, char *content, struct parser_state *state)
|
||||||
/* Properties */
|
/* Properties */
|
||||||
} else if (!strcasecmp(nodename, "serverDecoration")) {
|
} else if (!strcasecmp(nodename, "serverDecoration")) {
|
||||||
set_property(content, &state->current_window_rule->server_decoration);
|
set_property(content, &state->current_window_rule->server_decoration);
|
||||||
|
} else if (!strcasecmp(nodename, "iconPriority")) {
|
||||||
|
if (!strcasecmp(content, "client")) {
|
||||||
|
state->current_window_rule->icon_prefer_client = LAB_PROP_TRUE;
|
||||||
|
} else if (!strcasecmp(content, "server")) {
|
||||||
|
state->current_window_rule->icon_prefer_client = LAB_PROP_FALSE;
|
||||||
|
} else {
|
||||||
|
wlr_log(WLR_ERROR,
|
||||||
|
"Invalid value for window rule property 'iconPriority'");
|
||||||
|
}
|
||||||
} else if (!strcasecmp(nodename, "skipTaskbar")) {
|
} else if (!strcasecmp(nodename, "skipTaskbar")) {
|
||||||
set_property(content, &state->current_window_rule->skip_taskbar);
|
set_property(content, &state->current_window_rule->skip_taskbar);
|
||||||
} else if (!strcasecmp(nodename, "skipWindowSwitcher")) {
|
} else if (!strcasecmp(nodename, "skipWindowSwitcher")) {
|
||||||
|
|
|
||||||
|
|
@ -2400,6 +2400,7 @@ view_update_title(struct view *view)
|
||||||
assert(view);
|
assert(view);
|
||||||
ssd_update_title(view->ssd);
|
ssd_update_title(view->ssd);
|
||||||
wl_signal_emit_mutable(&view->events.new_title, NULL);
|
wl_signal_emit_mutable(&view->events.new_title, NULL);
|
||||||
|
wl_signal_emit_mutable(&view->events.set_icon, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,10 @@ window_rules_get_property(struct view *view, const char *property)
|
||||||
&& !strcasecmp(property, "fixedPosition")) {
|
&& !strcasecmp(property, "fixedPosition")) {
|
||||||
return rule->fixed_position;
|
return rule->fixed_position;
|
||||||
}
|
}
|
||||||
|
if (rule->icon_prefer_client
|
||||||
|
&& !strcasecmp(property, "iconPreferClient")) {
|
||||||
|
return rule->icon_prefer_client;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return LAB_PROP_UNSPECIFIED;
|
return LAB_PROP_UNSPECIFIED;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue