Skip to content

Commit c19cbbd

Browse files
committed
Add minimize and maximize features on window frame
Add a condition in twin_window_dispatch() to handle clicks on the minimize and maximize buttons located on the window frame. The positions of these buttons are calculated for click detection. A minimized window is inactive, even if it remains at the top of the screen. A window is considered active when it is the topmost window and is not minimized. When the window is active, its title bar turns blue. Signed-off-by: Wei-Hsin Yeh <weihsinyeh168@gmail.com>
1 parent 0b046ce commit c19cbbd

File tree

3 files changed

+65
-9
lines changed

3 files changed

+65
-9
lines changed

include/twin.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -443,6 +443,7 @@ struct _twin_window {
443443
twin_rect_t client;
444444
twin_rect_t damage;
445445
bool active;
446+
bool minimize;
446447
bool client_grab;
447448
bool want_focus;
448449
bool draw_queued;

src/screen.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99

1010
#include "twin_private.h"
1111

12+
#define TWIN_BW 0
13+
#define TWIN_TITLE_HEIGHT 20
14+
1215
twin_screen_t *twin_screen_create(twin_coord_t width,
1316
twin_coord_t height,
1417
twin_put_begin_t put_begin,
@@ -135,6 +138,12 @@ static void twin_screen_span_pixmap(twin_screen_t maybe_unused *screen,
135138
return;
136139
if (p->y + p->height <= y)
137140
return;
141+
142+
/* Skip drawing the window's client area if the window is minimized. */
143+
if (p->window->minimize &&
144+
y >= p->y + TWIN_BW + TWIN_TITLE_HEIGHT + TWIN_BW)
145+
return;
146+
138147
/* bounds check in x */
139148
p_left = left;
140149
if (p_left < p->x)

src/window.c

Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ twin_window_t *twin_window_create(twin_screen_t *screen,
3636
window->screen = screen;
3737
window->style = style;
3838
window->active = false;
39+
window->minimize = false;
3940
switch (window->style) {
4041
case TwinWindowApplication:
4142
left = TWIN_BW;
@@ -179,7 +180,7 @@ bool twin_window_valid_range(twin_window_t *window,
179180
y < window->pixmap->y + window->pixmap->height - offset_y) {
180181
if (y < window->pixmap->y + (window->client.top))
181182
return !twin_pixmap_transparent(window->pixmap, x, y);
182-
return true;
183+
return !window->minimize;
183184
}
184185
return false;
185186
}
@@ -494,21 +495,66 @@ bool twin_window_dispatch(twin_window_t *window, twin_event_t *event)
494495
twin_event_t ev = *event;
495496
bool delegate = true;
496497

498+
twin_fixed_t bw = twin_int_to_fixed(TWIN_TITLE_BW);
499+
twin_fixed_t t_h = twin_int_to_fixed(window->client.top) - bw;
500+
twin_fixed_t t_arc_2 = t_h * 2 / 3;
501+
twin_fixed_t c_right = twin_int_to_fixed(window->client.right) - bw / 2;
502+
twin_fixed_t name_height = t_h - bw - bw / 2;
503+
twin_fixed_t icon_size = name_height * 8 / 10;
504+
twin_fixed_t menu_x = t_arc_2;
505+
twin_fixed_t text_x = menu_x + icon_size + bw;
506+
twin_fixed_t text_width;
507+
twin_fixed_t title_right;
508+
twin_path_t *path = twin_path_create();
509+
const char *name = window->name;
510+
511+
text_width = twin_width_utf8(path, name);
512+
twin_path_destroy(path);
513+
title_right = (text_x + text_width + bw + icon_size + bw + icon_size + bw +
514+
icon_size + t_arc_2);
515+
516+
if (title_right < c_right)
517+
c_right = title_right;
518+
519+
twin_fixed_t close_x = c_right - t_arc_2 - icon_size;
520+
twin_fixed_t max_x = close_x - bw - icon_size;
521+
twin_fixed_t min_x = max_x - bw - icon_size;
522+
int local_x, local_y;
523+
497524
switch (ev.kind) {
498525
case TwinEventButtonDown:
526+
local_y = ev.u.pointer.screen_y - window->pixmap->y;
527+
if (local_y >= 0 && local_y <= TWIN_BW + TWIN_TITLE_HEIGHT + TWIN_BW) {
528+
local_x = ev.u.pointer.screen_x - window->pixmap->x;
529+
if (local_x > twin_fixed_to_int(min_x) &&
530+
local_x < twin_fixed_to_int(max_x)) {
531+
window->minimize = true;
532+
twin_pixmap_damage(window->pixmap, 0, 0, window->pixmap->width,
533+
window->pixmap->height);
534+
} else if (local_x > twin_fixed_to_int(max_x) &&
535+
local_x < twin_fixed_to_int(close_x)) {
536+
window->minimize = false;
537+
twin_pixmap_damage(window->pixmap, 0, 0, window->pixmap->width,
538+
window->pixmap->height);
539+
}
540+
}
499541
case TwinEventActivate:
500542
/* Set window active. */
501543
/*
502-
* When the box is trigger by TwinEventButtonDown, its window's title
503-
* bar needs to change color and be put onto the toppest layer.
544+
* A minimized window is inactive. When the box is triggered by
545+
* TwinEventButtonDown and the window is not minimized, it becomes
546+
* active. For a window to be considered active, it must be the topmost
547+
* window on the screen. The window's title bar turns blue to indicate
548+
* the active state.
504549
*/
505-
if (!window->active) {
550+
if (window->minimize)
551+
window->active = false;
552+
else
506553
window->active = true;
507-
twin_window_frame(window);
508-
if (window != window->screen->top->window) {
509-
window->screen->top->window->active = false;
510-
twin_window_frame(window->screen->top->window);
511-
}
554+
twin_window_frame(window);
555+
if (window != window->screen->top->window) {
556+
window->screen->top->window->active = false;
557+
twin_window_frame(window->screen->top->window);
512558
}
513559
#if defined(CONFIG_DROP_SHADOW)
514560
/* Handle drop shadow. */

0 commit comments

Comments
 (0)