compositor: blur-behind windows
This commit is contained in:
parent
54a1bcc5ff
commit
264d11a618
@ -61,6 +61,15 @@ static void mouse_stop_drag(yutani_globals_t * yg);
|
||||
static void window_move(yutani_globals_t * yg, yutani_server_window_t * window, int x, int y);
|
||||
static yutani_server_window_t * top_at(yutani_globals_t * yg, uint16_t x, uint16_t y);
|
||||
|
||||
#define ENABLE_BLUR_BEHIND
|
||||
#ifdef ENABLE_BLUR_BEHIND
|
||||
#define BLUR_CLIP_MAX 20
|
||||
#define BLUR_KERNEL 10
|
||||
static sprite_t * blur_sprite = NULL;
|
||||
static gfx_context_t * blur_ctx = NULL;
|
||||
static gfx_context_t * clip_ctx = NULL;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Print usage information.
|
||||
*/
|
||||
@ -730,7 +739,7 @@ static int yutani_blit_window(yutani_globals_t * yg, yutani_server_window_t * wi
|
||||
|
||||
double opacity = (double)(window->opacity) / 255.0;
|
||||
|
||||
if (window->rotation || window == yg->resizing_window || window->anim_mode) {
|
||||
if (window->rotation || window == yg->resizing_window || window->anim_mode || (window->server_flags & YUTANI_WINDOW_FLAG_BLUR_BEHIND)) {
|
||||
double m[2][3];
|
||||
|
||||
gfx_matrix_identity(m);
|
||||
@ -803,6 +812,12 @@ static int yutani_blit_window(yutani_globals_t * yg, yutani_server_window_t * wi
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef ENABLE_BLUR_BEHIND
|
||||
if (window->server_flags & YUTANI_WINDOW_FLAG_BLUR_BEHIND) {
|
||||
extern void draw_sprite_transform_blur(gfx_context_t * ctx, gfx_context_t * blur_ctx, const sprite_t * sprite, gfx_matrix_t matrix, float alpha, uint8_t threshold);
|
||||
draw_sprite_transform_blur(yg->backend_ctx, blur_ctx, &_win_sprite, m, opacity, window->alpha_threshold);
|
||||
} else
|
||||
#endif
|
||||
if (matrix_is_translation(m)) {
|
||||
draw_sprite_alpha(yg->backend_ctx, &_win_sprite, m[0][2], m[1][2], opacity);
|
||||
} else {
|
||||
@ -995,6 +1010,16 @@ static void resize_display(yutani_globals_t * yg) {
|
||||
reinit_graphics_yutani(yg->backend_ctx, yg->host_window);
|
||||
yutani_window_resize_done(yg->host_context, yg->host_window);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BLUR_BEHIND
|
||||
sprite_free(blur_sprite);
|
||||
free(blur_ctx);
|
||||
blur_sprite = create_sprite(yg->backend_ctx->width, yg->backend_ctx->height, ALPHA_OPAQUE);
|
||||
blur_ctx = init_graphics_sprite(blur_sprite);
|
||||
clip_ctx->width = yg->backend_ctx->width;
|
||||
clip_ctx->height = yg->backend_ctx->height;
|
||||
#endif
|
||||
|
||||
TRACE("graphics context resized...");
|
||||
yg->width = yg->backend_ctx->width;
|
||||
yg->height = yg->backend_ctx->height;
|
||||
@ -1041,12 +1066,19 @@ static void redraw_windows(yutani_globals_t * yg) {
|
||||
}
|
||||
|
||||
gfx_clear_clip(yg->backend_ctx);
|
||||
#ifdef ENABLE_BLUR_BEHIND
|
||||
gfx_clear_clip(clip_ctx);
|
||||
#endif
|
||||
|
||||
/* If the mouse has moved, that counts as two damage regions */
|
||||
if ((yg->last_mouse_x != tmp_mouse_x) || (yg->last_mouse_y != tmp_mouse_y)) {
|
||||
has_updates = 2;
|
||||
gfx_add_clip(yg->backend_ctx, yg->last_mouse_x / MOUSE_SCALE - MOUSE_OFFSET_X, yg->last_mouse_y / MOUSE_SCALE - MOUSE_OFFSET_Y, MOUSE_WIDTH, MOUSE_HEIGHT);
|
||||
gfx_add_clip(yg->backend_ctx, tmp_mouse_x / MOUSE_SCALE - MOUSE_OFFSET_X, tmp_mouse_y / MOUSE_SCALE - MOUSE_OFFSET_Y, MOUSE_WIDTH, MOUSE_HEIGHT);
|
||||
#ifdef ENABLE_BLUR_BEHIND
|
||||
gfx_add_clip(clip_ctx, yg->last_mouse_x / MOUSE_SCALE - MOUSE_OFFSET_X - BLUR_CLIP_MAX, yg->last_mouse_y / MOUSE_SCALE - MOUSE_OFFSET_Y - BLUR_CLIP_MAX, MOUSE_WIDTH + BLUR_CLIP_MAX * 2, MOUSE_HEIGHT + BLUR_CLIP_MAX * 2);
|
||||
gfx_add_clip(clip_ctx, tmp_mouse_x / MOUSE_SCALE - MOUSE_OFFSET_X - BLUR_CLIP_MAX, tmp_mouse_y / MOUSE_SCALE - MOUSE_OFFSET_Y - BLUR_CLIP_MAX, MOUSE_WIDTH + BLUR_CLIP_MAX * 2, MOUSE_HEIGHT + BLUR_CLIP_MAX * 2);
|
||||
#endif
|
||||
}
|
||||
|
||||
yg->last_mouse_x = tmp_mouse_x;
|
||||
@ -1075,12 +1107,22 @@ static void redraw_windows(yutani_globals_t * yg) {
|
||||
/* We add a clip region for each window in the update queue */
|
||||
has_updates = 1;
|
||||
gfx_add_clip(yg->backend_ctx, rect->x, rect->y, rect->width, rect->height);
|
||||
#ifdef ENABLE_BLUR_BEHIND
|
||||
gfx_add_clip(clip_ctx, rect->x - BLUR_CLIP_MAX, rect->y - BLUR_CLIP_MAX, rect->width + BLUR_CLIP_MAX * 2, rect->height + BLUR_CLIP_MAX * 2);
|
||||
#endif
|
||||
free(rect);
|
||||
free(win);
|
||||
}
|
||||
|
||||
/* Render */
|
||||
if (has_updates) {
|
||||
|
||||
#ifdef ENABLE_BLUR_BEHIND
|
||||
/* Extend clips */
|
||||
char * oclip = yg->backend_ctx->clips;
|
||||
yg->backend_ctx->clips = clip_ctx->clips;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* In theory, we should restrict this to windows within the clip region,
|
||||
* but calculating that may be more trouble than it's worth;
|
||||
@ -1088,6 +1130,11 @@ static void redraw_windows(yutani_globals_t * yg) {
|
||||
*/
|
||||
yutani_blit_windows(yg);
|
||||
|
||||
#ifdef ENABLE_BLUR_BEHIND
|
||||
/* Restore clip context */
|
||||
yg->backend_ctx->clips = oclip;
|
||||
#endif
|
||||
|
||||
/* Send VirtualBox rects */
|
||||
yutani_post_vbox_rects(yg);
|
||||
|
||||
@ -1555,6 +1602,18 @@ static void handle_key_event(yutani_globals_t * yg, struct yutani_msg_key_event
|
||||
yg->debug_bounds = (1-yg->debug_bounds);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifdef ENABLE_BLUR_BEHIND
|
||||
if ((ke->event.action == KEY_ACTION_DOWN) &&
|
||||
(ke->event.modifiers & KEY_MOD_LEFT_SUPER) &&
|
||||
(ke->event.modifiers & KEY_MOD_LEFT_SHIFT) &&
|
||||
(ke->event.keycode == 'v')) {
|
||||
if (focused->z != YUTANI_ZORDER_BOTTOM && focused->z != YUTANI_ZORDER_TOP) {
|
||||
focused->server_flags ^= YUTANI_WINDOW_FLAG_BLUR_BEHIND;
|
||||
mark_window(yg, focused);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
/* Screenshot key */
|
||||
if ((ke->event.action == KEY_ACTION_DOWN) &&
|
||||
@ -2180,6 +2239,14 @@ int main(int argc, char * argv[]) {
|
||||
yg->backend_ctx = init_graphics_fullscreen_double_buffer();
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BLUR_BEHIND
|
||||
blur_sprite = create_sprite(yg->backend_ctx->width, yg->backend_ctx->height, ALPHA_OPAQUE);
|
||||
blur_ctx = init_graphics_sprite(blur_sprite);
|
||||
clip_ctx = calloc(1, sizeof(gfx_context_t));
|
||||
clip_ctx->width = yg->backend_ctx->width;
|
||||
clip_ctx->height = yg->backend_ctx->height;
|
||||
#endif
|
||||
|
||||
if (!yg->backend_ctx) {
|
||||
free(yg);
|
||||
TRACE("Failed to open framebuffer, bailing.");
|
||||
|
@ -441,7 +441,8 @@ static void handle_key_event(struct yutani_msg_key_event * ke) {
|
||||
(ke->event.action == KEY_ACTION_DOWN)) {
|
||||
/* show menu */
|
||||
if (!alt_f2) {
|
||||
alt_f2 = yutani_window_create(yctx, ALTF2_WIDTH, ALTF2_HEIGHT);
|
||||
alt_f2 = yutani_window_create_flags(yctx, ALTF2_WIDTH, ALTF2_HEIGHT, YUTANI_WINDOW_FLAG_BLUR_BEHIND);
|
||||
yutani_window_update_shape(yctx, alt_f2, 5);
|
||||
yutani_window_move(yctx, alt_f2, center_x(ALTF2_WIDTH), center_y(ALTF2_HEIGHT));
|
||||
a2ctx = init_graphics_yutani_double_buffer(alt_f2);
|
||||
redraw_altf2();
|
||||
@ -495,7 +496,8 @@ static void handle_key_event(struct yutani_msg_key_event * ke) {
|
||||
new_focused = active_window + direction;
|
||||
/* Create tab window */
|
||||
alttab = yutani_window_create_flags(yctx, ALTTAB_WIDTH, ALTTAB_HEIGHT,
|
||||
YUTANI_WINDOW_FLAG_NO_STEAL_FOCUS | YUTANI_WINDOW_FLAG_NO_ANIMATION);
|
||||
YUTANI_WINDOW_FLAG_NO_STEAL_FOCUS | YUTANI_WINDOW_FLAG_NO_ANIMATION | YUTANI_WINDOW_FLAG_BLUR_BEHIND);
|
||||
yutani_window_update_shape(yctx, alttab, 5);
|
||||
|
||||
yutani_set_stack(yctx, alttab, YUTANI_ZORDER_OVERLAY);
|
||||
|
||||
|
@ -65,6 +65,7 @@ static void usage(char * argv[]) {
|
||||
" -x --grid \033[3mMake resizes round to nearest match for character cell size.\033[0m\n"
|
||||
" -n --no-frame \033[3mDisable decorations.\033[0m\n"
|
||||
" -g --geometry \033[3mSet requested terminal size WIDTHxHEIGHT\033[0m\n"
|
||||
" -B --blurred \033[3mBlur background behind terminal.\033[0m\n"
|
||||
"\n"
|
||||
" This terminal emulator provides basic support for VT220 escapes and\n"
|
||||
" XTerm extensions, including 256 color support and font effects.\n",
|
||||
@ -2289,6 +2290,7 @@ static void parse_geometry(char ** argv, char * str) {
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
|
||||
int _flags = 0;
|
||||
window_width = char_width * 80;
|
||||
window_height = char_height * 24;
|
||||
|
||||
@ -2300,12 +2302,13 @@ int main(int argc, char ** argv) {
|
||||
{"grid", no_argument, 0, 'x'},
|
||||
{"no-frame", no_argument, 0, 'n'},
|
||||
{"geometry", required_argument, 0, 'g'},
|
||||
{"blurred", no_argument, 0, 'B'},
|
||||
{0,0,0,0}
|
||||
};
|
||||
|
||||
/* Read some arguments */
|
||||
int index, c;
|
||||
while ((c = getopt_long(argc, argv, "bhxnFls:g:", long_opts, &index)) != -1) {
|
||||
while ((c = getopt_long(argc, argv, "bhxnFls:g:B", long_opts, &index)) != -1) {
|
||||
if (!c) {
|
||||
if (long_opts[index].flag == 0) {
|
||||
c = long_opts[index].val;
|
||||
@ -2336,6 +2339,9 @@ int main(int argc, char ** argv) {
|
||||
case 'g':
|
||||
parse_geometry(argv,optarg);
|
||||
break;
|
||||
case 'B':
|
||||
_flags = YUTANI_WINDOW_FLAG_BLUR_BEHIND;
|
||||
break;
|
||||
case '?':
|
||||
break;
|
||||
default:
|
||||
@ -2370,7 +2376,8 @@ int main(int argc, char ** argv) {
|
||||
init_decorations();
|
||||
struct decor_bounds bounds;
|
||||
decor_get_bounds(NULL, &bounds);
|
||||
window = yutani_window_create(yctx, window_width + bounds.width, window_height + bounds.height + menu_bar_height);
|
||||
window = yutani_window_create_flags(yctx, window_width + bounds.width, window_height + bounds.height + menu_bar_height, _flags);
|
||||
yutani_window_update_shape(yctx, window, 20);
|
||||
}
|
||||
|
||||
if (_fullscreen) {
|
||||
|
@ -480,6 +480,7 @@ struct yutani_msg_clipboard {
|
||||
#define YUTANI_WINDOW_FLAG_ALT_ANIMATION (1 << 3)
|
||||
#define YUTANI_WINDOW_FLAG_DIALOG_ANIMATION (1 << 4)
|
||||
#define YUTANI_WINDOW_FLAG_NO_ANIMATION (1 << 5)
|
||||
#define YUTANI_WINDOW_FLAG_BLUR_BEHIND (1 << 8)
|
||||
|
||||
/* YUTANI_SPECIAL_REQUEST
|
||||
*
|
||||
|
@ -405,6 +405,12 @@ void blur_context_box(gfx_context_t * _src, int radius) {
|
||||
_box_blur_vertical(_src,radius);
|
||||
}
|
||||
|
||||
void blur_from_into(gfx_context_t * _src, gfx_context_t * _dest, int radius) {
|
||||
|
||||
draw_fill(_dest, rgb(255,0,0));
|
||||
|
||||
}
|
||||
|
||||
static int (*load_sprite_jpg)(sprite_t *, const char *) = NULL;
|
||||
static int (*load_sprite_png)(sprite_t *, const char *) = NULL;
|
||||
|
||||
@ -979,6 +985,66 @@ void draw_sprite_transform(gfx_context_t * ctx, const sprite_t * sprite, gfx_mat
|
||||
sprite_free(scanline);
|
||||
}
|
||||
|
||||
void draw_sprite_transform_blur(gfx_context_t * ctx, gfx_context_t * blur_ctx, const sprite_t * sprite, gfx_matrix_t matrix, float alpha, uint8_t threshold) {
|
||||
double inverse[2][3];
|
||||
|
||||
/* Calculate the inverse matrix for use in calculating sprite
|
||||
* coordinate from screen coordinate. */
|
||||
gfx_matrix_invert(matrix, inverse);
|
||||
|
||||
/* Use primary matrix to obtain corners of the transformed
|
||||
* sprite in screen coordinates. */
|
||||
double ul_x, ul_y;
|
||||
double ll_x, ll_y;
|
||||
double ur_x, ur_y;
|
||||
double lr_x, lr_y;
|
||||
|
||||
apply_matrix(0, 0, matrix, &ul_x, &ul_y);
|
||||
apply_matrix(0, sprite->height, matrix, &ll_x, &ll_y);
|
||||
apply_matrix(sprite->width, 0, matrix, &ur_x, &ur_y);
|
||||
apply_matrix(sprite->width, sprite->height, matrix, &lr_x, &lr_y);
|
||||
|
||||
/* Use the corners to calculate bounds within the target context. */
|
||||
int32_t _left = clamp(fmin(fmin(ul_x, ll_x), fmin(ur_x, lr_x)), 0, ctx->width);
|
||||
int32_t _top = clamp(fmin(fmin(ul_y, ll_y), fmin(ur_y, lr_y)), 0, ctx->height);
|
||||
int32_t _right = clamp(fmax(fmax(ul_x+1, ll_x+1), fmax(ur_x+1, lr_x+1)), 0, ctx->width);
|
||||
int32_t _bottom = clamp(fmax(fmax(ul_y+1, ll_y+1), fmax(ur_y+1, lr_y+1)), 0, ctx->height);
|
||||
|
||||
blur_ctx->clips_size = ctx->clips_size;
|
||||
blur_ctx->clips = ctx->clips;
|
||||
blur_ctx->backbuffer = ctx->backbuffer;
|
||||
gfx_context_t * f = init_graphics_subregion(blur_ctx, _left, _top, _right - _left, _bottom - _top);
|
||||
flip(f);
|
||||
f->backbuffer = f->buffer;
|
||||
blur_context_box(f, 10);
|
||||
free(f);
|
||||
blur_ctx->backbuffer = blur_ctx->buffer;
|
||||
blur_ctx->clips_size = 0;
|
||||
blur_ctx->clips = NULL;
|
||||
|
||||
sprite_t * scanline = create_sprite(_right - _left, 1, ALPHA_EMBEDDED);
|
||||
sprite_t * blurline = create_sprite(_right - _left, 1, ALPHA_EMBEDDED);
|
||||
uint8_t alp = alpha * 255;
|
||||
|
||||
for (int32_t _y = _top; _y < _bottom; ++_y) {
|
||||
if (!_is_in_clip(ctx, _y)) continue;
|
||||
for (int32_t _x = _left; _x < _right; ++_x) {
|
||||
double u, v;
|
||||
apply_matrix(_x, _y, inverse, &u, &v);
|
||||
SPRITE(scanline,_x - _left,0) = gfx_bilinear_interpolation(sprite, u, v);
|
||||
SPRITE(blurline,_x - _left,0) = (_ALP(SPRITE(scanline,_x - _left,0)) > threshold) ? GFX(blur_ctx,_x,_y) : 0;
|
||||
}
|
||||
apply_alpha_vector(blurline->bitmap, blurline->width, alp);
|
||||
apply_alpha_vector(scanline->bitmap, scanline->width, alp);
|
||||
draw_sprite(ctx,blurline,_left,_y);
|
||||
draw_sprite(ctx,scanline,_left,_y);
|
||||
}
|
||||
|
||||
sprite_free(scanline);
|
||||
sprite_free(blurline);
|
||||
|
||||
}
|
||||
|
||||
void draw_sprite_rotate(gfx_context_t * ctx, const sprite_t * sprite, int32_t x, int32_t y, float rotation, float alpha) {
|
||||
gfx_matrix_t m;
|
||||
gfx_matrix_identity(m);
|
||||
|
Loading…
Reference in New Issue
Block a user