diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index b705fd4..aeec419 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -4,14 +4,17 @@ "name": "Linux", "includePath": [ "${workspaceFolder}/**", - "/usr/include/gtk-3.0", + "/usr/include/gtk-4.0", + "/usr/include/libadwaita-1", "/usr/include/glib-2.0", "/usr/lib/glib-2.0/include", "/usr/include/pango-1.0", "/usr/include/harfbuzz", "/usr/include/cairo", "/usr/include/gdk-pixbuf-2.0", - "/usr/include/atk-1.0" + "/usr/include/atk-1.0", + "/usr/include/graphene-1.0", + "/usr/lib/graphene-1.0/include/" ], "defines": [], "compilerPath": "/usr/bin/gcc", @@ -21,4 +24,4 @@ } ], "version": 4 -} \ No newline at end of file +} diff --git a/build-debug.sh b/build-debug.sh index af55fd3..cddc28c 100755 --- a/build-debug.sh +++ b/build-debug.sh @@ -1,2 +1,2 @@ #!/bin/bash -gcc -g -pthread `pkg-config --cflags gtk+-3.0` -o build/app.debug src/main.c `pkg-config --libs gtk+-3.0` -l ddcutil +gcc -g -pthread `pkg-config --cflags gtk4 libadwaita-1` -o build/app.debug src/main.c `pkg-config --libs gtk4 libadwaita-1` -l ddcutil diff --git a/build.sh b/build.sh index 5bdafbe..d65aac8 100755 --- a/build.sh +++ b/build.sh @@ -1,2 +1,2 @@ #!/bin/bash -gcc -pthread `pkg-config --cflags gtk+-3.0` -o build/app src/main.c `pkg-config --libs gtk+-3.0` -l ddcutil +gcc -pthread `pkg-config --cflags gtk4 libadwaita-1` -o build/app src/main.c `pkg-config --libs gtk4 libadwaita-1` -l ddcutil diff --git a/debian/control b/debian/control index 3afb908..86e466d 100644 --- a/debian/control +++ b/debian/control @@ -1,8 +1,8 @@ Package: luminance -Version: 1.0.3 +Version: 1.1.0 Architecture: amd64 Maintainer: Swapnil Devesh Homepage: https://github.com/sidevesh/Luminance Description: A simple GTK application to control brightness of displays including external displays supporting DDC/CI License: GPL-3.0 -Depends: libgtk-3-0, ddcutil, libddcutil4 +Depends: libgtk-4-1, libadwaita-1-0, ddcutil, libddcutil4 diff --git a/info.c b/info.c index 47b63d1..73b417b 100644 --- a/info.c +++ b/info.c @@ -1,4 +1,4 @@ -#define APP_INFO_VERSION_NUMBER "1.0.3" +#define APP_INFO_VERSION_NUMBER "1.1.0" #define APP_INFO_PACKAGE_NAME "com.sidevesh.Luminance" #define APP_INFO_DISPLAY_NAME "Luminance" #define APP_INFO_ICON_NAME "com.sidevesh.Luminance" diff --git a/rpm/com.sidevesh.Luminance.spec b/rpm/com.sidevesh.Luminance.spec index 5b03861..7f95bc2 100644 --- a/rpm/com.sidevesh.Luminance.spec +++ b/rpm/com.sidevesh.Luminance.spec @@ -1,5 +1,5 @@ Name: com.sidevesh.Luminance -Version: 1.0.3 +Version: 1.1.0 Release: 1%{?dist} Summary: A simple GTK application to control brightness of displays including external displays supporting DDC/CI @@ -9,9 +9,10 @@ BuildArch: x86_64 # Define the BuildRequires and Requires packages BuildRequires: pkgconfig(glib-2.0) -BuildRequires: pkgconfig(gtk+-3.0) +BuildRequires: pkgconfig(gtk4) -Requires: gtk3 +Requires: gtk4 +Requires: libadwaita Requires: ddcutil %description diff --git a/src/main.c b/src/main.c index 0309336..b182886 100644 --- a/src/main.c +++ b/src/main.c @@ -3,7 +3,7 @@ #include #include #include - +#include #include "./constants/main.c" #include "./osd/main.c" #include "./states/displays.c" @@ -40,7 +40,7 @@ void update_window_contents_in_ui() { } static void activate_gtk_ui(GtkApplication *app) { - initialize_application_window(app); + initialize_application_window(GTK_APPLICATION(app)); update_window_contents_in_ui(); load_displays(update_window_contents_in_ui, update_window_contents_in_ui); } @@ -54,7 +54,6 @@ int ensure_displays_are_present_in_cli() { } } -// Function to list all displays and their brightness int list_displays_in_cli() { for (guint index = 0; index < displays_count(); index++) { gchar *label = get_display_name(index); @@ -65,7 +64,6 @@ int list_displays_in_cli() { return 0; } -// Function to get the brightness percentage of a specified display int get_display_brightness_in_cli(guint display_number) { for (guint index = 0; index < displays_count(); index++) { if ((index + 1) == display_number) { @@ -90,14 +88,13 @@ void set_brightness_percentage_in_cli(guint display_index, double brightness_per fprintf(stderr, "Invalid display number: %d\n", display_index + 1); } -// Function to set the brightness of a specified display int set_display_brightness_if_needed_in_cli(guint display_number, guint brightness_percentage, gchar option, gchar show_osd) { - load_displays(NULL, NULL); - ensure_displays_are_present_in_cli(); - gdouble linked_all_displays_brightness_percentage = -1; gdouble non_linked_all_displays_brightness_percentages_average = -1; + load_displays(NULL, NULL); + ensure_displays_are_present_in_cli(); + for (guint index = 0; index < displays_count(); index++) { if (display_number == 0 || (index + 1) == display_number) { gdouble current_brightness_percentage = get_display_brightness_percentage(index); @@ -158,7 +155,6 @@ int set_display_brightness_if_needed_in_cli(guint display_number, guint brightne return 0; } -// Function to display command-line arguments and help information int display_help_in_cli() { printf("Usage: %s [OPTIONS]\n", APP_INFO_PACKAGE_NAME); printf("An application to control brightness of displays including external displays supporting DDC/CI\n"); @@ -180,7 +176,6 @@ int display_help_in_cli() { return 0; } -// CLI argument parsing int parse_cli_arguments(int argc, char **argv) { struct option long_options[] = { {"list-displays", no_argument, NULL, 'l'}, @@ -303,11 +298,9 @@ int parse_cli_arguments(int argc, char **argv) { if (status == 0 && show_osd != 0) { show_osd_after_brightness_change(show_osd); } - return status; } -// Entry point of the program int main(int argc, char **argv) { // Check if the lock file exists if (g_file_test(LOCK_FILE_PATH, G_FILE_TEST_EXISTS)) { @@ -336,8 +329,9 @@ int main(int argc, char **argv) { #else flags = G_APPLICATION_FLAGS_NONE; #endif - GtkApplication *app; - app = gtk_application_new(APP_INFO_PACKAGE_NAME, flags); + + AdwApplication *app; + app = adw_application_new(APP_INFO_PACKAGE_NAME, flags); g_signal_connect(app, "activate", G_CALLBACK(activate_gtk_ui), NULL); status = g_application_run(G_APPLICATION(app), argc, argv); g_object_unref(app); diff --git a/src/ui/components/display_brightness_scale.c b/src/ui/components/display_brightness_scale.c index 71b988d..818e35c 100644 --- a/src/ui/components/display_brightness_scale.c +++ b/src/ui/components/display_brightness_scale.c @@ -1,16 +1,23 @@ #include #include "../constants/main.c" + +static char* format_brightness_value(GtkScale *scale, gdouble value, gpointer data) { + return g_strdup_printf(" %d%%", (int)value); +} + GtkWidget* get_display_brightness_scale(gdouble last_value, gdouble max_value) { GtkWidget *scale = gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL, 0, max_value, 1); - gtk_range_set_value(GTK_RANGE(scale), last_value); + + gtk_scale_set_draw_value(GTK_SCALE(scale), TRUE); gtk_scale_set_value_pos(GTK_SCALE(scale), GTK_POS_RIGHT); + gtk_scale_set_format_value_func(GTK_SCALE(scale), format_brightness_value, NULL, NULL); + gtk_widget_set_halign(scale, GTK_ALIGN_FILL); gtk_widget_set_hexpand(scale, TRUE); - gtk_widget_set_valign(scale, GTK_ALIGN_START); - gtk_widget_set_halign(scale, 0.0); gtk_widget_set_margin_start(scale, MARGIN_UNIT / 4); gtk_widget_set_margin_end(scale, MARGIN_UNIT / 2); gtk_widget_set_margin_bottom(scale, MARGIN_UNIT); + gtk_range_set_value(GTK_RANGE(scale), last_value); return scale; } diff --git a/src/ui/components/display_icon.c b/src/ui/components/display_icon.c index 30962e9..ab74f7a 100644 --- a/src/ui/components/display_icon.c +++ b/src/ui/components/display_icon.c @@ -2,9 +2,10 @@ #include "../constants/main.c" GtkWidget* get_display_icon() { - GtkWidget *icon = gtk_image_new_from_icon_name("video-display-symbolic", GTK_ICON_SIZE_DIALOG); - gtk_widget_set_valign(icon, GTK_ALIGN_CENTER); - gtk_widget_set_margin_start(icon, MARGIN_UNIT); + GtkWidget *icon = gtk_image_new_from_icon_name("video-display-symbolic"); - return icon; + gtk_image_set_pixel_size(GTK_IMAGE(icon), 56); + gtk_widget_set_margin_start(icon, MARGIN_UNIT); + + return icon; } diff --git a/src/ui/components/display_label.c b/src/ui/components/display_label.c index c4d6178..f852ac0 100644 --- a/src/ui/components/display_label.c +++ b/src/ui/components/display_label.c @@ -3,10 +3,9 @@ GtkWidget* get_display_label(gchar *text) { GtkWidget *label = gtk_label_new(text); + gtk_label_set_xalign(GTK_LABEL(label), 0.0); gtk_widget_set_hexpand(label, FALSE); - gtk_widget_set_valign(label, GTK_ALIGN_START); - gtk_widget_set_halign(label, 0.0); gtk_widget_set_margin_start(label, MARGIN_UNIT); gtk_widget_set_margin_end(label, MARGIN_UNIT); gtk_widget_set_margin_top(label, MARGIN_UNIT); diff --git a/src/ui/components/link_brightness_check_button.c b/src/ui/components/link_brightness_check_button.c index 48e46c9..ddb2fcd 100644 --- a/src/ui/components/link_brightness_check_button.c +++ b/src/ui/components/link_brightness_check_button.c @@ -3,11 +3,13 @@ GtkWidget* get_link_brightness_checkbox(gboolean initial_value) { GtkWidget *link_brightness_checkbox = gtk_check_button_new_with_label("Sync brightness of all displays"); + gtk_check_button_set_active(GTK_CHECK_BUTTON(link_brightness_checkbox), initial_value); + gtk_widget_set_margin_start(link_brightness_checkbox, MARGIN_UNIT); gtk_widget_set_margin_end(link_brightness_checkbox, MARGIN_UNIT); gtk_widget_set_margin_top(link_brightness_checkbox, MARGIN_UNIT); gtk_widget_set_margin_bottom(link_brightness_checkbox, MARGIN_UNIT); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(link_brightness_checkbox), initial_value); + gtk_widget_set_halign(link_brightness_checkbox, GTK_ALIGN_END); return link_brightness_checkbox; } diff --git a/src/ui/components/separator.c b/src/ui/components/separator.c index f3b4587..8b54c49 100644 --- a/src/ui/components/separator.c +++ b/src/ui/components/separator.c @@ -3,7 +3,8 @@ GtkWidget* get_separator() { GtkWidget *separator = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL); - gtk_widget_set_halign(separator, 0); + + gtk_widget_set_halign(separator, GTK_ALIGN_FILL); gtk_widget_set_margin_start(separator, 0); return separator; diff --git a/src/ui/screens/no_displays.c b/src/ui/screens/no_displays.c index 7d5620c..a275a3c 100644 --- a/src/ui/screens/no_displays.c +++ b/src/ui/screens/no_displays.c @@ -10,51 +10,38 @@ void _on_no_displays_screen_refresh_button_clicked(GtkWidget *widget, gpointer d GtkWidget* get_no_displays_screen() { GtkWidget *box, *image, *title, *subtitle, *button; - GtkStyleContext *image_style_context, *button_style_context; GtkCssProvider *button_css_provider; box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10); - gtk_box_set_spacing(GTK_BOX(box), 0); - gtk_box_set_homogeneous(GTK_BOX(box), FALSE); - gtk_widget_set_halign(box, GTK_ALIGN_CENTER); - gtk_widget_set_valign(box, GTK_ALIGN_CENTER); gtk_widget_set_margin_top(box, MARGIN_UNIT * 2.4); gtk_widget_set_margin_start(box, MARGIN_UNIT); gtk_widget_set_margin_end(box, MARGIN_UNIT); gtk_widget_set_margin_bottom(box, MARGIN_UNIT); - image = gtk_image_new_from_icon_name("video-display-symbolic", GTK_ICON_SIZE_DIALOG); - image_style_context = gtk_widget_get_style_context(image); - gtk_style_context_add_class(image_style_context, "dim-label"); + image = gtk_image_new_from_icon_name("video-display-symbolic"); + gtk_widget_add_css_class(image, "dim-label"); gtk_image_set_pixel_size(GTK_IMAGE(image), 128); - gtk_widget_set_halign(image, GTK_ALIGN_CENTER); - gtk_widget_set_valign(image, GTK_ALIGN_CENTER); + gtk_widget_set_size_request(image, 128, 128); gtk_widget_set_margin_bottom(image, MARGIN_UNIT * 2); - gtk_box_pack_start(GTK_BOX(box), image, FALSE, FALSE, 0); + gtk_box_append(GTK_BOX(box), image); title = gtk_label_new(NULL); - gtk_label_set_markup (GTK_LABEL(title), "No compatible displays found"); - gtk_widget_set_halign(title, GTK_ALIGN_CENTER); - gtk_widget_set_valign(title, GTK_ALIGN_CENTER); - gtk_box_pack_start(GTK_BOX(box), title, FALSE, FALSE, 5); + gtk_label_set_markup(GTK_LABEL(title), "No compatible displays found"); + gtk_box_append(GTK_BOX(box), title); subtitle = gtk_label_new("Try refreshing if you have just connected the displays"); - gtk_widget_set_halign(subtitle, GTK_ALIGN_CENTER); - gtk_widget_set_valign(subtitle, GTK_ALIGN_CENTER); gtk_widget_set_margin_bottom(subtitle, MARGIN_UNIT); - gtk_box_pack_start(GTK_BOX(box), subtitle, FALSE, FALSE, 5); + gtk_box_append(GTK_BOX(box), subtitle); button = gtk_button_new_with_label("Refresh"); - button_style_context = gtk_widget_get_style_context(button); - gtk_style_context_add_class(button_style_context, "circular"); + gtk_widget_add_css_class(button, "circular"); button_css_provider = gtk_css_provider_new(); - gtk_css_provider_load_from_data(button_css_provider, "button {padding: 10px;}", -1, NULL); - gtk_style_context_add_provider(button_style_context, GTK_STYLE_PROVIDER(button_css_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + gtk_css_provider_load_from_string(button_css_provider, "button {padding-left: 12px;padding-right: 12px;padding-top: 4px;padding-bottom: 4px;}"); + gtk_style_context_add_provider(gtk_widget_get_style_context(button), GTK_STYLE_PROVIDER(button_css_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); gtk_widget_set_halign(button, GTK_ALIGN_CENTER); gtk_widget_set_valign(button, GTK_ALIGN_CENTER); - gtk_box_pack_start(GTK_BOX(box), button, FALSE, FALSE, 5); - - g_signal_connect(button, "clicked", G_CALLBACK(_on_no_displays_screen_refresh_button_clicked), NULL); + g_signal_connect(button, "clicked", G_CALLBACK(_on_no_displays_screen_refresh_button_clicked), NULL); + gtk_box_append(GTK_BOX(box), button); return box; } diff --git a/src/ui/screens/refreshing_displays.c b/src/ui/screens/refreshing_displays.c index fc9b33c..7b15a0b 100644 --- a/src/ui/screens/refreshing_displays.c +++ b/src/ui/screens/refreshing_displays.c @@ -3,7 +3,6 @@ GtkWidget* get_refreshing_displays_screen() { GtkWidget *box, *image, *title, *spinner; - GtkStyleContext *image_style_context; box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10); gtk_box_set_spacing(GTK_BOX(box), 0); @@ -15,29 +14,21 @@ GtkWidget* get_refreshing_displays_screen() { gtk_widget_set_margin_end(box, MARGIN_UNIT); gtk_widget_set_margin_bottom(box, MARGIN_UNIT); - image = gtk_image_new_from_icon_name("system-search-symbolic", GTK_ICON_SIZE_DIALOG); - - image_style_context = gtk_widget_get_style_context(image); - gtk_style_context_add_class(image_style_context, "dim-label"); + image = gtk_image_new_from_icon_name("system-search-symbolic"); + gtk_widget_add_css_class(image, "dim-label"); gtk_image_set_pixel_size(GTK_IMAGE(image), 128); - gtk_widget_set_halign(image, GTK_ALIGN_CENTER); - gtk_widget_set_valign(image, GTK_ALIGN_CENTER); gtk_widget_set_margin_bottom(image, MARGIN_UNIT * 2); - gtk_box_pack_start(GTK_BOX(box), image, FALSE, FALSE, 0); + gtk_box_append(GTK_BOX(box), image); title = gtk_label_new(NULL); gtk_label_set_markup (GTK_LABEL(title), "Refreshing displays..."); - gtk_widget_set_halign(title, GTK_ALIGN_CENTER); - gtk_widget_set_valign(title, GTK_ALIGN_CENTER); gtk_widget_set_margin_bottom(title, MARGIN_UNIT); - gtk_box_pack_start(GTK_BOX(box), title, FALSE, FALSE, 5); + gtk_box_append(GTK_BOX(box), title); spinner = gtk_spinner_new(); gtk_widget_set_size_request(spinner, 32, 32); - gtk_widget_set_halign(spinner, GTK_ALIGN_CENTER); - gtk_widget_set_valign(spinner, GTK_ALIGN_CENTER); gtk_widget_set_margin_bottom(spinner, MARGIN_UNIT * 2.7); - gtk_box_pack_start(GTK_BOX(box), spinner, FALSE, FALSE, 5); + gtk_box_append(GTK_BOX(box), spinner); gtk_spinner_start(GTK_SPINNER(spinner)); return box; diff --git a/src/ui/screens/show_displays.c b/src/ui/screens/show_displays.c index 9fad70d..db80482 100644 --- a/src/ui/screens/show_displays.c +++ b/src/ui/screens/show_displays.c @@ -1,5 +1,4 @@ #include - #include "../../states/displays.c" typedef struct display_section { @@ -14,49 +13,36 @@ typedef struct display_section { display_section **_display_sections; guint _display_sections_count = 0; -gboolean _set_brightness(GtkWidget *widget, GdkEvent *event, guint data) { +void _update_display_brightness(GtkRange *range, guint data) { guint index_of_display_section = GPOINTER_TO_UINT(data); + guint new_value = gtk_range_get_value(range); - display_section *display_section = _display_sections[index_of_display_section]; - - guint16 new_brightness_percentage = gtk_range_get_value(GTK_RANGE(widget)); - set_display_brightness_percentage(display_section->display_index, new_brightness_percentage); + // Clamp the new value between 0 and 100 + new_value = CLAMP(new_value, 0.0, 100.0); + guint16 new_brightness_percentage = (guint16)new_value; + set_display_brightness_percentage(index_of_display_section, new_brightness_percentage); if (get_is_brightness_linked()) { for (guint index = 0; index < _display_sections_count; index++) { - GtkWidget *scale = _display_sections[index]->scale; - - if (_display_sections[index]->display_index == display_section->display_index) { - continue; + if (_display_sections[index]->display_index == index_of_display_section) { + continue; // Skip the current display } - gtk_range_set_value(GTK_RANGE(scale), new_brightness_percentage); + GtkRange *linked_range = GTK_RANGE(_display_sections[index]->scale); + gtk_range_set_value(linked_range, new_value); set_display_brightness_percentage(_display_sections[index]->display_index, new_brightness_percentage); } } - - return FALSE; } -void _update_display_brightness_scales(GtkRange *range, guint data) { - guint index_of_display_section = GPOINTER_TO_UINT(data); - - guint new_value = gtk_range_get_value(range); - for (guint index = 0; index < _display_sections_count; index++) { - if (get_is_brightness_linked() || index == index_of_display_section) { - gtk_range_set_value(GTK_RANGE(_display_sections[index]->scale), new_value); - } - } -} +void _link_brightness(GtkCheckButton *link_brightness_checkbox) { + gboolean is_brightness_linked = gtk_check_button_get_active(link_brightness_checkbox); + gdouble max_scale_percentage = 0; -void _link_brightness(GtkToggleButton *link_brightness_checkbox) { - gboolean is_brightness_linked = gtk_toggle_button_get_active(link_brightness_checkbox); set_is_brightness_linked(is_brightness_linked); - if (!is_brightness_linked) { return; } - gdouble max_scale_percentage = 0; for (guint index = 0; index < _display_sections_count; index++) { guint percentage_value = gtk_range_get_value(GTK_RANGE(_display_sections[index]->scale)); max_scale_percentage = percentage_value > max_scale_percentage ? percentage_value : max_scale_percentage; @@ -70,23 +56,20 @@ void _link_brightness(GtkToggleButton *link_brightness_checkbox) { GtkWidget* get_show_displays_screen() { GtkWidget *grid, *link_brightness_checkbox; + display_section **sections = malloc(displays_count()); + display_section *sibling = NULL; grid = gtk_grid_new(); - - display_section **sections = malloc(displays_count()); _display_sections = sections; _display_sections_count = displays_count(); - display_section *sibling = NULL; - for (guint index = 0; index < displays_count(); index++) { display_section *display_section_instance = malloc(sizeof(display_section)); display_section_instance->display_index = index; display_section_instance->label = get_display_label(get_display_name(index)); display_section_instance->scale = get_display_brightness_scale(get_display_brightness_percentage(index), 100.0); - g_signal_connect(display_section_instance->scale, "button-release-event", G_CALLBACK(_set_brightness), GUINT_TO_POINTER(index)); - g_signal_connect(display_section_instance->scale, "scroll-event", G_CALLBACK(_set_brightness), GUINT_TO_POINTER(index)); - g_signal_connect(display_section_instance->scale, "value-changed", G_CALLBACK(_update_display_brightness_scales), GUINT_TO_POINTER(index)); + g_signal_connect(display_section_instance->scale, "value-changed", G_CALLBACK(_update_display_brightness), GUINT_TO_POINTER(index)); + display_section_instance->separator_left_column = get_separator(); display_section_instance->separator_right_column = get_separator(); display_section_instance->icon = get_display_icon(); @@ -105,8 +88,8 @@ GtkWidget* get_show_displays_screen() { } link_brightness_checkbox = get_link_brightness_checkbox(get_is_brightness_linked()); - g_signal_connect(link_brightness_checkbox, "toggled", G_CALLBACK(_link_brightness), NULL); gtk_grid_attach_next_to(GTK_GRID(grid), link_brightness_checkbox, sibling->separator_right_column, GTK_POS_BOTTOM, 1, 1); + g_signal_connect(link_brightness_checkbox, "toggled", G_CALLBACK(_link_brightness), NULL); return grid; } diff --git a/src/ui/window.c b/src/ui/window.c index 1d58bce..1a258ed 100644 --- a/src/ui/window.c +++ b/src/ui/window.c @@ -1,17 +1,15 @@ #include - +#include #include "../constants/main.c" #include "./constants/main.c" - #include "../states/displays.c" #include "../states/laptop_lid.c" #include "../states/should_hide_internal_if_lid_closed.c" GtkWidget *_window; GtkWidget *_window_header; - +GtkWidget *_menu_popover; GtkWidget* _last_window_content_screen = NULL; - GtkWidget *_refresh_displays_button = NULL; extern GtkApplication *app; @@ -22,76 +20,64 @@ void _on_window_refresh_button_clicked(GtkWidget *widget, gpointer data) { reload_displays(update_window_contents_in_ui, update_window_contents_in_ui); } -void _on_should_hide_internal_if_lid_closed_checkbox_toggled(GtkToggleButton *widget, gpointer data) { - gboolean should_hide_internal_if_lid_closed = gtk_toggle_button_get_active(widget); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), should_hide_internal_if_lid_closed); +void _on_should_hide_internal_if_lid_closed_checkbox_toggled(GtkCheckButton *widget, gpointer data) { + gboolean should_hide_internal_if_lid_closed = gtk_check_button_get_active(widget); + gtk_check_button_set_active(GTK_CHECK_BUTTON(widget), should_hide_internal_if_lid_closed); set_should_hide_internal_if_lid_closed(should_hide_internal_if_lid_closed); } -void _open_about_dialog() { - GtkWidget *about_dialog = gtk_about_dialog_new(); - gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about_dialog), APP_INFO_DISPLAY_NAME); - gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about_dialog), APP_INFO_VERSION_NUMBER); - gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about_dialog), APP_INFO_DESCRIPTION); - gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(about_dialog), APP_INFO_SOURCE_REPOSITORY_TITLE); - gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(about_dialog), APP_INFO_SOURCE_REPOSITORY_LINK); - gtk_about_dialog_set_license_type(GTK_ABOUT_DIALOG(about_dialog), APP_INFO_LICENSE); - gtk_about_dialog_set_logo_icon_name(GTK_ABOUT_DIALOG(about_dialog), APP_INFO_ICON_NAME); - gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(about_dialog), (const gchar *[]){ - APP_INFO_PROJECT_AUTHORS, - NULL - }); - gtk_about_dialog_set_artists(GTK_ABOUT_DIALOG(about_dialog), (const gchar *[]){ - APP_INFO_PROJECT_ARTISTS, - NULL - }); - gtk_dialog_run(GTK_DIALOG(about_dialog)); - gtk_widget_destroy(about_dialog); +void _open_about_dialog_and_close_popover() { + AdwDialog *about_dialog = adw_about_dialog_new(); + + gtk_popover_popdown(GTK_POPOVER(_menu_popover)); + adw_about_dialog_set_application_name(ADW_ABOUT_DIALOG(about_dialog), APP_INFO_DISPLAY_NAME); + adw_about_dialog_set_version(ADW_ABOUT_DIALOG(about_dialog), APP_INFO_VERSION_NUMBER); + adw_about_dialog_set_comments(ADW_ABOUT_DIALOG(about_dialog), APP_INFO_DESCRIPTION); + adw_about_dialog_set_website(ADW_ABOUT_DIALOG(about_dialog), APP_INFO_SOURCE_REPOSITORY_TITLE); + adw_about_dialog_set_issue_url(ADW_ABOUT_DIALOG(about_dialog), APP_INFO_SOURCE_REPOSITORY_LINK); + adw_about_dialog_set_license_type(ADW_ABOUT_DIALOG(about_dialog), APP_INFO_LICENSE); + adw_about_dialog_set_application_icon(ADW_ABOUT_DIALOG(about_dialog), APP_INFO_ICON_NAME); + const char *developers[] = { APP_INFO_PROJECT_AUTHORS, NULL }; + adw_about_dialog_set_developers(ADW_ABOUT_DIALOG(about_dialog), developers); + const char *artists[] = { APP_INFO_PROJECT_ARTISTS, NULL }; + adw_about_dialog_set_artists(ADW_ABOUT_DIALOG(about_dialog), artists); + adw_dialog_present(ADW_DIALOG(about_dialog), _window); } void initialize_application_window(GtkApplication *app) { _window = gtk_application_window_new(app); gtk_window_set_resizable(GTK_WINDOW(_window), FALSE); - gtk_window_set_geometry_hints(GTK_WINDOW(_window), NULL, &(GdkGeometry){.min_width = MINIMUM_WINDOW_WIDTH}, GDK_HINT_MIN_SIZE); - gtk_window_set_keep_above(GTK_WINDOW(_window), TRUE); + gtk_widget_set_size_request(_window, MINIMUM_WINDOW_WIDTH, -1); - _window_header = gtk_header_bar_new(); - gtk_header_bar_set_show_close_button(GTK_HEADER_BAR(_window_header), TRUE); + _window_header = gtk_header_bar_new(); + gtk_header_bar_set_show_title_buttons(GTK_HEADER_BAR(_window_header), TRUE); + gtk_header_bar_set_title_widget(GTK_HEADER_BAR(_window_header), gtk_label_new("")); - GtkWidget *menu_button = gtk_menu_button_new(); - GtkWidget *menu_image = gtk_image_new_from_icon_name("open-menu-symbolic", GTK_ICON_SIZE_BUTTON); - gtk_button_set_image(GTK_BUTTON(menu_button), menu_image); - - GtkWidget *menu_popover = gtk_popover_new(menu_button); + _menu_popover = gtk_popover_new(); GtkWidget *menu_box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); - GtkCssProvider *menu_box_css_provider = gtk_css_provider_new(); - gtk_css_provider_load_from_data(menu_box_css_provider, "box {padding: 5px;}", -1, NULL); - gtk_style_context_add_provider(gtk_widget_get_style_context(menu_box), GTK_STYLE_PROVIDER(menu_box_css_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); - - GtkCssProvider *menu_button_css_provider = gtk_css_provider_new(); - gtk_css_provider_load_from_data(menu_button_css_provider, "button.flat {min-width: 150px;font-weight: normal;}", -1, NULL); - gtk_style_context_add_provider(gtk_widget_get_style_context(menu_box), GTK_STYLE_PROVIDER(menu_button_css_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + GtkWidget *menu_button = gtk_menu_button_new(); + gtk_menu_button_set_icon_name(GTK_MENU_BUTTON(menu_button), "open-menu-symbolic"); if (get_has_lid()) { GtkWidget *should_hide_internal_if_lid_closed_checkbox = gtk_check_button_new_with_label("Hide built-in displays when lid is closed"); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(should_hide_internal_if_lid_closed_checkbox), get_should_hide_internal_if_lid_closed()); + gtk_check_button_set_active(GTK_CHECK_BUTTON(should_hide_internal_if_lid_closed_checkbox), get_should_hide_internal_if_lid_closed()); GtkStyleContext *should_hide_internal_if_lid_closed_checkbox_style_context = gtk_widget_get_style_context(should_hide_internal_if_lid_closed_checkbox); - gtk_style_context_add_class(should_hide_internal_if_lid_closed_checkbox_style_context, "flat"); - gtk_style_context_add_provider(gtk_widget_get_style_context(should_hide_internal_if_lid_closed_checkbox), GTK_STYLE_PROVIDER(menu_button_css_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); - GtkCssProvider *should_hide_internal_if_lid_closed_checkbox_css_provider = gtk_css_provider_new(); - gtk_css_provider_load_from_data(should_hide_internal_if_lid_closed_checkbox_css_provider, "checkbutton.flat {padding: 5px;}", -1, NULL); - gtk_style_context_add_provider(gtk_widget_get_style_context(should_hide_internal_if_lid_closed_checkbox), GTK_STYLE_PROVIDER(should_hide_internal_if_lid_closed_checkbox_css_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + gtk_css_provider_load_from_string(should_hide_internal_if_lid_closed_checkbox_css_provider, g_strdup_printf("checkbutton.flat {padding: 4px;margin-top: 4px;margin-bottom: 8px;}")); + gtk_style_context_add_provider(should_hide_internal_if_lid_closed_checkbox_style_context, GTK_STYLE_PROVIDER(should_hide_internal_if_lid_closed_checkbox_css_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + gtk_style_context_add_class(should_hide_internal_if_lid_closed_checkbox_style_context, "flat"); - GtkWidget *should_hide_internal_if_lid_closed_checkbox_label = gtk_bin_get_child(GTK_BIN(should_hide_internal_if_lid_closed_checkbox)); - gtk_label_set_xalign(GTK_LABEL(should_hide_internal_if_lid_closed_checkbox_label), 0.0); + gtk_box_append(GTK_BOX(menu_box), should_hide_internal_if_lid_closed_checkbox); g_signal_connect(should_hide_internal_if_lid_closed_checkbox, "toggled", G_CALLBACK(_on_should_hide_internal_if_lid_closed_checkbox_toggled), NULL); - gtk_box_pack_start(GTK_BOX(menu_box), should_hide_internal_if_lid_closed_checkbox, FALSE, FALSE, 0); GtkWidget *separator = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL); - gtk_box_pack_start(GTK_BOX(menu_box), separator, FALSE, FALSE, 0); + GtkStyleContext *separator_style_context = gtk_widget_get_style_context(separator); + GtkCssProvider *separator_css_provider = gtk_css_provider_new(); + gtk_css_provider_load_from_string(separator_css_provider, "separator {margin-bottom: 8px;}"); + gtk_style_context_add_provider(separator_style_context, GTK_STYLE_PROVIDER(separator_css_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); + gtk_box_append(GTK_BOX(menu_box), separator); } gchar about_button_label_text[100]; @@ -99,58 +85,54 @@ void initialize_application_window(GtkApplication *app) { GtkWidget *about_button = gtk_button_new_with_label(about_button_label_text); GtkStyleContext *about_button_style_context = gtk_widget_get_style_context(about_button); + GtkCssProvider *about_button_css_provider = gtk_css_provider_new(); + gtk_css_provider_load_from_string(about_button_css_provider, "button.flat {font-weight: normal;}"); + gtk_style_context_add_provider(about_button_style_context, GTK_STYLE_PROVIDER(about_button_css_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); gtk_style_context_add_class(about_button_style_context, "flat"); - gtk_style_context_add_provider(gtk_widget_get_style_context(about_button), GTK_STYLE_PROVIDER(menu_button_css_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); - GtkWidget *about_button_label = gtk_bin_get_child(GTK_BIN(about_button)); - gtk_label_set_xalign(GTK_LABEL(about_button_label), 0.0); - g_signal_connect(about_button, "clicked", G_CALLBACK(_open_about_dialog), NULL); - gtk_box_pack_start(GTK_BOX(menu_box), about_button, FALSE, FALSE, 0); + gtk_box_append(GTK_BOX(menu_box), about_button); + g_signal_connect(about_button, "clicked", G_CALLBACK(_open_about_dialog_and_close_popover), NULL); - gtk_container_add(GTK_CONTAINER(menu_popover), menu_box); - gtk_menu_button_set_popover(GTK_MENU_BUTTON(menu_button), menu_popover); - gtk_widget_show_all(menu_box); + gtk_popover_set_child(GTK_POPOVER(_menu_popover), menu_box); + gtk_menu_button_set_popover(GTK_MENU_BUTTON(menu_button), _menu_popover); gtk_header_bar_pack_end(GTK_HEADER_BAR(_window_header), menu_button); + gtk_widget_set_visible(menu_box, true); if (is_displays_loading() == FALSE) { - _refresh_displays_button = gtk_button_new_from_icon_name("view-refresh-symbolic", GTK_ICON_SIZE_BUTTON); + _refresh_displays_button = gtk_button_new_from_icon_name("view-refresh-symbolic"); gtk_header_bar_pack_start(GTK_HEADER_BAR(_window_header), _refresh_displays_button); g_signal_connect(_refresh_displays_button, "clicked", G_CALLBACK(_on_window_refresh_button_clicked), NULL); } GtkCssProvider *header_css_provider = gtk_css_provider_new(); - gtk_css_provider_load_from_data(header_css_provider, "headerbar {border-bottom: 0px;background-image: none;background-color: @theme_bg_color;}", -1, NULL); + gtk_css_provider_load_from_string(header_css_provider, "headerbar {border-bottom: 0px;background-image: none;background-color: @theme_bg_color;box-shadow: none;}"); gtk_style_context_add_provider(gtk_widget_get_style_context(_window_header), GTK_STYLE_PROVIDER(header_css_provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); - - gtk_window_set_titlebar(GTK_WINDOW(_window), _window_header); + gtk_window_set_titlebar(GTK_WINDOW(_window), _window_header); } void update_window_content_screen(GtkWidget *new_window_content_screen) { - if (_last_window_content_screen != NULL) { - gtk_container_remove(GTK_CONTAINER(_window), _last_window_content_screen); - gtk_widget_destroy(_last_window_content_screen); - } - gtk_container_add(GTK_CONTAINER(_window), new_window_content_screen); - gtk_window_resize(GTK_WINDOW(_window), gtk_widget_get_allocated_width(_window), gtk_widget_get_allocated_height(new_window_content_screen)); - _last_window_content_screen = new_window_content_screen; - - GtkWidget *_refresh_displays_button = NULL; - GList *children = gtk_container_get_children(GTK_CONTAINER(_window_header)); - if (g_list_length(children) > 1) { - _refresh_displays_button = g_list_nth_data(children, 0); + if (_last_window_content_screen != NULL) { + gtk_widget_unparent(_last_window_content_screen); + g_object_unref(_last_window_content_screen); } + gtk_window_set_child(GTK_WINDOW(_window), new_window_content_screen); + gtk_window_set_default_size(GTK_WINDOW(_window), gtk_widget_get_width(_window), gtk_widget_get_height(new_window_content_screen)); + _last_window_content_screen = new_window_content_screen; + if (is_displays_loading() == FALSE) { if (_refresh_displays_button == NULL) { - _refresh_displays_button = gtk_button_new_from_icon_name("view-refresh-symbolic", GTK_ICON_SIZE_BUTTON); + _refresh_displays_button = gtk_button_new_from_icon_name("view-refresh-symbolic"); gtk_header_bar_pack_start(GTK_HEADER_BAR(_window_header), _refresh_displays_button); g_signal_connect(_refresh_displays_button, "clicked", G_CALLBACK(_on_window_refresh_button_clicked), NULL); } } else { if (_refresh_displays_button != NULL) { - gtk_container_remove(GTK_CONTAINER(_window_header), _refresh_displays_button); - gtk_widget_destroy(_refresh_displays_button); + gtk_header_bar_remove(GTK_HEADER_BAR(_window_header), _refresh_displays_button); + gtk_widget_unparent(_refresh_displays_button); + g_object_unref(_refresh_displays_button); + _refresh_displays_button = NULL; } } - gtk_widget_show_all(_window); + gtk_widget_set_visible(_window, true); }