1
0
mirror of https://codeberg.org/vyivel/dulcepan/ synced 2025-06-24 22:44:18 +03:00

Compare commits

5 Commits

Author SHA1 Message Date
60518fe18e config: introduce quick-select-allow-editing
If false while quick-select is true, the left mouse button acts in the same
way as the right mouse button.
2025-03-08 23:41:46 +03:00
b9e94f9584 seat: only save due to quick-select when resizing ends
Moving a selection shouldn't trigger this.
2025-03-08 23:23:18 +03:00
8bc62fdae4 meson: bump version to 1.0.3 2025-03-08 22:56:40 +03:00
accbd01ad6 README.md: bump copyright year 2025-02-07 16:26:15 +03:00
0167c017a0 seat: allow toggling whole output selection
Closes: https://codeberg.org/vyivel/dulcepan/issues/20
2025-02-07 13:25:00 +00:00
8 changed files with 121 additions and 51 deletions

View File

@ -30,4 +30,4 @@ GPL-3.0-only
See `LICENSE` for more information. See `LICENSE` for more information.
Copyright © 2024 Kirill Primak Copyright © 2025 Kirill Primak

View File

@ -33,6 +33,10 @@ animation-duration = 0
# or when a whole output is selected with a mouse button. # or when a whole output is selected with a mouse button.
quick-select = false quick-select = false
# If true, dulcepan will allow editing the current selection if quick-select is
# true. Has no effect if quick-select is false.
quick-select-allow-editing = true
# If true, dulcepan will remember selection between runs. # If true, dulcepan will remember selection between runs.
# The state is stored at $XDG_CACHE_HOME/dulcepan. # The state is stored at $XDG_CACHE_HOME/dulcepan.
persistence = true persistence = true

View File

