From 2a18c192e4723b663631390b957cdb72725dd7b9 Mon Sep 17 00:00:00 2001 From: "K. Lange" Date: Fri, 14 Apr 2023 20:52:01 +0900 Subject: [PATCH] yutani: window minimization, first pass --- apps/compositor.c | 102 ++++++++++++++++++- base/usr/include/toaru/decorations.h | 1 + base/usr/include/toaru/yutani-server.h | 19 +++- base/usr/include/toaru/yutani.h | 1 + base/usr/share/ttk/fancy/button-minimize.png | Bin 0 -> 502 bytes lib/decor-fancy.c | 20 +++- lib/decorations.c | 7 ++ lib/panel_windowlist.c | 7 +- 8 files changed, 147 insertions(+), 10 deletions(-) create mode 100644 base/usr/share/ttk/fancy/button-minimize.png diff --git a/apps/compositor.c b/apps/compositor.c index e5457f1b..4e618286 100644 --- a/apps/compositor.c +++ b/apps/compositor.c @@ -61,6 +61,8 @@ static void notify_subscribers(yutani_globals_t * yg); 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); +static void window_unminimize(yutani_globals_t * yg, yutani_server_window_t * window); +static void window_finish_minimize(yutani_globals_t * yg, yutani_server_window_t * w); #define ENABLE_BLUR_BEHIND #ifdef ENABLE_BLUR_BEHIND @@ -256,6 +258,7 @@ static void unorder_window(yutani_globals_t * yg, yutani_server_window_t * w) { } list_t * zorder_owner = window_zorder_owner(yg, index); + if (!zorder_owner) return; node_t * n = list_find(zorder_owner, w); if (!n) return; list_delete(zorder_owner, n); @@ -324,6 +327,10 @@ static void set_focused_window(yutani_globals_t * yg, yutani_server_window_t * w return; /* Already focused */ } + if (w->minimized) { + window_unminimize(yg,w); + } + if (yg->focused_window) { /* Send focus change to old focused window */ yutani_msg_buildx_window_focus_change_alloc(response); @@ -412,6 +419,7 @@ static yutani_server_window_t * server_window_create(yutani_globals_t * yg, int win->server_flags = flags; win->opacity = 255; win->hidden = 1; + win->minimized = 0; char key[1024]; YUTANI_SHMKEY(yg->server_ident, key, 1024, win); @@ -618,8 +626,7 @@ static void draw_cursor(yutani_globals_t * yg, int x, int y, int cursor) { * around the cursor, but it is relatively slow. */ static yutani_server_window_t * check_top_at(yutani_globals_t * yg, yutani_server_window_t * w, uint16_t x, uint16_t y){ - if (!w) return NULL; - if (w->hidden) return NULL; + if (!w || w->hidden || w->minimized) return NULL; int32_t _x = -1, _y = -1; yutani_device_to_window(w, x, y, &_x, &_y); if (_x < 0 || _x >= w->width || _y < 0 || _y >= w->height) return NULL; @@ -726,7 +733,7 @@ static inline int matrix_is_translation(gfx_matrix_t m) { */ static int yutani_blit_window(yutani_globals_t * yg, yutani_server_window_t * window, int x, int y) { - if (window->hidden) { + if (window->hidden || window->minimized) { return 0; } @@ -777,6 +784,10 @@ static int yutani_blit_window(yutani_globals_t * yg, yutani_server_window_t * wi list_insert(yg->windows_to_remove, window); return 0; } + if (yutani_is_minimizing_animation[window->anim_mode]) { + list_insert(yg->windows_to_minimize, window); + return 0; + } window->anim_mode = 0; window->anim_start = 0; } else { @@ -808,6 +819,20 @@ static int yutani_blit_window(yutani_globals_t * yg, yutani_server_window_t * wi } } break; + case YUTANI_EFFECT_MINIMIZE: + { + frame = yutani_animation_lengths[window->anim_mode] - frame; + } /* fallthrough */ + case YUTANI_EFFECT_UNMINIMIZE: + { + double time_diff = ((double)frame / (float)yutani_animation_lengths[window->anim_mode]); + double x = 0.5 + time_diff * 0.5; + opacity *= time_diff; + //int t_x = (window->width * (1.0 - x)) / 2; + //gfx_matrix_translate(m, t_x, 0.0); + gfx_matrix_scale(m, 1.0, x); + } + break; default: break; } @@ -882,7 +907,7 @@ static void yutani_post_vbox_rects(yutani_globals_t * yg) { struct Rect * rects = (struct Rect *)(tmp+sizeof(int32_t)); -#define DO_WINDOW(win) if (win && !win->hidden && *count < 255 ) { \ +#define DO_WINDOW(win) if (win && !win->hidden && !win->minimized && *count < 255 ) { \ rects->x = (win)->x; \ rects->y = (win)->y; \ rects->xe = (win)->x + (win)->width; \ @@ -1277,6 +1302,13 @@ static void redraw_windows(yutani_globals_t * yg) { free(node); } + while (yg->windows_to_minimize->tail) { + node_t * node = list_pop(yg->windows_to_minimize); + window_finish_minimize(yg, node->value); + free(node); + + } + } if (yg->screenshot_frame) { @@ -1392,6 +1424,27 @@ static void window_remove_from_client(yutani_globals_t * yg, yutani_server_windo } } +static void window_finish_minimize(yutani_globals_t * yg, yutani_server_window_t * w) { + if (w->minimized) return; + w->minimized = 1; + w->anim_mode = 0; + w->anim_start = 0; + + unorder_window(yg,w); + if (w == yg->focused_window) { + yg->focused_window = NULL; + if (yg->menu_zs->tail && yg->menu_zs->tail->value) { + set_focused_window(yg, yg->menu_zs->tail->value); + } else if (yg->mid_zs->tail && yg->mid_zs->tail->value) { + set_focused_window(yg, yg->mid_zs->tail->value); + } + } + + list_insert(yg->minimized_zs, w); + + notify_subscribers(yg); +} + /** * Actually remove a window and free the associated resources. */ @@ -1445,6 +1498,9 @@ static uint32_t ad_flags(yutani_globals_t * yg, yutani_server_window_t * win) { if (win == yg->focused_window) { flags |= 1; } + if (win->minimized) { + flags |= 2; + } return flags; } @@ -1584,6 +1640,28 @@ static void window_reveal(yutani_globals_t * yg, yutani_server_window_t * window window->anim_start = yutani_current_time(yg); } +static void window_unminimize(yutani_globals_t * yg, yutani_server_window_t * window) { + if (!window->minimized) return; + + node_t * n = list_find(yg->minimized_zs, window); + if (n) { + list_delete(yg->minimized_zs, n); + free(n); + } + + list_insert(yg->mid_zs, window); + window->z = 1; + + window->minimized = 0; + window->anim_mode = YUTANI_EFFECT_UNMINIMIZE; //yutani_pick_animation(window->server_flags, 0); + window->anim_start = yutani_current_time(yg); +} + +static void window_minimize(yutani_globals_t * yg, yutani_server_window_t * window) { + window->anim_mode = YUTANI_EFFECT_MINIMIZE; //yutani_pick_animation(window->server_flags, 0); + window->anim_start = yutani_current_time(yg); +} + /** * Process a key event. * @@ -1622,6 +1700,12 @@ static void handle_key_event(yutani_globals_t * yg, struct yutani_msg_key_event mark_window(yg,focused); return; } + if ((ke->event.action == KEY_ACTION_DOWN) && + (ke->event.modifiers & KEY_MOD_LEFT_SUPER) && + (ke->event.keycode == 'a')) { + window_minimize(yg,focused); + return; + } #endif if ((ke->event.action == KEY_ACTION_DOWN) && (ke->event.modifiers & KEY_MOD_LEFT_ALT) && @@ -2371,6 +2455,8 @@ int main(int argc, char * argv[]) { yg->menu_zs = list_create(); yg->overlay_zs = list_create(); yg->windows_to_remove = list_create(); + yg->windows_to_minimize = list_create(); + yg->minimized_zs = list_create(); yg->window_subscribers = list_create(); @@ -2734,6 +2820,9 @@ int main(int argc, char * argv[]) { break; case YUTANI_MSG_QUERY_WINDOWS: { + foreach (node, yg->minimized_zs) { + yutani_query_result(yg, p->source, node->value); + } yutani_query_result(yg, p->source, yg->bottom_z); foreach (node, yg->mid_zs) { yutani_query_result(yg, p->source, node->value); @@ -2897,6 +2986,11 @@ int main(int argc, char * argv[]) { pex_send(yg->server, w->owner, response->size, (char *)response); } break; + case YUTANI_SPECIAL_REQUEST_MINIMIZE: + if (w) { + window_minimize(yg,w); + } + break; case YUTANI_SPECIAL_REQUEST_CLIPBOARD: { yutani_msg_buildx_clipboard_alloc(response, yg->clipboard_size); diff --git a/base/usr/include/toaru/decorations.h b/base/usr/include/toaru/decorations.h index ebccb90a..b17d9c26 100644 --- a/base/usr/include/toaru/decorations.h +++ b/base/usr/include/toaru/decorations.h @@ -66,6 +66,7 @@ extern yutani_window_t * decor_show_default_menu(yutani_window_t * window, int y #define DECOR_RESIZE 3 /* Resize button */ #define DECOR_MAXIMIZE 4 #define DECOR_RIGHT 5 +#define DECOR_MINIMIZE 6 #define DECOR_ACTIVE 0 #define DECOR_INACTIVE 1 diff --git a/base/usr/include/toaru/yutani-server.h b/base/usr/include/toaru/yutani-server.h index c6fd422a..7822c271 100644 --- a/base/usr/include/toaru/yutani-server.h +++ b/base/usr/include/toaru/yutani-server.h @@ -61,8 +61,8 @@ static int yutani_animation_lengths[] = { 0, /* None */ 200, /* Fade In */ 200, /* Fade Out */ - 0, /* Minimize */ - 0, /* Unminimized */ + 200, /* Minimize */ + 200, /* Unminimized */ 100, /* Squeeze in */ 100, /* Squeeze out */ 10, /* Disappear */ @@ -79,6 +79,17 @@ static int yutani_is_closing_animation[] = { 1, }; +static int yutani_is_minimizing_animation[] = { + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 0 +}; + /* Debug Options */ #define YUTANI_DEBUG_WINDOW_BOUNDS 1 #define YUTANI_DEBUG_WINDOW_SHAPES 1 @@ -161,6 +172,7 @@ typedef struct YutaniServerWindow { /* Window is hidden? */ int hidden; + int minimized; } yutani_server_window_t; typedef struct YutaniGlobals { @@ -312,6 +324,9 @@ typedef struct YutaniGlobals { uint64_t resize_release_time; int32_t resizing_init_w; int32_t resizing_init_h; + + list_t * windows_to_minimize; + list_t * minimized_zs; } yutani_globals_t; struct key_bind { diff --git a/base/usr/include/toaru/yutani.h b/base/usr/include/toaru/yutani.h index 039ab6d3..837a6517 100644 --- a/base/usr/include/toaru/yutani.h +++ b/base/usr/include/toaru/yutani.h @@ -488,6 +488,7 @@ struct yutani_msg_clipboard { */ #define YUTANI_SPECIAL_REQUEST_MAXIMIZE 1 #define YUTANI_SPECIAL_REQUEST_PLEASE_CLOSE 2 +#define YUTANI_SPECIAL_REQUEST_MINIMIZE 3 #define YUTANI_SPECIAL_REQUEST_CLIPBOARD 10 diff --git a/base/usr/share/ttk/fancy/button-minimize.png b/base/usr/share/ttk/fancy/button-minimize.png new file mode 100644 index 0000000000000000000000000000000000000000..cb7993690c72994fac4d7ad7ab9df6f72f14c169 GIT binary patch literal 502 zcmVEX>4Tx04R}tkv&MmKpe$i(@I6F4t5Z6h)|vEq9Ts93Pq?8YK2xEOfLO`CJjl7 zi=*ILaPVWX>fqw6tAnc`2!4RLx;QDiNQwVT3N2ziIPS;0dyl(!fKV?p%?iW-O}EWd zA}(gKt77mK0raC6qYz|f8FP}9M91-U44LCuqO|IySV+-+yn}z(^-JVZ$W;O( z#{w$QAiI9>Klt6Pm7kjQl0tEy>&0~1(5N}i_p#$NP5}QiaHY5Wl{zr{NqViN zMUH@hZQ$a%r73&BP<$@Bjb+ literal 0 HcmV?d00001 diff --git a/lib/decor-fancy.c b/lib/decor-fancy.c index 078dd6d5..1e678867 100644 --- a/lib/decor-fancy.c +++ b/lib/decor-fancy.c @@ -44,9 +44,10 @@ static struct TT_Font * _tt_font = NULL; #define BUTTON_CLOSE 0 #define BUTTON_MAXIMIZE 1 -#define ACTIVE 2 -#define INACTIVE 11 -static sprite_t * sprites[20]; +#define BUTTON_MINIMIZE 2 +#define ACTIVE 3 +#define INACTIVE 12 +static sprite_t * sprites[21]; #define TEXT_OFFSET ((window->decorator_flags & DECOR_FLAG_TILED) ? 5 : 10) #define BUTTON_OFFSET ((window->decorator_flags & DECOR_FLAG_TILED) ? 5 : 0) @@ -247,6 +248,12 @@ static void render_decorations_fancy(yutani_window_t * window, gfx_context_t * c draw_sprite_alpha_paint(ctx, sprites[BUTTON_MAXIMIZE], width + (BUTTON_OFFSET - 50) * TOTAL_SCALE, (16 - BUTTON_OFFSET) * TOTAL_SCALE, 1.0, title_color); + + if (width + (BUTTON_OFFSET - 72) * TOTAL_SCALE > bounds.left_width) { + draw_sprite_alpha_paint(ctx, sprites[BUTTON_MINIMIZE], + width + (BUTTON_OFFSET - 72) * TOTAL_SCALE, + (16 - BUTTON_OFFSET) * TOTAL_SCALE, 1.0, title_color); + } } } } @@ -265,6 +272,12 @@ static int check_button_press_fancy(yutani_window_t * window, int x, int y) { y >= 16 * TOTAL_SCALE && y <= 26 * TOTAL_SCALE) { return DECOR_MAXIMIZE; } + + if (x >= (int)window->width + (BUTTON_OFFSET - 72) * TOTAL_SCALE && + x <= (int)window->width + (BUTTON_OFFSET - 62) * TOTAL_SCALE && + y >= 16 * TOTAL_SCALE && y <= 26 * TOTAL_SCALE) { + return DECOR_MINIMIZE; + } } return 0; @@ -273,6 +286,7 @@ static int check_button_press_fancy(yutani_window_t * window, int x, int y) { void decor_init() { init_sprite(BUTTON_CLOSE, TTK_FANCY_PATH "button-close.png"); init_sprite(BUTTON_MAXIMIZE, TTK_FANCY_PATH "button-maximize.png"); + init_sprite(BUTTON_MINIMIZE, TTK_FANCY_PATH "button-minimize.png"); create_borders_from_spritesheet(ACTIVE, TTK_FANCY_PATH "borders-active.png"); create_borders_from_spritesheet(INACTIVE, TTK_FANCY_PATH "borders-inactive.png"); diff --git a/lib/decorations.c b/lib/decorations.c index 30a3eb60..da84fe6d 100644 --- a/lib/decorations.c +++ b/lib/decorations.c @@ -122,6 +122,10 @@ static void _decor_maximize(yutani_t * yctx, yutani_window_t * window) { } } +static void _decor_minimize(yutani_t * yctx, yutani_window_t * window) { + yutani_special_request(yctx, window, YUTANI_SPECIAL_REQUEST_MINIMIZE); +} + static yutani_window_t * _decor_menu_owner_window = NULL; static struct MenuList * _decor_menu = NULL; @@ -320,6 +324,9 @@ int decor_handle_event(yutani_t * yctx, yutani_msg_t * m) { case DECOR_MAXIMIZE: _decor_maximize(yctx, window); break; + case DECOR_MINIMIZE: + _decor_minimize(yctx, window); + break; default: break; } diff --git a/lib/panel_windowlist.c b/lib/panel_windowlist.c index 1627689d..97ada8fd 100644 --- a/lib/panel_windowlist.c +++ b/lib/panel_windowlist.c @@ -79,13 +79,18 @@ static int widget_draw_windowlist(struct PanelWidget * this, gfx_context_t * ctx } } + uint32_t text_color = TEXT_COLOR; + if (j == focused_app) text_color = HILIGHT_COLOR; + else if (ad->flags & 1) text_color = FOCUS_COLOR; + else if (ad->flags & 2) text_color = premultiply(rgba(_RED(TEXT_COLOR),_GRE(TEXT_COLOR),_BLU(TEXT_COLOR),127)); + if (title_width >= MIN_TEXT_WIDTH) { /* Ellipsifiy the title */ char * s = ellipsify(ad->name, 14, font, title_width - 4, NULL); sprite_t * icon = icon_get_48(ad->icon); gfx_context_t * subctx = init_graphics_subregion(ctx, i, 0, w, ctx->height); draw_sprite_scaled_alpha(subctx, icon, w - 48 - 2, 0, 48, 48, (ad->flags & 1) ? 1.0 : 0.7); - tt_draw_string_shadow(subctx, font, s, 14, 2, TEXT_Y_OFFSET, (j == focused_app) ? HILIGHT_COLOR : (ad->flags & 1) ? FOCUS_COLOR : TEXT_COLOR, rgb(0,0,0), 4); + tt_draw_string_shadow(subctx, font, s, 14, 2, TEXT_Y_OFFSET, text_color, rgb(0,0,0), 4); free(subctx); free(s); } else {