Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
- name: Install Dependencies
run: |
apt update
apt install -y libgee-0.8-dev libglib2.0-dev libgranite-7-dev libgtk-4-dev libadwaita-1-dev meson sassc valac
apt install -y libadwaita-1-dev libgee-0.8-dev libglib2.0-dev libgranite-7-dev libgtk-4-dev libpantheon-wayland-1-dev meson sassc valac
- name: Build
run: |
meson build -Dexample=true
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ Switchboard is just the container application for Switchboard Plugs, which provi

You'll need the following dependencies:

* libadwaita-1-dev (>= 1.4)
* libgee-0.8-dev
* libglib2.0-dev
* libgranite-7-dev
* libgtk-4-dev
* libadwaita-1-dev (>= 1.4)
* libpantheon-wayland-1-dev
* meson (>= 0.57.0)
* sassc
* valac
Expand Down
3 changes: 2 additions & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,15 @@ gnome = import('gnome')
i18n = import('i18n')
pkg = import('pkgconfig')

adwaita_dep = dependency('libadwaita-1', version: '>=1.4')
glib_dep = dependency('glib-2.0', version: '>=2.32')
gio_dep = dependency('gio-2.0')
gio_unix_dep = dependency('gio-unix-2.0')
gmodule_dep = dependency('gmodule-2.0')
gtk_dep = dependency('gtk4', version: '>=3.10')
gee_dep = dependency('gee-0.8')
granite_dep = dependency('granite-7', version: '>=7.0.0')
adwaita_dep = dependency('libadwaita-1', version: '>=1.4')
pantheon_wayland_dep = dependency('pantheon-wayland-1')
m_dep = meson.get_compiler('c').find_library('m', required : false)