@ -1,7 +1,7 @@
project( project(
'dulcepan', 'dulcepan',
'c', 'c',
version: '1.0.2', version: '1.0.3',
license: 'GPL-3.0-only', license: 'GPL-3.0-only',
default_options: [ default_options: [
'c_std=c11', 'c_std=c11',

View File

@ -125,6 +125,7 @@ void dp_config_load(struct dp_state *state, const char *user_path) {
.animation_duration = 0, .animation_duration = 0,
.png_compression = 6, .png_compression = 6,
.quick_select = false, .quick_select = false,
.quick_select_allow_editing = true,
.persistence = true, .persistence = true,
}; };
@ -243,6 +244,8 @@ void dp_config_load(struct dp_state *state, const char *user_path) {
load_int(value, line_idx, 0, 9, &config->png_compression); load_int(value, line_idx, 0, 9, &config->png_compression);
} else if (strcmp(key, "quick-select") == 0) { } else if (strcmp(key, "quick-select") == 0) {
load_bool(value, line_idx, &config->quick_select); load_bool(value, line_idx, &config->quick_select);
} else if (strcmp(key, "quick-select-allow-editing") == 0) {
load_bool(value, line_idx, &config->quick_select_allow_editing);
} else if (strcmp(key, "persistence") == 0) { } else if (strcmp(key, "persistence") == 0) {
load_bool(value, line_idx, &config->persistence); load_bool(value, line_idx, &config->persistence);
} else if (strcmp(key, "quit-key") == 0) { } else if (strcmp(key, "quit-key") == 0) {

View File

@ -126,6 +126,14 @@ struct dp_selection {
int resize_edges; int resize_edges;
// Resize anchor // Resize anchor
double resize_x, resize_y; double resize_x, resize_y;
// Used for toggling
struct {
// If not NULL, the current output has been selected via the dedicated
// action rather than by persistent state loading or manual resizing
struct dp_output *output;
double x, y, width, height;
} last_partial;
}; };
enum dp_file_format { enum dp_file_format {
@ -163,7 +171,10 @@ struct dp_config {
int animation_duration; // In milliseconds int animation_duration; // In milliseconds
int png_compression; int png_compression;
bool quick_select; bool quick_select;
bool quick_select_allow_editing;
bool persistence; bool persistence;
}; };
@ -200,6 +211,8 @@ struct dp_state {
const char *output_path; // May be NULL const char *output_path; // May be NULL
enum dp_file_format output_format; enum dp_file_format output_format;
bool allow_selection_editing;
bool show_cursors; bool show_cursors;
cairo_pattern_t *border_pattern; cairo_pattern_t *border_pattern;
@ -232,7 +245,7 @@ void dp_select_stop_interactive(struct dp_selection *selection);
void dp_select_notify_pointer_position( void dp_select_notify_pointer_position(
struct dp_selection *selection, struct dp_output *output, double x, double y); struct dp_selection *selection, struct dp_output *output, double x, double y);
void dp_select_whole(struct dp_selection *selection, struct dp_output *output); void dp_select_toggle_whole(struct dp_selection *selection, struct dp_output *output);
void dp_save(struct dp_state *state); void dp_save(struct dp_state *state);

View File

@ -176,7 +176,7 @@ static void help(const char *prog) {
"\n" "\n"
"Use the left or right mouse button to select a part of the output. A selection\n" "Use the left or right mouse button to select a part of the output. A selection\n"
"can also be moved and resized with the left mouse button. Clicking the middle\n" "can also be moved and resized with the left mouse button. Clicking the middle\n"
"mouse button selects the entire output.\n", "mouse button toggles the selection of the entire output.\n",
prog); prog);
} }
@ -248,6 +248,9 @@ int main(int argc, char **argv) {
state.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); state.xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
struct dp_config *config = &state.config; struct dp_config *config = &state.config;
state.allow_selection_editing = !config->quick_select || config->quick_select_allow_editing;
if (config->border_gradient != DP_BORDER_GRADIENT_NONE) { if (config->border_gradient != DP_BORDER_GRADIENT_NONE) {
state.border_pattern = cairo_pattern_create_linear(0, 0, 1, 0); state.border_pattern = cairo_pattern_create_linear(0, 0, 1, 0);
cairo_pattern_add_color_stop_rgba(state.border_pattern, 0, config->border_color[0], cairo_pattern_add_color_stop_rgba(state.border_pattern, 0, config->border_color[0],

View File

@ -92,7 +92,9 @@ static const struct wl_keyboard_listener keyboard_listener = {
.modifiers = keyboard_handle_modifiers, .modifiers = keyboard_handle_modifiers,
}; };
static enum wp_cursor_shape_device_v1_shape get_cursor_shape(struct dp_selection *selection) { static enum wp_cursor_shape_device_v1_shape get_cursor_shape(struct dp_state *state) {
if (state->allow_selection_editing) {
struct dp_selection *selection = &state->selection;
switch (selection->action) { switch (selection->action) {
case DP_SELECTION_ACTION_NONE: case DP_SELECTION_ACTION_NONE:
break; break;
@ -129,14 +131,16 @@ static enum wp_cursor_shape_device_v1_shape get_cursor_shape(struct dp_selection
} }
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_MOVE; return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_MOVE;
} }
}
// The default cursor // The default cursor
return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR; return WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR;
} }
static void update_cursor(struct dp_seat *seat) { static void update_cursor(struct dp_seat *seat) {
if (seat->cursor_shape_device != NULL) { if (seat->cursor_shape_device != NULL) {
wp_cursor_shape_device_v1_set_shape(seat->cursor_shape_device, seat->pointer_serial, wp_cursor_shape_device_v1_set_shape(
get_cursor_shape(&seat->state->selection)); seat->cursor_shape_device, seat->pointer_serial, get_cursor_shape(seat->state));
} }
} }
@ -182,7 +186,8 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer, uin
struct dp_selection *selection = &state->selection; struct dp_selection *selection = &state->selection;
if (button_state != WL_POINTER_BUTTON_STATE_PRESSED) { if (button_state != WL_POINTER_BUTTON_STATE_PRESSED) {
if (selection->width > 0 && selection->height > 0 && state->config.quick_select) { if (selection->action == DP_SELECTION_ACTION_RESIZING && selection->width > 0 &&
selection->height > 0 && state->config.quick_select) {
state->status = DP_STATUS_SAVED; state->status = DP_STATUS_SAVED;
} }
dp_select_stop_interactive(selection); dp_select_stop_interactive(selection);
@ -196,14 +201,14 @@ static void pointer_handle_button(void *data, struct wl_pointer *wl_pointer, uin
switch (button) { switch (button) {
case BTN_LEFT: case BTN_LEFT:
case BTN_RIGHT: case BTN_RIGHT:
dp_select_start_interactive( dp_select_start_interactive(selection, seat->ptr_output, seat->ptr_x, seat->ptr_y,
selection, seat->ptr_output, seat->ptr_x, seat->ptr_y, button == BTN_LEFT); state->allow_selection_editing && button == BTN_LEFT);
update_cursor(seat); update_cursor(seat);
break; break;
case BTN_MIDDLE: case BTN_MIDDLE:
dp_select_whole(selection, seat->ptr_output); dp_select_toggle_whole(selection, seat->ptr_output);
// dp_select_whole() doesn't invalidate the interactive state, so do it manually // Update the interaction state manually
dp_select_notify_pointer_position(selection, seat->ptr_output, seat->ptr_x, seat->ptr_y); dp_select_notify_pointer_position(selection, seat->ptr_output, seat->ptr_x, seat->ptr_y);
update_cursor(seat); update_cursor(seat);

View File

@ -20,6 +20,24 @@ static void set_selected_output(struct dp_selection *selection, struct dp_output
} }
} }
static inline bool has_last_partial(struct dp_selection *selection) {
return selection->last_partial.output != NULL;
}
static inline void reset_last_partial(struct dp_selection *selection) {
selection->last_partial.output = NULL;
}
static bool has_partial(struct dp_selection *selection) {
struct dp_output *output = selection->output;
if (output == NULL) {
return false;
}
return selection->x != 0 || selection->y != 0 || selection->width != output->effective_width ||
selection->height != output->effective_height;
}
static void update_action( static void update_action(
struct dp_selection *selection, struct dp_output *output, double x, double y) { struct dp_selection *selection, struct dp_output *output, double x, double y) {
if (output == selection->output) { if (output == selection->output) {
@ -161,6 +179,8 @@ void dp_select_start_interactive(struct dp_selection *selection, struct dp_outpu
update_action(selection, output, x, y); update_action(selection, output, x, y);
selection->action_active = true; selection->action_active = true;
reset_last_partial(selection);
if (modify_existing) { if (modify_existing) {
switch (selection->action) { switch (selection->action) {
case DP_SELECTION_ACTION_NONE: case DP_SELECTION_ACTION_NONE:
@ -213,13 +233,35 @@ void dp_select_notify_pointer_position(
} }
} }
void dp_select_whole(struct dp_selection *selection, struct dp_output *output) { void dp_select_toggle_whole(struct dp_selection *selection, struct dp_output *output) {
if (selection->output == output && has_last_partial(selection)) {
// Toggle the selection back to the last partial one
set_selected_output(selection, selection->last_partial.output);
selection->x = selection->last_partial.x;
selection->y = selection->last_partial.y;
selection->width = selection->last_partial.width;
selection->height = selection->last_partial.height;
reset_last_partial(selection);
} else {
// Don't save another whole output selection as partial
if (has_partial(selection) && !has_last_partial(selection)) {
selection->last_partial.output = selection->output;
selection->last_partial.x = selection->x;
selection->last_partial.y = selection->y;
selection->last_partial.width = selection->width;
selection->last_partial.height = selection->height;
}
set_selected_output(selection, output); set_selected_output(selection, output);
selection->x = 0; selection->x = 0;
selection->y = 0; selection->y = 0;
selection->width = output->effective_width; selection->width = output->effective_width;
selection->height = output->effective_height; selection->height = output->effective_height;
}
dp_output_redraw(output); dp_output_redraw(selection->output);
} }