diff --git a/base/usr/include/toaru/decorations.h b/base/usr/include/toaru/decorations.h index b17d9c26..6c9d3690 100644 --- a/base/usr/include/toaru/decorations.h +++ b/base/usr/include/toaru/decorations.h @@ -46,6 +46,8 @@ struct decor_bounds { extern void (*decor_render_decorations)(yutani_window_t *, gfx_context_t *, char *, int); extern int (*decor_check_button_press)(yutani_window_t *, int x, int y); extern int (*decor_get_bounds)(yutani_window_t *, struct decor_bounds *); +extern int decor_hover_button; +extern yutani_window_t * decor_hover_window; /* * Run me once to set things up @@ -67,6 +69,7 @@ extern yutani_window_t * decor_show_default_menu(yutani_window_t * window, int y #define DECOR_MAXIMIZE 4 #define DECOR_RIGHT 5 #define DECOR_MINIMIZE 6 +#define DECOR_REDRAW 7 #define DECOR_ACTIVE 0 #define DECOR_INACTIVE 1 diff --git a/base/usr/include/toaru/yutani.h b/base/usr/include/toaru/yutani.h index 87e0db56..52552838 100644 --- a/base/usr/include/toaru/yutani.h +++ b/base/usr/include/toaru/yutani.h @@ -567,6 +567,7 @@ extern gfx_context_t * init_graphics_yutani(yutani_window_t * window); extern gfx_context_t * init_graphics_yutani_double_buffer(yutani_window_t * window); extern void reinit_graphics_yutani(gfx_context_t * out, yutani_window_t * window); extern void release_graphics_yutani(gfx_context_t * gfx); +extern void yutani_internal_refocus(yutani_t * yctx, yutani_window_t * window); _End_C_Header diff --git a/lib/decor-fancy.c b/lib/decor-fancy.c index bda59ee1..32b83d5b 100644 --- a/lib/decor-fancy.c +++ b/lib/decor-fancy.c @@ -139,6 +139,8 @@ static char * ellipsify(char * input, int font_size, struct TT_Font * font, int return out; } +#define BUTTON_PAD 5 + static void render_decorations_fancy(yutani_window_t * window, gfx_context_t * ctx, char * title, int decors_active) { int width = window->width; int height = window->height; @@ -238,21 +240,39 @@ static void render_decorations_fancy(yutani_window_t * window, gfx_context_t * c tt_draw_string(ctx, _tt_font, title_offset, (TEXT_OFFSET + 14) * TOTAL_SCALE, title, title_color); } + uint32_t h_color = rgb(100,100,100); + uint32_t i_color = (decor_hover_window == window && decor_hover_button) ? ACTIVE_COLOR : title_color; + if (width + (BUTTON_OFFSET - 28) * TOTAL_SCALE > bounds.left_width) { + if (decor_hover_window == window && decor_hover_button == DECOR_CLOSE) { + draw_rounded_rectangle(ctx, + width + (BUTTON_OFFSET - 28 - BUTTON_PAD) * TOTAL_SCALE, + (16 - BUTTON_OFFSET - BUTTON_PAD) * TOTAL_SCALE, 8 + BUTTON_PAD * 2, 8 + BUTTON_PAD * 2, 4, h_color); + } draw_sprite_alpha_paint(ctx, sprites[BUTTON_CLOSE], width + (BUTTON_OFFSET - 28) * TOTAL_SCALE, - (16 - BUTTON_OFFSET) * TOTAL_SCALE, 1.0, title_color); + (16 - BUTTON_OFFSET) * TOTAL_SCALE, 1.0, i_color); if (width + (BUTTON_OFFSET - 50) * TOTAL_SCALE > bounds.left_width) { if (!(window->decorator_flags & DECOR_FLAG_NO_MAXIMIZE)) { + if (decor_hover_window == window && decor_hover_button == DECOR_MAXIMIZE) { + draw_rounded_rectangle(ctx, + width + (BUTTON_OFFSET - 50 - BUTTON_PAD) * TOTAL_SCALE, + (16 - BUTTON_OFFSET - BUTTON_PAD) * TOTAL_SCALE, 8 + BUTTON_PAD * 2, 8 + BUTTON_PAD * 2, 4, h_color); + } draw_sprite_alpha_paint(ctx, sprites[BUTTON_MAXIMIZE], width + (BUTTON_OFFSET - 50) * TOTAL_SCALE, - (16 - BUTTON_OFFSET) * TOTAL_SCALE, 1.0, title_color); + (16 - BUTTON_OFFSET) * TOTAL_SCALE, 1.0, i_color); if (width + (BUTTON_OFFSET - 72) * TOTAL_SCALE > bounds.left_width) { + if (decor_hover_window == window && decor_hover_button == DECOR_MINIMIZE) { + draw_rounded_rectangle(ctx, + width + (BUTTON_OFFSET - 72 - BUTTON_PAD) * TOTAL_SCALE, + (16 - BUTTON_OFFSET - BUTTON_PAD) * TOTAL_SCALE, 8 + BUTTON_PAD * 2, 8 + BUTTON_PAD * 2, 4, h_color); + } draw_sprite_alpha_paint(ctx, sprites[BUTTON_MINIMIZE], width + (BUTTON_OFFSET - 72) * TOTAL_SCALE, - (16 - BUTTON_OFFSET) * TOTAL_SCALE, 1.0, title_color); + (16 - BUTTON_OFFSET) * TOTAL_SCALE, 1.0, i_color); } } } @@ -260,23 +280,27 @@ static void render_decorations_fancy(yutani_window_t * window, gfx_context_t * c } static int check_button_press_fancy(yutani_window_t * window, int x, int y) { - if (x >= (int)window->width + (BUTTON_OFFSET - 28) * TOTAL_SCALE && - x <= (int)window->width + (BUTTON_OFFSET - 18) * TOTAL_SCALE && - y >= 16 * TOTAL_SCALE && y <= 26 * TOTAL_SCALE ) { - return DECOR_CLOSE; - } - - if (!(window->decorator_flags & DECOR_FLAG_NO_MAXIMIZE)) { - if (x >= (int)window->width + (BUTTON_OFFSET - 50) * TOTAL_SCALE && - x <= (int)window->width + (BUTTON_OFFSET - 40) * TOTAL_SCALE && - y >= 16 * TOTAL_SCALE && y <= 26 * TOTAL_SCALE) { - return DECOR_MAXIMIZE; + if (y >= (16 - BUTTON_OFFSET - BUTTON_PAD) * TOTAL_SCALE && y <= (16 - BUTTON_OFFSET + 8 + BUTTON_PAD) * TOTAL_SCALE ) { + if (x >= (int)window->width + (BUTTON_OFFSET - 28 - BUTTON_PAD) * TOTAL_SCALE && + x <= (int)window->width + (BUTTON_OFFSET - 28 + 8 + BUTTON_PAD) * TOTAL_SCALE) { + return DECOR_CLOSE; } - 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; + if (!(window->decorator_flags & DECOR_FLAG_NO_MAXIMIZE)) { + if (x >= (int)window->width + (BUTTON_OFFSET - 50 - BUTTON_PAD) * TOTAL_SCALE && + x <= (int)window->width + (BUTTON_OFFSET - 50 + 8 + BUTTON_PAD) * TOTAL_SCALE) { + return DECOR_MAXIMIZE; + } + + if (x >= (int)window->width + (BUTTON_OFFSET - 72 - BUTTON_PAD) * TOTAL_SCALE && + x <= (int)window->width + (BUTTON_OFFSET - 72 + 8 + BUTTON_PAD) * TOTAL_SCALE) { + return DECOR_MINIMIZE; + } + } + + if (x >= (int)window->width + (BUTTON_OFFSET - 72 - BUTTON_PAD) * TOTAL_SCALE && + x <= (int)window->width + (BUTTON_OFFSET - 28 + 8 + BUTTON_PAD) * TOTAL_SCALE) { + return DECOR_OTHER; } } diff --git a/lib/decorations.c b/lib/decorations.c index 7928ea7d..2163ce03 100644 --- a/lib/decorations.c +++ b/lib/decorations.c @@ -253,6 +253,8 @@ static yutani_scale_direction_t check_resize_direction(struct yutani_msg_window_ } static yutani_scale_direction_t old_resize_direction = SCALE_NONE; +int decor_hover_button = 0; +yutani_window_t * decor_hover_window = NULL; int decor_handle_event(yutani_t * yctx, yutani_msg_t * m) { if (m) { @@ -265,10 +267,16 @@ int decor_handle_event(yutani_t * yctx, yutani_msg_t * m) { decor_get_bounds(window, &bounds); if (!window) return 0; if (!(window->decorator_flags & DECOR_FLAG_DECORATED)) return 0; + if (me->command == YUTANI_MOUSE_EVENT_LEAVE && decor_hover_window == window) { + decor_hover_window = NULL; + decor_hover_button = 0; + yutani_internal_refocus(yctx, window); + return DECOR_REDRAW; + } if (within_decors(window, me->new_x, me->new_y)) { int button = decor_check_button_press(window, me->new_x, me->new_y); if (me->command == YUTANI_MOUSE_EVENT_DOWN && me->buttons & YUTANI_MOUSE_BUTTON_LEFT) { - if (!button) { + if (!button || button == DECOR_OTHER) { /* Resize edges */ yutani_scale_direction_t resize_direction = check_resize_direction(me, window); @@ -317,6 +325,9 @@ int decor_handle_event(yutani_t * yctx, yutani_msg_t * m) { } old_resize_direction = resize_direction; } + } else if (old_resize_direction != SCALE_NONE) { + yutani_window_show_mouse(yctx, window, YUTANI_CURSOR_TYPE_RESET); + old_resize_direction = SCALE_NONE; } } if (me->command == YUTANI_MOUSE_EVENT_CLICK || close_enough(me)) { @@ -337,13 +348,28 @@ int decor_handle_event(yutani_t * yctx, yutani_msg_t * m) { default: break; } + decor_hover_window = NULL; + decor_hover_button = 0; + yutani_internal_refocus(yctx, window); return button; } + if (button != decor_hover_button || window != decor_hover_window) { + decor_hover_button = button; + decor_hover_window = window; + yutani_internal_refocus(yctx, window); + return DECOR_REDRAW; + } } else { if (old_resize_direction != SCALE_NONE) { yutani_window_show_mouse(yctx, window, YUTANI_CURSOR_TYPE_RESET); old_resize_direction = SCALE_NONE; } + if (decor_hover_window == window) { + decor_hover_button = 0; + decor_hover_window = NULL; + yutani_internal_refocus(yctx, window); + return DECOR_REDRAW; + } } } break; diff --git a/lib/yutani.c b/lib/yutani.c index e9509726..fc8eb6a9 100644 --- a/lib/yutani.c +++ b/lib/yutani.c @@ -1156,3 +1156,15 @@ void release_graphics_yutani(gfx_context_t * gfx) { } free(gfx); } + +void yutani_internal_refocus(yutani_t * yctx, yutani_window_t * window) { + /* Check if a refocus is already in our queue to be processed */ + foreach(node, yctx->queued) { + yutani_msg_t * out = (yutani_msg_t *)node->value; + if (out->type == YUTANI_MSG_WINDOW_FOCUS_CHANGE) return; + } + /* Otherwise, produce an artificial one matching the reported focus state of the window */ + yutani_msg_t * msg = malloc(sizeof(struct yutani_message) + sizeof(struct yutani_msg_window_focus_change)); + yutani_msg_buildx_window_focus_change(msg, window->wid, window->focused); + list_insert(yctx->queued, msg); +}