subdir('data')
Expand Down
155 changes: 15 additions & 140 deletions src/Application.vala
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2011-2021 elementary, Inc. (https://elementary.io)
* Copyright 2011-2025 elementary, Inc. (https://elementary.io)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
Expand All @@ -21,15 +21,9 @@

namespace Switchboard {
public class SwitchboardApp : Gtk.Application {
private GLib.HashTable <Gtk.Widget, Switchboard.Plug> plug_widgets;
private Adw.NavigationView navigation_view;
private Gtk.Window main_window;
private Switchboard.CategoryView category_view;
private MainWindow main_window;

private static bool opened_directly = false;
private static string? link = null;
private static string? open_window = null;
private static string? plug_to_open = null;

construct {
application_id = "io.elementary.settings";
Expand Down Expand Up @@ -66,6 +60,7 @@ namespace Switchboard {
}

activate ();
((PantheonWayland.ExtendedBehavior) main_window).focus ();
}

public override void startup () {
Expand All @@ -82,19 +77,20 @@ namespace Switchboard {
gtk_settings.gtk_application_prefer_dark_theme = granite_settings.prefers_color_scheme == Granite.Settings.ColorScheme.DARK;
});

var back_action = new SimpleAction ("back", null);
var quit_action = new SimpleAction ("quit", null);

add_action (back_action);
add_action (quit_action);

set_accels_for_action ("app.quit", {"<Control>q"});

back_action.activate.connect (action_navigate_back);
quit_action.activate.connect (quit);
set_accels_for_action ("app.quit", {"<Control>q"});
add_action (quit_action);
}

public override void activate () {
if (main_window == null) {
main_window = new MainWindow ();
add_window (main_window);
}

main_window.present ();

var plugsmanager = Switchboard.PlugsManager.get_default ();
if (link != null) {
bool plug_found = load_setting_path (link, plugsmanager);
Expand All @@ -103,132 +99,11 @@ namespace Switchboard {
link = null;

// If plug_to_open was set from the command line
opened_directly = true;
main_window.opened_directly = true;
} else {
warning (_("Specified link '%s' does not exist, going back to the main panel").printf (link));
}
} else if (plug_to_open != null) {
foreach (var plug in plugsmanager.get_plugs ()) {
if (plug_to_open.has_suffix (plug.code_name)) {
load_plug (plug);
plug_to_open = null;

// If plug_to_open was set from the command line
opened_directly = true;
break;
}
}
}

// If app is already running, present the current window.
if (get_windows ().length () > 0) {
get_windows ().data.present ();
return;
}

plug_widgets = new GLib.HashTable <Gtk.Widget, Switchboard.Plug> (null, null);

category_view = new Switchboard.CategoryView (plug_to_open);

navigation_view = new Adw.NavigationView () {
pop_on_escape = false
};
navigation_view.add (category_view);

main_window = new Gtk.Window () {
application = this,
child = navigation_view,
height_request = 500,
icon_name = application_id,
title = _("System Settings"),
titlebar = new Gtk.Grid () { visible = false }
};
add_window (main_window);
main_window.present ();

/*
* This is very finicky. Bind size after present else set_titlebar gives us bad sizes
* Set maximize after height/width else window is min size on unmaximize
* Bind maximize as SET else get get bad sizes
*/
var settings = new Settings ("io.elementary.settings");
settings.bind ("window-height", main_window, "default-height", SettingsBindFlags.DEFAULT);
settings.bind ("window-width", main_window, "default-width", SettingsBindFlags.DEFAULT);

if (settings.get_boolean ("window-maximized")) {
main_window.maximize ();
}

settings.bind ("window-maximized", main_window, "maximized", SettingsBindFlags.SET);

shutdown.connect (() => {
navigation_view.visible_page.hidden ();
});

navigation_view.popped.connect (update_navigation);
navigation_view.pushed.connect (update_navigation);
}

private void update_navigation () {
main_window.title = navigation_view.visible_page.title;
}

public void load_plug (Switchboard.Plug plug) {
Idle.add (() => {
var plug_widget = plug.get_widget ();
if (plug_widget.parent == null) {
var navigation_page = new Adw.NavigationPage (plug_widget, plug.display_name);
navigation_page.hidden.connect (plug.hidden);
navigation_page.shown.connect (plug.shown);

navigation_view.add (navigation_page);
}

if (plug_widgets[plug_widget] == null) {
plug_widgets[plug_widget] = plug;
}

category_view.plug_search_result.foreach ((entry) => {
if (plug.display_name == entry.plug_name) {
if (entry.open_window == null) {
plug.search_callback (""); // open default in the switch
} else {
plug.search_callback (entry.open_window);
}
debug ("open section:%s of plug: %s", entry.open_window, plug.display_name);
return true;
}

return false;
});

// open window was set by command line argument
if (open_window != null) {
plug.search_callback (open_window);
open_window = null;
}

if (opened_directly) {
navigation_view.animate_transitions = false;
opened_directly = false;
} else if (navigation_view.animate_transitions == false) {
navigation_view.animate_transitions = true;
}

navigation_view.push ((Adw.NavigationPage) plug.get_widget ().parent);

return false;
}, GLib.Priority.DEFAULT_IDLE);
}

// Handles clicking the navigation button
private void action_navigate_back () {
if (navigation_view.get_previous_page (navigation_view.visible_page) == category_view) {
opened_directly = false;
navigation_view.animate_transitions = true;
}

navigation_view.pop ();
}

// Try to find a supported plug, fallback paths like "foo/bar" to "foo"
Expand All @@ -240,8 +115,8 @@ namespace Switchboard {
}

if (supported_settings.has_key (setting_path)) {
load_plug (plug);
open_window = supported_settings.get (setting_path);
main_window.load_plug (plug);
main_window.open_window = supported_settings.get (setting_path);
return true;
}
}
Expand Down
11 changes: 0 additions & 11 deletions src/CategoryView.vala
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

public class Switchboard.CategoryView : Adw.NavigationPage {
public Gee.ArrayList<SearchEntry?> plug_search_result { get; private set; }
public string? plug_to_open { get; construct set; default = null; }

private Gtk.SearchEntry search_box;
private Gtk.Stack stack;
Expand Down Expand Up @@ -149,10 +148,6 @@ public class Switchboard.CategoryView : Adw.NavigationPage {
add_controller (eventcontrollerkey);
}

public CategoryView (string? plug = null) {
Object (plug_to_open: plug);
}

public async void load_default_plugs () {
var plugsmanager = Switchboard.PlugsManager.get_default ();
plugsmanager.plug_added.connect ((plug) => {
Expand Down Expand Up @@ -205,12 +200,6 @@ public class Switchboard.CategoryView : Adw.NavigationPage {
if (any_found) {
stack.visible_child_name = "category-grid";
}

if (plug_to_open != null && plug_to_open.has_suffix (plug.code_name)) {
unowned var app = (SwitchboardApp) GLib.Application.get_default ();
app.load_plug (plug);
plug_to_open = null;
}
}

public static string? get_category_name (Switchboard.Plug.Category category) {
Expand Down
101 changes: 101 additions & 0 deletions src/MainWindow.vala
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* SPDX-License-Identifier: LGPL-2.1-or-later
* SPDX-FileCopyrightText: 2025 elementary, Inc. (https://elementary.io)
*/

public class Switchboard.MainWindow : Gtk.ApplicationWindow, PantheonWayland.ExtendedBehavior {
public string? open_window { get; set; default = null; }
public bool opened_directly { get; set; default = false; }

private GLib.HashTable <Gtk.Widget, Switchboard.Plug> plug_widgets;
private CategoryView category_view;
private Adw.NavigationView navigation_view;

construct {
plug_widgets = new GLib.HashTable <Gtk.Widget, Switchboard.Plug> (null, null);

category_view = new Switchboard.CategoryView ();

navigation_view = new Adw.NavigationView () {
pop_on_escape = false
};
navigation_view.add (category_view);

height_request = 500;
title = _("System Settings");
titlebar = new Gtk.Grid () { visible = false };
child = navigation_view;

navigation_view.popped.connect (update_navigation);
navigation_view.pushed.connect (update_navigation);

/*
* This is very finicky. Bind size after present else set_titlebar gives us bad sizes
* Set maximize after height/width else window is min size on unmaximize
* Bind maximize as SET else get get bad sizes
*/
var settings = new Settings ("io.elementary.settings");
settings.bind ("window-height", this, "default-height", SettingsBindFlags.DEFAULT);
settings.bind ("window-width", this, "default-width", SettingsBindFlags.DEFAULT);

if (settings.get_boolean ("window-maximized")) {
maximize ();
}

settings.bind ("window-maximized", this, "maximized", SettingsBindFlags.SET);

child.realize.connect (connect_to_shell);
}

private void update_navigation () {
title = navigation_view.visible_page.title;
}

public void load_plug (Switchboard.Plug plug) {
Idle.add (() => {
var plug_widget = plug.get_widget ();
if (plug_widget.parent == null) {
var navigation_page = new Adw.NavigationPage (plug_widget, plug.display_name);
navigation_page.hidden.connect (plug.hidden);
navigation_page.shown.connect (plug.shown);

navigation_view.add (navigation_page);
}

if (plug_widgets[plug_widget] == null) {
plug_widgets[plug_widget] = plug;
}

category_view.plug_search_result.foreach ((entry) => {
if (plug.display_name == entry.plug_name) {
if (entry.open_window == null) {
plug.search_callback (""); // open default in the switch
} else {
plug.search_callback (entry.open_window);
}
debug ("open section:%s of plug: %s", entry.open_window, plug.display_name);
return true;
}

return false;
});

// open window was set by command line argument
if (open_window != null) {
plug.search_callback (open_window);
open_window = null;
}

if (opened_directly) {
navigation_view.animate_transitions = false;
opened_directly = false;
} else if (navigation_view.animate_transitions == false) {
navigation_view.animate_transitions = true;
}

navigation_view.push ((Adw.NavigationPage) plug.get_widget ().parent);

return Source.REMOVE;
});
}
}
2 changes: 1 addition & 1 deletion src/Widgets/CategoryFlowBox.vala
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ namespace Switchboard {
attach (flowbox, 0, 1, 2, 1);

flowbox.child_activated.connect ((child) => {
((SwitchboardApp) GLib.Application.get_default ()).load_plug (((CategoryIcon) child).plug);
((MainWindow) get_root ()).load_plug (((CategoryIcon) child).plug);
});

flowbox.set_sort_func (plug_sort_func);
Expand Down
Loading