🔧 Start porting to GTK4

This commit is contained in:
Simon Schneegans
2023-02-01 05:36:50 +01:00
parent d6c89cd79b
commit 956cef56b4
3 changed files with 483 additions and 415 deletions
+122 -189
View File
@@ -31,9 +31,6 @@ const Me = imports.misc.extensionUtils.getCurrentExtension();
const utils = Me.imports.src.utils; const utils = Me.imports.src.utils;
const ProfileManager = Me.imports.src.ProfileManager.ProfileManager; const ProfileManager = Me.imports.src.ProfileManager.ProfileManager;
// This template widget class is defined at the bottom of this file.
var BurnMyWindowsEffectPage = null;
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
// The preferences dialog is organized in pages, each of which is loaded from a // // The preferences dialog is organized in pages, each of which is loaded from a //
// separate ui file. There's one page with general options, all other paged are loaded // // separate ui file. There's one page with general options, all other paged are loaded //
@@ -48,26 +45,26 @@ var PreferencesDialog = class PreferencesDialog {
// New effects must be registered here and in extension.js. // New effects must be registered here and in extension.js.
this._ALL_EFFECTS = [ this._ALL_EFFECTS = [
new Me.imports.src.effects.Apparition.Apparition(), // new Me.imports.src.effects.Apparition.Apparition(),
new Me.imports.src.effects.BrokenGlass.BrokenGlass(), // new Me.imports.src.effects.BrokenGlass.BrokenGlass(),
new Me.imports.src.effects.Doom.Doom(), // new Me.imports.src.effects.Doom.Doom(),
new Me.imports.src.effects.EnergizeA.EnergizeA(), // new Me.imports.src.effects.EnergizeA.EnergizeA(),
new Me.imports.src.effects.EnergizeB.EnergizeB(), // new Me.imports.src.effects.EnergizeB.EnergizeB(),
new Me.imports.src.effects.Fire.Fire(), // new Me.imports.src.effects.Fire.Fire(),
new Me.imports.src.effects.Glide.Glide(), // new Me.imports.src.effects.Glide.Glide(),
new Me.imports.src.effects.Glitch.Glitch(), // new Me.imports.src.effects.Glitch.Glitch(),
new Me.imports.src.effects.Hexagon.Hexagon(), // new Me.imports.src.effects.Hexagon.Hexagon(),
new Me.imports.src.effects.Incinerate.Incinerate(), // new Me.imports.src.effects.Incinerate.Incinerate(),
new Me.imports.src.effects.Matrix.Matrix(), // new Me.imports.src.effects.Matrix.Matrix(),
new Me.imports.src.effects.Pixelate.Pixelate(), // new Me.imports.src.effects.Pixelate.Pixelate(),
new Me.imports.src.effects.PixelWheel.PixelWheel(), // new Me.imports.src.effects.PixelWheel.PixelWheel(),
new Me.imports.src.effects.PixelWipe.PixelWipe(), // new Me.imports.src.effects.PixelWipe.PixelWipe(),
new Me.imports.src.effects.Portal.Portal(), // new Me.imports.src.effects.Portal.Portal(),
new Me.imports.src.effects.SnapOfDisintegration.SnapOfDisintegration(), // new Me.imports.src.effects.SnapOfDisintegration.SnapOfDisintegration(),
new Me.imports.src.effects.TRexAttack.TRexAttack(), // new Me.imports.src.effects.TRexAttack.TRexAttack(),
new Me.imports.src.effects.TVEffect.TVEffect(), // new Me.imports.src.effects.TVEffect.TVEffect(),
new Me.imports.src.effects.TVGlitch.TVGlitch(), // new Me.imports.src.effects.TVGlitch.TVGlitch(),
new Me.imports.src.effects.Wisps.Wisps(), // new Me.imports.src.effects.Wisps.Wisps(),
]; ];
// Load all of our resources. // Load all of our resources.
@@ -92,9 +89,6 @@ var PreferencesDialog = class PreferencesDialog {
Gtk.IconTheme.get_default().add_resource_path('/img'); Gtk.IconTheme.get_default().add_resource_path('/img');
} }
// Register the template widgets used in the settings dialog.
this._registerCustomClasses();
// Load the general user interface files. // Load the general user interface files.
this._builder = new Gtk.Builder(); this._builder = new Gtk.Builder();
this._builder.add_from_resource(`/ui/common/menus.ui`); this._builder.add_from_resource(`/ui/common/menus.ui`);
@@ -129,12 +123,19 @@ var PreferencesDialog = class PreferencesDialog {
// Maybe the service is masked... // Maybe the service is masked...
} }
this._builder.get_object('profile-power-profile').set_visible(hasPowerProfiles); let powerProfileRow = this._builder.get_object('profile-power-profile');
if (!utils.isADW()) {
powerProfileRow = powerProfileRow.get_parent().get_parent();
}
powerProfileRow.set_visible(hasPowerProfiles);
// The global color scheme is only available starting with GNOME Shell 42. We hide the // The global color scheme is only available starting with GNOME Shell 42. We hide the
// corresponding settings row on older versions. // corresponding settings row on older versions.
this._builder.get_object('profile-color-scheme') let colorSchemeRow = this._builder.get_object('profile-color-scheme');
.set_visible(utils.shellVersionIsAtLeast(42, 0)); if (!utils.isADW()) {
colorSchemeRow = colorSchemeRow.get_parent().get_parent();
}
colorSchemeRow.set_visible(utils.shellVersionIsAtLeast(42, 0));
this._builder.get_object('profile-choose-app-button').connect('clicked', () => { this._builder.get_object('profile-choose-app-button').connect('clicked', () => {
Gio.DBus.session.call('org.gnome.Shell', Gio.DBus.session.call('org.gnome.Shell',
@@ -154,138 +155,82 @@ var PreferencesDialog = class PreferencesDialog {
} }
}); });
// Starting with GNOME Shell 42, the settings dialog uses libadwaita. We use this to // This is our top-level widget which we will return later.
// create a completely different layout for the settings dialog. this._widget = this._builder.get_object('general-prefs');
if (utils.isADW()) {
// This is our top-level widget which we will return later. // Then add a preferences group for the effect expander rows.
this._widget = this._builder.get_object('general-prefs'); const group = this._builder.get_object('effects-group');
// Then add a preferences group for the effect expander rows. // This stores all expander rows for the effects. We use this to implement the
const group = this._builder.get_object('effects-group'); // accordion-like behavior of the effect settings.
this._effectRows = [];
// This stores all expander rows for the effects. We use this to implement the // Now add all the rows.
// accordion-functionality of the effect settings. this._ALL_EFFECTS.forEach(effect => {
this._effectRows = []; const [minMajor, minMinor] = effect.getMinShellVersion();
if (utils.shellVersionIsAtLeast(minMajor, minMinor)) {
// Now add all the rows. const uiFile = `/ui/${utils.getUIDir()}/${effect.getNick()}.ui`;
this._ALL_EFFECTS.forEach(effect => { const [hasPrefs] = Gio.resources_get_info(uiFile, 0);
const [minMajor, minMinor] = effect.getMinShellVersion();
if (utils.shellVersionIsAtLeast(minMajor, minMinor)) {
const uiFile = `/ui/${utils.getUIDir()}/${effect.getNick()}.ui`; let row;
const [hasPrefs] = Gio.resources_get_info(uiFile, 0); if (hasPrefs) {
// Add the settings page to the builder.
this._builder.add_from_resource(uiFile);
let row; // Add the effect's preferences (if any).
if (hasPrefs) { row = this._builder.get_object(`${effect.getNick()}-prefs`);
// Add the settings page to the builder. } else {
this._builder.add_from_resource(uiFile); row = Adw.ActionRow.new();
// Add the effect's preferences (if any).
row = this._builder.get_object(`${effect.getNick()}-prefs`);
} else {
row = Adw.ActionRow.new();
}
// On older versions of Adw (e.g. on GNOME Shell <43), the set_use_markup() does
// not yet exist.
if (row.set_use_markup) {
row.set_title('<b>' + effect.getLabel() + '</b>');
row.set_use_markup(true);
} else {
row.set_title(effect.getLabel());
}
// Un-expand any previously expanded effect row. This way we ensure that there
// is only one expanded row at any time.
if (hasPrefs) {
row.connect('notify::expanded', currentRow => {
if (currentRow.get_expanded()) {
this._effectRows.forEach(row => {
if (row != currentRow && row.set_expanded) {
row.set_expanded(false);
}
});
}
});
}
// The preview button.
const previewButton = Gtk.Button.new_from_icon_name('bmw-preview-symbolic');
previewButton.add_css_class('circular');
previewButton.add_css_class('flat');
previewButton.set_tooltip_text(_('Preview this effect'));
previewButton.set_valign(Gtk.Align.CENTER);
row.add_action(previewButton);
previewButton.connect('clicked', () => {
this._previewEffect(effect);
});
// Now add the toggle button for enabling and disabling the effect.
const button = Gtk.Switch.new();
button.set_tooltip_text(_('Use this effect'));
button.set_valign(Gtk.Align.CENTER);
this._builder.expose_object(`${effect.getNick()}-enable-effect`, button);
row.add_prefix(button);
group.add(row);
this._effectRows.push(row);
} }
});
}
// On older GNOME versions, we use a StackSidebar. The code below works on GTK3 and
// GTK4.
else {
// This is our top-level widget which we will return later. // On older versions of Adw (e.g. on GNOME Shell <43), the set_use_markup() does
this._widget = new Gtk.Box({ // not yet exist.
orientation: Gtk.Orientation.HORIZONTAL, if (row.set_use_markup) {
}); row.set_title('<b>' + effect.getLabel() + '</b>');
row.set_use_markup(true);
} else {
row.set_title(effect.getLabel());
}
const stack = new Gtk.Stack({ // Un-expand any previously expanded effect row. This way we ensure that there
transition_type: Gtk.StackTransitionType.SLIDE_UP_DOWN, // is only one expanded row at any time.
}); if (hasPrefs) {
row.connect('notify::expanded', currentRow => {
// Add the general options page. if (currentRow.get_expanded()) {
const generalPage = this._builder.get_object('general-prefs'); this._effectRows.forEach(row => {
generalPage.margin_start = 60; if (row != currentRow && row.set_expanded) {
generalPage.margin_end = 60; row.set_expanded(false);
stack.add_titled(generalPage, 'general', _('General Options')); }
});
this.gtkBoxAppend(this._widget, new Gtk.StackSidebar({stack: stack}));
this.gtkBoxAppend(this._widget, stack);
// Add all other effect pages.
this._ALL_EFFECTS.forEach(effect => {
const [minMajor, minMinor] = effect.getMinShellVersion();
if (utils.shellVersionIsAtLeast(minMajor, minMinor)) {
const page = new BurnMyWindowsEffectPage(effect, this);
page.margin_start = 60;
page.margin_end = 60;
page.margin_top = 60;
page.margin_bottom = 60;
const uiFile = `/ui/${utils.getUIDir()}/${effect.getNick()}.ui`;
const [hasPrefs] = Gio.resources_get_info(uiFile);
if (hasPrefs) {
// Add the settings page to the builder.
this._builder.add_from_resource(uiFile);
// Add the effect's preferences (if any).
const prefs = this._builder.get_object(`${effect.getNick()}-prefs`);
if (prefs) {
this.gtkBoxAppend(page, prefs);
} }
} });
stack.add_titled(page, effect.getNick(), effect.getLabel());
} }
});
} // The preview button.
const previewButton = Gtk.Button.new_from_icon_name('bmw-preview-symbolic');
previewButton.add_css_class('circular');
previewButton.add_css_class('flat');
previewButton.set_tooltip_text(_('Preview this effect'));
previewButton.set_valign(Gtk.Align.CENTER);
row.add_action(previewButton);
previewButton.connect('clicked', () => {
this._previewEffect(effect);
});
// Now add the toggle button for enabling and disabling the effect.
const button = Gtk.Switch.new();
button.set_tooltip_text(_('Use this effect'));
button.set_valign(Gtk.Align.CENTER);
this._builder.expose_object(`${effect.getNick()}-enable-effect`, button);
row.add_prefix(button);
group.add(row);
this._effectRows.push(row);
}
});
// Some things can only be done once the widget is shown as we do not have access to // Some things can only be done once the widget is shown as we do not have access to
// the toplevel widget before. // the toplevel widget before.
@@ -309,7 +254,7 @@ var PreferencesDialog = class PreferencesDialog {
// Starting with GNOME Shell 42, we have to hack our way through the widget tree // Starting with GNOME Shell 42, we have to hack our way through the widget tree
// of the Adw.PreferencesWindow... // of the Adw.PreferencesWindow...
if (Adw && utils.shellVersionIsAtLeast(42, 'beta')) { if (utils.isADW()) {
const header = this._findWidgetByType(window.get_content(), Adw.HeaderBar); const header = this._findWidgetByType(window.get_content(), Adw.HeaderBar);
header.pack_start(menu); header.pack_start(menu);
header.set_title_widget(this._builder.get_object('profile-button')); header.set_title_widget(this._builder.get_object('profile-button'));
@@ -330,6 +275,7 @@ var PreferencesDialog = class PreferencesDialog {
} else { } else {
window.get_titlebar().pack_start(menu); window.get_titlebar().pack_start(menu);
window.get_titlebar().set_title_widget(this._builder.get_object('profile-button'));
} }
const addURIAction = (name, uri) => { const addURIAction = (name, uri) => {
@@ -473,7 +419,7 @@ var PreferencesDialog = class PreferencesDialog {
const dialogTitle = _('Delete this Profile?'); const dialogTitle = _('Delete this Profile?');
const dialogSubtitle = _('The current effect profile will be permanently lost.'); const dialogSubtitle = _('The current effect profile will be permanently lost.');
if (Adw.MessageDialog) { if (utils.isADW() && Adw.MessageDialog) {
deleteProfileDialog = deleteProfileDialog =
new Adw.MessageDialog({heading: dialogTitle, body: dialogSubtitle}); new Adw.MessageDialog({heading: dialogTitle, body: dialogSubtitle});
deleteProfileDialog.add_response('cancel', _('Cancel')); deleteProfileDialog.add_response('cancel', _('Cancel'));
@@ -495,7 +441,7 @@ var PreferencesDialog = class PreferencesDialog {
deleteProfileDialog.set_hide_on_close(true); deleteProfileDialog.set_hide_on_close(true);
deleteProfileDialog.set_transient_for(window); deleteProfileDialog.set_transient_for(window);
deleteProfileDialog.connect('response', (d, response) => { deleteProfileDialog.connect('response', (dialog, response) => {
if (response == 'delete' || response == Gtk.ResponseType.OK) { if (response == 'delete' || response == Gtk.ResponseType.OK) {
// Stop editing the current profile. // Stop editing the current profile.
this._builder.get_object('edit-profile-button').active = false; this._builder.get_object('edit-profile-button').active = false;
@@ -512,7 +458,7 @@ var PreferencesDialog = class PreferencesDialog {
this._updateProfileMenu(); this._updateProfileMenu();
} }
d.hide(); dialog.hide();
}); });
const deleteProfileAction = Gio.SimpleAction.new('profile-delete', null); const deleteProfileAction = Gio.SimpleAction.new('profile-delete', null);
@@ -557,10 +503,16 @@ var PreferencesDialog = class PreferencesDialog {
return this._widget; return this._widget;
} }
// Connects a Gtk.ComboBox (or anything else which has an 'selected' property) to a // Connects an Adw.ComboRow (or anything else which has an 'selected' property) to a
// settings key. It also binds the corresponding reset button.
bindComboRow(settingsKey) {
this._bind(settingsKey, 'selected');
}
// Connects a Gtk.ComboBox (or anything else which has an 'active' property) to a
// settings key. It also binds the corresponding reset button. // settings key. It also binds the corresponding reset button.
bindComboBox(settingsKey) { bindComboBox(settingsKey) {
this._bind(settingsKey, 'selected'); this._bind(settingsKey, 'active');
} }
// Connects a Gtk.Entry (or anything else which has an 'text' property) to a // Connects a Gtk.Entry (or anything else which has an 'text' property) to a
@@ -664,11 +616,20 @@ var PreferencesDialog = class PreferencesDialog {
updateProfileButtonMenuIfChanged('profile-power-profile'); updateProfileButtonMenuIfChanged('profile-power-profile');
this.bindEntry('profile-app'); this.bindEntry('profile-app');
this.bindComboBox('profile-animation-type');
this.bindComboBox('profile-window-type'); if (utils.isADW()) {
this.bindComboBox('profile-color-scheme'); this.bindComboRow('profile-animation-type');
this.bindComboBox('profile-power-mode'); this.bindComboRow('profile-window-type');
this.bindComboBox('profile-power-profile'); this.bindComboRow('profile-color-scheme');
this.bindComboRow('profile-power-mode');
this.bindComboRow('profile-power-profile');
} else {
this.bindComboBox('profile-animation-type');
this.bindComboBox('profile-window-type');
this.bindComboBox('profile-color-scheme');
this.bindComboBox('profile-power-mode');
this.bindComboBox('profile-power-profile');
}
this.bindSwitch('profile-high-priority'); this.bindSwitch('profile-high-priority');
// Connect all effect settings. // Connect all effect settings.
@@ -826,34 +787,6 @@ var PreferencesDialog = class PreferencesDialog {
window.show_all(); window.show_all();
} }
} }
// Initializes template widgets used by the preferences dialog.
_registerCustomClasses() {
// If we are not using libadwaita, each effect page is based on a template widget.
// This template contains the title and the preview button.
if (!utils.isADW() && GObject.type_from_name('BurnMyWindowsEffectPage') == null) {
BurnMyWindowsEffectPage = GObject.registerClass(
{
GTypeName: 'BurnMyWindowsEffectPage',
Template: `resource:///ui/${utils.getUIDir()}/effectPage.ui`,
InternalChildren: ['label', 'button'],
},
class BurnMyWindowsEffectPage extends Gtk.Box { // ------------------------------
_init(effect, dialog) {
super._init();
// Set the effect's name as label.
this._label.label = effect.getLabel();
// Open the preview window once the preview button is clicked.
this._button.connect('clicked', () => {
dialog._previewEffect(effect);
});
}
});
}
}
} }
// This is used for setting up the translations. // This is used for setting up the translations.
-59
View File
@@ -1,59 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
SPDX-FileCopyrightText: Simon Schneegans <code@simonschneegans.de>
SPDX-License-Identifier: GPL-3.0-or-later
-->
<interface domain="burn-my-windows">
<requires lib="gtk" version="4.0" />
<template class="BurnMyWindowsEffectPage" parent="GtkBox">
<property name="orientation">vertical</property>
<property name="hexpand">1</property>
<property name="spacing">10</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkLabel" id="label">
<property name="xalign">0</property>
<property name="hexpand">1</property>
<style>
<class name="large-title" />
</style>
</object>
</child>
<child>
<object class="GtkButton" id="button">
<property name="valign">center</property>
<property name="child">
<object class="GtkBox">
<property name="margin_start">8</property>
<property name="margin_end">8</property>
<property name="spacing">6</property>
<child>
<object class="GtkImage">
<property name="icon_name">media-playback-start-symbolic</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="halign">start</property>
<property name="label" translatable="yes">Preview this effect</property>
</object>
</child>
</object>
</property>
<style>
<class name="pill-button" />
<class name="flat" />
</style>
</object>
</child>
</object>
</child>
</template>
</interface>
+361 -167
View File
@@ -8,201 +8,395 @@ SPDX-License-Identifier: GPL-3.0-or-later
<interface domain="burn-my-windows"> <interface domain="burn-my-windows">
<requires lib="gtk" version="4.0" /> <requires lib="gtk" version="4.0" />
<menu id="enabled-effects-menu"></menu> <!-- This will be added to the header bar. -->
<object class="GtkMenuButton" id="menu-button"> <object class="GtkMenuButton" id="menu-button">
<property name="menu-model">main-menu</property> <property name="menu-model">main-menu</property>
<property name="icon-name">heart-filled-symbolic</property> <property name="icon-name">heart-filled-symbolic</property>
</object> </object>
<!-- This will be added to the header bar. -->
<object class="GtkBox" id="profile-button">
<property name="halign">center</property>
<child>
<object class="GtkMenuButton" id="choose-profile-button">
<property name="menu-model">profile-menu</property>
</object>
</child>
<child>
<object class="GtkToggleButton" id="edit-profile-button">
<property name="icon-name">bmw-edit-profile-symbolic</property>
<property name="valign">center</property>
<binding name="active">
<lookup name="reveal-child">profile-editor-revealer</lookup>
</binding>
</object>
</child>
<style>
<class name="linked" />
</style>
</object>
<object class="GtkBox" id="general-prefs"> <object class="GtkBox" id="general-prefs">
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<property name="margin-top">60</property>
<property name="margin-bottom">60</property>
<child> <child>
<object class="GtkImage"> <object class="GtkRevealer" id="profile-editor-revealer">
<binding name="reveal-child">
<lookup name="active">edit-profile-button</lookup>
</binding>
<property name="child">
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="margin-top">20</property>
<property name="margin-bottom">20</property>
<property name="margin-start">20</property>
<property name="margin-end">20</property>
<property name="spacing">5</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Effect Profile Constraints</property>
<property name="halign">start</property>
<style>
<class name="heading" />
</style>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Define when the current effect settings should be used.</property>
<property name="halign">start</property>
</object>
</child>
<child>
<object class="GtkFrame">
<property name="margin-top">5</property>
<property name="margin-bottom">15</property>
<child>
<object class="GtkListBox">
<property name="selection-mode">none</property>
<property name="show-separators">1</property>
<style>
<class name="rich-list" />
</style>
<child>
<object class="GtkListBoxRow">
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Application Name</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkBox">
<property name="valign">center</property>
<style>
<class name="linked" />
</style>
<child>
<object class="GtkEntry" id="profile-app">
<property name="width-request">200</property>
</object>
</child>
<child>
<object class="GtkButton" id="profile-choose-app-button">
<property name="icon-name">bmw-select-app-symbolic</property>
<property name="valign">center</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkListBoxRow">
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Animation Type</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkComboBoxText" id="profile-animation-type">
<property name="width-request">200</property>
<items>
<item translatable="yes">Any</item>
<item translatable="yes">Opening Windows</item>
<item translatable="yes">Closing Windows</item>
</items>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkListBoxRow">
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Window Type</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkComboBoxText" id="profile-window-type">
<property name="width-request">200</property>
<items>
<item translatable="yes">Any</item>
<item translatable="yes">Normal Windows</item>
<item translatable="yes">Dialog Windows</item>
</items>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkListBoxRow">
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Color Scheme</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkComboBoxText" id="profile-color-scheme">
<property name="width-request">200</property>
<items>
<item translatable="yes">Any</item>
<item translatable="yes">Default Color Scheme</item>
<item translatable="yes">Dark Color Scheme</item>
</items>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkListBoxRow">
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Power Mode</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkComboBoxText" id="profile-power-mode">
<property name="width-request">200</property>
<items>
<item translatable="yes">Any</item>
<item translatable="yes">On Battery</item>
<item translatable="yes">Plugged In</item>
</items>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkListBoxRow">
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Power Profile</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkComboBoxText" id="profile-power-profile">
<property name="width-request">200</property>
<items>
<item translatable="yes">Any</item>
<item translatable="yes">Power-Saver Mode</item>
<item translatable="yes">Balanced Mode</item>
<item translatable="yes">Performance Mode</item>
<item translatable="yes">Power Saver or Balanced</item>
<item translatable="yes">Balanced or Performance</item>
</items>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Advanced Profile Options</property>
<property name="halign">start</property>
<style>
<class name="heading" />
</style>
</object>
</child>
<child>
<object class="GtkFrame">
<property name="margin-top">5</property>
<property name="margin-bottom">15</property>
<child>
<object class="GtkListBox">
<property name="selection-mode">none</property>
<property name="show-separators">1</property>
<style>
<class name="rich-list" />
</style>
<child>
<object class="GtkListBoxRow">
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="spacing">3</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">High Priority</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Force using this profile even if it has less constraints than another matching profile.</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
<property name="ellipsize">end</property>
<style>
<class name="dim-label" />
<class name="caption" />
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkSwitch" id="profile-high-priority">
<property name="valign">center</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkButton">
<property name="action-name">prefs.profile-delete</property>
<property name="label" translatable="yes">Delete this Profile...</property>
<property name="halign">start</property>
</object>
</child>
</object>
</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Effect Settings</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property> <property name="valign">center</property>
<property name="icon-name">burn-my-windows-symbolic</property> <property name="hexpand">1</property>
<property name="pixel_size">128</property>
</object> </object>
</child> </child>
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="label" translatable="yes">Welcome to Burn-My-Windows!</property> <property name="label" translatable="yes">If multiple are selected, one is chosen randomly.</property>
<property name="margin-top">8</property> <property name="xalign">0</property>
<property name="margin-bottom">6</property> <property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
<style> <style>
<class name="large-title" /> <class name="dim-label" />
<class name="caption" />
</style> </style>
</object> </object>
</child> </child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">If you like this extension, recommend it to your friends :)</property>
<property name="margin-bottom">36</property>
</object>
</child>
<child> <child>
<object class="GtkFrame"> <object class="GtkFrame">
<child> <child>
<object class="GtkListBox"> <object class="GtkListBox" id="effects-group">
<property name="selection-mode">none</property> <property name="selection-mode">none</property>
<property name="show-separators">1</property> <property name="show-separators">1</property>
<style> <style>
<class name="rich-list" /> <class name="rich-list" />
</style> </style>
<child>
<object class="GtkListBoxRow">
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="spacing">3</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Enabled Effects</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">If multiple are selected, one is chosen randomly.</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
<style>
<class name="dim-label" />
<class name="caption" />
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkMenuButton" id="enabled-effects-button">
<property name="label" translatable="yes">Choose Effects</property>
<property name="menu-model">enabled-effects-menu</property>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkListBoxRow">
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Also Add Effects to Dialogs</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkSwitch" id="destroy-dialogs">
<property name="halign">end</property>
<property name="valign">center</property>
</object>
</child>
<child>
<object class="GtkButton" id="reset-destroy-dialogs">
<property name="icon-name">edit-clear-symbolic</property>
<property name="tooltip-text" translatable="yes">Reset to Default Value</property>
<style>
<class name="flat" />
</style>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkListBoxRow">
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Disable on Battery Power</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkSwitch" id="disable-on-battery">
<property name="halign">end</property>
<property name="valign">center</property>
</object>
</child>
<child>
<object class="GtkButton" id="reset-disable-on-battery">
<property name="icon-name">edit-clear-symbolic</property>
<property name="tooltip-text" translatable="yes">Reset to Default Value</property>
<style>
<class name="flat" />
</style>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkListBoxRow" id="disable-on-power-save-row">
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Disable in Power-Save Mode</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkSwitch" id="disable-on-power-save">
<property name="halign">end</property>
<property name="valign">center</property>
</object>
</child>
<child>
<object class="GtkButton" id="reset-disable-on-power-save">
<property name="icon-name">edit-clear-symbolic</property>
<property name="tooltip-text" translatable="yes">Reset to Default Value</property>
<style>
<class name="flat" />
</style>
</object>
</child>
</object>
</child>
</object>
</child>
</object> </object>
</child> </child>
</object> </object>