feat: add text glow animation for client titles
feat: enhance alt-tab selection with bold font rendering refactor: simplify title bar color logic to use focused/unfocused states perf: increase focus animation duration for smoother transitions refactor: update build dependencies for decorations and workspace modules
This commit is contained in:
parent
f55f024d22
commit
b59c279bb0
BIN
build/ai.o
BIN
build/ai.o
Binary file not shown.
BIN
build/atoms.o
BIN
build/atoms.o
Binary file not shown.
BIN
build/client.o
BIN
build/client.o
Binary file not shown.
@ -1,7 +1,9 @@
|
||||
build/decorations.o: src/decorations.c include/decorations.h \
|
||||
include/dwn.h include/client.h include/config.h include/util.h
|
||||
include/dwn.h include/client.h include/config.h include/util.h \
|
||||
include/workspace.h
|
||||
include/decorations.h:
|
||||
include/dwn.h:
|
||||
include/client.h:
|
||||
include/config.h:
|
||||
include/util.h:
|
||||
include/workspace.h:
|
||||
|
||||
Binary file not shown.
BIN
build/keys.o
BIN
build/keys.o
Binary file not shown.
BIN
build/layout.o
BIN
build/layout.o
Binary file not shown.
BIN
build/panel.o
BIN
build/panel.o
Binary file not shown.
BIN
build/util.o
BIN
build/util.o
Binary file not shown.
@ -1,6 +1,6 @@
|
||||
build/workspace.o: src/workspace.c include/workspace.h include/dwn.h \
|
||||
include/client.h include/layout.h include/atoms.h include/util.h \
|
||||
include/config.h include/panel.h include/api.h
|
||||
include/config.h include/panel.h include/api.h include/decorations.h
|
||||
include/workspace.h:
|
||||
include/dwn.h:
|
||||
include/client.h:
|
||||
@ -10,3 +10,4 @@ include/util.h:
|
||||
include/config.h:
|
||||
include/panel.h:
|
||||
include/api.h:
|
||||
include/decorations.h:
|
||||
|
||||
Binary file not shown.
@ -72,6 +72,7 @@ Client *client_get_last(void);
|
||||
|
||||
void client_start_focus_animation(Client *client, bool gaining_focus);
|
||||
unsigned long client_get_animated_title_color(Client *client);
|
||||
unsigned long client_get_glow_text_color(Client *client);
|
||||
void client_update_animations(void);
|
||||
|
||||
#endif
|
||||
|
||||
@ -95,6 +95,13 @@ typedef struct {
|
||||
bool active;
|
||||
} ColorAnimation;
|
||||
|
||||
typedef struct {
|
||||
float phase;
|
||||
float speed;
|
||||
unsigned long base_color;
|
||||
bool active;
|
||||
} TextGlowAnimation;
|
||||
|
||||
typedef struct Client Client;
|
||||
typedef struct Workspace Workspace;
|
||||
typedef struct Monitor Monitor;
|
||||
@ -116,6 +123,7 @@ struct Client {
|
||||
SnapConstraint snap;
|
||||
unsigned long taskbar_color;
|
||||
ColorAnimation title_anim;
|
||||
TextGlowAnimation text_glow;
|
||||
Client *next;
|
||||
Client *prev;
|
||||
Client *mru_next;
|
||||
|
||||
@ -58,6 +58,7 @@ unsigned long generate_unique_color(void);
|
||||
unsigned long adjust_color_for_background(unsigned long color, unsigned long bg);
|
||||
unsigned long interpolate_color(unsigned long from, unsigned long to, float progress);
|
||||
unsigned long dim_color(unsigned long color, float factor);
|
||||
unsigned long glow_color(unsigned long base, float phase);
|
||||
|
||||
long get_time_ms(void);
|
||||
void sleep_ms(int ms);
|
||||
|
||||
58
src/client.c
58
src/client.c
@ -92,6 +92,11 @@ Client *client_create(Window window)
|
||||
client_update_class(client);
|
||||
client->taskbar_color = generate_unique_color();
|
||||
|
||||
client->text_glow.phase = (float)(rand() % 628) / 100.0f;
|
||||
client->text_glow.speed = 0.8f + (float)(rand() % 40) / 100.0f;
|
||||
client->text_glow.base_color = client->taskbar_color;
|
||||
client->text_glow.active = true;
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
@ -1289,7 +1294,7 @@ Client *client_get_last(void)
|
||||
}
|
||||
|
||||
|
||||
#define FOCUS_ANIMATION_DURATION_MS 200
|
||||
#define FOCUS_ANIMATION_DURATION_MS 400
|
||||
|
||||
void client_start_focus_animation(Client *client, bool gaining_focus)
|
||||
{
|
||||
@ -1298,7 +1303,7 @@ void client_start_focus_animation(Client *client, bool gaining_focus)
|
||||
}
|
||||
|
||||
unsigned long full_color = client->taskbar_color;
|
||||
unsigned long dimmed_color = dim_color(client->taskbar_color, 0.6f);
|
||||
unsigned long dimmed_color = dim_color(client->taskbar_color, 0.35f);
|
||||
|
||||
if (gaining_focus) {
|
||||
client->title_anim.from_color = dimmed_color;
|
||||
@ -1322,17 +1327,16 @@ unsigned long client_get_animated_title_color(Client *client)
|
||||
Workspace *ws = workspace_get(client->workspace);
|
||||
bool is_focused = (ws != NULL && ws->focused == client);
|
||||
|
||||
if (client->title_anim.active) {
|
||||
return interpolate_color(client->title_anim.from_color,
|
||||
client->title_anim.to_color,
|
||||
client->title_anim.progress);
|
||||
}
|
||||
const ColorScheme *colors = config_get_colors();
|
||||
return is_focused ? colors->title_focused_bg : colors->title_unfocused_bg;
|
||||
}
|
||||
|
||||
if (is_focused) {
|
||||
return client->taskbar_color;
|
||||
unsigned long client_get_glow_text_color(Client *client)
|
||||
{
|
||||
if (client == NULL || !client->text_glow.active) {
|
||||
return 0xFFFFFF;
|
||||
}
|
||||
|
||||
return dim_color(client->taskbar_color, 0.6f);
|
||||
return glow_color(client->text_glow.base_color, client->text_glow.phase);
|
||||
}
|
||||
|
||||
void client_update_animations(void)
|
||||
@ -1345,23 +1349,31 @@ void client_update_animations(void)
|
||||
bool needs_redraw = false;
|
||||
|
||||
for (Client *c = dwn->client_list; c != NULL; c = c->next) {
|
||||
if (!c->title_anim.active) {
|
||||
continue;
|
||||
if (c->title_anim.active) {
|
||||
long elapsed = now - c->title_anim.start_time;
|
||||
c->title_anim.progress = (float)elapsed / (float)FOCUS_ANIMATION_DURATION_MS;
|
||||
|
||||
if (c->title_anim.progress >= 1.0f) {
|
||||
c->title_anim.progress = 1.0f;
|
||||
c->title_anim.active = false;
|
||||
}
|
||||
needs_redraw = true;
|
||||
}
|
||||
|
||||
long elapsed = now - c->title_anim.start_time;
|
||||
c->title_anim.progress = (float)elapsed / (float)FOCUS_ANIMATION_DURATION_MS;
|
||||
|
||||
if (c->title_anim.progress >= 1.0f) {
|
||||
c->title_anim.progress = 1.0f;
|
||||
c->title_anim.active = false;
|
||||
if (c->text_glow.active && c->workspace == (unsigned int)dwn->current_workspace) {
|
||||
c->text_glow.phase += 0.01f * c->text_glow.speed;
|
||||
if (c->text_glow.phase > 6.283f) {
|
||||
c->text_glow.phase -= 6.283f;
|
||||
}
|
||||
needs_redraw = true;
|
||||
}
|
||||
|
||||
if (c->frame != None && c->workspace == (unsigned int)dwn->current_workspace) {
|
||||
Workspace *ws = workspace_get(c->workspace);
|
||||
bool focused = (ws != NULL && ws->focused == c);
|
||||
decorations_render(c, focused);
|
||||
needs_redraw = true;
|
||||
if (!(c->flags & CLIENT_MINIMIZED)) {
|
||||
Workspace *ws = workspace_get(c->workspace);
|
||||
bool focused = (ws != NULL && ws->focused == c);
|
||||
decorations_render(c, focused);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
#include "client.h"
|
||||
#include "config.h"
|
||||
#include "util.h"
|
||||
#include "workspace.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
@ -57,20 +58,27 @@ void decorations_render_title_bar(Client *client, bool focused)
|
||||
}
|
||||
|
||||
Display *dpy = dwn->display;
|
||||
const ColorScheme *colors = config_get_colors();
|
||||
int title_height = config_get_title_height();
|
||||
int border = client->border_width;
|
||||
const ColorScheme *colors = config_get_colors();
|
||||
|
||||
unsigned long bg_color = client_get_animated_title_color(client);
|
||||
unsigned long fg_color = adjust_color_for_background(colors->title_focused_fg, bg_color);
|
||||
Workspace *ws = workspace_get(client->workspace);
|
||||
bool is_focused = (ws != NULL && ws->focused == client);
|
||||
unsigned long bg_color = is_focused ? colors->title_focused_bg : colors->title_unfocused_bg;
|
||||
unsigned long fg_color = client->taskbar_color;
|
||||
fg_color = adjust_color_for_background(fg_color, bg_color);
|
||||
|
||||
XSetForeground(dpy, dwn->gc, bg_color);
|
||||
XFillRectangle(dpy, client->frame, dwn->gc,
|
||||
border, border,
|
||||
client->width, title_height);
|
||||
|
||||
if (client->title[0] != '\0' && dwn->xft_font != NULL) {
|
||||
int text_y = border + (title_height + dwn->xft_font->ascent) / 2;
|
||||
bool is_alt_tab_selection = (dwn->is_alt_tabbing && dwn->alt_tab_client == client);
|
||||
XftFont *title_font = (is_alt_tab_selection && dwn->xft_font_bold != NULL) ?
|
||||
dwn->xft_font_bold : dwn->xft_font;
|
||||
|
||||
if (client->title[0] != '\0' && title_font != NULL) {
|
||||
int text_y = border + (title_height + title_font->ascent) / 2;
|
||||
int text_x = border + BUTTON_PADDING;
|
||||
|
||||
int max_width = client->width - 3 * (BUTTON_SIZE + BUTTON_PADDING) - 2 * BUTTON_PADDING;
|
||||
@ -82,7 +90,7 @@ void decorations_render_title_bar(Client *client, bool focused)
|
||||
display_title[sizeof(display_title) - 4] = '\0';
|
||||
|
||||
XGlyphInfo extents;
|
||||
XftTextExtentsUtf8(dpy, dwn->xft_font,
|
||||
XftTextExtentsUtf8(dpy, title_font,
|
||||
(const FcChar8 *)display_title, strlen(display_title), &extents);
|
||||
int text_width = extents.xOff;
|
||||
|
||||
@ -100,7 +108,7 @@ void decorations_render_title_bar(Client *client, bool focused)
|
||||
display_title[cut] = '\0';
|
||||
title_truncated = true;
|
||||
|
||||
XftTextExtentsUtf8(dpy, dwn->xft_font,
|
||||
XftTextExtentsUtf8(dpy, title_font,
|
||||
(const FcChar8 *)display_title, strlen(display_title), &extents);
|
||||
text_width = extents.xOff;
|
||||
}
|
||||
@ -122,7 +130,7 @@ void decorations_render_title_bar(Client *client, bool focused)
|
||||
XftColorAllocValue(dpy, DefaultVisual(dpy, dwn->screen),
|
||||
dwn->colormap, &render_color, &xft_color);
|
||||
|
||||
XftDrawStringUtf8(xft_draw, &xft_color, dwn->xft_font,
|
||||
XftDrawStringUtf8(xft_draw, &xft_color, title_font,
|
||||
text_x, text_y,
|
||||
(const FcChar8 *)display_title, strlen(display_title));
|
||||
|
||||
@ -162,7 +170,10 @@ void decorations_render_buttons(Client *client, bool focused)
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned long bg_color = client_get_animated_title_color(client);
|
||||
const ColorScheme *colors = config_get_colors();
|
||||
Workspace *ws = workspace_get(client->workspace);
|
||||
bool is_focused = (ws != NULL && ws->focused == client);
|
||||
unsigned long bg_color = is_focused ? colors->title_focused_bg : colors->title_unfocused_bg;
|
||||
|
||||
XSetForeground(dpy, dwn->gc, bg_color);
|
||||
XFillRectangle(dpy, client->frame, dwn->gc, close_x, button_y, BUTTON_SIZE, BUTTON_SIZE);
|
||||
|
||||
@ -456,7 +456,7 @@ void panel_render_taskbar(Panel *panel, int x, int *width)
|
||||
if (minimized) {
|
||||
fg = colors->panel_fg;
|
||||
} else {
|
||||
fg = c->taskbar_color;
|
||||
fg = client_get_glow_text_color(c);
|
||||
}
|
||||
|
||||
if (focused && !minimized) {
|
||||
|
||||
23
src/util.c
23
src/util.c
@ -795,3 +795,26 @@ unsigned long dim_color(unsigned long color, float factor)
|
||||
|
||||
return rgb_to_pixel(r, g, b);
|
||||
}
|
||||
|
||||
unsigned long glow_color(unsigned long base, float phase)
|
||||
{
|
||||
int r, g, b;
|
||||
color_to_rgb(base, &r, &g, &b);
|
||||
|
||||
float mod_r = 0.25f * sinf(phase);
|
||||
float mod_g = 0.25f * sinf(phase + 2.094f);
|
||||
float mod_b = 0.25f * sinf(phase + 4.189f);
|
||||
|
||||
r = r + (int)(r * mod_r);
|
||||
g = g + (int)(g * mod_g);
|
||||
b = b + (int)(b * mod_b);
|
||||
|
||||
if (r > 255) r = 255;
|
||||
if (r < 0) r = 0;
|
||||
if (g > 255) g = 255;
|
||||
if (g < 0) g = 0;
|
||||
if (b > 255) b = 255;
|
||||
if (b < 0) b = 0;
|
||||
|
||||
return rgb_to_pixel(r, g, b);
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
#include "config.h"
|
||||
#include "panel.h"
|
||||
#include "api.h"
|
||||
#include "decorations.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
@ -551,10 +552,11 @@ void workspace_alt_tab_next(void)
|
||||
if (!dwn->is_alt_tabbing) {
|
||||
dwn->is_alt_tabbing = true;
|
||||
dwn->alt_tab_client = ws->focused;
|
||||
XGrabKeyboard(dwn->display, dwn->root, True,
|
||||
XGrabKeyboard(dwn->display, dwn->root, True,
|
||||
GrabModeAsync, GrabModeAsync, CurrentTime);
|
||||
}
|
||||
|
||||
Client *previous_selection = dwn->alt_tab_client;
|
||||
Client *current = dwn->alt_tab_client;
|
||||
if (current == NULL) {
|
||||
current = ws->mru_head;
|
||||
@ -566,8 +568,15 @@ void workspace_alt_tab_next(void)
|
||||
dwn->alt_tab_client = ws->mru_head;
|
||||
}
|
||||
|
||||
if (previous_selection != NULL && previous_selection->frame != None) {
|
||||
decorations_render(previous_selection, false);
|
||||
}
|
||||
|
||||
if (dwn->alt_tab_client != NULL) {
|
||||
client_focus(dwn->alt_tab_client, false);
|
||||
if (dwn->alt_tab_client->frame != None) {
|
||||
decorations_render(dwn->alt_tab_client, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -581,21 +590,28 @@ void workspace_alt_tab_prev(void)
|
||||
if (!dwn->is_alt_tabbing) {
|
||||
dwn->is_alt_tabbing = true;
|
||||
dwn->alt_tab_client = ws->focused;
|
||||
XGrabKeyboard(dwn->display, dwn->root, True,
|
||||
XGrabKeyboard(dwn->display, dwn->root, True,
|
||||
GrabModeAsync, GrabModeAsync, CurrentTime);
|
||||
}
|
||||
|
||||
Client *previous_selection = dwn->alt_tab_client;
|
||||
Client *current = dwn->alt_tab_client;
|
||||
|
||||
|
||||
if (current != NULL && current->mru_prev != NULL) {
|
||||
dwn->alt_tab_client = current->mru_prev;
|
||||
} else {
|
||||
dwn->alt_tab_client = ws->mru_tail;
|
||||
}
|
||||
|
||||
if (previous_selection != NULL && previous_selection->frame != None) {
|
||||
decorations_render(previous_selection, false);
|
||||
}
|
||||
|
||||
if (dwn->alt_tab_client != NULL) {
|
||||
client_focus(dwn->alt_tab_client, false);
|
||||
if (dwn->alt_tab_client->frame != None) {
|
||||
decorations_render(dwn->alt_tab_client, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user