csd: initial implementation of minimize/maximize/close buttons

This commit is contained in:
Daniel Eklöf 2020-03-02 20:29:28 +01:00
parent c845c90835
commit 9699c9b8bf
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
11 changed files with 268 additions and 21 deletions

View file

@ -372,7 +372,7 @@ parse_section_csd(const char *key, const char *value, struct config *conf,
conf->csd.color.border = color;
}
else if (strcmp(key, "titlebar") == 0) {
else if (strcmp(key, "titlebar-size") == 0) {
unsigned long pixels;
if (!str_to_ulong(value, 10, &pixels)) {
LOG_ERR("%s:%d: expected an integer: %s", path, lineno, value);
@ -382,7 +382,7 @@ parse_section_csd(const char *key, const char *value, struct config *conf,
conf->csd.title_height = pixels;
}
else if (strcmp(key, "border") == 0) {
else if (strcmp(key, "border-width") == 0) {
unsigned long pixels;
if (!str_to_ulong(value, 10, &pixels)) {
LOG_ERR("%s:%d: expected an integer: %s", path, lineno, value);
@ -392,6 +392,48 @@ parse_section_csd(const char *key, const char *value, struct config *conf,
conf->csd.border_width = pixels;
}
else if (strcmp(key, "button-width") == 0) {
unsigned long pixels;
if (!str_to_ulong(value, 10, &pixels)) {
LOG_ERR("%s:%d: expected an integer: %s", path, lineno, value);
return false;
}
conf->csd.button_width = pixels;
}
else if (strcmp(key, "button-minimize-color") == 0) {
uint32_t color;
if (!str_to_color(value, &color, true, path, lineno)) {
LOG_ERR("%s:%d: invalid button-minimize-color: %s", path, lineno, value);
return false;
}
conf->csd.color.minimize_set = true;
conf->csd.color.minimize = color;
}
else if (strcmp(key, "button-maximize-color") == 0) {
uint32_t color;
if (!str_to_color(value, &color, true, path, lineno)) {
LOG_ERR("%s:%d: invalid button-maximize-color: %s", path, lineno, value);
return false;
}
conf->csd.color.maximize_set = true;
conf->csd.color.maximize = color;
}
else if (strcmp(key, "button-close-color") == 0) {
uint32_t color;
if (!str_to_color(value, &color, true, path, lineno)) {
LOG_ERR("%s:%d: invalid button-close-color: %s", path, lineno, value);
return false;
}
conf->csd.color.close_set = true;
conf->csd.color.close = color;
}
return true;
}
@ -602,6 +644,7 @@ config_load(struct config *conf, const char *conf_path)
.preferred = CONF_CSD_PREFER_SERVER,
.title_height = 26,
.border_width = 5,
.button_width = 22,
.color = {
.title_set = false,
.border_set = false,

View file

@ -41,12 +41,19 @@ struct config {
int title_height;
int border_width;
int button_width;
struct {
bool title_set;
bool border_set;
bool minimize_set;
bool maximize_set;
bool close_set;
uint32_t title;
uint32_t border;
uint32_t minimize;
uint32_t maximize;
uint32_t close;
} color;
} csd;

View file

@ -83,6 +83,10 @@ applications can change these runtime.
This section controls the 16 ANSI colors and the default foreground
and background colors. Note that applications can change these runtime.
The colors are in RRGGBB format. That is, they do *not* have an alpha
component. You can configure the background transparency with the
_alpha_ option.
*foreground*
Default RRGGBB foreground color. This is the color used when no
ANSI color is being used. Default: _dcdccc_.
@ -112,29 +116,43 @@ Decorations). Note that the default is to *not* use CSDs, but instead
to use _SSDs_ (Server Side Decorations) when the compositor supports
it.
Note that unlike the colors defined in the _colors_ section, the color
values here are in AARRGGBB format. I.e. they contain an alpha
component.
*preferred*
Which type of window decorations to prefer: *client* (CSD) or
*server* (SSD). Note that this is only a hint to the
compositor. Depending on the compositor's configuration and
capabilities, it may not have any effect. Default: _server_.
*titlebar*
*titlebar-size*
Height, in pixels (but subject to output scaling), of the
titlebar, not including the window border. Default: _26_.
*border*
*border-width*
Width, in pixels (but subject to output scaling), of the
borders. Default: _5_.
*titlebar-color*
Titlebar AARRGGBB color. Note that unlike the other color values,
the *titlebar-color* value also has an _alpha_ component. Default:
use the default _foreground_ color.
Titlebar AARRGGBB color. Default: use the default _foreground_
color.
*border-color*
Border AARRGGBB color. Note that unlike the other color values,
the *border-color* value also has an _alpha_ component. Default:
_transparent_.
Border AARRGGBB color. Default: _transparent_.
*button-width*
Width, in pixels (but subject to output scaling), of the
minimize/maximize/close buttons. Default: _22_.
*button-minimize-color*
Minimize button's AARRGGBB color. Default: _ff0000ff_.
*button-maximize-color*
Maximize button's AARRGGBB color. Default: _ff00ff00_.
*button-close-color*
Close button's AARRGGBB color. Default: _ffff0000_.
# FONT FORMAT

8
footrc
View file

@ -36,7 +36,11 @@
[csd]
# preferred=server
# titlebar=26
# border=5
# titlebar-size=26
# border-width=5
# titlebar-color=<foreground color>
# border-color=00000000
# button-width=22
# button-minimize-color=ff0000ff
# button-maximize-color=ff00ff00
# button-close-color=ffff0000

81
input.c
View file

@ -24,6 +24,7 @@
#include "config.h"
#include "commands.h"
#include "keymap.h"
#include "quirks.h"
#include "render.h"
#include "search.h"
#include "selection.h"
@ -708,6 +709,28 @@ wl_pointer_enter(void *data, struct wl_pointer *wl_pointer,
render_xcursor_set(term);
break;
case TERM_SURF_BUTTON_MINIMIZE:
case TERM_SURF_BUTTON_MAXIMIZE:
case TERM_SURF_BUTTON_CLOSE: {
enum csd_surface idx =
term->active_surface == TERM_SURF_BUTTON_MINIMIZE ? CSD_SURF_MINIMIZE :
term->active_surface == TERM_SURF_BUTTON_MAXIMIZE ? CSD_SURF_MAXIMIZE :
CSD_SURF_CLOSE;
quirk_weston_subsurface_desync_on(term->window->csd.sub_surface[CSD_SURF_TITLE]);
quirk_weston_subsurface_desync_on(term->window->csd.sub_surface[idx]);
render_csd_button(term, idx);
quirk_weston_subsurface_desync_off(term->window->csd.sub_surface[idx]);
quirk_weston_subsurface_desync_off(term->window->csd.sub_surface[CSD_SURF_TITLE]);
wl_surface_commit(win->surface);
term->xcursor = "left_ptr";
render_xcursor_set(term);
break;
}
case TERM_SURF_NONE:
assert(false);
break;
@ -746,8 +769,43 @@ wl_pointer_leave(void *data, struct wl_pointer *wl_pointer,
= wl_surface_get_user_data(surface);
assert(old_moused == win->term);
}
enum term_surface active_surface = old_moused->active_surface;
old_moused->active_surface = TERM_SURF_NONE;
term_xcursor_update(old_moused);
switch (active_surface) {
case TERM_SURF_BUTTON_MINIMIZE:
case TERM_SURF_BUTTON_MAXIMIZE:
case TERM_SURF_BUTTON_CLOSE: {
enum csd_surface idx =
active_surface == TERM_SURF_BUTTON_MINIMIZE ? CSD_SURF_MINIMIZE :
active_surface == TERM_SURF_BUTTON_MAXIMIZE ? CSD_SURF_MAXIMIZE :
CSD_SURF_CLOSE;
quirk_weston_subsurface_desync_on(old_moused->window->csd.sub_surface[CSD_SURF_TITLE]);
quirk_weston_subsurface_desync_on(old_moused->window->csd.sub_surface[idx]);
render_csd_button(old_moused, idx);
quirk_weston_subsurface_desync_off(old_moused->window->csd.sub_surface[idx]);
quirk_weston_subsurface_desync_off(old_moused->window->csd.sub_surface[CSD_SURF_TITLE]);
wl_surface_commit(old_moused->window->surface);
break;
}
case TERM_SURF_NONE:
case TERM_SURF_GRID:
case TERM_SURF_SEARCH:
case TERM_SURF_TITLE:
case TERM_SURF_BORDER_LEFT:
case TERM_SURF_BORDER_RIGHT:
case TERM_SURF_BORDER_TOP:
case TERM_SURF_BORDER_BOTTOM:
break;
}
}
}
@ -787,6 +845,9 @@ wl_pointer_motion(void *data, struct wl_pointer *wl_pointer,
switch (term->active_surface) {
case TERM_SURF_NONE:
case TERM_SURF_SEARCH:
case TERM_SURF_BUTTON_MINIMIZE:
case TERM_SURF_BUTTON_MAXIMIZE:
case TERM_SURF_BUTTON_CLOSE:
break;
case TERM_SURF_TITLE:
@ -976,6 +1037,26 @@ wl_pointer_button(void *data, struct wl_pointer *wl_pointer,
return;
}
case TERM_SURF_BUTTON_MINIMIZE:
if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED)
xdg_toplevel_set_minimized(term->window->xdg_toplevel);
break;
case TERM_SURF_BUTTON_MAXIMIZE:
if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED) {
if (term->window->is_maximized)
xdg_toplevel_unset_maximized(term->window->xdg_toplevel);
else
xdg_toplevel_set_maximized(term->window->xdg_toplevel);
}
break;
case TERM_SURF_BUTTON_CLOSE:
if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED)
term_shutdown(term);
//LOG_ERR("unimplemented: terminate");
break;
case TERM_SURF_SEARCH:
break;

View file

@ -682,6 +682,9 @@ get_csd_data(const struct terminal *term, enum csd_surface surf_idx)
const int title_height = !term->window->is_fullscreen
? term->conf->csd.title_height * term->scale : 0;
const int button_width = !term->window->is_fullscreen
? term->conf->csd.button_width * term->scale : 0;
switch (surf_idx) {
case CSD_SURF_TITLE: return (struct csd_data){ 0, -title_height, term->width, title_height};
case CSD_SURF_LEFT: return (struct csd_data){-border_width, -title_height, border_width, title_height + term->height};
@ -689,6 +692,11 @@ get_csd_data(const struct terminal *term, enum csd_surface surf_idx)
case CSD_SURF_TOP: return (struct csd_data){-border_width, -title_height - border_width, term->width + 2 * border_width, border_width};
case CSD_SURF_BOTTOM: return (struct csd_data){-border_width, term->height, term->width + 2 * border_width, border_width};
/* Positioned relative to CSD_SURF_TITLE */
case CSD_SURF_MINIMIZE: return (struct csd_data){term->width - 3 * button_width, 0, button_width, title_height};
case CSD_SURF_MAXIMIZE: return (struct csd_data){term->width - 2 * button_width, 0, button_width, title_height};
case CSD_SURF_CLOSE: return (struct csd_data){term->width - 1 * button_width, 0, button_width, title_height};
case CSD_SURF_COUNT:
assert(false);
return (struct csd_data){0};
@ -780,6 +788,73 @@ render_csd_border(struct terminal *term, enum csd_surface surf_idx)
render_csd_part(term, surf, buf, info.width, info.height, &color);
}
void
render_csd_button(struct terminal *term, enum csd_surface surf_idx)
{
assert(surf_idx >= CSD_SURF_MINIMIZE);
if (term->window->use_csd != CSD_YES)
return;
struct csd_data info = get_csd_data(term, surf_idx);
struct wl_surface *surf = term->window->csd.surface[surf_idx];
if (info.width == 0 || info.height == 0)
return;
unsigned long cookie = shm_cookie_csd(term, surf_idx);
struct buffer *buf = shm_get_buffer(
term->wl->shm, info.width, info.height, cookie);
uint32_t _color;
uint16_t alpha = 0xffff;
bool is_active = false;
const bool *is_set = NULL;
const uint32_t *conf_color = NULL;
switch (surf_idx) {
case CSD_SURF_MINIMIZE:
_color = 0xff0000ff;
is_set = &term->conf->csd.color.minimize_set;
conf_color = &term->conf->csd.color.minimize;
is_active = term->active_surface == TERM_SURF_BUTTON_MINIMIZE;
break;
case CSD_SURF_MAXIMIZE:
_color = 0xff00ff00;
is_set = &term->conf->csd.color.maximize_set;
conf_color = &term->conf->csd.color.maximize;
is_active = term->active_surface == TERM_SURF_BUTTON_MAXIMIZE;
break;
case CSD_SURF_CLOSE:
_color = 0xffff0000;
is_set = &term->conf->csd.color.close_set;
conf_color = &term->conf->csd.color.close;
is_active = term->active_surface == TERM_SURF_BUTTON_CLOSE;
break;
default:
assert(false);
break;
}
if (is_active) {
if (*is_set) {
_color = *conf_color;
alpha = _color >> 24 | (_color >> 24 << 8);
}
} else {
_color = 0;
alpha = 0;
}
pixman_color_t color = color_hex_to_pixman_with_alpha(_color, alpha);
if (!term->visual_focus)
pixman_color_dim(&color);
render_csd_part(term, surf, buf, info.width, info.height, &color);
}
void
render_csd(struct terminal *term)
{
@ -798,7 +873,7 @@ render_csd(struct terminal *term)
if (width == 0 || height == 0) {
/* CSD borders aren't rendered in maximized mode */
assert(term->window->is_maximized);
assert(term->window->is_maximized || term->window->is_fullscreen);
wl_subsurface_set_position(sub, 0, 0);
wl_surface_attach(surf, NULL, 0, 0);
wl_surface_commit(surf);
@ -811,6 +886,8 @@ render_csd(struct terminal *term)
render_csd_title(term);
for (size_t i = CSD_SURF_LEFT; i <= CSD_SURF_BOTTOM; i++)
render_csd_border(term, i);
for (size_t i = CSD_SURF_MINIMIZE; i < CSD_SURF_COUNT; i++)
render_csd_button(term, i);
}
static void frame_callback(

View file

@ -19,6 +19,7 @@ bool render_xcursor_set(struct terminal *term);
void render_search_box(struct terminal *term);
void render_csd(struct terminal *term);
void render_csd_title(struct terminal *term);
void render_csd_button(struct terminal *term, enum csd_surface surf_idx);
struct render_worker_context {
int my_id;

View file

@ -2149,16 +2149,22 @@ term_surface_kind(const struct terminal *term, const struct wl_surface *surface)
return TERM_SURF_GRID;
else if (surface == term->window->search_surface)
return TERM_SURF_SEARCH;
else if (surface == term->window->csd.surface[0])
else if (surface == term->window->csd.surface[CSD_SURF_TITLE])
return TERM_SURF_TITLE;
else if (surface == term->window->csd.surface[1])
else if (surface == term->window->csd.surface[CSD_SURF_LEFT])
return TERM_SURF_BORDER_LEFT;
else if (surface == term->window->csd.surface[2])
else if (surface == term->window->csd.surface[CSD_SURF_RIGHT])
return TERM_SURF_BORDER_RIGHT;
else if (surface == term->window->csd.surface[3])
else if (surface == term->window->csd.surface[CSD_SURF_TOP])
return TERM_SURF_BORDER_TOP;
else if (surface == term->window->csd.surface[4])
else if (surface == term->window->csd.surface[CSD_SURF_BOTTOM])
return TERM_SURF_BORDER_BOTTOM;
else if (surface == term->window->csd.surface[CSD_SURF_MINIMIZE])
return TERM_SURF_BUTTON_MINIMIZE;
else if (surface == term->window->csd.surface[CSD_SURF_MAXIMIZE])
return TERM_SURF_BUTTON_MAXIMIZE;
else if (surface == term->window->csd.surface[CSD_SURF_CLOSE])
return TERM_SURF_BUTTON_CLOSE;
else
return TERM_SURF_NONE;
}

View file

@ -194,6 +194,9 @@ enum term_surface {
TERM_SURF_BORDER_RIGHT,
TERM_SURF_BORDER_TOP,
TERM_SURF_BORDER_BOTTOM,
TERM_SURF_BUTTON_MINIMIZE,
TERM_SURF_BUTTON_MAXIMIZE,
TERM_SURF_BUTTON_CLOSE,
};
struct terminal {

View file

@ -47,8 +47,12 @@ csd_instantiate(struct wl_window *win)
assert(win->csd.sub_surface[i] == NULL);
win->csd.surface[i] = wl_compositor_create_surface(wayl->compositor);
struct wl_surface *parent = i < CSD_SURF_MINIMIZE
? win->surface : win->csd.surface[CSD_SURF_TITLE];
win->csd.sub_surface[i] = wl_subcompositor_get_subsurface(
wayl->sub_compositor, win->csd.surface[i], win->surface);
wayl->sub_compositor, win->csd.surface[i], parent);
wl_subsurface_set_sync(win->csd.sub_surface[i]);
wl_surface_set_user_data(win->csd.surface[i], win);

View file

@ -88,6 +88,9 @@ enum csd_surface {
CSD_SURF_RIGHT,
CSD_SURF_TOP,
CSD_SURF_BOTTOM,
CSD_SURF_MINIMIZE,
CSD_SURF_MAXIMIZE,
CSD_SURF_CLOSE,
CSD_SURF_COUNT,
};
@ -103,8 +106,8 @@ struct wl_window {
enum {CSD_UNKNOWN, CSD_NO, CSD_YES } use_csd;
struct {
struct wl_surface *surface[5];
struct wl_subsurface *sub_surface[5];
struct wl_surface *surface[CSD_SURF_COUNT];
struct wl_subsurface *sub_surface[CSD_SURF_COUNT];
int move_timeout_fd;
uint32_t serial;
} csd;