diff --git a/resources/head.ui b/resources/head.ui index 70f5d42..dc0737a 100644 --- a/resources/head.ui +++ b/resources/head.ui @@ -2,11 +2,55 @@ - - 99999999999999 + + 16383 + 1 + 10 + + + False + + + True + False + 10 + 10 + 10 + 10 + vertical + + + + + + + + -16384 + 16383 + 1 + 10 + + + -16384 + 16383 + 1 + 10 + + + 2147483.647 + 1 + 10 + + + 99999 0.1 0.5 + + 16383 + 1 + 10 + True False @@ -52,8 +96,8 @@ True True start - 6 - scal + 9 + scale_adjustment 2 1 @@ -67,7 +111,7 @@ True False - _Scale + DPI _Scale True scale 1 @@ -77,20 +121,6 @@ 3 - - - True - False - Si_ze - True - width - 1 - - - 0 - 5 - - True @@ -105,184 +135,6 @@ 4 - - - True - False - _Refresh - True - refresh - 1 - - - 0 - 6 - - - - - True - False - start - 8 - - - True - True - 10 - number - - - - False - False - 0 - - - - - True - False - Hz - - - False - True - 1 - - - - - 1 - 6 - - - - - True - False - start - - - True - True - 6 - number - - - - False - True - 0 - - - - - 20 - True - False - , - - - False - True - 1 - - - - - True - True - 6 - number - - - - False - True - 2 - - - - - 1 - 4 - - - - - True - False - start - - - True - True - 6 - number - - - - False - True - 0 - - - - - 20 - True - False - × - - - False - True - 1 - - - - - True - True - 6 - number - - - - False - True - 2 - - - - - True - True - True - Select Mode Preset - 8 - modes - - - True - False - view-more-symbolic - - - - - False - True - 3 - - - - - 1 - 5 - - True @@ -325,13 +177,68 @@ True False - _Transform + Si_ze + True + width + 1 + + + 0 + 5 + + + + + True + False + start + 8 + + + True + True + 9 + number + refresh_adjustment + 3 + True + if-valid + + + False + True + 0 + + + + + True + False + Hz + + + False + True + 1 + + + + + 1 + 6 + + + + + True + False + _Refresh Rate True 1 0 - 7 + 6 @@ -349,6 +256,19 @@ 7 + + + True + False + _Transform + True + 1 + + + 0 + 7 + + _Flipped @@ -366,28 +286,126 @@ - - - - - - - - False - mode_button - - + True False - 10 - 10 - 10 - 10 - vertical + 8 + + + True + True + 6 + 0 + number + pos_x_adjustment + True + if-valid + + + 0 + 0 + + + + + True + True + 6 + 0 + number + pos_y_adjustment + True + if-valid + + + 2 + 0 + + + + + True + True + 4 + 0 + number + width_adjustment + True + if-valid + + + 0 + 1 + + + + + 20 + True + False + × + + + 1 + 1 + + + + + True + True + 4 + 0 + number + height_adjustment + True + if-valid + + + 2 + 1 + + + + + True + True + True + Select Mode Preset + 8 + 8 + modes + + + True + False + view-more-symbolic + + + + + 3 + 1 + + + + + + + 1 + 4 + 2 + + + + + + + diff --git a/resources/resources.xml b/resources/resources.xml index 80556eb..185f865 100644 --- a/resources/resources.xml +++ b/resources/resources.xml @@ -1,7 +1,7 @@ - waydisplay.ui + wdisplay.ui head.ui style.css diff --git a/resources/style.css b/resources/style.css index 566ac6e..f250845 100644 --- a/resources/style.css +++ b/resources/style.css @@ -7,3 +7,13 @@ spinner { spinner.visible { opacity: 1; } + +.head { + border: 1px solid @borders; + border-radius: 1px; + background-color: @theme_bg_color; + transition: background-color 200ms ease-in-out; +} +.head:hover { + background-color: @theme_selected_bg_color; +} diff --git a/resources/waydisplay.ui b/resources/wdisplay.ui similarity index 60% rename from resources/waydisplay.ui rename to resources/wdisplay.ui index b6f32c4..c156ded 100644 --- a/resources/waydisplay.ui +++ b/resources/wdisplay.ui @@ -2,78 +2,180 @@ + + + False + + + True + False + 10 + 10 + 10 + 10 + vertical + + + True + True + True + app.auto-apply + _Automatically Apply Changes + + + False + True + 0 + + + + + False Waydisplay + True False - + True - True - 400 - True + False + vertical - - True - True - - - True - False - 400 - - - - - - True - False - - - - - True + False - vertical - - - True + True + start + error + True + False + + + False - center - 8 - 8 - 8 - True - heads_stack - - - False - True - 0 - - - - - True - False - crossfade + 6 + end False + False + 0 + + + + + False + 16 + + + True + False + True + 0 + + + True + True + 2 + + + + + True True - 1 + 0 + + + + + + + + False + True + 0 + + + + + True + True + 400 + True + + + True + True + + + True + False + 400 + + + + + + True + False + + + + + True + False + vertical + + + True + False + center + 8 + 8 + 8 + 8 + 8 + True + heads_stack + + + False + True + 0 + + + + + True + False + crossfade + + + + + + False + True + 1 + + + + + False + False - False - False + True + True + 1 @@ -94,59 +196,6 @@ True - - - False - True - start - error - True - False - - - - False - 6 - end - - - - - - False - False - 0 - - - - - False - 16 - - - True - False - True - 0 - - - True - True - 2 - - - - - True - True - 0 - - - - - 1 - - @@ -158,7 +207,7 @@ True False - Waydisplay + wdisplay False True @@ -230,6 +279,25 @@ + + + True + True + True + main_menu + + + True + False + open-menu-symbolic + + + + + end + 1 + + title diff --git a/src/main.c b/src/main.c index 1ac45da..c8b5db9 100644 --- a/src/main.c +++ b/src/main.c @@ -41,6 +41,7 @@ __attribute__((noreturn)) void wd_fatal_error(int status, const char *message) { static const char *MODE_PREFIX = "mode"; static const char *TRANSFORM_PREFIX = "transform"; +static const char *APP_PREFIX = "app"; #define NUM_ROTATIONS 4 static const char *ROTATE_IDS[NUM_ROTATIONS] = { @@ -66,25 +67,27 @@ static bool has_changes(const struct wd_state *state) { if (head->enabled != gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "enabled")))) { return TRUE; } - if (head->scale != gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(builder, "scale")))) { + double old_scale = round(head->scale * 100.) / 100.; + double new_scale = round(gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(builder, "scale"))) * 100.) / 100.; + if (old_scale != new_scale) { return TRUE; } - if (head->x != atoi(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(builder, "pos_x"))))) { + if (head->x != gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(builder, "pos_x")))) { return TRUE; } - if (head->y != atoi(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(builder, "pos_y"))))) { + if (head->y != gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(builder, "pos_y")))) { return TRUE; } int w = head->mode != NULL ? head->mode->width : head->custom_mode.width; - if (w != atoi(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(builder, "width"))))) { + if (w != gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(builder, "width")))) { return TRUE; } int h = head->mode != NULL ? head->mode->height : head->custom_mode.height; - if (h != atoi(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(builder, "height"))))) { + if (h != gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(builder, "height")))) { return TRUE; } int r = head->mode != NULL ? head->mode->refresh : head->custom_mode.refresh; - if (r / 1000. != atof(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(builder, "refresh"))))) { + if (r / 1000. != gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(builder, "refresh")))) { return TRUE; } for (int i = 0; i < NUM_ROTATIONS; i++) { @@ -109,10 +112,85 @@ static bool has_changes(const struct wd_state *state) { return FALSE; } +void fill_output_from_form(struct wd_head_config *output, GtkWidget *form) { + GtkBuilder *builder = GTK_BUILDER(g_object_get_data(G_OBJECT(form), "builder")); + output->head = g_object_get_data(G_OBJECT(form), "head"); + output->enabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "enabled"))); + output->scale = gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(builder, "scale"))); + output->x = gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(builder, "pos_x"))); + output->y = gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(builder, "pos_y"))); + output->width = gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(builder, "width"))); + output->height = gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(builder, "height"))); + output->refresh = gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(builder, "refresh"))) * 1000.; + gboolean flipped = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "flipped"))); + for (int i = 0; i < NUM_ROTATIONS; i++) { + GtkWidget *rotate = GTK_WIDGET(gtk_builder_get_object(builder, ROTATE_IDS[i])); + gboolean selected; + g_object_get(rotate, "active", &selected, NULL); + if (selected) { + switch (i) { + case 0: output->transform = flipped ? WL_OUTPUT_TRANSFORM_FLIPPED : WL_OUTPUT_TRANSFORM_NORMAL; break; + case 1: output->transform = flipped ? WL_OUTPUT_TRANSFORM_FLIPPED_90 : WL_OUTPUT_TRANSFORM_90; break; + case 2: output->transform = flipped ? WL_OUTPUT_TRANSFORM_FLIPPED_180 : WL_OUTPUT_TRANSFORM_180; break; + case 3: output->transform = flipped ? WL_OUTPUT_TRANSFORM_FLIPPED_270 : WL_OUTPUT_TRANSFORM_270; break; + } + break; + } + } +} + +static gboolean send_apply(gpointer data) { + struct wd_state *state = data; + struct wl_list *outputs = calloc(1, sizeof(*outputs)); + wl_list_init(outputs); + g_autoptr(GList) forms = gtk_container_get_children(GTK_CONTAINER(state->stack)); + for (GList *form_iter = forms; form_iter != NULL; form_iter = form_iter->next) { + struct wd_head_config *output = calloc(1, sizeof(*output)); + wl_list_insert(outputs, &output->link); + fill_output_from_form(output, GTK_WIDGET(form_iter->data)); + } + wd_apply_state(state, outputs); + state->apply_pending = false; + return FALSE; +} + +static void apply_state(struct wd_state *state) { + gtk_stack_set_visible_child_name(GTK_STACK(state->header_stack), "title"); + if (!state->autoapply) { + gtk_style_context_add_class(gtk_widget_get_style_context(state->spinner), "visible"); + gtk_overlay_set_overlay_pass_through(GTK_OVERLAY(state->overlay), state->spinner, FALSE); + + gtk_widget_set_sensitive(state->stack_switcher, FALSE); + gtk_widget_set_sensitive(state->stack, FALSE); + gtk_widget_set_sensitive(state->zoom_in, FALSE); + gtk_widget_set_sensitive(state->zoom_reset, FALSE); + gtk_widget_set_sensitive(state->zoom_out, FALSE); + gtk_widget_set_sensitive(state->menu_button, FALSE); + } + + /* queue this once per iteration in order to prevent duplicate updates */ + if (!state->apply_pending) { + state->apply_pending = true; + g_idle_add(send_apply, state); + } +} + +static gboolean apply_done_reset(gpointer data) { + wd_ui_reset_all(data); + return FALSE; +} + // BEGIN FORM CALLBACKS static void show_apply(struct wd_state *state) { - bool changed = has_changes(state); - gtk_stack_set_visible_child_name(GTK_STACK(state->header_stack), changed ? "apply" : "title"); + const gchar *page = "title"; + if (has_changes(state)) { + if (state->autoapply) { + apply_state(state); + } else { + page = "apply"; + } + } + gtk_stack_set_visible_child_name(GTK_STACK(state->header_stack), page); gtk_widget_queue_draw(state->canvas); } @@ -167,12 +245,9 @@ static void update_mode_entries(GtkWidget *form, int32_t w, int32_t h, int32_t r GtkWidget *height = GTK_WIDGET(gtk_builder_get_object(builder, "height")); GtkWidget *refresh = GTK_WIDGET(gtk_builder_get_object(builder, "refresh")); - g_autofree gchar *widthstr = g_strdup_printf("%d", w); - gtk_entry_set_text(GTK_ENTRY(width), widthstr); - g_autofree gchar *heightstr = g_strdup_printf("%d", h); - gtk_entry_set_text(GTK_ENTRY(height), heightstr); - g_autofree gchar *refreshstr = g_strdup_printf("%0.3f", r / 1000.0); - gtk_entry_set_text(GTK_ENTRY(refresh), refreshstr); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(width), w); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(height), h); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(refresh), r / 1000.); } static void mode_selected(GSimpleAction *action, GVariant *param, gpointer data) { @@ -203,6 +278,10 @@ static void update_canvas_size(struct wd_state *state) { w = head->mode->width; h = head->mode->height; } + if (head->scale > 0.) { + w /= head->scale; + h /= head->scale; + } int x2 = head->x + w; int y2 = head->y + h; @@ -255,10 +334,8 @@ static void update_head_form(GtkWidget *form, unsigned int fields) { gtk_spin_button_set_value(GTK_SPIN_BUTTON(scale), head->scale); } if (fields & WD_FIELD_POSITION) { - g_autofree gchar *xstr = g_strdup_printf("%d", head->x); - gtk_entry_set_text(GTK_ENTRY(pos_x), xstr); - g_autofree gchar *ystr = g_strdup_printf("%d", head->y); - gtk_entry_set_text(GTK_ENTRY(pos_y), ystr); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(pos_x), head->x); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(pos_y), head->y); } if (fields & WD_FIELD_MODE) { @@ -362,11 +439,11 @@ void wd_ui_reset_heads(struct wd_state *state) { g_signal_connect_swapped(gtk_builder_get_object(builder, "enabled"), "toggled", G_CALLBACK(update_sensitivity), form); g_signal_connect_swapped(gtk_builder_get_object(builder, "enabled"), "toggled", G_CALLBACK(show_apply), state); g_signal_connect_swapped(gtk_builder_get_object(builder, "scale"), "value-changed", G_CALLBACK(show_apply), state); - g_signal_connect_swapped(gtk_builder_get_object(builder, "pos_x"), "changed", G_CALLBACK(show_apply), state); - g_signal_connect_swapped(gtk_builder_get_object(builder, "pos_y"), "changed", G_CALLBACK(show_apply), state); - g_signal_connect_swapped(gtk_builder_get_object(builder, "width"), "changed", G_CALLBACK(show_apply), state); - g_signal_connect_swapped(gtk_builder_get_object(builder, "height"), "changed", G_CALLBACK(show_apply), state); - g_signal_connect_swapped(gtk_builder_get_object(builder, "refresh"), "changed", G_CALLBACK(show_apply), state); + g_signal_connect_swapped(gtk_builder_get_object(builder, "pos_x"), "value-changed", G_CALLBACK(show_apply), state); + g_signal_connect_swapped(gtk_builder_get_object(builder, "pos_y"), "value-changed", G_CALLBACK(show_apply), state); + g_signal_connect_swapped(gtk_builder_get_object(builder, "width"), "value-changed", G_CALLBACK(show_apply), state); + g_signal_connect_swapped(gtk_builder_get_object(builder, "height"), "value-changed", G_CALLBACK(show_apply), state); + g_signal_connect_swapped(gtk_builder_get_object(builder, "refresh"), "value-changed", G_CALLBACK(show_apply), state); g_signal_connect_swapped(gtk_builder_get_object(builder, "flipped"), "toggled", G_CALLBACK(show_apply), state); } else { @@ -418,7 +495,11 @@ void wd_ui_apply_done(struct wd_state *state, struct wl_list *outputs) { gtk_widget_set_sensitive(state->zoom_in, TRUE); gtk_widget_set_sensitive(state->zoom_reset, TRUE); gtk_widget_set_sensitive(state->zoom_out, TRUE); - show_apply(state); + gtk_widget_set_sensitive(state->menu_button, TRUE); + if (!state->autoapply) { + show_apply(state); + } + g_idle_add(apply_done_reset, state); } void wd_ui_show_error(struct wd_state *state, const char *message) { @@ -427,33 +508,6 @@ void wd_ui_show_error(struct wd_state *state, const char *message) { gtk_info_bar_set_revealed(GTK_INFO_BAR(state->info_bar), TRUE); } -void fill_output_from_form(struct wd_head_config *output, GtkWidget *form) { - GtkBuilder *builder = GTK_BUILDER(g_object_get_data(G_OBJECT(form), "builder")); - output->head = g_object_get_data(G_OBJECT(form), "head"); - output->enabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "enabled"))); - output->scale = gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(builder, "scale"))); - output->x = atoi(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(builder, "pos_x")))); - output->y = atoi(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(builder, "pos_y")))); - output->width = atoi(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(builder, "width")))); - output->height = atoi(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(builder, "height")))); - output->refresh = atof(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(builder, "refresh")))) * 1000.; - gboolean flipped = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "flipped"))); - for (int i = 0; i < NUM_ROTATIONS; i++) { - GtkWidget *rotate = GTK_WIDGET(gtk_builder_get_object(builder, ROTATE_IDS[i])); - gboolean selected; - g_object_get(rotate, "active", &selected, NULL); - if (selected) { - switch (i) { - case 0: output->transform = flipped ? WL_OUTPUT_TRANSFORM_FLIPPED : WL_OUTPUT_TRANSFORM_NORMAL; break; - case 1: output->transform = flipped ? WL_OUTPUT_TRANSFORM_FLIPPED_90 : WL_OUTPUT_TRANSFORM_90; break; - case 2: output->transform = flipped ? WL_OUTPUT_TRANSFORM_FLIPPED_180 : WL_OUTPUT_TRANSFORM_180; break; - case 3: output->transform = flipped ? WL_OUTPUT_TRANSFORM_FLIPPED_270 : WL_OUTPUT_TRANSFORM_270; break; - } - break; - } - } -} - // BEGIN GLOBAL CALLBACKS static void cleanup(GtkWidget *window, gpointer state) { g_free(state); @@ -482,15 +536,17 @@ gboolean draw(GtkWidget *widget, cairo_t *cr, gpointer data) { GtkBuilder *builder = GTK_BUILDER(g_object_get_data(G_OBJECT(form_iter->data), "builder")); gboolean enabled = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gtk_builder_get_object(builder, "enabled"))); if (enabled) { - int x = atoi(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(builder, "pos_x")))); - int y = atoi(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(builder, "pos_y")))); - int w = atoi(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(builder, "width")))); - int h = atoi(gtk_entry_get_text(GTK_ENTRY(gtk_builder_get_object(builder, "height")))); + int x = gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(builder, "pos_x"))); + int y = gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(builder, "pos_y"))); + int w = gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(builder, "width"))); + int h = gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(builder, "height"))); + double scale = gtk_spin_button_get_value(GTK_SPIN_BUTTON(gtk_builder_get_object(builder, "scale"))); + if (scale <= 0.) scale = 1.; cairo_rectangle(cr, x * state->zoom + .5 - scroll_x - state->xorigin, y * state->zoom + .5 - scroll_y - state->yorigin, - w * state->zoom, - h * state->zoom); + w * state->zoom / scale, + h * state->zoom / scale); cairo_stroke(cr); } } @@ -505,26 +561,7 @@ static void cancel_changes(GtkButton *button, gpointer data) { } static void apply_changes(GtkButton *button, gpointer data) { - struct wd_state *state = data; - gtk_stack_set_visible_child_name(GTK_STACK(state->header_stack), "title"); - gtk_style_context_add_class(gtk_widget_get_style_context(state->spinner), "visible"); - gtk_overlay_set_overlay_pass_through(GTK_OVERLAY(state->overlay), state->spinner, FALSE); - - gtk_widget_set_sensitive(state->stack_switcher, FALSE); - gtk_widget_set_sensitive(state->stack, FALSE); - gtk_widget_set_sensitive(state->zoom_in, FALSE); - gtk_widget_set_sensitive(state->zoom_reset, FALSE); - gtk_widget_set_sensitive(state->zoom_out, FALSE); - - struct wl_list *outputs = calloc(1, sizeof(*outputs)); - wl_list_init(outputs); - g_autoptr(GList) forms = gtk_container_get_children(GTK_CONTAINER(state->stack)); - for (GList *form_iter = forms; form_iter != NULL; form_iter = form_iter->next) { - struct wd_head_config *output = calloc(1, sizeof(*output)); - wl_list_insert(outputs, &output->link); - fill_output_from_form(output, GTK_WIDGET(form_iter->data)); - } - wd_apply_state(state, outputs); + apply_state(data); } static void update_zoom(struct wd_state *state) { @@ -567,6 +604,12 @@ static void info_bar_animation_done(GObject *object, GParamSpec *pspec, gpointer } } +static void auto_apply_selected(GSimpleAction *action, GVariant *param, gpointer data) { + struct wd_state *state = data; + state->autoapply = !state->autoapply; + g_simple_action_set_state(action, g_variant_new_boolean(state->autoapply)); +} + static void activate(GtkApplication* app, gpointer user_data) { GdkDisplay *gdk_display = gdk_display_get_default(); if (!GDK_IS_WAYLAND_DISPLAY(gdk_display)) { @@ -582,7 +625,7 @@ static void activate(GtkApplication* app, gpointer user_data) { gtk_style_context_add_provider_for_screen(gdk_screen_get_default(), GTK_STYLE_PROVIDER(css_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); - GtkBuilder *builder = gtk_builder_new_from_resource("/wd.ui"); + GtkBuilder *builder = gtk_builder_new_from_resource("/wdisplay.ui"); GtkWidget *window = GTK_WIDGET(gtk_builder_get_object(builder, "heads_window")); state->header_stack = GTK_WIDGET(gtk_builder_get_object(builder, "header_stack")); state->stack_switcher = GTK_WIDGET(gtk_builder_get_object(builder, "heads_stack_switcher")); @@ -596,6 +639,7 @@ static void activate(GtkApplication* app, gpointer user_data) { state->overlay = GTK_WIDGET(gtk_builder_get_object(builder, "overlay")); state->info_bar = GTK_WIDGET(gtk_builder_get_object(builder, "heads_info")); state->info_label = GTK_WIDGET(gtk_builder_get_object(builder, "heads_info_label")); + state->menu_button = GTK_WIDGET(gtk_builder_get_object(builder, "menu_button")); gtk_builder_add_callback_symbol(builder, "heads_draw", G_CALLBACK(draw)); gtk_builder_add_callback_symbol(builder, "apply_changes", G_CALLBACK(apply_changes)); gtk_builder_add_callback_symbol(builder, "cancel_changes", G_CALLBACK(cancel_changes)); @@ -603,10 +647,20 @@ static void activate(GtkApplication* app, gpointer user_data) { gtk_builder_add_callback_symbol(builder, "zoom_reset", G_CALLBACK(zoom_reset)); gtk_builder_add_callback_symbol(builder, "zoom_in", G_CALLBACK(zoom_in)); gtk_builder_add_callback_symbol(builder, "info_response", G_CALLBACK(info_response)); + gtk_builder_add_callback_symbol(builder, "destroy", G_CALLBACK(cleanup)); gtk_builder_connect_signals(builder, state); gtk_box_set_homogeneous(GTK_BOX(gtk_builder_get_object(builder, "zoom_box")), FALSE); update_zoom(state); + GSimpleActionGroup *main_actions = g_simple_action_group_new(); + gtk_widget_insert_action_group(state->menu_button, APP_PREFIX, G_ACTION_GROUP(main_actions)); + g_object_unref(main_actions); + + GSimpleAction *autoapply_action = g_simple_action_new_stateful("auto-apply", NULL, + g_variant_new_boolean(state->autoapply)); + g_signal_connect(autoapply_action, "activate", G_CALLBACK(auto_apply_selected), state); + g_action_map_add_action(G_ACTION_MAP(main_actions), G_ACTION(autoapply_action)); + /* first child of GtkInfoBar is always GtkRevealer */ g_autoptr(GList) info_children = gtk_container_get_children(GTK_CONTAINER(state->info_bar)); g_signal_connect(info_children->data, "notify::child-revealed", G_CALLBACK(info_bar_animation_done), state); @@ -620,7 +674,6 @@ static void activate(GtkApplication* app, gpointer user_data) { gtk_application_add_window(app, GTK_WINDOW(window)); gtk_widget_show_all(window); - g_signal_connect(window, "destroy", G_CALLBACK(cleanup), state); g_object_unref(builder); } // END GLOBAL CALLBACKS diff --git a/src/meson.build b/src/meson.build index 326fd5f..a70af58 100644 --- a/src/meson.build +++ b/src/meson.build @@ -17,5 +17,6 @@ executable( wayland_client, client_protos, gtk - ] + ], + install: true ) diff --git a/src/outputs.c b/src/outputs.c index cc78b90..363629d 100644 --- a/src/outputs.c +++ b/src/outputs.c @@ -65,7 +65,6 @@ static void config_handle_failed(void *data, struct zwlr_output_configuration_v1 *config) { struct wd_pending_config *pending = data; zwlr_output_configuration_v1_destroy(config); - wd_ui_reset_all(pending->state); wd_ui_apply_done(pending->state, NULL); wd_ui_show_error(pending->state, "The display server was not able to process your changes."); @@ -76,7 +75,6 @@ static void config_handle_cancelled(void *data, struct zwlr_output_configuration_v1 *config) { struct wd_pending_config *pending = data; zwlr_output_configuration_v1_destroy(config); - wd_ui_reset_all(pending->state); wd_ui_apply_done(pending->state, NULL); wd_ui_show_error(pending->state, "The display configuration was modified by the server before updates were processed. " diff --git a/src/wdisplay.h b/src/wdisplay.h index 303ac3d..a7ce955 100644 --- a/src/wdisplay.h +++ b/src/wdisplay.h @@ -103,6 +103,8 @@ struct wd_state { struct wl_list heads; uint32_t serial; + bool apply_pending; + bool autoapply; double zoom; int xorigin; int yorigin; @@ -119,6 +121,7 @@ struct wd_state { GtkWidget *overlay; GtkWidget *info_bar; GtkWidget *info_label; + GtkWidget *menu_button; }; /*