Compare commits

...

10 commits

20 changed files with 1323 additions and 941 deletions

View file

@ -2,7 +2,7 @@ using Deskcandy.Candy;
namespace Deskcandy {
public class Application : Gtk.Application {
public signal void initialized(BaseCandy candy);
public signal void initialized(BaseCandy[] candies);
private Gtk.Window window;
private Gtk.Window desktop_window;
@ -18,15 +18,19 @@ namespace Deskcandy {
this.add_action(toggle_enabled);
this.set_up_actions();
this._candies = { new XScreensaver(), new Mpv() };
this._candies = { new XScreensaver(), new Video() };
}
private async void initialize_async() {
foreach (var candy in this._candies) {
yield candy.initialize();
try {
yield candy.initialize();
} catch (Error e) {
error(@"Failed to load candy: $(e.message)");
}
}
initialized(this._candies[1]);
initialized(this._candies);
}
private void on_toggle_enabled() {
@ -35,10 +39,12 @@ namespace Deskcandy {
private void set_up_actions() {
var a_about = new SimpleAction("about", null);
a_about.activate.connect((widget) => {
message("about...");
var about_dialog = new Gtk.AboutDialog();
about_dialog.destroy_with_parent = true;
about_dialog.transient_for = this.window;
about_dialog.modal = true;
about_dialog.present();
});
this.add_action(a_about);

View file

@ -1,9 +1,11 @@
namespace Deskcandy.Candy {
public abstract class BaseCandy : Object {
public string name { get; set; }
protected BaseCandy() {
}
public abstract async void initialize();
public abstract async void initialize() throws Error;
public abstract Subprocess launch(uint socket_id) throws Error;
}

View file

@ -1,14 +0,0 @@
namespace Deskcandy.Candy {
class Mpv : BaseCandy {
public Mpv() {
}
public override async void initialize() {
}
public override Subprocess launch(uint socket_id) throws Error {
message("Launching mpv video...");
return new Subprocess(SubprocessFlags.NONE, "mpv", @"--wid=$socket_id", "--no-audio", "--video-unscaled=downscale-big", "--video-zoom=20", "/home/vv/Videos/Sprite_Fright_-_Open_Movie_by_Blender_Studio.webm");
}
}
}

30
src/candy/video.vala Normal file
View file

@ -0,0 +1,30 @@
namespace Deskcandy.Candy {
public class Video : BaseCandy {
public bool loop { get; set; default = true; }
public double speed { get; set; default = 100.0; }
public Video() {
}
public override async void initialize() throws Error {
}
public override Subprocess launch(uint socket_id) throws Error {
message("Launching mpv video...");
var args = new Array<string>();
args.append_val("mpv");
args.append_val(@"--wid=$socket_id");
args.append_val("--no-audio");
args.append_val("--no-terminal");
// TODO: temp
args.append_val("--video-unscaled=downscale-big");
args.append_val("--video-zoom=20");
args.append_val(@"--speed=$(this.speed)");
if (this.loop) {
args.append_val("--loop");
}
args.append_val(this.name);
return new Subprocess.newv(args.steal(), SubprocessFlags.NONE);
}
}
}

View file

@ -1,21 +1,40 @@
namespace Deskcandy.Candy {
class XScreensaver : BaseCandy {
public string config_dir { get; private set; }
public string path_dir { get; private set; }
public class XScreensaver : BaseCandy {
public string config_path { get; private set; }
public string saver_path { get; private set; }
public List<XScreensaverConfig> configs;
public XScreensaver() {
this.configs = new List<XScreensaverConfig>();
}
public override async void initialize() {
public override async void initialize() throws Error {
yield this.hacky_determine_directories();
var config_dir = File.new_for_path(this.config_path);
var enumerator = yield config_dir.enumerate_children_async("standard::*", FileQueryInfoFlags.NOFOLLOW_SYMLINKS);
FileInfo info;
message(@"Parsing configs in $(this.config_path)");
while ((info = enumerator.next_file()) != null) {
var name = info.get_name();
if (!name.has_suffix(".xml")) {
continue;
}
var config = yield new XScreensaverConfig(config_dir.resolve_relative_path(name));
this.configs.append(config);
}
message(@"Found $(this.configs.length()) screensavers.");
}
public override Subprocess launch(uint socket_id) throws Error {
message("Launching XScreensaver...");
return new Subprocess(SubprocessFlags.NONE, @"$(this.path_dir)/abstractile", "-window-id", socket_id.to_string());
return new Subprocess(SubprocessFlags.NONE, @"$(this.saver_path)/$(this.name)", "-window-id", socket_id.to_string());
}
private async void hacky_determine_directories() {
// TODO: Make this a first-time thing and save to config
warning("HACK: launching xscreensaver-settings to figure out the configuration");
try {
SourceFunc callback = this.hacky_determine_directories.callback;
@ -49,11 +68,11 @@ namespace Deskcandy.Candy {
while ((line = dis.read_line_utf8()) != null) {
MatchInfo info;
if (config_dir_regex.match(line, 0, out info)) {
this.config_dir = info.fetch(1);
message(@"Found xscreensaver config dir: $(this.config_dir)");
this.config_path = info.fetch(1);
message(@"Found xscreensaver config dir: $(this.config_path)");
} else if (path_dir_regex.match(line, 0, out info)) {
this.path_dir = info.fetch(1);
message(@"Found xscreensaver path dir: $(this.path_dir)");
this.saver_path = info.fetch(1);
message(@"Found xscreensaver path dir: $(this.saver_path)");
}
}
} catch (IOError e) {

View file

@ -0,0 +1,32 @@
namespace Deskcandy.Candy {
public class XScreensaverConfig : GXml.Element {
[Description(nick="::name")]
public string name { get; set; }
[Description(nick="::_label")]
public string label { get; set; }
[Description(nick="::gl")]
public string gl { get; set; }
public string description { get; set; }
public string arg { get; set;}
public async XScreensaverConfig(File file) throws Error {
this.initialize("screensaver");
yield this.read_from_file_async(file);
var tag = this.get_child("command");
this.arg = tag.get_attribute("arg");
tag = this.get_child("_description");
this.description = tag.text_content.strip();
debug(@"Loaded $this");
}
public string to_string() {
return @"Screensaver: $(this.label) [$(this.name)]";
}
}
}

View file

@ -4,5 +4,9 @@
<file>window.ui</file>
<file>desktop_window.ui</file>
<file>main_menu.ui</file>
<file>editor_page.ui</file>
<file>presets_page.ui</file>
<file>screensaver_form.ui</file>
<file>video_form.ui</file>
</gresource>
</gresources>

View file

@ -3,7 +3,6 @@
<interface>
<requires lib="gtk+" version="3.24"/>
<template class="DeskcandyDesktopWindow" parent="GtkWindow">
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can-focus">False</property>
<property name="resizable">False</property>

View file

@ -23,19 +23,21 @@ namespace Deskcandy {
}
this.socket = new Gtk.Socket();
this.socket.set_visible(true);
this.add(this.socket);
this.socket.visible = true;
this.visible = true;
try {
this.proc = candy.launch((uint)this.socket.get_id());
//this.proc = candy.launch((uint)this.socket.get_id());
} catch (Error e) {
error(e.message);
}
}
private void on_initialized(BaseCandy candy) {
private void on_initialized(BaseCandy[] candies) {
this.present();
this.refresh_socket(candy);
this.refresh_socket(candies[0]);
}
}
}

272
src/editor_page.ui Normal file
View file

@ -0,0 +1,272 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.24"/>
<template class="DeskcandyEditorPage" parent="GtkBin">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="border-width">0</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="spacing">5</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Preset Name Goes Here</property>
<attributes>
<attribute name="weight" value="bold"/>
<attribute name="scale" value="1.25"/>
</attributes>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="action-name">editor.rename</property>
<property name="relief">none</property>
<property name="always-show-image">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">document-edit-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="placeholder-text" translatable="yes">Enter a description for the preset.</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkStackSwitcher">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="homogeneous">True</property>
<property name="stack">preset_type_stack</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkStack" id="preset_type_stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="transition-type">slide-left-right</property>
<signal name="notify::visible-child-name" handler="on_preset_type_stack_visible_child_name_notify" swapped="no"/>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="spacing">5</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Opacity</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScale" id="opacity_range">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="adjustment">opacity_adjustment</property>
<property name="round-digits">0</property>
<property name="digits">0</property>
<property name="value-pos">left</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkExpander">
<property name="visible">True</property>
<property name="can-focus">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="border-width">5</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property>
<child>
<object class="GtkCheckButton" id="low_priority_check">
<property name="label" translatable="yes">Low CPU Priority</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="spacing">5</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Extra Options</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkEntry" id="extra_options">
<property name="visible">True</property>
<property name="can-focus">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Advanced</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">5</property>
</packing>
</child>
<child>
<object class="GtkButtonBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkButton" id="cancel_edit_preset_button">
<property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<signal name="clicked" handler="on_cancel_edit_preset_button_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="save_preset_button">
<property name="label" translatable="yes">Save</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="action-name">presets.save</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">7</property>
</packing>
</child>
</object>
</child>
</template>
<object class="GtkAdjustment" id="opacity_adjustment">
<property name="upper">100</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
</object>
</interface>

47
src/editor_page.vala Normal file
View file

@ -0,0 +1,47 @@
using Deskcandy.Candy;
namespace Deskcandy {
[GtkTemplate(ui = "/moe/solarpunk/Deskcandy/editor_page.ui")]
public class EditorPage : Gtk.Bin {
public signal void preset_type_changed(string type);
[GtkChild]
private unowned Gtk.Stack preset_type_stack;
private new unowned Window parent;
private ScreensaverForm screensaver_form;
private VideoForm video_form;
public EditorPage(Window parent) {
this.parent = parent;
this.screensaver_form = new ScreensaverForm();
this.preset_type_stack.add_titled(screensaver_form, "screensaver", "Screen Saver");
this.video_form = new VideoForm();
this.preset_type_stack.add_titled(video_form, "video", "Video");
}
public void on_initialized(BaseCandy[] candies) {
// TODO: clean this up
this.screensaver_form.on_initialized((XScreensaver)candies[0]);
this.video_form.on_initialized((Video)candies[1]);
}
[GtkCallback]
private void on_preset_type_stack_visible_child_name_notify(Object o, ParamSpec param) {
if (this.preset_type_stack.visible_child_name == null) {
return;
}
message(@"preset type: $(this.preset_type_stack.visible_child_name)");
preset_type_changed(this.preset_type_stack.visible_child_name);
}
[GtkCallback]
private void on_cancel_edit_preset_button_clicked(Gtk.Widget w) {
this.parent.main_stack.visible_child_name = "presets";
}
}
}

View file

@ -3,15 +3,21 @@ deskcandy_sources = [
'window.vala',
'desktop_window.vala',
'application.vala',
'editor_page.vala',
'presets_page.vala',
'screensaver_form.vala',
'video_form.vala',
'candy/base.vala',
'candy/xscreensaver.vala',
'candy/mpv.vala'
'candy/xscreensaver_config.vala',
'candy/video.vala'
]
deskcandy_deps = [
dependency('gio-2.0', version: '>= 2.50'),
dependency('gtk+-3.0', version: '>= 3.22'),
dependency('gxml-0.20', version: '>= 0.20'),
]
gnome = import('gnome')

376
src/presets_page.ui Normal file
View file

@ -0,0 +1,376 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.24"/>
<template class="DeskcandyPresetsPage" parent="GtkBin">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkBox" id="presets_page">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property>
<child>
<object class="GtkSearchEntry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="primary-icon-name">edit-find-symbolic</property>
<property name="primary-icon-activatable">False</property>
<property name="primary-icon-sensitive">False</property>
<property name="placeholder-text" translatable="yes">Search for presets</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkTreeView" id="presets_list">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="model">presets_liststore</property>
<property name="headers-clickable">False</property>
<property name="search-column">0</property>
<property name="fixed-height-mode">True</property>
<property name="activate-on-single-click">True</property>
<child internal-child="selection">
<object class="GtkTreeSelection"/>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="sizing">fixed</property>
<property name="fixed-width">30</property>
<child>
<object class="GtkCellRendererToggle" id="preset_enabled">
<property name="radio">True</property>
</object>
<attributes>
<attribute name="active">2</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="resizable">True</property>
<property name="sizing">fixed</property>
<property name="title" translatable="yes">Name</property>
<property name="clickable">True</property>
<property name="sort-column-id">0</property>
<child>
<object class="GtkCellRendererText" id="preset_name"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="resizable">True</property>
<property name="sizing">fixed</property>
<property name="title" translatable="yes">Description</property>
<property name="clickable">True</property>
<property name="sort-column-id">1</property>
<child>
<object class="GtkCellRendererText" id="preset_description"/>
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButtonBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="spacing">5</property>
<property name="layout-style">end</property>
<child>
<object class="GtkButton">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="relief">none</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">document-edit-symbolic</property>
<property name="icon_size">2</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkMenuButton" id="delete_preset_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="focus-on-click">False</property>
<property name="receives-default">True</property>
<property name="relief">none</property>
<property name="direction">up</property>
<property name="popover">delete_preset_confirm</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">list-remove-symbolic</property>
<property name="icon_size">2</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkMenuButton" id="add_preset">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="focus-on-click">False</property>
<property name="receives-default">True</property>
<property name="relief">none</property>
<property name="popover">new_preset_popover</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">list-add-symbolic</property>
<property name="icon_size">2</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</template>
<object class="GtkPopover" id="delete_preset_confirm">
<property name="width-request">150</property>
<property name="can-focus">False</property>
<property name="border-width">10</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Confirm Delete</property>
<property name="xalign">0</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="padding">5</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Are you sure you want to delete this preset?</property>
<property name="wrap">True</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButtonBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="spacing">5</property>
<property name="layout-style">end</property>
<child>
<object class="GtkButton" id="cancel_delete_preset_button">
<property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="can-default">True</property>
<property name="has-default">True</property>
<property name="receives-default">True</property>
<signal name="clicked" handler="on_cancel_delete_preset_button_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="confirm_delete_preset_button">
<property name="label" translatable="yes">Delete</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="action-name">presets.delete</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkPopover" id="new_preset_popover">
<property name="width-request">150</property>
<property name="can-focus">False</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="border-width">10</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">New Preset</property>
<property name="xalign">0</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Enter a name for the new preset:</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkEntry">
<property name="visible">True</property>
<property name="can-focus">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButtonBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="spacing">5</property>
<property name="layout-style">end</property>
<child>
<object class="GtkButton" id="cancel_new_preset_button">
<property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<signal name="clicked" handler="on_cancel_new_preset_button_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="confirm_new_preset_button">
<property name="label" translatable="yes">Create</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="can-default">True</property>
<property name="has-default">True</property>
<property name="receives-default">True</property>
<property name="action-name">presets.create</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
</child>
</object>
<object class="GtkListStore" id="presets_liststore">
<columns>
<!-- column-name name -->
<column type="gchararray"/>
<!-- column-name description -->
<column type="gchararray"/>
<!-- column-name enabled -->
<column type="gboolean"/>
</columns>
</object>
</interface>

44
src/presets_page.vala Normal file
View file

@ -0,0 +1,44 @@
namespace Deskcandy {
[GtkTemplate(ui = "/moe/solarpunk/Deskcandy/presets_page.ui")]
public class PresetsPage : Gtk.Bin {
private new unowned Window parent;
public PresetsPage(Window parent) {
this.parent = parent;
var preset_action_group = new SimpleActionGroup();
var create_preset = new SimpleAction("create", null);
preset_action_group.add_action(create_preset);
create_preset.activate.connect(this.on_create_preset);
var delete_preset = new SimpleAction("delete", null);
delete_preset.activate.connect(this.on_delete_preset);
preset_action_group.add_action(delete_preset);
this.insert_action_group("presets", preset_action_group);
}
private void on_create_preset(SimpleAction a, Variant? v) {
this.parent.main_stack.visible_child_name = "editor";
}
private void on_delete_preset(SimpleAction a, Variant? v) {
message("delete");
}
[GtkCallback]
private void on_cancel_new_preset_button_clicked(Gtk.Widget w) {
var popover = (Gtk.Popover)w.get_ancestor(typeof(Gtk.Popover));
popover.popdown();
this.parent.main_stack.visible_child_name = "presets";
}
[GtkCallback]
private void on_cancel_delete_preset_button_clicked(Gtk.Widget w) {
var popover = (Gtk.Popover)w.get_ancestor(typeof(Gtk.Popover));
popover.popdown();
}
}
}

76
src/screensaver_form.ui Normal file
View file

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.24"/>
<template class="DeskcandyScreensaverForm" parent="GtkBin">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">5</property>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkTreeView" id="screensaver_chooser">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="model">screensavers_liststore</property>
<property name="headers-clickable">False</property>
<property name="search-column">0</property>
<property name="activate-on-single-click">True</property>
<signal name="row-activated" handler="on_screensaver_chooser_row_activated" swapped="no"/>
<child>
<object class="GtkTreeViewColumn">
<property name="resizable">True</property>
<property name="title" translatable="yes">Name</property>
<child>
<object class="GtkCellRendererText" id="ss_name"/>
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkTreeViewColumn">
<property name="resizable">True</property>
<property name="title" translatable="yes">Description</property>
<child>
<object class="GtkCellRendererText" id="ss_description">
<property name="single-paragraph-mode">True</property>
</object>
<attributes>
<attribute name="text">1</attribute>
</attributes>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</template>
<object class="GtkListStore" id="screensavers_liststore">
<columns>
<!-- column-name label -->
<column type="gchararray"/>
<!-- column-name description -->
<column type="gchararray"/>
<!-- column-name name -->
<column type="gchararray"/>
</columns>
</object>
</interface>

32
src/screensaver_form.vala Normal file
View file

@ -0,0 +1,32 @@
using Deskcandy.Candy;
namespace Deskcandy {
[GtkTemplate(ui = "/moe/solarpunk/Deskcandy/screensaver_form.ui")]
public class ScreensaverForm : Gtk.Bin {
[GtkChild]
private unowned Gtk.ListStore screensavers_liststore;
private unowned XScreensaver xss;
public void on_initialized(XScreensaver xss) {
this.xss = xss;
Gtk.TreeIter iter;
this.screensavers_liststore.clear();
foreach (XScreensaverConfig config in xss.configs) {
this.screensavers_liststore.append(out iter);
this.screensavers_liststore.set(iter, 0, config.label, 1, config.description, 2, config.name);
}
}
[GtkCallback]
private void on_screensaver_chooser_row_activated(Gtk.TreeView treeview, Gtk.TreePath path, Gtk.TreeViewColumn col) {
Gtk.TreeIter iter;
if (treeview.model.get_iter(out iter, path)) {
string name;
treeview.model.get(iter, 2, out name);
this.xss.name = name;
}
}
}
}

99
src/video_form.ui Normal file
View file

@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.24"/>
<template class="DeskcandyVideoForm" parent="GtkBin">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkFileChooserButton" id="video_chooser">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="valign">start</property>
<property name="filter">video_file_filter</property>
<property name="title" translatable="yes">Select Video</property>
<signal name="file-set" handler="on_video_property_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="spacing">5</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Speed</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScale" id="video_speed_slider">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="adjustment">video_speed_adjustment</property>
<property name="round-digits">2</property>
<property name="digits">2</property>
<property name="value-pos">left</property>
<signal name="value-changed" handler="on_video_property_changed" swapped="no"/>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="video_loop_checkbox">
<property name="label" translatable="yes">Loop</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="active">True</property>
<property name="draw-indicator">True</property>
<signal name="toggled" handler="on_video_property_changed" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</template>
<object class="GtkFileFilter" id="video_file_filter">
<mime-types>
<mime-type>video/*</mime-type>
</mime-types>
</object>
<object class="GtkAdjustment" id="video_speed_adjustment">
<property name="lower">0.01</property>
<property name="upper">5</property>
<property name="value">1</property>
<property name="step-increment">0.01</property>
<property name="page-increment">0.10</property>
</object>
</interface>

27
src/video_form.vala Normal file
View file

@ -0,0 +1,27 @@
using Deskcandy.Candy;
namespace Deskcandy {
[GtkTemplate(ui = "/moe/solarpunk/Deskcandy/video_form.ui")]
public class VideoForm : Gtk.Bin {
[GtkChild]
private unowned Gtk.FileChooserButton video_chooser;
[GtkChild]
private unowned Gtk.CheckButton video_loop_checkbox;
[GtkChild]
private unowned Gtk.Range video_speed_slider;
private unowned Video video;
public void on_initialized(Video video) {
this.video = video;
}
[GtkCallback]
private void on_video_property_changed() {
this.video.name = this.video_chooser.get_filename();
this.video.loop = this.video_loop_checkbox.get_active();
this.video.speed = this.video_speed_slider.get_value();
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -9,54 +9,75 @@ namespace Deskcandy {
[GtkChild]
private unowned Gtk.MenuButton open_menu_button;
[GtkChild]
private unowned Gtk.Box preview;
private unowned Gtk.Bin preview;
[GtkChild]
private unowned Gtk.HeaderBar headerbar;
public unowned Gtk.Stack main_stack { get; private set; }
[GtkChild]
private unowned Gtk.Stack main_stack;
private unowned Gtk.Label candy_status;
private BaseCandy active_candy;
private Subprocess proc;
private XScreensaver xss;
private Video video;
private EditorPage editor_page;
public Window (Application app) {
Object (application: app);
var preset_action_group = new SimpleActionGroup();
var create_preset = new SimpleAction("create", null);
preset_action_group.add_action(create_preset);
create_preset.activate.connect(this.on_create_preset);
var delete_preset = new SimpleAction("delete", null);
delete_preset.activate.connect(this.on_delete_preset);
preset_action_group.add_action(delete_preset);
this.insert_action_group("presets", preset_action_group);
var builder = new Gtk.Builder.from_resource("/moe/solarpunk/Deskcandy/main_menu.ui");
var menu = (GLib.MenuModel)builder.get_object("main_menu");
this.open_menu_button.menu_model = menu;
app.initialized.connect(this.on_initialized);
app.notify["enabled"].connect(this.on_notify_enabled);
var presets_page = new PresetsPage(this);
this.main_stack.add_titled(presets_page, "presets", "Presets");
this.editor_page = new EditorPage(this);
this.editor_page.preset_type_changed.connect(this.on_preset_type_changed);
this.main_stack.add_titled(this.editor_page, "editor", "Edit Preset");
}
public void on_initialized(BaseCandy candy) {
this.refresh_socket(candy);
public void on_initialized(BaseCandy[] candies) {
this.xss = (XScreensaver)candies[0];
this.video = (Video)candies[1];
this.active_candy = this.xss;
foreach (BaseCandy candy in candies) {
candy.notify.connect(this.refresh_socket);
}
this.editor_page.on_initialized(candies);
}
private void refresh_socket(BaseCandy candy) {
private void on_preset_type_changed(string type) {
switch (type) {
case "video":
this.active_candy = this.video;
break;
case "screensaver":
this.active_candy = this.xss;
break;
}
if (this.active_candy.name != null && this.active_candy.name != "") {
this.refresh_socket();
}
}
private void refresh_socket() {
if (this.socket != null) {
this.preview.remove(this.socket);
this.proc.send_signal(15);
}
this.socket = new Gtk.Socket();
this.socket.realize();
this.socket.expand = true;
this.socket.visible = true;
this.preview.add(this.socket);
try {
this.proc = candy.launch((uint)this.socket.get_id());
this.proc = this.active_candy.launch((uint)this.socket.get_id());
} catch (Error e) {
error(e.message);
}
@ -68,35 +89,18 @@ namespace Deskcandy {
this.application.quit();
}
private void on_create_preset(SimpleAction a, Variant? v) {
this.main_stack.visible_child_name = "editor_page";
}
[GtkCallback]
private void on_cancel_edit_preset_button_clicked(Gtk.Widget w) {
this.main_stack.visible_child_name = "presets_page";
}
private void on_main_stack_visible_child_name_notify(Object o, ParamSpec param) {
if (this.main_stack.visible_child_name == null) {
return;
}
[GtkCallback]
private void on_cancel_new_preset_button_clicked(Gtk.Widget w) {
var popover = (Gtk.Popover)w.get_ancestor(typeof(Gtk.Popover));
popover.popdown();
this.main_stack.visible_child_name = "presets_page";
}
[GtkCallback]
private void on_cancel_delete_preset_button_clicked(Gtk.Widget w) {
var popover = (Gtk.Popover)w.get_ancestor(typeof(Gtk.Popover));
popover.popdown();
}
private void on_delete_preset(SimpleAction a, Variant? v) {
message("delete");
message(@"page: $(this.main_stack.visible_child_name)");
}
private void on_notify_enabled(Object o, GLib.ParamSpec param) {
var val = ((Application)o).enabled;
this.headerbar.subtitle = val ? "started" : "stopped";
this.candy_status.label = val ? "Candy started" : "Candy stopped";
}
}
}