screen-selector 0.1.1

A reimplementation of Unity’s ScreenSelector.so plugin, using GTK 4
Documentation
// SPDX-License-Identifier: GPL-3.0-only

use crate::callbacks::*;

use gtk::glib;
use gtk::prelude::*;

pub fn load_screen_selector_window(title: String, _icon: String, pixbuf_path: String) -> i32 {
    let app = gtk::Application::builder()
        .application_id("fr.linkmauve.ScreenSelector")
        .build();

    app.connect_activate(move |app| {
        let builder = gtk::Builder::from_resource("/fr/linkmauve/ScreenSelector/window.ui");
        let window: gtk::ApplicationWindow = builder.object("screenSelectorWindow").unwrap();
        let banner: gtk::Picture = builder.object("bannerImage").unwrap();
        let input_list: gtk::TreeView = builder.object("inputList").unwrap();
        let input_list_store: gtk::ListStore = builder.object("inputListStore").unwrap();
        let resolution_list: gtk::TreeView = builder.object("resolutionList").unwrap();
        let resolution_list_store: gtk::ListStore = builder.object("resolutionListStore").unwrap();
        let quality_list: gtk::TreeView = builder.object("qualityList").unwrap();
        let quality_list_store: gtk::ListStore = builder.object("qualityListStore").unwrap();
        let display_combo: gtk::ComboBoxText = builder.object("displayCombo").unwrap();
        let windowed_checkbutton: gtk::CheckButton = builder.object("windowedCheckbutton").unwrap();
        let ok: gtk::Button = builder.object("playButton").unwrap();
        let cancel: gtk::Button = builder.object("quitButton").unwrap();

        window.set_title(Some(&title));
        // TODO: figure out how to pass a path here.
        //window.set_icon_from_file(Some(&icon));
        let display_combo2 = display_combo.clone();
        let resolution_list2 = resolution_list.clone();
        let windowed_checkbutton2 = windowed_checkbutton.clone();
        let quality_list2 = quality_list.clone();
        ok.connect_clicked(glib::clone!(@weak app => move |_| {
            if let Some(display) = display_combo2.active() {
                set_selected_display(display);
            }
            let selection = resolution_list2.selection();
            selection.selected_foreach(|model, _, iter| {
                if let Ok(width) = model.get(iter, 0).get::<u32>() {
                    if let Ok(height) = model.get(iter, 1).get::<u32>() {
                        set_selected_resolution(width, height, windowed_checkbutton2.is_active());
                    }
                }
            });
            let selection = quality_list2.selection();
            selection.selected_foreach(|_, path, _| {
                if let Some(level) = path.indices().pop() {
                    set_selected_quality_level(level);
                }
            });
            app.quit();
        }));

        cancel.connect_clicked(glib::clone!(@weak app => move |_| {
            app.quit();
            std::process::exit(0);
        }));

        banner.set_filename(Some(&pixbuf_path));

        for (control, primary, secondary) in iter_axis_description() {
            let iter = input_list_store.append();
            input_list_store.set(&iter, &[(0, &control), (1, &primary), (2, &secondary)]);
        }
        input_list.connect_row_activated(|_, path, _| {
            if let Some(axis) = path.indices().pop() {
                // TODO: figure out this second parameter.
                configure_axis(axis, 1);
            }
        });

        let quality_levels = get_quality_levels();
        let selected_quality_level = get_selected_quality_level();
        for (i, quality) in quality_levels.into_iter().enumerate() {
            let iter = quality_list_store.append();
            quality_list_store.set(&iter, &[(0, &quality)]);
            if i as i32 == selected_quality_level {
                let selection = quality_list.selection();
                selection.select_iter(&iter);
            }
        }

        display_combo.connect_changed(move |display_combo| {
            if let Some(selected_display) = display_combo.active() {
                resolution_list_store.clear();
                let resolutions = get_resolutions(selected_display);
                let (selected_width, selected_height, windowed) = get_selected_resolution();
                windowed_checkbutton.set_active(windowed);
                for (width, height) in resolutions {
                    let resolution = format!("{}×{}", width, height);
                    let iter = resolution_list_store.append();
                    resolution_list_store
                        .set(&iter, &[(0, &width), (1, &height), (2, &resolution)]);
                    if width == selected_width && height == selected_height {
                        let selection = resolution_list.selection();
                        selection.select_iter(&iter);
                    }
                }
            }
        });

        for name in get_displays().iter() {
            display_combo.append_text(name);
        }
        let selected_display = get_selected_display();
        display_combo.set_active(Some(selected_display));
        {
            let display_combo = display_combo.upcast::<gtk::ComboBox>();
            if let Some(model) = display_combo.model() {
                if model.iter_n_children(None) <= 1 {
                    display_combo.set_button_sensitivity(gtk::SensitivityType::Off);
                }
            }
        }

        // Show the window.
        window.show();
        app.add_window(&window);
    });

    app.run();
    1
}