You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
330 lines
10 KiB
330 lines
10 KiB
'use strict';
|
|
|
|
const {Gdk, Gio, GLib, Gtk, GObject} = imports.gi;
|
|
|
|
const Util = imports.util;
|
|
const Widgets = imports.widgets;
|
|
const LibSnapcast = imports.snapcast;
|
|
const Avahi = imports.avahi;
|
|
|
|
var SnapControlWindow = GObject.registerClass({
|
|
Template: Util.getBuilderFile('appwindow.ui')
|
|
, InternalChildren: [
|
|
'storeServerProps'
|
|
, 'storeServers'
|
|
, 'titlebar'
|
|
, 'cbtServers'
|
|
, 'spinner'
|
|
, 'btnInfo'
|
|
, 'btnAppMenu'
|
|
, 'vBox'
|
|
, 'labelState'
|
|
, 'popoverConfig'
|
|
]
|
|
}, class SnapControlWindow extends Gtk.ApplicationWindow {
|
|
_init(params) {
|
|
super._init(Object.assign({
|
|
title: _("Snapcast Control")
|
|
, role: _("Snapcast Control")
|
|
, 'show-menubar': false
|
|
, 'icon-name': pkg.id
|
|
, name: 'snap-control-window'
|
|
}, params));
|
|
|
|
this._settings = Util.getSettings(pkg.id);
|
|
this._btnAppMenu.set_menu_model(this.application.get_app_menu());
|
|
|
|
this.AS = new Avahi.AvahiSnapcast();
|
|
this.AS.connect('added', (AS, server) => {
|
|
// XXX: Check if not exists
|
|
this._storeServers.set(
|
|
this._storeServers.append()
|
|
, [0, 1, 2, 3, 4, 5]
|
|
, [server.name, server.hostname.toLowerCase(), server.domain, server.ip, server.port, false]
|
|
);
|
|
this._cbtServers.set_sensitive(true);
|
|
if (this.snapcast._state == LibSnapcast.ClientStates.connected) {
|
|
let [tie, iter] = this._storeServers.get_iter_first();
|
|
let model = this._cbtServers.get_model();
|
|
while (tie) {
|
|
let host = [this._storeServers.get_value(iter, 3), this._storeServers.get_value(iter, 4)].join(':');
|
|
if (host === this.snapcast.host) {
|
|
this._cbtServers.set_active_iter(iter);
|
|
break;
|
|
}
|
|
tie = this._storeServers.iter_next(iter);
|
|
}
|
|
} else if (this._cbtServers.get_active() === -1) {
|
|
this._cbtServers.set_active(0);
|
|
}
|
|
});
|
|
|
|
this.AS.connect('removed', (AS, name) => {
|
|
let [tie, iter] = this._storeServers.get_iter_first();
|
|
let model = this._cbtServers.get_model();
|
|
while (tie) {
|
|
if (this._storeServers.get_value(iter, 0) === name) {
|
|
if (this._storeServers.get_value(iter, 5) === false) {
|
|
this._storeServers.remove(iter);
|
|
}
|
|
break;
|
|
}
|
|
tie = this._storeServers.iter_next(iter);
|
|
}
|
|
if (this._cbtServers.get_active() === -1) {
|
|
this._cbtServers.set_active(0);
|
|
}
|
|
});
|
|
|
|
this._spinner.start();
|
|
|
|
this._popoverConfig.connect('closed', () => {
|
|
this._btnInfo.set_active(false);
|
|
});
|
|
this._btnInfo.connect('toggled', (btn) => {
|
|
if (btn.get_active()) {
|
|
this._popoverConfig.set_relative_to(this._btnInfo);
|
|
//this._popoverConfig.show_all();
|
|
this._popoverConfig.popup();
|
|
} else {
|
|
this._popoverConfig.popdown();
|
|
}
|
|
});
|
|
/*
|
|
this._cbtServers.set_has_tooltip(true);
|
|
this._cbtServers.connect('query-tooltip', (widget, x, y, keyboar_mode, tooltip) => {
|
|
this._popoverConfig.set_relative_to(widget);
|
|
this._popoverConfig.show_all();
|
|
this._popoverConfig.popup();
|
|
log(this._popoverConfig);
|
|
return false;
|
|
});
|
|
*/
|
|
this._btnAppMenu = new Gtk.MenuButton();
|
|
this._btnAppMenu.set_menu_model(this.application.get_app_menu());
|
|
this._btnAppMenu.set_image(new Gtk.Image({ 'icon-name': 'open-menu-symbolic' }));
|
|
|
|
this.show_all();
|
|
|
|
let lastUsed = this._settings.get_string('last-used');
|
|
this.snapcast = new LibSnapcast.Snapcast(lastUsed);
|
|
this.snapcast.connect("state::ready", this._on_snapcast_ready.bind(this));
|
|
this.snapcast.connect("state::disconnected", this._on_snapcast_disconnected.bind(this));
|
|
this.snapcast.connect("state::connecting", this._on_snapcast_connecting.bind(this));
|
|
this.snapcast.connect("updated", this._on_snapcast_updated.bind(this));
|
|
this.snapcast.enable();
|
|
|
|
this._cbtServers.connect('changed', (combo) => {
|
|
let [tie, tree_iter] = combo.get_active_iter();
|
|
let activeItem = combo.get_active();
|
|
let model = combo.get_model();
|
|
if (tie) {
|
|
let hostname = this._storeServers.get_value(tree_iter, 1)
|
|
, domain = this._storeServers.get_value(tree_iter, 2)
|
|
, ip = this._storeServers.get_value(tree_iter, 3)
|
|
, port = this._storeServers.get_value(tree_iter, 4)
|
|
, host;
|
|
if (ip !== "") {
|
|
host = ip;
|
|
} else {
|
|
host = hostname;
|
|
if (domain !== "") {
|
|
host += '.' + domain;
|
|
}
|
|
}
|
|
if (port === "") {
|
|
port = 1705;
|
|
}
|
|
this.snapcast.host = [host, port].join(':');
|
|
}
|
|
});
|
|
|
|
this.AS.enable();
|
|
}
|
|
|
|
_on_snapcast_updated() {
|
|
log("SNAPCAST_UPDATED");
|
|
this.updateInfoPopover();
|
|
//this._popoverConfig.add(this.buildInfoPopover());
|
|
}
|
|
|
|
_on_snapcast_disconnected() {
|
|
log("SNAPCAST_DISCONNECTED");
|
|
this._titlebar.set_subtitle(_("Disconnected"));
|
|
this._vBox.foreach((child) => {
|
|
if (child instanceof Widgets.GroupWidget) {
|
|
this._vBox.remove(child);
|
|
}
|
|
});
|
|
if (this._popoverConfig.is_visible()) {
|
|
this._popoverConfig.popdown();
|
|
}
|
|
this._btnInfo.set_sensitive(false);
|
|
this._btnInfo.set_visible(false);
|
|
this._labelState.set_visible(true);
|
|
}
|
|
|
|
_on_snapcast_connecting() {
|
|
this._spinner.start();
|
|
this._spinner.set_visible(true);
|
|
}
|
|
|
|
_on_snapcast_ready() {
|
|
log("SNAPCAST_READY");
|
|
this._titlebar.set_subtitle(_("Connected"));
|
|
this._settings.set_string('last-used', this.snapcast.host);
|
|
this._labelState.set_visible(false);
|
|
this._spinner.stop();
|
|
this._spinner.set_visible(false);
|
|
this._btnInfo.set_sensitive(true);
|
|
this._btnInfo.set_visible(true);
|
|
this.snapcast.sServer.connect("streams::added", this._on_snapcast_stream_added.bind(this));
|
|
this.snapcast.sServer.connect("streams::deleted", this._on_snapcast_stream_deleted.bind(this));
|
|
this.snapcast.sServer.connect("groups::added", this._on_snapcast_group_added.bind(this));
|
|
this.snapcast.sServer.connect("groups::deleted", this._on_snapcast_group_deleted.bind(this));
|
|
this.snapcast.sServer.connect("clients::added", this._on_snapcast_client_added.bind(this));
|
|
this.snapcast.sServer.connect("clients::deleted", this._on_snapcast_client_deleted.bind(this));
|
|
}
|
|
|
|
_on_snapcast_stream_added() {
|
|
// XXX
|
|
}
|
|
|
|
_on_snapcast_stream_deleted() {
|
|
// XXX
|
|
}
|
|
|
|
_on_snapcast_group_added(event, group) {
|
|
this._vBox.add(new Widgets.GroupWidget(this, this.snapcast, group));
|
|
this._refresh_window_size();
|
|
}
|
|
|
|
_on_snapcast_group_deleted(event, group_id) {
|
|
this._refresh_window_size();
|
|
}
|
|
|
|
_on_snapcast_client_added(event, client) {
|
|
this._refresh_window_size();
|
|
}
|
|
|
|
_on_snapcast_client_deleted(event, client) {
|
|
this._refresh_window_size();
|
|
}
|
|
|
|
_refresh_window_size() {
|
|
let [wm, wn] = this.get_preferred_width();
|
|
let [hm, hn] = this._vBox.get_preferred_height();
|
|
let [thm, thn] = this._titlebar.get_preferred_height();
|
|
let ch = 0;
|
|
this._vBox.get_children().forEach((child) => {
|
|
let [chm, chn] = child.get_preferred_height();
|
|
ch = ch + chn + (this._vBox.get_spacing() * 2);
|
|
});
|
|
ch += this._vBox.get_parent().get_margin_top() + this._vBox.get_parent().get_margin_bottom();
|
|
let nh = thn + this._vBox.get_margin_top() + this._vBox.get_margin_bottom() + ch;
|
|
let display = this.get_display();
|
|
let monitor = display.get_monitor_at_window(this.get_window());
|
|
let wa = monitor.get_workarea();
|
|
if (nh > wa.height - thn) {
|
|
nh = wa.height - thn;
|
|
}
|
|
this.resize(wn, nh);
|
|
}
|
|
|
|
updateInfoPopover() {
|
|
this._storeServerProps.clear();
|
|
let props = this.snapcast.sServer.server;
|
|
this._storeServerProps.set(this._storeServerProps.append(), [0,1],
|
|
[_("Name: "), props.snapserver.name]);
|
|
this._storeServerProps.set(this._storeServerProps.append(), [0,1],
|
|
[_("Hostname: "), props.host.name]);
|
|
this._storeServerProps.set(this._storeServerProps.append(), [0,1],
|
|
[_("Operating System: "), props.host.os]);
|
|
if (props.host.arch !== "") {
|
|
this._storeServerProps.set(this._storeServerProps.append(), [0,1],
|
|
[_("Architecture: "), props.host.arch]);
|
|
}
|
|
this._storeServerProps.set(this._storeServerProps.append(), [0,1],
|
|
[_("Snapserver Version: "), props.snapserver.version]);
|
|
this._storeServerProps.set(this._storeServerProps.append(), [0,1],
|
|
[_("Protocol Version: "), props.snapserver.protocolVersion]);
|
|
this._storeServerProps.set(this._storeServerProps.append(), [0,1],
|
|
[_("Control Version: "), props.snapserver.controlProtocolVersion]);
|
|
this._storeServerProps.set(this._storeServerProps.append(), [0,1],
|
|
[_("Streams: "), Object.keys(this.snapcast.sServer.streams).length]);
|
|
}
|
|
|
|
showServersWindow() {
|
|
log('SHOW SERVER WINDOWS');
|
|
let modal = new Gtk.Dialog({
|
|
default_width: 250
|
|
, modal: true
|
|
, transient_for: this
|
|
, title: _("Servers")
|
|
, use_header_bar: false
|
|
});
|
|
|
|
let contentArea = modal.get_content_area()
|
|
, actionArea = modal.get_action_area();
|
|
|
|
let treeview = new Gtk.TreeView({
|
|
model: this._storeServers
|
|
, 'headers-visible': false
|
|
});
|
|
let sel = treeview.get_selection();
|
|
sel.set_mode(Gtk.SelectionMode.NONE);
|
|
|
|
let renderer0 = new Gtk.CellRendererText();
|
|
let renderer1 = new Gtk.CellRendererText();
|
|
let renderer2 = new Gtk.CellRendererText();
|
|
let renderer3 = new Gtk.CellRendererText();
|
|
let renderer4 = new Gtk.CellRendererText();
|
|
let renderer5 = new Gtk.CellRendererText();
|
|
|
|
let column0 = new Gtk.TreeViewColumn({ title: "ID" });
|
|
let column1 = new Gtk.TreeViewColumn({ title: "Hostname" });
|
|
let column2 = new Gtk.TreeViewColumn({ title: "Domain" });
|
|
let column3 = new Gtk.TreeViewColumn({ title: "IP" });
|
|
let column4 = new Gtk.TreeViewColumn({ title: "Port" });
|
|
let column5 = new Gtk.TreeViewColumn({ title: "Manual" });
|
|
|
|
column0.pack_start(renderer0, false);
|
|
column0.add_attribute(renderer0, "text", 0);
|
|
column1.pack_start(renderer1, false);
|
|
column1.add_attribute(renderer1, "text", 1);
|
|
column2.pack_start(renderer2, false);
|
|
column2.add_attribute(renderer2, "text", 2);
|
|
column2.pack_start(renderer3, false);
|
|
column2.add_attribute(renderer3, "text", 3);
|
|
column2.pack_start(renderer4, false);
|
|
column2.add_attribute(renderer4, "text", 4);
|
|
column2.pack_start(renderer5, false);
|
|
column2.add_attribute(renderer5, "text", 5);
|
|
|
|
treeview.append_column(column0);
|
|
treeview.append_column(column1);
|
|
treeview.append_column(column2);
|
|
treeview.append_column(column3);
|
|
treeview.append_column(column4);
|
|
treeview.append_column(column5);
|
|
|
|
treeview.set_margin_top(10);
|
|
treeview.set_margin_bottom(10);
|
|
|
|
contentArea.add(treeview);
|
|
|
|
let boxBtn = new Gtk.ButtonBox({
|
|
orientation: Gtk.Orientation.HORIZONTAL
|
|
});
|
|
boxBtn.set_layout(Gtk.ButtonBoxStyle.EDGE);
|
|
let btnOk = Gtk.Button.new_from_stock(Gtk.STOCK_OK);
|
|
btnOk.connect("clicked", () => {
|
|
modal.close();
|
|
});
|
|
boxBtn.add(btnOk);
|
|
actionArea.add(boxBtn);
|
|
|
|
modal.show_all();
|
|
}
|
|
});
|