forked from brl/citadel-tools
Not used anymore
This commit is contained in:
parent
9760dfc501
commit
79fb3b38dd
@ -1,19 +0,0 @@
|
||||
[package]
|
||||
name = "citadel-realms-ui"
|
||||
description = "Citadel Realms UI"
|
||||
version = "0.1.0"
|
||||
authors = ["Bruce Leidl <bruce@subgraph.com>"]
|
||||
edition = "2018"
|
||||
homepage = "https://subgraph,com"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
dbus = "0.8"
|
||||
nix = "0.17.0"
|
||||
fuzzy-matcher = "0.3.7"
|
||||
gtk = "0.9.0"
|
||||
gdk = "0.13.2"
|
||||
gio = "0.9.1"
|
||||
glib = "0.10.2"
|
||||
pango = "0.9.1"
|
@ -1,202 +0,0 @@
|
||||
# Auto-Generated by cargo-bitbake 0.3.14
|
||||
#
|
||||
inherit cargo
|
||||
|
||||
# If this is git based prefer versioned ones if they exist
|
||||
# DEFAULT_PREFERENCE = "-1"
|
||||
|
||||
# how to get citadel-realms-ui could be as easy as but default to a git checkout:
|
||||
# SRC_URI += "crate://crates.io/citadel-realms-ui/0.1.0"
|
||||
SRC_URI += "git://github.com/mckinney-subgraph/citadel-tools;protocol=https;nobranch=1;branch=installer_ui"
|
||||
SRCREV = "695dc9da2115f5f3f731b711b4b127b45d7a137f"
|
||||
S = "${WORKDIR}/git"
|
||||
CARGO_SRC_DIR = "citadel-realms-ui"
|
||||
PV_append = ".AUTOINC+695dc9da21"
|
||||
|
||||
# please note if you have entries that do not begin with crate://
|
||||
# you must change them to how that package can be fetched
|
||||
SRC_URI += " \
|
||||
crate://crates.io/addr2line/0.12.1 \
|
||||
crate://crates.io/adler32/1.1.0 \
|
||||
crate://crates.io/ansi_term/0.11.0 \
|
||||
crate://crates.io/anyhow/1.0.33 \
|
||||
crate://crates.io/arc-swap/0.4.7 \
|
||||
crate://crates.io/array-macro/1.0.3 \
|
||||
crate://crates.io/atk-sys/0.10.0 \
|
||||
crate://crates.io/atk/0.9.0 \
|
||||
crate://crates.io/atty/0.2.14 \
|
||||
crate://crates.io/autocfg/1.0.0 \
|
||||
crate://crates.io/backtrace/0.3.49 \
|
||||
crate://crates.io/bincode/1.2.1 \
|
||||
crate://crates.io/bitflags/1.2.1 \
|
||||
crate://crates.io/block-buffer/0.9.0 \
|
||||
crate://crates.io/block-cipher/0.7.1 \
|
||||
crate://crates.io/blowfish/0.5.0 \
|
||||
crate://crates.io/byteorder/1.3.4 \
|
||||
crate://crates.io/cairo-rs/0.9.1 \
|
||||
crate://crates.io/cairo-sys-rs/0.10.0 \
|
||||
crate://crates.io/cc/1.0.54 \
|
||||
crate://crates.io/cfg-if/0.1.10 \
|
||||
crate://crates.io/chrono/0.4.11 \
|
||||
crate://crates.io/clap/2.33.1 \
|
||||
crate://crates.io/cpuid-bool/0.1.2 \
|
||||
crate://crates.io/crc32fast/1.2.0 \
|
||||
crate://crates.io/crossbeam-channel/0.3.9 \
|
||||
crate://crates.io/crossbeam-utils/0.6.6 \
|
||||
crate://crates.io/crypto-mac/0.8.0 \
|
||||
crate://crates.io/cursive/0.11.0 \
|
||||
crate://crates.io/dbus/0.6.5 \
|
||||
crate://crates.io/dbus/0.8.4 \
|
||||
crate://crates.io/digest/0.9.0 \
|
||||
crate://crates.io/either/1.6.1 \
|
||||
crate://crates.io/enum-map-derive/0.4.3 \
|
||||
crate://crates.io/enum-map-internals/0.1.3 \
|
||||
crate://crates.io/enum-map/0.5.0 \
|
||||
crate://crates.io/enumset/0.3.19 \
|
||||
crate://crates.io/enumset_derive/0.3.2 \
|
||||
crate://crates.io/failure/0.1.8 \
|
||||
crate://crates.io/failure_derive/0.1.8 \
|
||||
crate://crates.io/filetime/0.2.10 \
|
||||
crate://crates.io/futures-channel/0.3.6 \
|
||||
crate://crates.io/futures-core/0.3.6 \
|
||||
crate://crates.io/futures-executor/0.3.6 \
|
||||
crate://crates.io/futures-io/0.3.6 \
|
||||
crate://crates.io/futures-macro/0.3.6 \
|
||||
crate://crates.io/futures-sink/0.3.6 \
|
||||
crate://crates.io/futures-task/0.3.6 \
|
||||
crate://crates.io/futures-util/0.3.6 \
|
||||
crate://crates.io/futures/0.3.6 \
|
||||
crate://crates.io/fuzzy-matcher/0.3.7 \
|
||||
crate://crates.io/gdk-pixbuf-sys/0.10.0 \
|
||||
crate://crates.io/gdk-pixbuf/0.9.0 \
|
||||
crate://crates.io/gdk-sys/0.10.0 \
|
||||
crate://crates.io/gdk/0.13.2 \
|
||||
crate://crates.io/generic-array/0.14.4 \
|
||||
crate://crates.io/getrandom/0.1.15 \
|
||||
crate://crates.io/gimli/0.21.0 \
|
||||
crate://crates.io/gio-sys/0.10.1 \
|
||||
crate://crates.io/gio/0.9.1 \
|
||||
crate://crates.io/glib-macros/0.10.1 \
|
||||
crate://crates.io/glib-sys/0.10.1 \
|
||||
crate://crates.io/glib/0.10.2 \
|
||||
crate://crates.io/gobject-sys/0.10.0 \
|
||||
crate://crates.io/gtk-sys/0.10.0 \
|
||||
crate://crates.io/gtk/0.9.2 \
|
||||
crate://crates.io/heck/0.3.1 \
|
||||
crate://crates.io/hermit-abi/0.1.14 \
|
||||
crate://crates.io/hex/0.4.2 \
|
||||
crate://crates.io/hmac/0.8.1 \
|
||||
crate://crates.io/inotify-sys/0.1.3 \
|
||||
crate://crates.io/inotify/0.8.3 \
|
||||
crate://crates.io/itertools/0.9.0 \
|
||||
crate://crates.io/lazy_static/1.4.0 \
|
||||
crate://crates.io/libc/0.2.71 \
|
||||
crate://crates.io/libdbus-sys/0.2.1 \
|
||||
crate://crates.io/libflate/0.1.27 \
|
||||
crate://crates.io/libsodium-sys/0.2.5 \
|
||||
crate://crates.io/log/0.4.8 \
|
||||
crate://crates.io/md-5/0.9.1 \
|
||||
crate://crates.io/memchr/2.3.3 \
|
||||
crate://crates.io/miniz_oxide/0.3.7 \
|
||||
crate://crates.io/nix/0.17.0 \
|
||||
crate://crates.io/num-complex/0.2.4 \
|
||||
crate://crates.io/num-integer/0.1.43 \
|
||||
crate://crates.io/num-iter/0.1.41 \
|
||||
crate://crates.io/num-rational/0.2.4 \
|
||||
crate://crates.io/num-traits/0.2.12 \
|
||||
crate://crates.io/num/0.2.1 \
|
||||
crate://crates.io/numtoa/0.1.0 \
|
||||
crate://crates.io/object/0.20.0 \
|
||||
crate://crates.io/once_cell/1.4.0 \
|
||||
crate://crates.io/opaque-debug/0.2.3 \
|
||||
crate://crates.io/opaque-debug/0.3.0 \
|
||||
crate://crates.io/owning_ref/0.4.1 \
|
||||
crate://crates.io/pango-sys/0.10.0 \
|
||||
crate://crates.io/pango/0.9.1 \
|
||||
crate://crates.io/pin-project-internal/0.4.22 \
|
||||
crate://crates.io/pin-project/0.4.22 \
|
||||
crate://crates.io/pin-utils/0.1.0 \
|
||||
crate://crates.io/pkg-config/0.3.17 \
|
||||
crate://crates.io/ppv-lite86/0.2.9 \
|
||||
crate://crates.io/proc-macro-crate/0.1.5 \
|
||||
crate://crates.io/proc-macro-error-attr/1.0.4 \
|
||||
crate://crates.io/proc-macro-error/1.0.4 \
|
||||
crate://crates.io/proc-macro-hack/0.5.16 \
|
||||
crate://crates.io/proc-macro-nested/0.1.6 \
|
||||
crate://crates.io/proc-macro2/0.4.30 \
|
||||
crate://crates.io/proc-macro2/1.0.18 \
|
||||
crate://crates.io/pwhash/0.3.1 \
|
||||
crate://crates.io/quote/0.6.13 \
|
||||
crate://crates.io/quote/1.0.7 \
|
||||
crate://crates.io/rand/0.7.3 \
|
||||
crate://crates.io/rand_chacha/0.2.2 \
|
||||
crate://crates.io/rand_core/0.5.1 \
|
||||
crate://crates.io/rand_hc/0.2.0 \
|
||||
crate://crates.io/redox_syscall/0.1.56 \
|
||||
crate://crates.io/redox_termios/0.1.1 \
|
||||
crate://crates.io/rle-decode-fast/1.0.1 \
|
||||
crate://crates.io/rpassword/4.0.5 \
|
||||
crate://crates.io/rustc-demangle/0.1.16 \
|
||||
crate://crates.io/same-file/1.0.6 \
|
||||
crate://crates.io/serde/1.0.112 \
|
||||
crate://crates.io/serde_derive/1.0.112 \
|
||||
crate://crates.io/sha-1/0.9.1 \
|
||||
crate://crates.io/sha2/0.9.1 \
|
||||
crate://crates.io/signal-hook-registry/1.2.0 \
|
||||
crate://crates.io/signal-hook/0.1.16 \
|
||||
crate://crates.io/slab/0.4.2 \
|
||||
crate://crates.io/sodiumoxide/0.2.5 \
|
||||
crate://crates.io/stable_deref_trait/1.1.1 \
|
||||
crate://crates.io/strsim/0.8.0 \
|
||||
crate://crates.io/strum/0.18.0 \
|
||||
crate://crates.io/strum_macros/0.18.0 \
|
||||
crate://crates.io/subtle/2.3.0 \
|
||||
crate://crates.io/syn/0.15.44 \
|
||||
crate://crates.io/syn/1.0.31 \
|
||||
crate://crates.io/synstructure/0.12.4 \
|
||||
crate://crates.io/system-deps/1.3.2 \
|
||||
crate://crates.io/take_mut/0.2.2 \
|
||||
crate://crates.io/tar/0.4.29 \
|
||||
crate://crates.io/termion/1.5.5 \
|
||||
crate://crates.io/textwrap/0.11.0 \
|
||||
crate://crates.io/thiserror-impl/1.0.21 \
|
||||
crate://crates.io/thiserror/1.0.21 \
|
||||
crate://crates.io/thread_local/1.0.1 \
|
||||
crate://crates.io/time/0.1.43 \
|
||||
crate://crates.io/toml/0.4.10 \
|
||||
crate://crates.io/toml/0.5.6 \
|
||||
crate://crates.io/typenum/1.12.0 \
|
||||
crate://crates.io/unicode-segmentation/1.6.0 \
|
||||
crate://crates.io/unicode-width/0.1.7 \
|
||||
crate://crates.io/unicode-xid/0.1.0 \
|
||||
crate://crates.io/unicode-xid/0.2.0 \
|
||||
crate://crates.io/vcpkg/0.2.10 \
|
||||
crate://crates.io/vec_map/0.8.2 \
|
||||
crate://crates.io/version-compare/0.0.10 \
|
||||
crate://crates.io/version_check/0.9.2 \
|
||||
crate://crates.io/void/1.0.2 \
|
||||
crate://crates.io/walkdir/2.3.1 \
|
||||
crate://crates.io/wasi/0.9.0+wasi-snapshot-preview1 \
|
||||
crate://crates.io/winapi-i686-pc-windows-gnu/0.4.0 \
|
||||
crate://crates.io/winapi-util/0.1.5 \
|
||||
crate://crates.io/winapi-x86_64-pc-windows-gnu/0.4.0 \
|
||||
crate://crates.io/winapi/0.3.9 \
|
||||
crate://crates.io/xattr/0.2.2 \
|
||||
crate://crates.io/xi-unicode/0.1.0 \
|
||||
"
|
||||
|
||||
|
||||
|
||||
# FIXME: update generateme with the real MD5 of the license file
|
||||
LIC_FILES_CHKSUM = " \
|
||||
"
|
||||
|
||||
SUMMARY = "Citadel Realms UI"
|
||||
HOMEPAGE = "https://subgraph,com"
|
||||
LICENSE = "CLOSED"
|
||||
|
||||
# includes this file if it exists but does not fail
|
||||
# this is useful for anything you may want to override from
|
||||
# what cargo-bitbake generates.
|
||||
include citadel-realms-ui-${PV}.inc
|
||||
include citadel-realms-ui.inc
|
@ -1,216 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.22.2 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<object class="GtkWindow" id="config-dialog">
|
||||
<property name="width_request">600</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="modal">True</property>
|
||||
<child type="titlebar">
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">20</property>
|
||||
<property name="margin_right">20</property>
|
||||
<property name="margin_top">20</property>
|
||||
<property name="margin_bottom">30</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_top">10</property>
|
||||
<property name="margin_bottom">20</property>
|
||||
<property name="spacing">10</property>
|
||||
<child>
|
||||
<object class="GtkImage">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">10</property>
|
||||
<property name="icon_name">computer</property>
|
||||
<property name="icon_size">3</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="config-realm-name">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<style>
|
||||
<class name="config-realm-name"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</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">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="margin_bottom">10</property>
|
||||
<property name="label" translatable="yes">Options</property>
|
||||
<style>
|
||||
<class name="config-heading"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="config-option-list">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="margin_left">20</property>
|
||||
<property name="margin_right">20</property>
|
||||
<property name="margin_bottom">20</property>
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkGrid">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="column_spacing">60</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">RealmFS</property>
|
||||
<style>
|
||||
<class name="config-heading"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="config-realmfs-combo">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<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">Overlay</property>
|
||||
<style>
|
||||
<class name="config-heading"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkComboBoxText" id="config-overlay-combo">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="halign">start</property>
|
||||
<items>
|
||||
<item id="overlay-none" translatable="yes">None</item>
|
||||
<item id="overlay-tmpfs" translatable="yes">TmpFS</item>
|
||||
<item id="overlay-storage" translatable="yes">Storage Partition</item>
|
||||
</items>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<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">Terminal Theme</property>
|
||||
<style>
|
||||
<class name="config-heading"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">0</property>
|
||||
<property name="top_attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="theme-choose-button">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="left_attach">1</property>
|
||||
<property name="top_attach">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">3</property>
|
||||
</packing>
|
||||
</child>
|
||||
<style>
|
||||
<class name="config-main-box"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
<style>
|
||||
<class name="config-dialog"/>
|
||||
<class name="main-window"/>
|
||||
</style>
|
||||
</object>
|
||||
<object class="GtkSizeGroup">
|
||||
<widgets>
|
||||
<widget name="config-realmfs-combo"/>
|
||||
<widget name="config-overlay-combo"/>
|
||||
<widget name="theme-choose-button"/>
|
||||
</widgets>
|
||||
</object>
|
||||
</interface>
|
@ -1,40 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Generated with glade 3.22.2 -->
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.20"/>
|
||||
<object class="GtkBox" id="config-option">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkCheckButton" id="config-option-check">
|
||||
<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="GtkLabel" id="config-option-label">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Hehehehe</property>
|
||||
<style>
|
||||
<class name="config-option-description"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
<style>
|
||||
<class name="config-option"/>
|
||||
</style>
|
||||
</object>
|
||||
</interface>
|
@ -1,21 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.24"/>
|
||||
<object class="GtkWindow" id="config-dialog">
|
||||
<style>
|
||||
<class name="config-dialog" />
|
||||
</style>
|
||||
|
||||
<child>
|
||||
<object class="GtkBox" id="main-box">
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="option-list">
|
||||
<property name="orientation">vertical</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</interface>
|
@ -1,95 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.24"/>
|
||||
<object class="GtkWindow" id="main-window">
|
||||
<property name="width_request">600</property>
|
||||
<property name="decorated">False</property>
|
||||
<property name="modal">True</property>
|
||||
<property name="window_position">center</property>
|
||||
<style>
|
||||
<class name="main-window" />
|
||||
</style>
|
||||
|
||||
<child>
|
||||
<object class="GtkBox" id="main-box">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">20</property>
|
||||
<property name="margin_left">20</property>
|
||||
<property name="margin_right">20</property>
|
||||
<property name="margin_top">20</property>
|
||||
<property name="margin_bottom">20</property>
|
||||
|
||||
<child>
|
||||
<object class="GtkBox" id="current-realm-box">
|
||||
<property name="orientation">horizontal</property>
|
||||
<property name="spacing">10</property>
|
||||
|
||||
<child>
|
||||
<object class="GtkImage" id="current-realm-icon">
|
||||
<property name="icon-name">computer</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="GtkLabel" id="current-realm">
|
||||
<property name="halign">start</property>
|
||||
<style>
|
||||
<class name="current-realm" />
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="GtkBox" id="input-box">
|
||||
<child>
|
||||
<object class="GtkEntry" id="input-entry">
|
||||
<style>
|
||||
<class name="input-entry" />
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="GtkBox" id="result-box">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="homogeneous">True</property>
|
||||
<style>
|
||||
<class name="result-box"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
</interface>
|
@ -1,63 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk+" version="3.24"/>
|
||||
<object class="GtkBox" id="item-entry">
|
||||
<property name="spacing">25</property>
|
||||
<style>
|
||||
<class name="item-entry"/>
|
||||
</style>
|
||||
|
||||
<child>
|
||||
<object class="GtkImage" id="item-icon">
|
||||
<property name="margin-left">20</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="GtkBox">
|
||||
<property name="orientation">vertical</property>
|
||||
<property name="spacing">5</property>
|
||||
<!--
|
||||
<property name="margin-top">10</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
-->
|
||||
|
||||
<child>
|
||||
<object class="GtkLabel" id="item-name">
|
||||
<!-- <property name="hexpand">True</property> -->
|
||||
<property name="halign">start</property>
|
||||
<style>
|
||||
<class name="item-name"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
<child>
|
||||
<object class="GtkLabel" id="item-description">
|
||||
<property name="hexpand">True</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="margin-bottom">10</property>
|
||||
<style>
|
||||
<class name="item-description"/>
|
||||
</style>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
@ -1,121 +0,0 @@
|
||||
/**
|
||||
* App Window
|
||||
*/
|
||||
@define-color bg_color #3C4141;
|
||||
@define-color window_bg @bg_color;
|
||||
@define-color window_border_color #3A3A3A;
|
||||
|
||||
/**
|
||||
* Current realm
|
||||
*/
|
||||
@define-color realm_name #FFFDF7;
|
||||
|
||||
/**
|
||||
* Input
|
||||
*/
|
||||
@define-color selected_bg_color #4675ab;
|
||||
@define-color selected_fg_color #d5eaff;
|
||||
@define-color input_color #ddd;
|
||||
@define-color caret_color darker(@input_color);
|
||||
|
||||
/**
|
||||
* Result items
|
||||
*/
|
||||
@define-color item_name #ddd;
|
||||
@define-color item_text #999;
|
||||
@define-color item_box_selected #285C99;
|
||||
@define-color item_text_selected #99ccff;
|
||||
@define-color item_name_selected #eee;
|
||||
|
||||
@binding-set ConfigFocus
|
||||
{
|
||||
bind "j" { "move-focus" (down) };
|
||||
bind "k" { "move-focus" (up) };
|
||||
}
|
||||
|
||||
checkbutton:focus + label {
|
||||
border-bottom-style: solid;
|
||||
border-bottom-width: 1px;
|
||||
border-bottom-color: #008cb3;
|
||||
}
|
||||
|
||||
.config-main-box {
|
||||
-gtk-key-bindings: ConfigFocus;
|
||||
}
|
||||
.config-dialog {
|
||||
-gtk-key-bindings: ConfigFocus;
|
||||
}
|
||||
|
||||
.main-window {
|
||||
background-color: @window_bg;
|
||||
border-color: @window_border_color;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.input-entry {
|
||||
color: @input_color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selected text in input
|
||||
*/
|
||||
.input-entry *:selected,
|
||||
.input-entry *:focus,
|
||||
*:selected:focus {
|
||||
background-color: alpha (@selected_bg_color, 0.9);
|
||||
color: @selected_fg_color;
|
||||
}
|
||||
|
||||
.config-heading {
|
||||
/*
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
*/
|
||||
font: 20px Sans;
|
||||
}
|
||||
|
||||
.config-realm-name {
|
||||
font: 20px Sans;
|
||||
color: @realm_name;
|
||||
}
|
||||
|
||||
.current-realm {
|
||||
font: 20px Sans;
|
||||
color: @realm_name;
|
||||
}
|
||||
|
||||
.item-text {
|
||||
color: @item_text;
|
||||
}
|
||||
.item-name {
|
||||
color: @item_name;
|
||||
}
|
||||
|
||||
.config-option.selected {
|
||||
background-color: #56f9a0;
|
||||
}
|
||||
|
||||
.selected.item-entry {
|
||||
background-color: @item_box_selected;
|
||||
}
|
||||
|
||||
.selected.item-entry .item-text {
|
||||
color: @item_text_selected;
|
||||
}
|
||||
|
||||
.selected.item-entry .item-name {
|
||||
color: @item_name_selected;
|
||||
}
|
||||
|
||||
.no-window-shadow {
|
||||
margin: -20px;
|
||||
}
|
||||
|
||||
window entry {
|
||||
font: 30px Sans
|
||||
}
|
||||
|
||||
.item-name {
|
||||
font: 30px Sans
|
||||
}
|
||||
|
@ -1,55 +0,0 @@
|
||||
|
||||
use gtk::prelude::*;
|
||||
use crate::{Error, Result};
|
||||
|
||||
pub struct Builder {
|
||||
builder: gtk::Builder,
|
||||
}
|
||||
|
||||
impl Builder {
|
||||
pub fn new(source: &str) -> Self {
|
||||
let builder = gtk::Builder::from_string(source);
|
||||
Builder { builder }
|
||||
}
|
||||
|
||||
fn ok_or_err<T>(type_name: &str, name: &str, object: Option<T>) -> Result<T> {
|
||||
object.ok_or(Error::Builder(format!("failed to load {} {}", type_name, name)))
|
||||
}
|
||||
|
||||
pub fn get_window(&self, name: &str) -> Result<gtk::Window> {
|
||||
Self::ok_or_err("GtkWindow", name, self.builder.get_object(name))
|
||||
}
|
||||
|
||||
pub fn get_entry(&self, name: &str) -> Result<gtk::Entry> {
|
||||
Self::ok_or_err("GtkEntry", name, self.builder.get_object(name))
|
||||
}
|
||||
|
||||
pub fn get_box(&self, name: &str) -> Result<gtk::Box> {
|
||||
Self::ok_or_err("GtkBox", name, self.builder.get_object(name))
|
||||
}
|
||||
|
||||
pub fn get_check_button(&self, name: &str) -> Result<gtk::CheckButton> {
|
||||
Self::ok_or_err("GtkCheckButton", name, self.builder.get_object(name))
|
||||
}
|
||||
|
||||
pub fn get_button(&self, name: &str) -> Result<gtk::Button> {
|
||||
Self::ok_or_err("GtkButton", name, self.builder.get_object(name))
|
||||
}
|
||||
|
||||
pub fn get_grid(&self, name: &str) -> Result<gtk::Grid> {
|
||||
Self::ok_or_err("GtkGrid", name, self.builder.get_object(name))
|
||||
}
|
||||
|
||||
|
||||
pub fn get_label(&self, name: &str) -> Result<gtk::Label> {
|
||||
Self::ok_or_err("GtkLabel", name, self.builder.get_object(name))
|
||||
}
|
||||
|
||||
pub fn get_image(&self, name: &str) -> Result<gtk::Image> {
|
||||
Self::ok_or_err("GtkImage", name, self.builder.get_object(name))
|
||||
}
|
||||
|
||||
pub fn get_combo_box_text(&self, name: &str) -> Result<gtk::ComboBoxText> {
|
||||
Self::ok_or_err("GtkComboBoxText", name, self.builder.get_object(name))
|
||||
}
|
||||
}
|
@ -1,121 +0,0 @@
|
||||
|
||||
use gtk::prelude::*;
|
||||
use gdk::ModifierType;
|
||||
use gdk::keys::constants;
|
||||
use crate::{Result,Builder};
|
||||
use crate::realms::Entity;
|
||||
use std::collections::HashMap;
|
||||
|
||||
static CONFIG_FLAGS: &[(&str, &str)] = &[
|
||||
("use-gpu", "Use GPU in Realm"),
|
||||
("use-wayland", "Use Wayland in Realm"),
|
||||
("use-x11", "Use X11 in Realm"),
|
||||
("use-sound", "Use Sound in Realm"),
|
||||
("use-shared-dir", "Mount /Shared directory in Realm"),
|
||||
("use-network", "Realm has network access"),
|
||||
("use-kvm", "Use KVM (/dev/kvm) in Realm"),
|
||||
("use-ephemeral-home", "Use ephemeral tmpfs mount for home directory"),
|
||||
];
|
||||
|
||||
const CONFIG_DIALOG: &str = include_str!("../data/config-dialog.ui");
|
||||
const CONFIG_OPTION: &str = include_str!("../data/config-option.ui");
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct ConfigOption {
|
||||
name: &'static str,
|
||||
option: gtk::Box,
|
||||
check: gtk::CheckButton,
|
||||
style: gtk::StyleContext,
|
||||
}
|
||||
|
||||
impl ConfigOption {
|
||||
fn create(name: &'static str, description: &str, val: bool) -> Result<Self> {
|
||||
let builder = Builder::new(CONFIG_OPTION);
|
||||
let option = builder.get_box("config-option")?;
|
||||
|
||||
let check = builder.get_check_button("config-option-check")?;
|
||||
check.set_active(val);
|
||||
let label = builder.get_label("config-option-label")?;
|
||||
label.set_text(description);
|
||||
let style = option.get_style_context();
|
||||
Ok(ConfigOption { name, option, check, style })
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub struct ConfigDialog {
|
||||
options: Vec<ConfigOption>,
|
||||
}
|
||||
|
||||
impl ConfigDialog {
|
||||
|
||||
pub fn open(realm: &Entity, config: HashMap<String,String>, parent: >k::Window) -> Result<Self> {
|
||||
let builder = Builder::new(CONFIG_DIALOG);
|
||||
let window = builder.get_window("config-dialog")?;
|
||||
let option_list = builder.get_box("config-option-list")?;
|
||||
let name_label = builder.get_label("config-realm-name")?;
|
||||
|
||||
name_label.set_text(realm.name());
|
||||
window.set_decorated(false);
|
||||
|
||||
let mut options = Vec::new();
|
||||
for (name,desc) in CONFIG_FLAGS {
|
||||
let val = match config.get(*name).map(|s| s.as_str()) {
|
||||
Some("true") => true,
|
||||
Some("false") => false,
|
||||
_ => false,
|
||||
};
|
||||
let option = ConfigOption::create(name, desc, val)?;
|
||||
option_list.pack_start(&option.option, false, false, 5);
|
||||
options.push(option);
|
||||
}
|
||||
|
||||
let overlay = builder.get_combo_box_text("config-overlay-combo")?;
|
||||
println!("config: {:?}", config);
|
||||
let overlay_id = match config.get("overlay").map(|s| s.as_str()) {
|
||||
Some("tmpfs") => "overlay-tmpfs",
|
||||
Some("storage") => "overlay-storage",
|
||||
_ => "overlay-none"
|
||||
};
|
||||
overlay.set_active_id(Some(overlay_id));
|
||||
|
||||
let realmfs = builder.get_combo_box_text("config-realmfs-combo")?;
|
||||
for fs in realm.realmfs_list() {
|
||||
println!("adding {}", fs.name());
|
||||
// realmfs.append(Some(fs.name()), fs.name());
|
||||
ComboBoxTextExt::append(&realmfs, Some(fs.name()), fs.name());
|
||||
}
|
||||
|
||||
let scheme = builder.get_button("theme-choose-button")?;
|
||||
if let Some(name) = config.get("terminal-scheme") {
|
||||
// scheme.set_label(name);
|
||||
ButtonExt::set_label(&scheme, name);
|
||||
}
|
||||
|
||||
window.set_opacity(0.85);
|
||||
window.set_transient_for(Some(parent));
|
||||
parent.hide();
|
||||
window.show_all();
|
||||
window.connect_key_press_event({
|
||||
let win = window.clone();
|
||||
let parent = parent.clone();
|
||||
move |_,key| {
|
||||
let state = key.get_state();
|
||||
let keyval = key.get_keyval();
|
||||
let esc = keyval == constants::Escape ||
|
||||
(state == ModifierType::CONTROL_MASK && keyval.to_unicode().unwrap() == '[');
|
||||
if esc {
|
||||
parent.show();
|
||||
unsafe {
|
||||
win.destroy();
|
||||
}
|
||||
}
|
||||
Inhibit(false)
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
Ok(ConfigDialog { options })
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +0,0 @@
|
||||
|
||||
use std::result;
|
||||
|
||||
use dbus;
|
||||
|
||||
pub type Result<T> = result::Result<T, Error>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
Dbus(dbus::Error),
|
||||
Nix(nix::Error),
|
||||
Builder(String),
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
use std::os::unix::io::RawFd;
|
||||
use std::thread;
|
||||
|
||||
use glib::Continue;
|
||||
use nix::unistd::close;
|
||||
use nix::errno::Errno;
|
||||
use nix::sys::socket::{
|
||||
socket,listen,bind,connect,accept,AddressFamily,SockType,SockFlag,SockAddr,UnixAddr
|
||||
};
|
||||
|
||||
use crate::{Error,Result};
|
||||
|
||||
static SOCKET_NAME: &[u8] = b"citadel-realms-ui";
|
||||
|
||||
enum BindResult {
|
||||
BindOk,
|
||||
BindFailed(Error),
|
||||
BindAddrInUse,
|
||||
}
|
||||
|
||||
///
|
||||
/// Determine if another instance is already running and if so signal it to quit.
|
||||
///
|
||||
/// This window is launched from a GNOME shortcut key that is meant to 'toggle' the
|
||||
/// window so that if the shortcut key is used while the window is already open the
|
||||
/// running instance will close.
|
||||
///
|
||||
/// This class will attempt to create a Unix domain stream socket in the abstract
|
||||
/// namespace bound to the fixed name `SOCKET_NAME`. If no other instance is running
|
||||
/// then this name will be available and the bind will succeed. In this case a thread
|
||||
/// is spawned to listen for connections to the socket and the process will exit
|
||||
/// the main GTK loop by calling `gtk::main_quit()` upon a connection to the listening
|
||||
/// socket.
|
||||
///
|
||||
/// If the bind fails because the socket name is already in use, then another instance is
|
||||
/// running. A connection is then made to the socket to signal the running instance to exit.
|
||||
///
|
||||
pub struct InstanceTracker {
|
||||
fd: RawFd,
|
||||
}
|
||||
|
||||
impl InstanceTracker {
|
||||
pub fn create() -> Result<Self> {
|
||||
let fd = socket(AddressFamily::Unix, SockType::Stream, SockFlag::empty(), None)
|
||||
.map_err(Error::Nix)?;
|
||||
Ok(InstanceTracker { fd } )
|
||||
}
|
||||
|
||||
fn addr() -> SockAddr {
|
||||
SockAddr::Unix(UnixAddr::new_abstract(SOCKET_NAME)
|
||||
.expect("UnixAddr::new_abstract()"))
|
||||
}
|
||||
|
||||
fn try_bind(&self) -> BindResult {
|
||||
let addr = Self::addr();
|
||||
match bind(self.fd, &addr) {
|
||||
Err(nix::Error::Sys(Errno::EADDRINUSE)) => BindResult::BindAddrInUse,
|
||||
Err(err) => BindResult::BindFailed(Error::Nix(err)),
|
||||
Ok(()) => BindResult::BindOk,
|
||||
}
|
||||
}
|
||||
|
||||
fn connect(&self) -> bool {
|
||||
let addr = Self::addr();
|
||||
if let Err(err) = connect(self.fd, &addr) {
|
||||
println!("Failed to connect to instance socket: {}", err);
|
||||
return false;
|
||||
}
|
||||
if let Err(err) = close(self.fd) {
|
||||
println!("error closing socket: {}", err);
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn spawn_reader(&self) {
|
||||
thread::spawn({
|
||||
let fd = self.fd;
|
||||
move || {
|
||||
let _ = listen(fd, 1);
|
||||
let _ = accept(fd);
|
||||
glib::idle_add(|| {
|
||||
gtk::main_quit();
|
||||
Continue(false)
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn bind(&self, toggle: bool) -> bool {
|
||||
match self.try_bind() {
|
||||
BindResult::BindAddrInUse => {
|
||||
if toggle {
|
||||
self.connect();
|
||||
}
|
||||
false
|
||||
},
|
||||
|
||||
BindResult::BindOk => {
|
||||
self.spawn_reader();
|
||||
true
|
||||
}
|
||||
BindResult::BindFailed(err) => {
|
||||
println!("error binding: {:?}", err);
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,40 +0,0 @@
|
||||
mod config;
|
||||
mod error;
|
||||
mod builder;
|
||||
mod instance;
|
||||
mod matcher;
|
||||
mod realms;
|
||||
mod results;
|
||||
mod ui;
|
||||
|
||||
use ui::Ui;
|
||||
|
||||
pub use error::{Result,Error};
|
||||
pub use builder::Builder;
|
||||
pub use config::ConfigDialog;
|
||||
|
||||
fn main() {
|
||||
|
||||
let tracker = match instance::InstanceTracker::create() {
|
||||
Ok(tracker) => tracker,
|
||||
Err(err) => {
|
||||
eprintln!("Failed to create instance tracker: {:?}", err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
if !tracker.bind(true) {
|
||||
return;
|
||||
}
|
||||
if let Err(err) = gtk::init() {
|
||||
eprintln!("Failed to initialize GTK: {:?}", err);
|
||||
return;
|
||||
}
|
||||
let ui = match Ui::build() {
|
||||
Ok(ui) => ui,
|
||||
Err(err) => {
|
||||
eprintln!("Error: {:?}", err);
|
||||
return;
|
||||
}
|
||||
};
|
||||
ui.run();
|
||||
}
|
@ -1,177 +0,0 @@
|
||||
|
||||
use std::rc::Rc;
|
||||
use fuzzy_matcher::FuzzyMatcher;
|
||||
use fuzzy_matcher::skim::SkimMatcherV2;
|
||||
|
||||
use crate::results::{ResultList, ResultType};
|
||||
use crate::realms::{Realms,Entity};
|
||||
use crate::Result;
|
||||
use std::cmp::Ordering;
|
||||
|
||||
struct RealmMatcher<'a> {
|
||||
matcher: SkimMatcherV2,
|
||||
query: &'a str,
|
||||
rtype: ResultType,
|
||||
match_all: bool,
|
||||
match_current: bool,
|
||||
match_system: bool,
|
||||
match_running_only: bool,
|
||||
}
|
||||
|
||||
impl <'a> RealmMatcher<'a> {
|
||||
fn new(query: &'a str, rtype: ResultType, match_all: bool, match_current: bool, match_running_only: bool) -> Self {
|
||||
RealmMatcher {
|
||||
matcher: SkimMatcherV2::default(),
|
||||
query, rtype, match_all, match_current, match_running_only,
|
||||
match_system: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn terminal_matcher(query: &'a str) -> Self {
|
||||
RealmMatcher::new(query, ResultType::Terminal, false, true, false)
|
||||
}
|
||||
|
||||
fn stop_realm_matcher(query: &'a str) -> Self {
|
||||
RealmMatcher::new(query, ResultType::StopRealm, false, true, true)
|
||||
}
|
||||
|
||||
fn restart_realm_matcher(query: &'a str) -> Self {
|
||||
RealmMatcher::new(query, ResultType::RestartRealm, false, true, true)
|
||||
}
|
||||
|
||||
fn config_realm_matcher(query: &'a str) -> Self {
|
||||
RealmMatcher::new(query, ResultType::ConfigRealm, false, true, false)
|
||||
}
|
||||
|
||||
fn update_realmfs_matcher(query: &'a str) -> Self {
|
||||
RealmMatcher::new(query, ResultType::UpdateRealmFS, false, true, false)
|
||||
}
|
||||
|
||||
fn all_realms_matcher() -> Self {
|
||||
RealmMatcher::new("", ResultType::Realm, true, false, false)
|
||||
}
|
||||
|
||||
fn realms_matcher(query: &'a str) -> Self {
|
||||
RealmMatcher::new(query, ResultType::Realm, false, false, false)
|
||||
}
|
||||
|
||||
fn match_realm_query(&self, realm: &Entity) -> Option<Entity> {
|
||||
self.matcher.fuzzy_indices(realm.name(), self.query)
|
||||
.map(|(score, indices)|
|
||||
realm.clone_with_match_info(score, indices))
|
||||
}
|
||||
|
||||
fn match_realm_flags(&self, realm: &Entity) -> bool {
|
||||
if !self.match_current && realm.is_current() {
|
||||
false
|
||||
} else if !self.match_system && realm.is_system_realm() {
|
||||
false
|
||||
} else if self.match_running_only && !realm.is_running() {
|
||||
false
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fn match_realm(&self, realm: &Entity) -> Option<Entity> {
|
||||
let flags_ok = self.match_realm_flags(realm);
|
||||
if self.match_all && flags_ok {
|
||||
Some(realm.clone())
|
||||
} else if flags_ok {
|
||||
self.match_realm_query(realm)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn sort_realms(&self, realms: &mut Vec<Entity>) {
|
||||
realms.sort_by(|a, b| {
|
||||
if a.is_running() && !b.is_running() {
|
||||
Ordering::Less
|
||||
} else if b.is_running() && !a.is_running() {
|
||||
Ordering::Greater
|
||||
} else {
|
||||
a.match_score().cmp(&b.match_score())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn is_realmfs_update(&self) -> bool {
|
||||
self.rtype == ResultType::UpdateRealmFS
|
||||
}
|
||||
|
||||
fn _match_realmfs(&self, _realms: &[Entity], _realmfs: &[Entity]) -> (Vec<Entity>, Vec<Entity>) {
|
||||
(Vec::new(), Vec::new())
|
||||
}
|
||||
|
||||
fn match_realm_list(&self, realms: &[Entity]) -> Vec<Entity> {
|
||||
let mut matched = Vec::new();
|
||||
|
||||
for r in realms {
|
||||
if let Some(realm) = self.match_realm(r) {
|
||||
matched.push(realm);
|
||||
}
|
||||
}
|
||||
self.sort_realms(&mut matched);
|
||||
matched
|
||||
}
|
||||
|
||||
fn result_type(&self) -> ResultType {
|
||||
self.rtype
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Matcher {
|
||||
realms: Rc<Realms>,
|
||||
}
|
||||
|
||||
impl Matcher {
|
||||
pub fn new() -> Result<Self> {
|
||||
let mut realms = Realms::connect()?;
|
||||
realms.reload_realms()?;
|
||||
let realms = Rc::new(realms);
|
||||
|
||||
Ok(Matcher { realms })
|
||||
}
|
||||
|
||||
pub fn current_realm(&self) -> Option<&Entity> {
|
||||
self.realms.current_realm()
|
||||
}
|
||||
|
||||
fn parse(text: &str) -> RealmMatcher {
|
||||
if text == "*" {
|
||||
return RealmMatcher::all_realms_matcher();
|
||||
}
|
||||
if let Some(idx) = text.find(' ') {
|
||||
let (a, b) = text.split_at(idx);
|
||||
let b = &b[1..];
|
||||
match a {
|
||||
"t" => RealmMatcher::terminal_matcher(b),
|
||||
"s" => RealmMatcher::stop_realm_matcher(b),
|
||||
"r" => RealmMatcher::restart_realm_matcher(b),
|
||||
"c" => RealmMatcher::config_realm_matcher(b),
|
||||
"u" => RealmMatcher::update_realmfs_matcher(b),
|
||||
_ => RealmMatcher::realms_matcher(text)
|
||||
}
|
||||
} else {
|
||||
RealmMatcher::realms_matcher(text)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&self, text: &str, results: &ResultList) {
|
||||
results.clear_list();
|
||||
if text.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
let matcher = Self::parse(text);
|
||||
if matcher.is_realmfs_update() {
|
||||
let realms = matcher.match_realm_list(self.realms.realmfs());
|
||||
results.create_result_items(matcher.result_type(), realms);
|
||||
} else {
|
||||
let realms = matcher.match_realm_list(self.realms.realms());
|
||||
results.create_result_items(matcher.result_type(), realms);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,244 +0,0 @@
|
||||
|
||||
use std::time::Duration;
|
||||
use std::rc::Rc;
|
||||
use std::cell::RefCell;
|
||||
|
||||
use dbus::blocking::{Connection,Proxy};
|
||||
use crate::{Result, Error, ConfigDialog};
|
||||
use std::collections::HashMap;
|
||||
|
||||
|
||||
#[derive(Clone,PartialEq)]
|
||||
enum EntityType{
|
||||
Realm,
|
||||
RealmFS,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Entity {
|
||||
realms: RefCell<Realms>,
|
||||
etype: EntityType,
|
||||
name: String,
|
||||
description: Option<String>,
|
||||
realmfs: Option<String>,
|
||||
flags: Option<usize>,
|
||||
match_score: i64,
|
||||
match_indices: Option<Vec<usize>>,
|
||||
}
|
||||
|
||||
impl Entity {
|
||||
fn new_realm(realms: Realms, (name, description, realmfs, flags): (String, String, String, u8)) -> Self {
|
||||
Self::new(realms, EntityType::Realm, name, Some(description), Some(realmfs), Some(flags as usize))
|
||||
}
|
||||
|
||||
fn new_realmfs(realms: Realms, name: String) -> Self {
|
||||
Self::new(realms, EntityType::RealmFS, name, None, None, None)
|
||||
}
|
||||
|
||||
fn new(realms: Realms, etype: EntityType, name: String, description: Option<String>, realmfs: Option<String>, flags: Option<usize>) -> Self {
|
||||
let realms = RefCell::new(realms);
|
||||
let match_score = 0;
|
||||
let match_indices = None;
|
||||
Entity { realms, etype, name, description, realmfs, flags, match_score, match_indices }
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
|
||||
pub fn description(&self) -> &str {
|
||||
self.description.as_ref().map(|s| s.as_str()).unwrap_or("")
|
||||
}
|
||||
|
||||
fn has_flag(&self, flag: usize) -> bool {
|
||||
self.flags.map(|v| v & flag != 0).unwrap_or(false)
|
||||
}
|
||||
pub fn is_running(&self) -> bool {
|
||||
self.has_flag(0x01)
|
||||
}
|
||||
|
||||
pub fn is_system_realm(&self) -> bool {
|
||||
self.has_flag(0x04)
|
||||
}
|
||||
|
||||
pub fn is_current(&self) -> bool {
|
||||
self.has_flag(0x02)
|
||||
}
|
||||
|
||||
pub fn is_realm(&self) -> bool {
|
||||
self.etype == EntityType::Realm
|
||||
}
|
||||
|
||||
pub fn realmfs_list(&self) -> Vec<Entity> {
|
||||
self.realms.borrow().cached_realmfs.clone()
|
||||
}
|
||||
|
||||
fn with_realm<F>(&self, f: F) -> bool
|
||||
where F: Fn(&str) -> Result<()>
|
||||
{
|
||||
if !self.is_realm() {
|
||||
return false;
|
||||
}
|
||||
if let Err(err) = f(self.name()) {
|
||||
println!("error calling dbus method: {:?}", err);
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
pub fn activate(&self) -> bool {
|
||||
self.with_realm(|name| self.realms.borrow().set_current_realm(name))
|
||||
}
|
||||
pub fn open_terminal(&self) -> bool {
|
||||
self.with_realm(|name| self.realms.borrow().open_terminal(name))
|
||||
}
|
||||
|
||||
pub fn stop_realm(&self) -> bool {
|
||||
self.with_realm(|name| self.realms.borrow().stop_realm(name))
|
||||
}
|
||||
pub fn restart_realm(&self) -> bool {
|
||||
self.with_realm(|name| self.realms.borrow().restart_realm(name))
|
||||
}
|
||||
|
||||
pub fn config_realm(&self, window: >k::Window) -> bool {
|
||||
if !self.is_realm() {
|
||||
return false;
|
||||
}
|
||||
let config = match self.realms.borrow().get_realm_config(self.name()) {
|
||||
Ok(config) => config,
|
||||
Err(err) => {
|
||||
println!("Error requesting realm config for {}: {:?}", self.name(), err);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
let config: HashMap<String,String> = config.into_iter().collect();
|
||||
let _c = ConfigDialog::open(self, config, window);
|
||||
false
|
||||
}
|
||||
|
||||
pub fn update_realmfs(&self) -> bool {
|
||||
if self.is_realm() {
|
||||
return false;
|
||||
}
|
||||
if let Err(err) = self.realms.borrow().update_realmfs(self.name()) {
|
||||
println!("error calling dbus method: {:?}", err);
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
|
||||
pub fn clone_with_match_info(&self, score: i64, indices: Vec<usize>) -> Self {
|
||||
let mut e = self.clone();
|
||||
e.match_score = score;
|
||||
e.match_indices = Some(indices);
|
||||
e
|
||||
}
|
||||
|
||||
pub fn match_indices(&self) -> Option<&[usize]> {
|
||||
self.match_indices.as_ref().map(|v| v.as_slice())
|
||||
}
|
||||
|
||||
pub fn match_score(&self) -> i64 {
|
||||
self.match_score
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Realms {
|
||||
conn: Rc<Connection>,
|
||||
cached_realms: Vec<Entity>,
|
||||
cached_realmfs: Vec<Entity>,
|
||||
}
|
||||
|
||||
impl Realms {
|
||||
|
||||
pub fn connect() -> Result<Self> {
|
||||
let conn = Connection::new_system().map_err(Error::Dbus)?;
|
||||
let conn = Rc::new(conn);
|
||||
let cached_realms = Vec::new();
|
||||
let cached_realmfs = Vec::new();
|
||||
Ok(Realms { conn, cached_realms, cached_realmfs })
|
||||
}
|
||||
|
||||
pub fn current_realm(&self) -> Option<&Entity> {
|
||||
self.cached_realms.iter().find(|r| r.is_current())
|
||||
}
|
||||
|
||||
|
||||
fn with_proxy<'a>(&self) -> Proxy<'a, &Connection> {
|
||||
self.conn.with_proxy("com.subgraph.realms",
|
||||
"/com/subgraph/realms",
|
||||
Duration::from_millis(5000))
|
||||
}
|
||||
|
||||
pub fn realms(&self) -> &[Entity] {
|
||||
&self.cached_realms
|
||||
}
|
||||
|
||||
pub fn realmfs(&self) -> &[Entity] {
|
||||
&self.cached_realmfs
|
||||
}
|
||||
|
||||
pub fn reload_realms(&mut self) -> Result<()> {
|
||||
let realms = self.list()?;
|
||||
self.cached_realms.clear();
|
||||
self.cached_realms.extend_from_slice(&realms);
|
||||
|
||||
let realmfs = self.get_realmfs_list()?;
|
||||
self.cached_realmfs.clear();
|
||||
self.cached_realmfs.extend_from_slice(&realmfs);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn list(&self) -> Result<Vec<Entity>> {
|
||||
let (list,): (Vec<(String, String, String, u8)>,) = self.with_proxy().method_call("com.subgraph.realms.Manager", "List", ()).map_err(Error::Dbus)?;
|
||||
let realms = list.into_iter()
|
||||
.map(|(n,d,fs, f)| Entity::new_realm(self.clone(), (n,d,fs,f)))
|
||||
.collect();
|
||||
Ok(realms)
|
||||
}
|
||||
|
||||
pub fn open_terminal(&self, realm: &str) -> Result<()> {
|
||||
self.with_proxy().method_call("com.subgraph.realms.Manager", "Terminal", (realm,))
|
||||
.map_err(Error::Dbus)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn stop_realm(&self, realm: &str) -> Result<()> {
|
||||
self.with_proxy().method_call("com.subgraph.realms.Manager", "Stop", (realm,))
|
||||
.map_err(Error::Dbus)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn restart_realm(&self, realm: &str) -> Result<()> {
|
||||
self.with_proxy().method_call("com.subgraph.realms.Manager", "Restart", (realm,))
|
||||
.map_err(Error::Dbus)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_current_realm(&self, realm: &str) -> Result<()> {
|
||||
self.with_proxy().method_call("com.subgraph.realms.Manager", "SetCurrent", (realm,))
|
||||
.map_err(Error::Dbus)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn update_realmfs(&self, realmfs: &str) -> Result<()> {
|
||||
self.with_proxy().method_call("com.subgraph.realms.Manager", "UpdateRealmFS", (realmfs,))
|
||||
.map_err(Error::Dbus)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_realm_config(&self, realm: &str) -> Result<Vec<(String,String)>> {
|
||||
let (config,): (Vec<(String,String)>,) = self.with_proxy().method_call("com.subgraph.realms.Manager", "RealmConfig", (realm, ))
|
||||
.map_err(Error::Dbus)?;
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
pub fn get_realmfs_list(&self) -> Result<Vec<Entity>> {
|
||||
let (list,): (Vec<String>,) = self.with_proxy().method_call("com.subgraph.realms.Manager", "ListRealmFS", ())
|
||||
.map_err(Error::Dbus)?;
|
||||
Ok(list.into_iter().map(|name| Entity::new_realmfs(self.clone(), name)).collect())
|
||||
}
|
||||
}
|
@ -1,292 +0,0 @@
|
||||
use std::rc::Rc;
|
||||
use std::cell::{RefCell,RefMut};
|
||||
|
||||
|
||||
use gtk::prelude::*;
|
||||
use gtk::{IconSize};
|
||||
|
||||
use crate::realms::Entity;
|
||||
use crate::{Result,Builder};
|
||||
|
||||
const UI: &str = include_str!("../data/result.ui");
|
||||
|
||||
#[derive(Debug,Copy,Clone,PartialEq)]
|
||||
pub enum ResultType {
|
||||
ConfigRealm,
|
||||
Realm,
|
||||
Terminal,
|
||||
StopRealm,
|
||||
RestartRealm,
|
||||
UpdateRealmFS,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ResultItem {
|
||||
entity: Entity,
|
||||
item: gtk::Box,
|
||||
style: gtk::StyleContext,
|
||||
result_type: ResultType,
|
||||
}
|
||||
|
||||
impl ResultItem {
|
||||
|
||||
pub fn create(result_type: ResultType, entity: &Entity, parent: >k::Box) -> Result<Self> {
|
||||
let entity = entity.clone();
|
||||
let builder = Builder::new(UI);
|
||||
let item = builder.get_box("item-entry")?;
|
||||
let icon = builder.get_image("item-icon")?;
|
||||
let name = builder.get_label("item-name")?;
|
||||
let desc = builder.get_label("item-description")?;
|
||||
|
||||
if entity.is_realm() {
|
||||
name.set_text(entity.name());
|
||||
} else {
|
||||
name.set_text(&format!("{}-realmfs", entity.name()));
|
||||
}
|
||||
|
||||
match result_type {
|
||||
ResultType::ConfigRealm => {
|
||||
icon.set_from_icon_name(Some("emblem-system"), IconSize::Dialog);
|
||||
desc.set_text("Configure Realm");
|
||||
if let Some(indices) = entity.match_indices() {
|
||||
Self::highlight_indices(&name, indices);
|
||||
}
|
||||
},
|
||||
ResultType::Realm => {
|
||||
icon.set_from_icon_name(Some("computer"), IconSize::Dialog);
|
||||
icon.set_sensitive(entity.is_running());
|
||||
if let Some(indices) = entity.match_indices() {
|
||||
Self::highlight_indices(&name, indices);
|
||||
}
|
||||
|
||||
if entity.description().is_empty() {
|
||||
unsafe {
|
||||
desc.destroy();
|
||||
}
|
||||
} else {
|
||||
desc.set_text(entity.description());
|
||||
}
|
||||
},
|
||||
ResultType::Terminal => {
|
||||
desc.set_text("Open Terminal");
|
||||
icon.set_from_icon_name(Some("utilities-terminal"), IconSize::Dialog);
|
||||
icon.set_sensitive(entity.is_running());
|
||||
if let Some(indices) = entity.match_indices() {
|
||||
Self::highlight_indices(&name, indices);
|
||||
}
|
||||
}
|
||||
ResultType::StopRealm => {
|
||||
desc.set_text("Stop Realm");
|
||||
icon.set_from_icon_name(Some("system-shutdown-symbolic"), IconSize::Dialog);
|
||||
if let Some(indices) = entity.match_indices() {
|
||||
Self::highlight_indices(&name, indices);
|
||||
}
|
||||
}
|
||||
ResultType::RestartRealm => {
|
||||
desc.set_text("Restart Realm");
|
||||
icon.set_from_icon_name(Some("system-reboot-symbolic"), IconSize::Dialog);
|
||||
if let Some(indices) = entity.match_indices() {
|
||||
Self::highlight_indices(&name, indices);
|
||||
}
|
||||
}
|
||||
|
||||
ResultType::UpdateRealmFS => {
|
||||
desc.set_text("Update RealmFS");
|
||||
icon.set_from_icon_name(Some("drive-harddisk-symbolic"), IconSize::Dialog);
|
||||
if let Some(indices) = entity.match_indices() {
|
||||
Self::highlight_indices(&name, indices);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
parent.pack_start(&item, false, true, 0);
|
||||
let style = item.get_style_context();
|
||||
item.show_all();
|
||||
Ok(ResultItem { entity, item, style, result_type })
|
||||
}
|
||||
|
||||
fn highlight_range(attrs: &pango::AttrList, start: u32, end: u32) {
|
||||
let mut a = pango::Attribute::new_foreground(40000, 40000, 40000).unwrap();
|
||||
a.set_start_index(start);
|
||||
a.set_end_index(end);
|
||||
attrs.insert(a);
|
||||
}
|
||||
|
||||
fn indices_to_ranges(indices: &[usize]) -> Vec<(u32, u32)> {
|
||||
let mut ranges = Vec::new();
|
||||
if indices.is_empty() {
|
||||
return ranges;
|
||||
}
|
||||
|
||||
let first = indices[0] as u32;
|
||||
let mut current = (first, first);
|
||||
|
||||
for i in &indices[1..] {
|
||||
let idx = *i as u32;
|
||||
if current.1 + 1 == idx {
|
||||
current.1 = idx;
|
||||
} else {
|
||||
ranges.push(current);
|
||||
current = (idx, idx);
|
||||
}
|
||||
}
|
||||
ranges.push(current);
|
||||
ranges
|
||||
}
|
||||
|
||||
fn highlight_indices(label: >k::Label, indices: &[usize]) {
|
||||
if indices.is_empty() {
|
||||
return;
|
||||
}
|
||||
let ranges = Self::indices_to_ranges(indices);
|
||||
let attrs = pango::AttrList::new();
|
||||
for (start, end) in ranges {
|
||||
Self::highlight_range(&attrs, start, end + 1);
|
||||
}
|
||||
LabelExt::set_attributes(label, Some(&attrs));
|
||||
}
|
||||
|
||||
|
||||
fn set_selected(&self) {
|
||||
self.style.add_class("selected");
|
||||
}
|
||||
|
||||
fn set_unselected(&self) {
|
||||
self.style.remove_class("selected");
|
||||
}
|
||||
|
||||
fn activate(&self, window: >k::Window) -> bool {
|
||||
match self.result_type {
|
||||
ResultType::Realm => self.entity.activate(),
|
||||
ResultType::Terminal => self.entity.open_terminal(),
|
||||
ResultType::StopRealm => self.entity.stop_realm(),
|
||||
ResultType::RestartRealm => self.entity.restart_realm(),
|
||||
ResultType::ConfigRealm => self.entity.config_realm(window),
|
||||
ResultType::UpdateRealmFS => self.entity.update_realmfs(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ResultItems {
|
||||
items: Vec<ResultItem>,
|
||||
selected: Option<usize>,
|
||||
}
|
||||
|
||||
impl ResultItems {
|
||||
fn new() -> Self {
|
||||
ResultItems {
|
||||
items: Vec::new(),
|
||||
selected: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn clear(&mut self, parentbox: >k::Box) {
|
||||
self.selected = None;
|
||||
for item in self.items.drain(..) {
|
||||
ContainerExt::remove(parentbox, &item.item);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_item(&mut self, rtype: ResultType, realm: &Entity, parent: >k::Box) -> Result<()> {
|
||||
let item = ResultItem::create(rtype, realm, parent)?;
|
||||
self.items.push(item);
|
||||
if self.selected.is_none() {
|
||||
self.select(0);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn select(&mut self, idx: usize) {
|
||||
if let Some(selected) = self.selected {
|
||||
if let Some(item) = self.items.get(selected) {
|
||||
item.set_unselected();
|
||||
}
|
||||
}
|
||||
if let Some(item) = self.items.get(idx) {
|
||||
item.set_selected();
|
||||
self.selected = Some(idx);
|
||||
}
|
||||
}
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
self.items.is_empty()
|
||||
}
|
||||
|
||||
fn selection_down(&mut self) {
|
||||
if self.is_empty() {
|
||||
return;
|
||||
}
|
||||
let idx = match self.selected {
|
||||
Some(idx) => (idx + 1) % self.items.len(),
|
||||
None => 0
|
||||
};
|
||||
self.select(idx);
|
||||
}
|
||||
|
||||
fn selection_up(&mut self) {
|
||||
if self.is_empty() {
|
||||
return;
|
||||
}
|
||||
let idx = match self.selected {
|
||||
Some(0) => self.items.len() - 1,
|
||||
Some(idx) => idx - 1,
|
||||
None => self.items.len() - 1,
|
||||
};
|
||||
self.select(idx);
|
||||
}
|
||||
|
||||
fn activate_selected(&self, window: >k::Window) -> bool {
|
||||
if let Some(idx) = self.selected {
|
||||
if let Some(item) = self.items.get(idx) {
|
||||
return item.activate(window);
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ResultList {
|
||||
result_box: gtk::Box,
|
||||
items: Rc<RefCell<ResultItems>>,
|
||||
}
|
||||
|
||||
impl ResultList {
|
||||
pub fn new(result_box: gtk::Box) -> Self {
|
||||
ResultList {
|
||||
result_box,
|
||||
items: Rc::new(RefCell::new(ResultItems::new())),
|
||||
}
|
||||
}
|
||||
|
||||
fn items_mut(&self) -> RefMut<ResultItems> {
|
||||
self.items.borrow_mut()
|
||||
}
|
||||
|
||||
pub fn clear_list(&self) {
|
||||
self.items_mut().clear(&self.result_box);
|
||||
self.result_box.set_margin_top(0);
|
||||
self.result_box.set_margin_bottom(0);
|
||||
}
|
||||
|
||||
pub fn selection_down(&self) {
|
||||
self.items_mut().selection_down();
|
||||
}
|
||||
|
||||
pub fn selection_up(&self) {
|
||||
self.items_mut().selection_up();
|
||||
}
|
||||
|
||||
pub fn create_result_items(&self, rtype: ResultType, entities: Vec<Entity>) {
|
||||
for r in &entities {
|
||||
if let Err(err) = self.items.borrow_mut().create_item(rtype, r, &self.result_box) {
|
||||
println!("failed to create {:?} item for realm {}: {:?}", rtype, r.name(), err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn activate_selected(&self, window: >k::Window) -> bool {
|
||||
self.items.borrow().activate_selected(window)
|
||||
}
|
||||
}
|
@ -1,152 +0,0 @@
|
||||
|
||||
use gtk::prelude::*;
|
||||
use gtk::StyleContext;
|
||||
use gdk::ModifierType;
|
||||
use gdk::keys::constants;
|
||||
|
||||
use crate::matcher::Matcher;
|
||||
use crate::results::ResultList;
|
||||
use crate::{Result,Builder};
|
||||
|
||||
const STYLE: &str = include_str!("../data/style.css");
|
||||
const MAIN_UI: &str = include_str!("../data/main.ui");
|
||||
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Ui {
|
||||
window: gtk::Window,
|
||||
window_size: (i32, i32),
|
||||
input: gtk::Entry,
|
||||
result_list: ResultList,
|
||||
matcher: Matcher,
|
||||
}
|
||||
|
||||
impl Ui {
|
||||
pub fn run(&self) {
|
||||
gtk::main();
|
||||
}
|
||||
|
||||
pub fn build() -> Result<Self> {
|
||||
let builder = Builder::new(MAIN_UI);
|
||||
let window = builder.get_window("main-window")?;
|
||||
let current = builder.get_label("current-realm")?;
|
||||
let input = builder.get_entry("input-entry")?;
|
||||
let result_box = builder.get_box("result-box")?;
|
||||
|
||||
window.set_opacity(0.85);
|
||||
window.set_icon_name(Some("cs-privacy"));
|
||||
|
||||
window.show_all();
|
||||
|
||||
let window_size = window.get_size();
|
||||
|
||||
let matcher = Matcher::new()?;
|
||||
if let Some(realm) = matcher.current_realm() {
|
||||
current.set_text(realm.name());
|
||||
} else {
|
||||
current.hide();
|
||||
}
|
||||
|
||||
let result_list = ResultList::new(result_box);
|
||||
|
||||
let ui = Ui {
|
||||
window, window_size, input, result_list, matcher,
|
||||
};
|
||||
ui.setup_signals();
|
||||
ui.setup_style();
|
||||
Ok(ui)
|
||||
}
|
||||
|
||||
|
||||
fn setup_signals(&self) {
|
||||
let ui = self.clone();
|
||||
self.input.connect_activate(move |_| { ui.on_activate() });
|
||||
let ui = self.clone();
|
||||
self.input.connect_changed(move |e| {
|
||||
let s = e.get_text();
|
||||
ui.on_entry_changed(s.to_string().as_str());
|
||||
});
|
||||
let ui = self.clone();
|
||||
self.input.connect_key_press_event(move |_,k| {
|
||||
ui.on_key_press(k);
|
||||
Inhibit(false)
|
||||
});
|
||||
|
||||
|
||||
/*
|
||||
self.window.connect_focus_out_event(move |_,_| {
|
||||
gtk::idle_add(|| {
|
||||
gtk::main_quit();
|
||||
Continue(false)
|
||||
});
|
||||
Inhibit(false)
|
||||
|
||||
});
|
||||
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
fn setup_style(&self) {
|
||||
if let Some(settings) = gtk::Settings::get_default() {
|
||||
settings.set_property_gtk_application_prefer_dark_theme(true);
|
||||
}
|
||||
let css = gtk::CssProvider::new();
|
||||
|
||||
if let Err(err) = css.load_from_data(STYLE.as_bytes()) {
|
||||
println!("Error parsing CSS style: {}", err);
|
||||
return;
|
||||
}
|
||||
if let Some(screen) = gdk::Screen::get_default() {
|
||||
StyleContext::add_provider_for_screen(&screen, &css, gtk::STYLE_PROVIDER_PRIORITY_USER);
|
||||
}
|
||||
}
|
||||
|
||||
fn on_activate(&self) {
|
||||
if self.result_list.activate_selected(&self.window) {
|
||||
println!("activated");
|
||||
self.input.set_text("");
|
||||
glib::idle_add_local({
|
||||
let (w,h) = self.window_size;
|
||||
let window = self.window.clone();
|
||||
move || {
|
||||
window.resize(w, h);
|
||||
gtk::main_quit();
|
||||
Continue(false)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn on_entry_changed(&self, text: &str) {
|
||||
self.matcher.update(text, &self.result_list);
|
||||
let (w,h) = self.window_size;
|
||||
self.window.resize(w, h);
|
||||
}
|
||||
|
||||
fn is_escape_key(keyval: gdk::keys::Key, state: ModifierType) -> bool {
|
||||
keyval == constants::Escape ||
|
||||
(state == ModifierType::CONTROL_MASK && keyval.to_unicode().unwrap() == '[')
|
||||
}
|
||||
|
||||
fn on_key_press(&self, key: &gdk::EventKey) {
|
||||
let state = key.get_state();
|
||||
let keyval = key.get_keyval();
|
||||
|
||||
if Self::is_escape_key(key.get_keyval(), key.get_state()) {
|
||||
gtk::main_quit();
|
||||
}
|
||||
if keyval == constants::Up {
|
||||
self.result_list.selection_up();
|
||||
} else if keyval == constants::Down {
|
||||
self.result_list.selection_down();
|
||||
} else if state == ModifierType::CONTROL_MASK {
|
||||
match keyval.to_unicode().unwrap() {
|
||||
'n'|'j' => self.result_list.selection_down(),
|
||||
'p'|'k' => self.result_list.selection_up(),
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user