diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..fa8c607 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,20 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true + +# CI config +[*.{yml,yaml}] +indent_style = space +indent_size = 2 + +# Python and generated Python source code +[{*.py,komorebi/*.in}] +indent_style = space +indent_size = 4 + +# Meson build files +[*.build] +indent_style = space +indent_size = 4 diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..62e0fcf --- /dev/null +++ b/.flake8 @@ -0,0 +1,7 @@ +[flake8] +ignore = + W503, # line break before binary operator (follow PEP8 style guide) +per-file-ignores = + komorebi.py:E402 + komorebi-wallpaper-creator.py:E402 +max-line-length = 127 diff --git a/.gitignore b/.gitignore index 617c97f..23228d6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ build builddir +__pycache__ diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..07be207 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "python.linting.flake8Enabled": true, + "python.linting.enabled": true +} diff --git a/README.md b/README.md index a66eae9..01b22bb 100644 --- a/README.md +++ b/README.md @@ -167,4 +167,4 @@ If your issue has not already been reported, please report it [here](https://git ### Thanks To: -Pete Lewis ([@PJayB](https://github.com/PJayB)) for adding multi-monitor support +Pete Lewis ([@PJayB](https://github.com/PJayB)) for adding multi-monitor support \ No newline at end of file diff --git a/config.vala.in b/config.vala.in deleted file mode 100644 index 869a469..0000000 --- a/config.vala.in +++ /dev/null @@ -1,6 +0,0 @@ -namespace Config { - const string package_name = @PACKAGE_NAME@; - const string package_version = @PACKAGE_VERSION@; - const string package_datadir = @PKGDATADIR@; - const string datadir = @DATADIR@; -} diff --git a/komorebi-wallpaper-creator.py b/komorebi-wallpaper-creator.py new file mode 100755 index 0000000..d7bdeda --- /dev/null +++ b/komorebi-wallpaper-creator.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 + +import argparse +import gi +import logging +import sys +import os + +gi.require_versions({ + 'Clutter': '1.0', + 'Gtk': '3.0' +}) + +from gi.repository import Gtk, Gio + +import komorebi +from komorebi.wallpaper_creator.window import WallpaperWindow + + +def main_parser(): + parser = argparse.ArgumentParser() + parser.add_argument('-v', '--version', + action='version', + help='show current version', + version=f'Version: {komorebi.__version__}\nMaintained by: Komorebi Team') + parser.add_argument('-l', '--log', + type=str, + choices=['NORMAL', 'INFO', 'DEBUG'], + default='NORMAL', + help="set logging level for komorebi") + return parser + + +def main(): + print(f'Welcome to {komorebi.__package_name__} Wallpaper Creator') + + parser = main_parser() + args = parser.parse_args() + + log_level = logging.WARNING + log_format = '' + + if args.log: + if args.log == 'INFO': + log_level = logging.INFO + log_format = '[%(levelname)s]: %(message)s' + elif args.log == 'DEBUG': + log_level = logging.DEBUG + log_format = '[%(levelname)s] (%(asctime)s): %(message)s' + + logging.basicConfig(format=log_format, level=log_level, datefmt='%H:%M:%S') + + # Load resources + resource_path = os.path.join(komorebi.__package_datadir__, 'komorebi.gresource') + resource = Gio.Resource.load(resource_path) + Gio.resources_register(resource) + + Gtk.init(sys.argv) + logging.debug('Gtk initialized') + + window = WallpaperWindow() + + main_settings = Gtk.Settings.get_default() + main_settings.props.gtk_application_prefer_dark_theme = True + main_settings.props.gtk_xft_antialias = 1 + main_settings.props.gtk_xft_rgba = "none" + main_settings.props.gtk_xft_hintstyle = "slight" + + window.show_all() + + Gtk.main() + + +if __name__ == '__main__': + main() diff --git a/komorebi.py b/komorebi.py new file mode 100755 index 0000000..9c54877 --- /dev/null +++ b/komorebi.py @@ -0,0 +1,154 @@ +#!/usr/bin/env python3 + +import argparse +import os +import gi +import signal +import sys +import logging + +gi.require_versions({ + 'Gtk': '3.0', + 'GObject': '2.0', + 'GtkClutter': '1.0', + 'Clutter': '1.0', + 'ClutterGst': '3.0', + 'Gdk': '3.0', + 'GdkPixbuf': '2.0', + 'Gst': '1.0', + 'WebKit2': '4.0', +}) + +from gi.repository import Gio, Gtk, GtkClutter, Gdk, Gst, Clutter + +from komorebi.preferences_window import PreferencesWindow +from komorebi.settings import ConfigKeys, Settings +import komorebi.utilities + +from komorebi.screen import Screen + + +def check_desktop_compatible(): + return not(os.environ.get('XDG_SESSION_TYPE') == 'wayland' or os.environ.get('WAYLAND_DISPLAY')) + + +def main_parser(): + parser = argparse.ArgumentParser() + parser.add_argument('-v', '--version', + action='version', + help='show current version', + version=f'Version: {komorebi.__version__}\nMaintained by: Komorebi Team') + parser.add_argument('-ss', '--single-screen', + action='store_true', + help='force komorebi to run only on the main screen') + parser.add_argument('-l', '--log', + type=str, + choices=['NORMAL', 'INFO', 'DEBUG'], + default='NORMAL', + help="set logging level for komorebi") + return parser + + +def _on_destroy(*args): + logging.info("Quitting...") + Clutter.main_quit() + + +def main(): + print(f'Welcome to {komorebi.__package_name__}') + + # Handle Ctrl-C + signal.signal(signal.SIGINT, signal.SIG_DFL) + + # Parse the arguments + parser = main_parser() + args = parser.parse_args() + + # Setup logger + log_level = logging.WARNING + log_format = '[%(levelname)s]: %(message)s' + + if args.log: + if args.log == 'INFO': + log_level = logging.INFO + elif args.log == 'DEBUG': + log_level = logging.DEBUG + log_format = '[%(levelname)s] (%(asctime)s): %(message)s' + + logging.basicConfig(format=log_format, level=log_level, datefmt='%H:%M:%S') + + # Ensure we are not on Wayland + if not check_desktop_compatible(): + logging.error('Wayland detected. Not supported (yet) :(') + logging.info('Contribute to Komorebi and add the support! <3') + return + + # Initialize backends + GtkClutter.init(sys.argv) + logging.debug("GtkClutter initialized") + + Settings.load_settings() + logging.debug("Configuration file read") + + logging.info('loading Gst') + Gst.init(sys.argv) + logging.debug('Gst initialized') + + # Load resources + resource_path = os.path.join(komorebi.__package_datadir__, 'komorebi.gresource') + resource = Gio.Resource.load(resource_path) + Gio.resources_register(resource) + + display = Gdk.Display.get_default() + if args.single_screen: + monitor_count = 1 + else: + monitor_count = display.get_n_monitors() + logging.info(f"Monitor Count - {monitor_count}") + + komorebi.utilities.init_clipboard(display) + + # Initialize Screen's + screen_list = [Screen(i) for i in range(monitor_count)] + + # Setup some GTK properties + main_settings = Gtk.Settings.get_default() + main_settings.props.gtk_application_prefer_dark_theme = True + main_settings.props.gtk_xft_antialias = 1 + main_settings.props.gtk_xft_rgba = "none" + main_settings.props.gtk_xft_hintstyle = "slight" + + # Setup preferences window + def _on_settings_changed(_, setting_key): + logging.debug("Setting " + str(setting_key) + " changed!") + if setting_key == ConfigKeys.WALLPAPER_NAME: + for screen in screen_list: + screen.load_wallpaper(Settings.wallpaper_name) + elif setting_key == ConfigKeys.AUTOSTART: + komorebi.utilities.toggle_autostart() + else: + for screen in screen_list: + screen.on_settings_changed(setting_key) + return True + + prefs_window = PreferencesWindow() + prefs_window.connect('settings-changed', _on_settings_changed) + + # Setup screens + def _on_settings_request_event(_, wallpaper_tab): + prefs_window.show(wallpaper_tab) + return True + + for screen in screen_list: + screen.connect("destroy", _on_destroy) + screen.load_wallpaper(Settings.wallpaper_name) + screen.fade_in() + screen.connect('settings_requested', _on_settings_request_event) + + # Start Clutter backend + logging.debug("Starting Clutter backend...") + Clutter.main() + + +if __name__ == '__main__': + main() diff --git a/komorebi/__init__.in b/komorebi/__init__.in new file mode 100644 index 0000000..cd65bc8 --- /dev/null +++ b/komorebi/__init__.in @@ -0,0 +1,4 @@ +__package_name__ = @PACKAGE_NAME@ +__version__ = @PACKAGE_VERSION@ +__package_datadir__ = @PKGDATADIR@ +__datadir__ = @DATADIR@ diff --git a/komorebi/bubblemenu/item.py b/komorebi/bubblemenu/item.py new file mode 100644 index 0000000..933145b --- /dev/null +++ b/komorebi/bubblemenu/item.py @@ -0,0 +1,74 @@ +import logging +from enum import IntEnum + +from gi.repository import Clutter + + +# View modes for a menu item +class ViewMode(IntEnum): + VISIBLE = 0 # Item is visible and interactive + GREYED = 1 # Item is visible but "greyed" out, can't be interacted with + INVISIBLE = 2 # Item is invisible and doesn't occupy space on the menu + + +class BubbleMenuItem(Clutter.Text): + # Properties + _view_mode = ViewMode.VISIBLE + + def __init__(self, text, callback): + Clutter.Text.__init__(self) + logging.debug(f'Initializing BubbleMenuItem(text="{text}")') + + # Setup properties + self.set_x_align(Clutter.ActorAlign.START) + self.set_x_expand(True) + self.set_reactive(False) + self.set_selectable(False) + self.set_margin_top(5) + + self.set_font_name('Lato 15') + self.set_text(text) + self.set_color(Clutter.Color.from_string('white')[1]) + + self.signals_setup() + + self.hide() + + self.connect_after("button_press_event", callback) + logging.debug('Initialized BubbleMenuItem') + + def signals_setup(self): + def _on_button_press_event(self, e): + self.set_opacity(100) + return False + + def _on_motion_event(self, e): + self.set_opacity(200) + return True + + def _on_leave_event(self, e): + self.set_opacity(255) + return True + + self.connect_after("button_press_event", _on_button_press_event) + self.connect_after("motion_event", _on_motion_event) + self.connect_after("leave_event", _on_leave_event) + + def show_item(self): + if self._view_mode != ViewMode.INVISIBLE: + self.show() + self.set_opacity(255 if self._view_mode == ViewMode.VISIBLE else 10) + self.set_reactive(self._view_mode == ViewMode.VISIBLE) + + def hide_item(self): + self.hide() + self.set_reactive(False) + + def set_view_mode(self, view_mode): + self._view_mode = view_mode + if self._view_mode == ViewMode.VISIBLE: + self.set_opacity(255) + elif self._view_mode == ViewMode.GREYED: + self.set_opacity(10) + elif self._view_mode == ViewMode.INVISIBLE: + self.hide() diff --git a/komorebi/bubblemenu/menu.py b/komorebi/bubblemenu/menu.py new file mode 100644 index 0000000..9ab4288 --- /dev/null +++ b/komorebi/bubblemenu/menu.py @@ -0,0 +1,107 @@ +import logging + +from gi.repository import Clutter, GObject + + +class BubbleMenu(Clutter.Actor): + # Screen info + screen_width = None + screen_height = None + + # Signal handlers + signal_handlers = [] + + # Layout + options_layout = Clutter.BoxLayout(orientation=Clutter.Orientation.VERTICAL, spacing=5) + hierarchy_layout = Clutter.BoxLayout(orientation=Clutter.Orientation.VERTICAL) + + # Hierarchies + overlay_options = None + wallpaper_options = None + meta_options = None + + def __init__(self, screen): + Clutter.Actor.__init__(self) + logging.debug('Loading BubbleMenu...') + + # Get screen dimensions + self.screen_width = screen.width + self.screen_height = screen.height + + # Set initial properties + self.set_layout_manager(self.hierarchy_layout) + self.set_opacity(0) + self.set_margin_top(5) + self.set_margin_right(5) + self.set_margin_left(20) + self.set_margin_bottom(5) + + # Initialize and add hierarchies + self.overlay_options = Clutter.Actor() + self.wallpaper_options = Clutter.Actor() + self.meta_options = Clutter.Actor() + for hierarchy in [self.overlay_options, self.wallpaper_options, self.meta_options]: + hierarchy.set_layout_manager(self.options_layout) + hierarchy.set_x_align(Clutter.ActorAlign.START) + hierarchy.set_x_expand(True) + self.add_child(hierarchy) + + logging.debug('Loaded BubbleMenu') + + def connect_weak(self, detailed_signal, handler, *args): + self.signal_handlers.append(super().connect(detailed_signal, handler, *args)) + + def disconnect_all(self): + for signal in self.signal_handlers: + self.disconnect(signal) + self.signal_handlers = [] + + def fade_in(self, e): + # Make sure we don't display offscreen + x = min(e.x, self.screen_width - (self.get_width() + 15 * 2)) + y = min(e.y, self.screen_height - (self.get_height() + 15 * 2)) + + self.set_opacity(0) + self.set_x(x) + self.set_y(y) + self.save_easing_state() + self.set_easing_duration(90) + + self.set_x(x + 15) + self.set_y(y + 15) + self.set_scale(1, 1) + self.set_opacity(255) + self.set_easing_mode(Clutter.AnimationMode.EASE_IN_SINE) + self.restore_easing_state() + + self.emit('menu_opened', e) + + for hierarchy in self.get_children(): + for child in hierarchy.get_children(): + child.show_item() + + logging.debug("BubbleMenu faded in") + + def fade_out(self): + self.save_easing_state() + self.set_easing_duration(90) + self.set_scale(0.9, 0.9) + self.set_opacity(0) + self.set_easing_mode(Clutter.AnimationMode.EASE_IN_SINE) + self.restore_easing_state() + + self.emit('menu_closed') + + for hierarchy in self.get_children(): + for child in hierarchy.get_children(): + child.hide_item() + + logging.debug("BubbleMenu faded out") + + @GObject.Signal(arg_types=(GObject.TYPE_PYOBJECT,)) + def menu_opened(self, event): + pass + + @GObject.Signal() + def menu_closed(self): + pass diff --git a/komorebi/overlays/asset.py b/komorebi/overlays/asset.py new file mode 100644 index 0000000..d5ffc1c --- /dev/null +++ b/komorebi/overlays/asset.py @@ -0,0 +1,168 @@ +import logging + +from gi.repository import Clutter, Cogl, GdkPixbuf, Gio, GLib + +import komorebi +from komorebi.overlays.base import Overlay, OverlayType + + +class Asset(Overlay): + # Screen info + screen_width = None + screen_height = None + + # Settings + visible = None + animation_mode = None + animation_speed = None + asset_width = None + asset_height = None + + # Image(Asset) and its pixbuf + image = None + pixbuf = None + + asset_animation_timeout_handle = None + + # Animation-specific variables + clouds_direction = 'right' + fade_type = 'in' + + def __init__(self, screen, config_file): + Overlay.__init__(self) + logging.debug('Loading Asset...') + + self.screen_width = screen.width + self.screen_height = screen.height + self.set_size(self.screen_width, self.screen_height) + self.image = Clutter.Image() + + name = config_file.get_string('Info', 'Name') + self.load_settings(config_file) + self.set_asset(name) + + self.set_content(self.image) + logging.debug('Loaded Asset') + + def on_unload(self): + logging.debug('Unloading Asset...') + if self.asset_animation_timeout_handle: + GLib.source_remove(self.asset_animation_timeout_handle) + self.asset_animation_timeout_handle = 0 + + def __del__(self): + logging.debug('Unloaded Asset') + + def load_settings(self, config_file): + self.visible = config_file.get_boolean(OverlayType.ASSET.value, 'Visible') + + self.animation_mode = config_file.get_string(OverlayType.ASSET.value, 'AnimationMode') + self.animation_speed = config_file.get_integer(OverlayType.ASSET.value, 'AnimationSpeed') + + self.asset_width = config_file.get_integer(OverlayType.ASSET.value, 'Width') + self.asset_height = config_file.get_integer(OverlayType.ASSET.value, 'Height') + + def register_menu_actions(self, menu): + def _on_menu_open(_1, _2, self): + # FIXME: Looks ugly to hide the asset overlay, try to blend in + self.hide() + return False + + def _on_menu_close(_, self): + self.show() + return False + + menu.connect_weak('menu_opened', _on_menu_open, self) + menu.connect_weak('menu_closed', _on_menu_close, self) + + def set_asset(self, name): + if self.asset_width <= 0: + self.asset_width = self.screen_width + if self.asset_height <= 0: + self.asset_height = self.screen_height + + asset_path = f'{komorebi.__package_datadir__}/{name}/assets.png' + + if not Gio.File.new_for_path(asset_path).query_exists(): + logging.warning(f'asset with path: {asset_path} does not exist!') + return + + if self.asset_width != 0 and self.asset_height != 0: + self.pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(asset_path, self.asset_width, self.asset_height, False) + else: + self.pixbuf = GdkPixbuf.Pixbuf.new_from_file(asset_path) + + self.image.set_data(self.pixbuf.get_pixels(), + Cogl.PixelFormat.RGBA_8888 if self.pixbuf.get_has_alpha() else Cogl.PixelFormat.RGB_888, + self.pixbuf.get_width(), self.pixbuf.get_height(), self.pixbuf.get_rowstride()) + + self.set_x(0) + self.set_y(0) + self.set_opacity(255) + self.remove_all_transitions() + + self.animate() if self.should_animate() else self.fade_in() + + def should_animate(self): + if self.animation_mode == 'noanimation': + if self.asset_animation_timeout_handle: + GLib.Source.remove(self.asset_animation_timeout_handle) + self.asset_animation_timeout_handle = 0 + + self.remove_all_transitions() + self.fade_out() + return False + + return True + + def animate(self): + def _on_animation_timeout(self): + if self.animation_mode == 'clouds': + if self.clouds_direction == 'right': + if self.get_x() + (self.get_width() / 2) >= self.screen_width: + self.clouds_direction = 'left' + else: + self.save_easing_state() + self.set_easing_duration(self.animation_speed * 100) + self.props.x += 60 + self.set_easing_mode(Clutter.AnimationMode.LINEAR) + self.restore_easing_state() + else: + if self.get_x() <= 0: + self.clouds_direction = 'right' + else: + self.save_easing_state() + self.set_easing_duration(self.animation_speed * 100) + self.props.x -= 60 + self.set_easing_mode(Clutter.AnimationMode.LINEAR) + self.restore_easing_state() + elif self.animation_mode == 'light': + if self.fade_type == 'in': + self.fade_in(self.animation_speed * 100) + self.fade_type = 'out' + else: + self.fade_out(self.animation_speed * 100) + self.fade_type = 'in' + + return True + + if self.animation_speed <= 10: + self.animation_speed = 100 + logging.warning('The Asset Animation Speed has been adjusted in this wallpaper.' + 'Please consider updating it to at least 100') + + self.asset_animation_timeout_handle = GLib.timeout_add(self.animation_speed * 30, _on_animation_timeout, self) + + def fade_in(self, custom_duration=90): + self.save_easing_state() + self.set_easing_duration(custom_duration) + self.props.opacity = 255 + self.set_easing_mode(Clutter.AnimationMode.LINEAR) + self.restore_easing_state() + + def fade_out(self, custom_duration=90): + self.save_easing_state() + self.set_easing_duration(custom_duration) + self.props.opacity = 0 + self.set_easing_mode(Clutter.AnimationMode.LINEAR) + self.restore_easing_state() diff --git a/komorebi/overlays/base.py b/komorebi/overlays/base.py new file mode 100644 index 0000000..749ac84 --- /dev/null +++ b/komorebi/overlays/base.py @@ -0,0 +1,27 @@ +import enum + +from gi.repository import Clutter + + +class Overlay(Clutter.Actor): + def __init__(self): + Clutter.Actor.__init__(self) + + # Called whenever it's time to register behaviour dependent on the menu + def register_menu_actions(self, menu): + pass + + # Called whenever a setting was changed globally. + # Returns if the object is to be removed or not. + def on_settings_changed(self, setting_key): + pass + + # Called when this object is about to be unloaded + def on_unload(self): + pass + + +class OverlayType(enum.Enum): + CLOCK = 'DateTime' + ASSET = 'Asset' + DESKTOP = 'Desktop' diff --git a/komorebi/overlays/clock.py b/komorebi/overlays/clock.py new file mode 100644 index 0000000..5c56cff --- /dev/null +++ b/komorebi/overlays/clock.py @@ -0,0 +1,293 @@ +import logging + +from gi.repository import Clutter, GLib + +from komorebi.overlays.base import Overlay, OverlayType +from komorebi.settings import Settings +from komorebi.utilities import MarginIndex, RotationIndex + + +class Clock(Overlay): + # Screen info + screen_width = None + screen_height = None + + # Signals + time_text_width_signal = None + + # Overlay settings + parallax = None + position = None + alignment = None + always_on_top = None + margin = None + rotation = None + + text_color = None + text_font = None + text_alpha = None + + shadow_color = None + shadow_font = None + shadow_alpha = None + + # Text Content + text_container_actor = None + time_text = None + date_text = None + + # Shadow Content + shadow_container_actor = None + time_shadow_text = None + date_shadow_text = None + + # Vertical Box Layout + box_layout = Clutter.BoxLayout(orientation=Clutter.Orientation.VERTICAL) + + # Time updater + timeout_handle = None + + # Time format + time_format = None + + # Ability to drag + drag_action = None + + def __init__(self, screen, config_file): + Overlay.__init__(self) + logging.debug('Loading Clock...') + + if not config_file.get_boolean('DateTime', 'Visible'): + # FIXME: Dirty way to disable Clock when wallpaper definitions say so; + # When wallpaper files get rewritten this will be implicitely handled + return + + self.screen_width = screen.width + self.screen_height = screen.height + + self.text_container_actor = Clutter.Actor() + self.time_text = Clutter.Text() + self.date_text = Clutter.Text() + + self.shadow_container_actor = Clutter.Actor() + self.time_shadow_text = Clutter.Text() + self.date_shadow_text = Clutter.Text() + + self.drag_action = Clutter.DragAction() + + # Properties + self.text_container_actor.set_layout_manager(self.box_layout) + self.shadow_container_actor.set_layout_manager(self.box_layout) + + self.set_background_color(Clutter.Color(0, 0, 0, 0)) + self.set_opacity(0) + self.set_reactive(True) + + self.text_container_actor.set_background_color(Clutter.Color(0, 0, 0, 0)) + self.shadow_container_actor.set_background_color(Clutter.Color(0, 0, 0, 0)) + + self.time_text.set_x_expand(True) + self.time_text.set_y_expand(True) + + self.time_shadow_text.set_x_expand(True) + self.time_shadow_text.set_y_expand(True) + + # Load settings and initialize + self.load_settings(config_file) + self.set_date_time() + + self.shadow_container_actor.add_effect(Clutter.BlurEffect()) + + self.add_action(self.drag_action) + + self.text_container_actor.add_child(self.time_text) + self.text_container_actor.add_child(self.date_text) + + self.shadow_container_actor.add_child(self.time_shadow_text) + self.shadow_container_actor.add_child(self.date_shadow_text) + + self.add_child(self.shadow_container_actor) + self.add_child(self.text_container_actor) + + # Signals + self.signals_setup(screen) + + logging.debug('Loaded Clock') + + def load_settings(self, config_file): + self.parallax = config_file.get_boolean(OverlayType.CLOCK.value, 'Parallax') + + # Initialize margin list + self.margin = [None] * 4 + self.margin[MarginIndex.LEFT.value] = config_file.get_integer(OverlayType.CLOCK.value, 'MarginLeft') + self.margin[MarginIndex.TOP.value] = config_file.get_integer(OverlayType.CLOCK.value, 'MarginTop') + self.margin[MarginIndex.BOTTOM.value] = config_file.get_integer(OverlayType.CLOCK.value, 'MarginBottom') + self.margin[MarginIndex.RIGHT.value] = config_file.get_integer(OverlayType.CLOCK.value, 'MarginRight') + + # Initialize rotation list + self.rotation = [None] * 3 + self.rotation[RotationIndex.X.value] = config_file.get_double(OverlayType.CLOCK.value, 'RotationX') + self.rotation[RotationIndex.Y.value] = config_file.get_double(OverlayType.CLOCK.value, 'RotationY') + self.rotation[RotationIndex.Z.value] = config_file.get_double(OverlayType.CLOCK.value, 'RotationZ') + + self.position = config_file.get_string(OverlayType.CLOCK.value, 'Position') + self.alignment = config_file.get_string(OverlayType.CLOCK.value, 'Alignment') + self.always_on_top = config_file.get_boolean(OverlayType.CLOCK.value, 'AlwaysOnTop') + + self.text_color = config_file.get_string(OverlayType.CLOCK.value, 'Color') + self.text_alpha = config_file.get_integer(OverlayType.CLOCK.value, 'Alpha') + + self.shadow_color = config_file.get_string(OverlayType.CLOCK.value, 'ShadowColor') + self.shadow_alpha = config_file.get_integer(OverlayType.CLOCK.value, 'ShadowAlpha') + + self.time_font = config_file.get_string(OverlayType.CLOCK.value, 'TimeFont') + self.date_font = config_file.get_string(OverlayType.CLOCK.value, 'DateFont') + + def signals_setup(self, screen): + def _on_motion_notify_event(screen, event, self): + # FIXME: Hardcoded from old code, easily a customizable property + layer_coeff = 70 + self.set_x((screen.stage.get_width() - self.get_width()) / 2 + - (event.x - screen.stage.get_width() / 2) / layer_coeff) + self.set_y((screen.stage.get_height() - self.get_height()) / 2 + - (event.y - screen.stage.get_height() / 2) / layer_coeff) + return False + + if self.parallax and self.position == 'center': + screen.connect_weak('motion_notify_event', _on_motion_notify_event, self) + + def on_unload(self): + logging.debug('Unloading Clock...') + if self.timeout_handle: + GLib.source_remove(self.timeout_handle) + if self.time_text_width_signal: + self.time_text.disconnect(self.time_text_width_signal) + + def __del__(self): + logging.debug('Unloaded Clock') + + def register_menu_actions(self, menu): + def _on_menu_open(_1, _2, self): + self.hide() + return False + + def _on_menu_close(_, self): + self.show() + return False + + menu.connect_weak('menu_opened', _on_menu_open, self) + menu.connect_weak('menu_closed', _on_menu_close, self) + + def set_date_time(self): + self.set_alignment() + self.set_rotation() + + if self.get_opacity() < 1: + self.fade_in() + + self.set_opacity(self.text_alpha) + self.shadow_container_actor.set_opacity(self.shadow_alpha) + + self.set_position() + + def _on_notify_width_event(_1, _2, self): + self.set_position() + self.set_margins() + + self.time_text_width_signal = self.time_text.connect('notify::width', _on_notify_width_event, self) + + if self.timeout_handle: + # No need to re-create timeout loop if it exists already + return + + def _on_timeout(self): + self.time_format = '%H:%M' if Settings.time_twenty_four else '%l:%M %p' + + glib_time = GLib.DateTime.new_now_local().format(self.time_format) + glib_date = GLib.DateTime.new_now_local().format('%A, %B %e') + + self.time_text.set_markup(f"{glib_time}") + self.date_text.set_markup(f"{glib_date}") + + # Apply same to shadows + self.time_shadow_text.set_markup(f"{glib_time}") + self.date_shadow_text.set_markup(f"{glib_date}") + return True + + self.timeout_handle = Clutter.threads_add_timeout(GLib.PRIORITY_DEFAULT, 200, _on_timeout, self) + + def set_alignment(self): + if self.alignment == 'start': + self.time_text.set_x_align(Clutter.ActorAlign.START) + self.time_shadow_text.set_x_align(Clutter.ActorAlign.START) + elif self.alignment == 'center': + self.time_text.set_x_align(Clutter.ActorAlign.CENTER) + self.time_shadow_text.set_x_align(Clutter.ActorAlign.CENTER) + else: + self.time_text.set_x_align(Clutter.ActorAlign.END) + self.time_shadow_text.set_x_align(Clutter.ActorAlign.END) + + def set_position(self): + if self.position == 'top_right': + self.set_x(self.screen_width - self.get_width()) + self.set_y(0) + elif self.position == 'top_center': + self.set_x((self.screen_width / 2) - (self.get_width() / 2)) + self.set_y(0) + elif self.position == 'top_left': + self.set_x(0) + self.set_y(0) + elif self.position == 'center_right': + self.set_x(self.screen_width - self.get_width()) + self.set_y((self.screen_height / 2) - (self.get_height() / 2)) + elif self.position == 'center': + self.set_x((self.screen_width / 2) - (self.get_width() / 2)) + self.set_y((self.screen_height / 2) - (self.get_height() / 2)) + elif self.position == 'center_left': + self.set_x(0) + self.set_y((self.screen_height / 2) - (self.get_height() / 2)) + elif self.position == 'bottom_right': + self.set_x(self.screen_width - self.get_width()) + self.set_y(self.screen_height - self.get_height()) + elif self.position == 'bottom_center': + self.set_x((self.screen_width / 2) - (self.get_width() / 2)) + self.set_y(self.screen_height - self.get_height()) + elif self.position == 'bottom_left': + self.set_x(0) + self.set_y(self.screen_height - self.get_height()) + + def set_margins(self): + self.set_translation(self.margin[MarginIndex.LEFT.value] - self.margin[MarginIndex.RIGHT.value], + self.margin[MarginIndex.TOP.value] - self.margin[MarginIndex.BOTTOM.value], + 0) + + def set_rotation(self): + self.set_rotation_angle(Clutter.RotateAxis.X_AXIS, self.rotation[RotationIndex.X.value]) + self.set_rotation_angle(Clutter.RotateAxis.Y_AXIS, self.rotation[RotationIndex.Y.value]) + self.set_rotation_angle(Clutter.RotateAxis.Z_AXIS, self.rotation[RotationIndex.Z.value]) + + def move_to(self, x=-1, y=-1): + self.save_easing_state() + self.set_easing_duration(90) + if x != -1: + self.set_x(x) + if y != -1: + self.set_y(y) + self.set_easing_mode(Clutter.AnimationMode.EASE_IN_SINE) + self.restore_easing_state() + + def fade_in(self, custom_duration=90): + self.save_easing_state() + self.set_easing_duration(90) + self.set_opacity(self.text_alpha) + self.set_easing_mode(Clutter.AnimationMode.EASE_IN_SINE) + self.restore_easing_state() + self.set_reactive(True) + + def fade_out(self): + self.save_easing_state() + self.set_easing_duration(90) + self.set_opacity(0) + self.set_easing_mode(Clutter.AnimationMode.EASE_IN_SINE) + self.restore_easing_state() + self.set_reactive(False) diff --git a/komorebi/overlays/desktop.py b/komorebi/overlays/desktop.py new file mode 100644 index 0000000..f482810 --- /dev/null +++ b/komorebi/overlays/desktop.py @@ -0,0 +1,754 @@ +from komorebi.settings import ConfigKeys +import logging + +from gi.repository import Clutter, Cogl, Gdk, GdkPixbuf, Gio, GLib, Gtk, Pango + +from komorebi.bubblemenu.item import BubbleMenuItem, ViewMode +from komorebi.overlays.base import Overlay + +from komorebi.settings import Settings +import komorebi.utilities + + +class RowLabel(Gtk.EventBox): + # Switch between mainBox and 'Copied' label + stack = None + + # Contains both labels + main_box = None + + name_label = None + value_label = None + copied_label = None + + css = """*, *:disabled { + transition: 150ms ease-in; + background-color: @transparent; + background-image: none; + border: none; + border-color: @transparent; + box-shadow: inset 1px 2px rgba(0,0,0,0); + border-radius: 3px; + color: white; + text-shadow:0px 2px 3px rgba(0,0,0,0.9); + -gtk-icon-shadow: 0px 1px 4px rgba(0, 0, 0, 0.4); + } + .:hover { + transition: 50ms ease-out; + border-style: outset; + background-color: rgba(0, 0, 0, 0.9); + }""" + + def __init__(self, name_str): + Gtk.EventBox.__init__(self) + + self.stack = Gtk.Stack() + self.main_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=20) + self.name_label = Gtk.Label(label=name_str) + self.value_label = Gtk.Label(label='Value') + self.copied_label = Gtk.Label(label=name_str + ' copied') + + self.set_margin_top(10) + self.set_margin_bottom(10) + self.set_margin_left(10) + self.set_margin_right(10) + self.add_events(Gdk.EventMask.ALL_EVENTS_MASK) + komorebi.utilities.apply_css([self], self.css) + + self.stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE) + self.stack.set_transition_duration(300) + + self.value_label.set_line_wrap(True) + self.value_label.set_max_width_chars(19) + self.value_label.set_ellipsize(Pango.EllipsizeMode.MIDDLE) + + self.name_label.set_halign(Gtk.Align.START) + self.value_label.set_halign(Gtk.Align.END) + + # Signals + self.setup_signals() + + self.main_box.pack_start(self.name_label, True, True, 0) + self.main_box.pack_end(self.value_label, True, True, 0) + + self.stack.add_named(self.main_box, 'main_box') + self.stack.add_named(self.copied_label, 'copied_label') + + self.stack.set_visible_child(self.main_box) + + self.add(self.stack) + + def setup_signals(self): + def _on_button_press_event(self, e): + # Set the clipboard's value + komorebi.utilities.clipboard.set_text(self.value_label.get_label(), -1) + self.stack.set_visible_child(self.copied_label) + + def _on_timeout(): + self.stack.set_visible_child(self.main_box) + return False + + GLib.timeout_add(600, _on_timeout) + return False + + self.connect('button_press_event', _on_button_press_event) + + def set_value(self, value_str): + if value_str: + self.value_label.set_label(value_str) + self.value_label.set_tooltip_text(value_str) + + +class ResponsiveGrid(Overlay): + # Limit of items per column + items_limit = 8 + + # Layouts (HORIZONTAL/VERTICAL) + horizontal_layout = Clutter.BoxLayout(orientation=Clutter.Orientation.HORIZONTAL, spacing=50) + vertical_layout = Clutter.BoxLayout(orientation=Clutter.Orientation.VERTICAL, spacing=30) + + def __init__(self, screen): + Overlay.__init__(self) + + self.set_size(screen.width, screen.height) + + self.set_layout_manager(self.horizontal_layout) + self.set_y_align(Clutter.ActorAlign.START) + + def append(self, item): + last_child = self.get_last_child() + if last_child is not None: + if last_child.get_n_children() < self.items_limit: + last_child.add_child(item) + return + + # Create a new column and add the new item to it + column_actor = Clutter.Actor(layout_manager=self.vertical_layout, y_align=Clutter.ActorAlign.START, y_expand=True) + + column_actor.add_child(item) + self.add_child(column_actor) + + def clear_icons(self): + for child in self.get_children(): + child.destroy_all_children() + self.remove_child(child) + + +class Icon(Clutter.Actor): + # Title of the file + title_name = '' + + box_layout = Clutter.BoxLayout(orientation=Clutter.Orientation.VERTICAL) + + icon_actor = None + icon_image = None + title_text = None + + # Ability to drag + drag_action = None + + def __init__(self, name, pixbuf, icon_size): + Clutter.Actor.__init__(self) + + self.title_name = name + + self.main_actor = Clutter.Actor() + self.icon_actor = Clutter.Actor() + self.icon_image = Clutter.Image() + self.title_text = Clutter.Text() + self.drag_action = Clutter.DragAction() + + # Setup widgets + self.icon_image.set_data(pixbuf.get_pixels(), + Cogl.PixelFormat.RGBA_8888 if pixbuf.get_has_alpha() else Cogl.PixelFormat.RGB_888, + icon_size, icon_size, pixbuf.get_rowstride()) + self.title_text.set_markup(f"{self.title_name}") + + self.set_layout_manager(self.box_layout) + self.set_reactive(True) + self.set_height(83) + self.set_opacity(0) + + self.set_pivot_point(0.5, 0.5) + + self.icon_actor.set_size(icon_size, icon_size) + + self.title_text.set_line_wrap(True) + self.title_text.set_max_length(10) + self.title_text.set_ellipsize(Pango.EllipsizeMode.END) + + self.setup_signals() + + # Add widgets + self.icon_actor.add_action(self.drag_action) + self.icon_actor.set_content(self.icon_image) + self.add_child(self.icon_actor) + self.add_child(self.title_text) + + def setup_signals(self): + def _on_button_press_event(self, event): + if event.button != Gdk.BUTTON_SECONDARY: + self.scaled_scale() + return False + + def _on_button_release_event(self, event): + self.save_easing_state() + self.set_easing_duration(90) + self.set_scale(1.0, 1.0) + self.set_easing_mode(Clutter.AnimationMode.EASE_IN_SINE) + self.restore_easing_state() + + self.connect('button_press_event', _on_button_press_event) + self.connect('button_release_event', _on_button_release_event) + + def scaled_scale(self): + self.save_easing_state() + self.set_easing_duration(90) + self.set_scale(0.9, 0.9) + self.set_easing_mode(Clutter.AnimationMode.EASE_IN_SINE) + self.restore_easing_state() + + def trash(self): + self.save_easing_state() + self.set_easing_duration(90) + self.set_scale(0.9, 0.9) + self.set_opacity(0) + self.set_easing_mode(Clutter.AnimationMode.EASE_IN_SINE) + self.restore_easing_state() + + def dim_icon(self): + self.save_easing_state() + self.set_easing_duration(400) + self.set_opacity(100) + self.title_text.set_opacity(100) + self.set_easing_mode(Clutter.AnimationMode.EASE_IN_SINE) + self.restore_easing_state() + + def un_dim_icon(self, with_scale=False): + if with_scale: + self.set_scale(0.5, 0.5) + + self.save_easing_state() + self.set_easing_duration(400) + self.set_opacity(255) + if with_scale: + self.set_scale(1.0, 1.0) + + self.title_text.set_opacity(255) + self.set_easing_mode(Clutter.AnimationMode.EASE_IN_SINE) + self.restore_easing_state() + + +class TrashIcon(Icon): + def __init__(self, icon_size): + Icon.__init__(self, 'Trash', komorebi.utilities.get_icon_from('user-trash', icon_size), icon_size) + + # Signals + self.setup_trash_signals() + + def setup_trash_signals(self): + def _on_button_trash_release_event(_, event): + if event.button == Gdk.BUTTON_PRIMARY: + Gio.AppInfo.launch_default_for_uri('trash://', None) + return False + + self.connect('button_release_event', _on_button_trash_release_event) + + +class FolderIcon(Icon): + # Path from file to later be opened + path = '' + + def __init__(self, name, pixbuf, path, icon_size): + Icon.__init__(self, name, pixbuf, icon_size) + + self.path = path + + self.setup_folder_signals() + + def setup_folder_signals(self): + def _on_button_folder_release_event(_, event): + if event.button == Gdk.BUTTON_PRIMARY: + Gio.AppInfo.launch_default_for_uri(f'file://{self.path}', None) + return False + + self.connect('button_release_event', _on_button_folder_release_event) + + +class ApplicationIcon(Icon): + # Path from application to later be opened + path = None + command = None + + def __init__(self, name, pixbuf, path, command, icon_size): + Icon.__init__(self, name, pixbuf, icon_size) + + self.path = path + self.command = command + + self.setup_application_signals() + + def setup_application_signals(self): + def _on_button_application_release_event(_, event): + if event.button == Gdk.BUTTON_PRIMARY: + Gio.AppInfo.create_from_commandline(self.command, None, Gio.AppInfoCreateFlags.NONE).launch(None, None) + return False + + self.connect('button_release_event', _on_button_application_release_event) + + +class InfoWindow(Gtk.Window): + # Box containing everything + main_box = None + + # Box contains close button (acts like HeaderBar) + header_bar = None + + # Box contains title label, and size + top_box = None + + # Close/Hide button + close_button = None + + # File/Directory title + title_label = None + + # File/Directory size + size_label = None + + # Separator + separator = None + + # Box more file info and properties + file_info_box = None + + # Location + location_label = None + + # Type + type_label = None + + # Accessed + accessed_label = None + + # Modified + modified_label = None + + # Owner + owner_label = None + + header_bar_css = """*{ + background-color: rgba(25,25,25,0.7); + border-width: 0px; + box-shadow: none; + border-top-left-radius: 0.6em; + border-top-right-radius: 0.6em; + border-color: @transparent; + }""" + window_css = """*{ + background-color: rgba(25,25,25,0.7); + border-width: 0px; + box-shadow: none; + border-bottom-left-radius: 0.6em; + border-bottom-right-radius: 0.6em; + color: white; + }""" + separator_css = """*{ + color: rgba(51,51,51,0.6); + }""" + + def __init__(self): + Gtk.Window.__init__(self) + + self.main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0) + self.header_bar = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=5) + self.top_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5) + self.close_button = Gtk.Button() + self.title_label = Gtk.Label(label='No name') + self.size_label = Gtk.Label(label='Size unknown') + self.separator = Gtk.Separator(orientation=Gtk.Orientation.HORIZONTAL) + self.file_info_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5) + self.location_label = RowLabel('Location') + self.type_label = RowLabel('Type') + self.accessed_label = RowLabel('Accessed') + self.modified_label = RowLabel('Modified') + self.owner_label = RowLabel('Owner') + + # Configure window + self.set_size_request(340, 390) + self.set_resizable(False) + self.set_titlebar(self.header_bar) + komorebi.utilities.apply_alpha(self) + komorebi.utilities.apply_css([self], self.window_css) + + # Configure widgets + komorebi.utilities.apply_css([self.header_bar], self.header_bar_css) + self.close_button.set_halign(Gtk.Align.START) + + self.title_label.set_halign(Gtk.Align.CENTER) + self.title_label.set_line_wrap(True) + self.title_label.set_max_width_chars(19) + self.title_label.set_ellipsize(Pango.EllipsizeMode.MIDDLE) + self.title_label.set_selectable(True) + + self.separator.set_margin_top(10) + self.separator.set_margin_bottom(10) + komorebi.utilities.apply_css([self.separator], self.separator_css) + + self.file_info_box.set_margin_top(20) + self.file_info_box.set_margin_bottom(20) + self.file_info_box.set_margin_left(20) + self.file_info_box.set_margin_right(20) + + # Signals + self.signals_setup() + + # Add widgets + self.close_button.add(Gtk.Image.new_from_resource('/org/komorebi-team/komorebi/close_btn.svg')) + self.header_bar.pack_start(self.close_button, False, False, 0) + + self.top_box.add(self.title_label) + self.top_box.add(self.size_label) + + self.file_info_box.add(self.location_label) + self.file_info_box.add(self.type_label) + self.file_info_box.add(self.accessed_label) + self.file_info_box.add(self.modified_label) + self.file_info_box.add(self.owner_label) + + self.main_box.add(self.top_box) + self.main_box.add(self.separator) + self.main_box.add(self.file_info_box) + + self.add(self.main_box) + self.close_button.grab_focus() + + def signals_setup(self): + def _on_close_button_button_press_event(*args): + self.hide() + return False + + self.close_button.connect('button_press_event', _on_close_button_button_press_event) + + # Set window information + def set_info_from_path(self, path): + file = Gio.File.new_for_path(path) + file_info = file.query_info(f'{Gio.FILE_ATTRIBUTE_STANDARD_SIZE},{Gio.FILE_ATTRIBUTE_STANDARD_TYPE},' + f'{Gio.FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE},{Gio.FILE_ATTRIBUTE_TIME_ACCESS},' + f'{Gio.FILE_ATTRIBUTE_TIME_CHANGED},{Gio.FILE_ATTRIBUTE_OWNER_USER}', + Gio.FileQueryInfoFlags.NONE) + + accessed_time = file_info.get_attribute_uint64(Gio.FILE_ATTRIBUTE_TIME_ACCESS) + modified_time = file_info.get_attribute_uint64(Gio.FILE_ATTRIBUTE_TIME_CHANGED) + owner = file_info.get_attribute_string(Gio.FILE_ATTRIBUTE_OWNER_USER) + + self.title_label.set_markup(f"{file.get_basename()}") + self.size_label.set_markup(f"{GLib.format_size(file_info.get_size())}") + + self.location_label.set_value(path) + self.type_label.set_value(file_info.get_attribute_string(Gio.FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE)) + + format_str = '%m/%d/%Y %H:%M' if Settings.time_twenty_four else '%m/%d/%Y %l:%M %p' + + self.accessed_label.set_value(GLib.DateTime.new_from_unix_utc(accessed_time).to_local().format(format_str)) + self.modified_label.set_value(GLib.DateTime.new_from_unix_utc(modified_time).to_local().format(format_str)) + self.owner_label.set_value(owner) + + +class Desktop(ResponsiveGrid): + # Screen info + screen_height = None + + # Menu options + new_folder_item = None + copy_path_item = None + paste_item = None + move_to_trash_item = None + get_info_item = None + + # Utils + icon_size = None + desktop_path = None + + info_window = None + file_monitor = None + file_monitor_signal = None + icons_list = None + selected_icon = None + + def __init__(self, screen): + ResponsiveGrid.__init__(self, screen) + logging.debug('Loading Desktop...') + + self.screen_height = screen.height + self.set_size(screen.width, self.screen_height) + + self.info_window = InfoWindow() + self.icons_list = [] + + self.set_margin_top(60) + self.set_margin_left(120) + self.set_y_expand(True) + self.icon_size = 64 + self.desktop_path = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DESKTOP) + + self.monitor_changes() + self.get_desktops() + + logging.debug('Loaded Desktop') + + def on_unload(self): + logging.debug('Unloading Desktop...') + self.new_folder_item.destroy() + self.copy_path_item.destroy() + self.paste_item.destroy() + self.move_to_trash_item.destroy() + self.get_info_item.destroy() + + if self.file_monitor_signal: + self.file_monitor.disconnect(self.file_monitor_signal) + + def __del__(self): + logging.debug('Unloaded Desktop') + + def on_settings_changed(self, setting_key): + if (setting_key == ConfigKeys.SHOW_DESKTOP + and not Settings.show_desktop_icons): + self.on_unload() + return True + return False + + # Internal callbacks + def _on_create_new_folder(self, item, e): + untitled_folder = Gio.File.new_for_path(self.get_untitled_folder_name()) + untitled_folder.make_directory_async(GLib.PRIORITY_DEFAULT, None, None, None) + return False + + def _on_copy_path(self, item, e): + icon = self.selected_icon + komorebi.utilities.clipboard.set_text(icon.path, len(icon.path)) + komorebi.utilities.clipboard.store() + return False + + def _on_paste(self, item, e): + # Get the actual GLib file + path = komorebi.utilities.clipboard.wait_for_text() + file = Gio.File.new_for_path(path) + desktop_file = Gio.File.new_for_path(self.desktop_path + '/' + file.get_basename()) + file.copy(desktop_file, Gio.FileCopyFlags.NONE, None) + return False + + def _on_move_to_trash(self, item, e): + icon = self.selected_icon + + icon.trash() + source_file = Gio.File.new_for_path(icon.path) + + try: + source_file.trash() + except GLib.Error as err: + logging.warning(f'Error deleting {icon.title_name}: {err}') + + return False + + def _on_get_info(self, item, e): + icon = self.selected_icon + self.info_window.set_info_from_path(icon.path) + self.info_window.show_all() + return False + + def register_menu_actions(self, menu): + # Register the actions + self.new_folder_item = BubbleMenuItem('New Folder', self._on_create_new_folder) + self.copy_path_item = BubbleMenuItem('Copy Path', self._on_copy_path) + self.paste_item = BubbleMenuItem('Paste', self._on_paste) + self.move_to_trash_item = BubbleMenuItem('Move to Trash', self._on_move_to_trash) + self.get_info_item = BubbleMenuItem('Get Info', self._on_get_info) + + # Add them to the menu + menu.overlay_options.add_child(self.move_to_trash_item) + menu.overlay_options.add_child(self.copy_path_item) + menu.overlay_options.add_child(self.get_info_item) + menu.overlay_options.add_child(self.new_folder_item) + menu.overlay_options.add_child(self.paste_item) + + # Callbacks for when menu opens and closes + def _on_menu_open(menu, e, self): + # Dim unselected icons + for icon in self.icons_list: + if e.source != icon: + icon.dim_icon() + else: + self.selected_icon = icon + + # If there's a selected icon, configure avaliable options + if self.selected_icon: + # Hide meta options + menu.meta_options.hide() + menu.wallpaper_options.hide() + if isinstance(self.selected_icon, TrashIcon): + for item in [self.move_to_trash_item, self.copy_path_item, self.get_info_item, + self.new_folder_item, self.paste_item]: + item.set_view_mode(ViewMode.INVISIBLE) + else: + self.move_to_trash_item.set_view_mode(ViewMode.VISIBLE) + self.copy_path_item.set_view_mode(ViewMode.VISIBLE) + self.get_info_item.set_view_mode(ViewMode.VISIBLE) + self.new_folder_item.set_view_mode(ViewMode.INVISIBLE) + self.paste_item.set_view_mode(ViewMode.INVISIBLE) + else: + self.move_to_trash_item.set_view_mode(ViewMode.INVISIBLE) + self.copy_path_item.set_view_mode(ViewMode.INVISIBLE) + self.get_info_item.set_view_mode(ViewMode.INVISIBLE) + self.new_folder_item.set_view_mode(ViewMode.VISIBLE) + # FIXME: This line hangs if user "spams" the menu with right-click; investigate further + if komorebi.utilities.clipboard.wait_for_text() is not None: + self.paste_item.set_view_mode(ViewMode.VISIBLE) + else: + self.paste_item.set_view_mode(ViewMode.GREYED) + + return False + + def _on_menu_close(_, self): + # Restore meta options + menu.meta_options.show() + menu.wallpaper_options.show() + + for icon in self.icons_list: + icon.un_dim_icon() + self.selected_icon = None + + return False + + menu.connect_weak('menu_opened', _on_menu_open, self) + menu.connect_weak('menu_closed', _on_menu_close, self) + + def monitor_changes(self): + def _on_file_monitor_changed(file_mon, file, other_file, event): + if event is Gio.FileMonitorEvent.DELETED or event is Gio.FileMonitorEvent.CREATED: + self.get_desktops() + + self.file_monitor = Gio.File.new_for_path(self.desktop_path).monitor(Gio.FileMonitorFlags.NONE) + self.file_monitor_signal = self.file_monitor.connect("changed", _on_file_monitor_changed) + + # Get .desktop's + def get_desktops(self): + self.icons_list.clear() + self.grab_desktop_paths() + self.add_trash_icon() + self.add_icons_from_queue() + + # Adds all icons from the queue + def add_icons_from_queue(self): + import math + self.items_limit = math.floor(self.screen_height / (83 + self.vertical_layout.get_spacing())) + self.clear_icons() + self.destroy_all_children() + + for icon in self.icons_list: + self.append(icon) + icon.un_dim_icon() + + # Async get desktop items + def grab_desktop_paths(self): + desktop_file = Gio.File.new_for_path(self.desktop_path) + + it = desktop_file.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS) + info = it.next_file() + + while info is not None: + name = info.get_name() + file_path = self.desktop_path + "/" + name + desktop_file = Gio.File.new_for_path(file_path) + icon = None + + # Check if file is .desktop + if desktop_file.get_basename().endswith(".desktop"): + key_file = GLib.KeyFile() + key_file.load_from_file(desktop_file.get_path(), GLib.KeyFileFlags.NONE) + + # Make sure the key_file has the required keys + if (key_file.get_value(GLib.KEY_FILE_DESKTOP_GROUP, GLib.KEY_FILE_DESKTOP_KEY_NAME) is None + or key_file.get_value(GLib.KEY_FILE_DESKTOP_GROUP, GLib.KEY_FILE_DESKTOP_KEY_ICON) is None + or key_file.get_value(GLib.KEY_FILE_DESKTOP_GROUP, GLib.KEY_FILE_DESKTOP_KEY_EXEC) is None): + continue + + name = key_file.get_string(GLib.KEY_FILE_DESKTOP_GROUP, GLib.KEY_FILE_DESKTOP_KEY_NAME) + icon_path = key_file.get_string(GLib.KEY_FILE_DESKTOP_GROUP, GLib.KEY_FILE_DESKTOP_KEY_ICON) + icon_pixbuf = komorebi.utilities.get_icon_from(icon_path, self.icon_size) + command = key_file.get_string(GLib.KEY_FILE_DESKTOP_GROUP, GLib.KEY_FILE_DESKTOP_KEY_EXEC) + icon = ApplicationIcon(name, icon_pixbuf, desktop_file.get_path(), command, self.icon_size) + else: + icon_path = self.load_icon(desktop_file) + + if icon_path is None: + if desktop_file.query_file_type(Gio.FileQueryInfoFlags.NONE) is Gio.FileType.DIRECTORY: + icon_path = "folder" + else: + icon_query = desktop_file.query_info("standard::icon", Gio.FileQueryInfoFlags.NONE) \ + .get_icon().to_string().split(' ') + if len(icon_query) > 1: + icon_path = icon_query[-1] + + icon_pixbuf = komorebi.utilities.get_icon_from(icon_path, self.icon_size) + else: + icon_pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(icon_path, self.icon_size, self.icon_size, False) + + icon = FolderIcon(name, icon_pixbuf, desktop_file.get_path(), self.icon_size) + + self.icons_list.append(icon) + + info = it.next_file() + + # Adds trash icon + def add_trash_icon(self): + self.icons_list.append(TrashIcon(self.icon_size)) + + # Finds the icon of a file and returns as str + def load_icon(self, file): + # Check if it's a .desktop + if file.get_basename().endswith(".desktop"): + try: + key_file = GLib.KeyFile() + key_file.load_from_file(file.get_path(), GLib.KeyFileFlags.NONE) + return key_file.get_string(GLib.KEY_FILE_DESKTOP_GROUP, GLib.KEY_FILE_DESKTOP_KEY_ICON) + except GLib.Error: + pass + + standard = Gio.FILE_ATTRIBUTE_STANDARD_ICON + thumb = Gio.FILE_ATTRIBUTE_THUMBNAIL_PATH + custom_icon = 'standard::icon' + custom_name = 'metadata::custom-icon-name' + + query = f'{standard},{thumb},{custom_icon},{custom_name}' + + info = file.query_info(query, Gio.FileQueryInfoFlags.NONE) + + # Looks for a thumbnail + thumb_icon = info.get_attribute_byte_string(thumb) + if thumb_icon is not None and thumb_icon != '': + return thumb_icon + + # Otherwise try to get the icon from the fileinfo + return None + + def fade_in(self): + self.save_easing_state() + self.set_easing_duration(200) + self.set_opacity(255) + self.set_easing_mode(Clutter.AnimationMode.EASE_IN_SINE) + self.restore_easing_state() + + def fade_out(self): + self.save_easing_state() + self.set_easing_duration(200) + self.set_opacity(0) + self.set_easing_mode(Clutter.AnimationMode.EASE_IN_SINE) + self.restore_easing_state() + + # Returns a new Untitled Folder name + def get_untitled_folder_name(self, count=0): + path = self.desktop_path + f'/New Folder{count}' + if Gio.File.new_for_path(path).query_exists(): + path = self.get_untitled_folder_name(count + 1) + return path diff --git a/komorebi/preferences_window.py b/komorebi/preferences_window.py new file mode 100644 index 0000000..c67bc81 --- /dev/null +++ b/komorebi/preferences_window.py @@ -0,0 +1,422 @@ +import logging +import os + +from gi.repository import Gdk, GdkPixbuf, Gio, GLib, GObject, Gtk, Clutter + +import komorebi.utilities +from komorebi.settings import ConfigKeys, Settings + + +class Thumbnail(Gtk.EventBox): + name = '' + overlay = None + thumbnail_image = None + border_image = None + revealer = None + + def __init__(self, path, name): + Gtk.EventBox.__init__(self) + + self.name = name + self.overlay = Gtk.Overlay() + self.thumbnail_image = Gtk.Image(pixbuf=GdkPixbuf.Pixbuf.new_from_file_at_scale( + os.path.join(path, self.name, 'wallpaper.jpg'), 150, 100, False + )) + self.border_image = Gtk.Image.new_from_resource('/org/komorebi-team/komorebi/thumbnail_border.svg') + self.revealer = Gtk.Revealer() + + self.revealer.set_reveal_child(False) + self.revealer.add(self.border_image) + + self.add_events(Gdk.EventMask.BUTTON_RELEASE_MASK) + self.revealer.set_transition_duration(200) + self.revealer.set_transition_type(Gtk.RevealerTransitionType.CROSSFADE) + + self.overlay.add(self.thumbnail_image) + self.overlay.add_overlay(self.revealer) + self.add(self.overlay) + + def set_border(self, visible): + self.revealer.set_reveal_child(visible) + + +class WallpapersSelector(Gtk.ScrolledWindow): + # Komorebi can't find wallpapers if this variable doesn't have a trailing slash. Hacky, but it works. Fix later on. + path = f'{komorebi.__package_datadir__}/' + + grid = None + row = None + column = None + + def __init__(self): + Gtk.ScrolledWindow.__init__(self) + logging.debug('Loading WallpapersSelector..') + + # Setup widgets and properties + self.grid = Gtk.Grid() + self.row = self.column = 0 + + self.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) + self.set_vexpand(True) + self.props.margin = 20 + + self.grid.set_halign(Gtk.Align.CENTER) + self.grid.set_row_spacing(5) + self.grid.set_column_spacing(20) + + self.add(self.grid) + + logging.debug('Loaded WallpapersSelector...') + + def get_wallpapers(self): + # Internal callback for thumbnail selection + def _on_thumb_button_press_event(self, e, wallpaper_selector): + if e.button == Gdk.BUTTON_PRIMARY: + # Make the selection on wallpaper_Selector + for thumb in wallpaper_selector.grid.get_children(): + thumb.set_border(self.name == thumb.name) + + wallpaper_selector.emit('wallpaper_changed', self.name) + return True + + self.clear_grid() + + # Fetch existing wallpapers + for path in Settings.get_wallpaper_paths(): + wallpapers_folder = Gio.File.new_for_path(path) + try: + enumerator = wallpapers_folder.enumerate_children('standard::*', Gio.FileQueryInfoFlags.NOFOLLOW_SYMLINKS) + info = enumerator.next_file() + + while info is not None: + name = info.get_name() + full_path = os.path.join(path, name) + + if (Gio.File.new_for_path(os.path.join(full_path, 'wallpaper.jpg')).query_exists() + and Gio.File.new_for_path(os.path.join(full_path, 'config')).query_exists()): + # Wallpaper detected + logging.debug(f"Loading wallpaper thumbnail \"{name}\"") + + thumb = Thumbnail(path, name) + self.add_thumbnail(thumb) + if name == Settings.wallpaper_name: + thumb.set_border(True) + thumb.connect('button_press_event', _on_thumb_button_press_event, self) + else: + logging.warning(f'found an invalid wallpaper with name: {name}') + + info = enumerator.next_file() + except GLib.Error: + logging.warning(f"could not read directory '{path}'") + + def add_thumbnail(self, thumbnail): + self.grid.attach(thumbnail, self.column, self.row, 1, 1) + + if self.column >= 3: + self.row += 1 + self.column = 0 + else: + self.column += 1 + + thumbnail.show_all() + + def clear_grid(self): + for widget in self.grid.get_children(): + self.grid.remove(widget) + + self.row = self.column = 0 + + @GObject.Signal(arg_types=(str,)) + def wallpaper_changed(self, wallpaper_name): + pass + + +class PreferencesWindow(Gtk.Window): + header_bar = None + + hide_button = None + quit_button = None + + # Contains two page (Preferences and Wallpapers) + notebook = None + + # Contains preferences page widgets + preferences_page = None + + about_grid = None + + title_box = None + title_label = None + about_label = None + + twenty_four_hours_button = None + enable_autostart_button = None + show_desktop_icons_button = None + enable_video_wallpapers_button = None + mute_playback_button = None + pause_playback_button = None + + bottom_preferences_box = None + + donate_button = None + report_button = None + + # Contains wallpapers page widgets + wallpapers_page = None + + info_bar = None + + wallpapers_selector = None + + bottom_wallpapers_box = None + + current_wallpaper_label = None + + # Triggered when pointer leaves window + can_destroy = None + + # Add some style + notebook_css = """ + *{ + background: none; + background-color: rgba(0, 0, 0, 0.60); + box-shadow: none; + color: white; + border-width: 0; + } + .notebook.header { + background-color: rgb(0,0,0); + } + .notebook notebook:focus tab { + background: none; + border-width: 0; + border-radius: 0px; + border-color: transparent; + border-image-width: 0; + border-image: none; + background-color: red; + } + """ + + header_css = """ + *{ + background: rgba(0, 0, 0, 0.7); + background-color: rgb(0, 0, 0); + box-shadow: none; + color: white; + border-width: 0px; + box-shadow: none; + border-image: none; + border: none; + } + """ + + info_bar_css = """ + *{ + background: #f44336; + background-color: #f44336; + box-shadow: none; + color: white; + border-width: 0px; + box-shadow: none; + border-image: none; + border: none; + } + """ + + def __init__(self): + Gtk.Window.__init__(self) + logging.debug('Loading PreferencesWindow...') + + # Initialize widgets + self.header_bar = Gtk.HeaderBar() + self.hide_button = Gtk.Button(label='Hide', margin_top=6, margin_start=6, halign=Gtk.Align.START) + self.quit_button = Gtk.Button(label='Quit Komorebi', margin_top=6, margin_start=6) + + self.notebook = Gtk.Notebook(hexpand=True, vexpand=True) + self.preferences_page = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5, margin_top=20, + margin_bottom=10, margin_left=20, margin_right=20, halign=Gtk.Align.CENTER) + self.about_grid = Gtk.Grid(halign=Gtk.Align.CENTER, margin_bottom=30, column_spacing=0, row_spacing=0) + + self.title_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5, margin_top=15, + margin_start=10, halign=Gtk.Align.START) + self.title_label = Gtk.Label() + self.about_label = Gtk.Label() + + self.twenty_four_hours_button = Gtk.CheckButton(label='Use 24-hour time') + self.enable_autostart_button = Gtk.CheckButton(label='Launch Komorebi on system startup') + self.show_desktop_icons_button = Gtk.CheckButton(label='Show desktop icons') + self.enable_video_wallpapers_button = Gtk.CheckButton(label='Enable Video Wallpaper') + self.mute_playback_button = Gtk.CheckButton(label='Mute Video playback') + self.pause_playback_button = Gtk.CheckButton(label='Pause Video playback on un-focus') + + self.bottom_preferences_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10, margin_top=10) + self.donate_button = Gtk.Button(label='Donate', valign=Gtk.Align.CENTER) + self.report_button = Gtk.Button(label='Report an issue', valign=Gtk.Align.CENTER) + + self.wallpapers_page = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10) + self.info_bar = Gtk.InfoBar(message_type=Gtk.MessageType.WARNING, show_close_button=False) + self.wallpapers_selector = WallpapersSelector() + self.bottom_wallpapers_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10) + self.current_wallpaper_label = Gtk.Label(selectable=True) + + self.can_destroy = False + + # Configure the window + self.set_size_request(760, 500) + self.set_resizable(False) + self.set_position(Gtk.WindowPosition.CENTER) + self.set_titlebar(self.header_bar) + komorebi.utilities.apply_css([self.notebook], self.notebook_css) + komorebi.utilities.apply_css([self.info_bar], self.info_bar_css) + komorebi.utilities.apply_css([self.header_bar, self.hide_button, self.quit_button, self.donate_button, + self.report_button], self.header_css) + komorebi.utilities.apply_alpha([self]) + + # Setup widgets + self.title_label.set_markup("Komorebi") + self.about_label.set_markup("by Komorebi Team") + + self.twenty_four_hours_button.set_active(Settings.time_twenty_four) + self.enable_autostart_button.set_active(Settings.autostart) + self.show_desktop_icons_button.set_active(Settings.show_desktop_icons) + self.enable_video_wallpapers_button.set_active(Settings.enable_video_wallpapers) + self.mute_playback_button.set_active(Settings.mute_playback) + self.pause_playback_button.set_active(Settings.pause_playback) + + self.set_wallpaper_name_label() + + # Properties + self.bottom_wallpapers_box.props.margin = 25 + self.bottom_wallpapers_box.set_margin_top(10) + + self.setup_signals() + + # Add widgets + self.header_bar.add(self.hide_button) + self.header_bar.pack_end(self.quit_button) + + self.title_box.add(self.title_label) + self.title_box.add(self.about_label) + + self.about_grid.attach(Gtk.Image.new_from_resource('/org/komorebi-team/komorebi/komorebi.svg'), 0, 0, 1, 1) + self.about_grid.attach(self.title_box, 1, 0, 1, 1) + + self.bottom_preferences_box.pack_start(self.donate_button, True, True, 0) + self.bottom_preferences_box.pack_end(self.report_button, True, True, 0) + + self.preferences_page.add(self.about_grid) + self.preferences_page.add(self.twenty_four_hours_button) + self.preferences_page.add(self.enable_autostart_button) + self.preferences_page.add(self.show_desktop_icons_button) + self.preferences_page.add(self.enable_video_wallpapers_button) + self.preferences_page.add(self.mute_playback_button) + self.preferences_page.add(self.pause_playback_button) + self.preferences_page.pack_end(self.bottom_preferences_box, True, True, 0) + + self.bottom_wallpapers_box.add(Gtk.Image.new_from_resource('/org/komorebi-team/komorebi/info.svg')) + self.bottom_wallpapers_box.add(self.current_wallpaper_label) + + if not komorebi.utilities.can_play_videos(): + self.info_bar.get_content_area().add(Gtk.Label(label="gstreamer1.0-libav is missing. " + "You won't be able to set video wallpapers without it.")) + self.wallpapers_page.add(self.info_bar) + + self.wallpapers_page.add(self.wallpapers_selector) + self.wallpapers_page.add(self.bottom_wallpapers_box) + + self.notebook.append_page(self.wallpapers_page, Gtk.Label(label='Wallpapers')) + self.notebook.append_page(self.preferences_page, Gtk.Label(label='Preferences')) + + self.notebook.child_set_property(self.preferences_page, 'tab-expand', True) + self.notebook.child_set_property(self.wallpapers_page, 'tab-expand', True) + + self.add(self.notebook) + + # Start hidden; this is created at initialization, not on request + self.hide() + + logging.debug("Loaded PreferencesWindow") + + # Overrides + def show(self, wallpaper_menu): + self.wallpapers_selector.get_wallpapers() + self.show_all() + self.notebook.set_current_page(0 if wallpaper_menu else 1) + self.grab_focus() + + # Signals + def setup_signals(self): + def _on_hide_button_released(*args): + self.hide() + + def _on_quit_button_released(*args): + logging.info('Quitting Komorebi. Good bye :)') + Clutter.main_quit() + + def _on_donate_button_released(*args): + logging.info('Thank you <3') + Gio.AppInfo.launch_default_for_uri('https://goo.gl/Yr1RQe', None) # Thank you <3 + self.hide() + + def _on_report_button_released(*args): + logging.info('Thank you <3') + Gio.AppInfo.launch_default_for_uri('https://goo.gl/aaJgN7', None) # Thank you <3 + self.hide() + + def _on_twenty_four_hours_button_toggled(_, self): + Settings.time_twenty_four = self.twenty_four_hours_button.props.active + Settings.save_configuration_file() + self.emit('settings-changed', ConfigKeys.TIME_TWENTY_FOUR) + + def _on_enable_autostart_button_toggled(_, self): + Settings.autostart = self.enable_autostart_button.props.active + Settings.save_configuration_file() + self.emit('settings-changed', ConfigKeys.AUTOSTART) + + def _on_show_desktop_icons_button_toggled(_, self): + Settings.show_desktop_icons = self.show_desktop_icons_button.props.active + Settings.save_configuration_file() + self.emit('settings-changed', ConfigKeys.SHOW_DESKTOP) + + def _on_enable_video_wallpapers_button_toggled(_, self): + Settings.enable_video_wallpapers = self.enable_video_wallpapers_button.props.active + Settings.save_configuration_file() + self.emit('settings-changed', ConfigKeys.ENABLE_VIDEO) + + def _on_mute_playback_button_toggled(_, self): + Settings.mute_playback = self.mute_playback_button.props.active + Settings.save_configuration_file() + self.emit('settings-changed', ConfigKeys.MUTE_PLAYBACK) + + def _on_pause_playback_button_toggled(_, self): + Settings.pause_playback = self.pause_playback_button.props.active + Settings.save_configuration_file() + self.emit('settings-changed', ConfigKeys.PAUSE_PLAYBACK) + + def _on_wallpaper_changed(_, wallpaper_name, self): + Settings.wallpaper_name = wallpaper_name + Settings.save_configuration_file() + self.set_wallpaper_name_label() + self.emit('settings-changed', ConfigKeys.WALLPAPER_NAME) + + self.hide_button.connect('released', _on_hide_button_released) + self.quit_button.connect('released', _on_quit_button_released) + self.donate_button.connect('released', _on_donate_button_released) + self.report_button.connect('released', _on_report_button_released) + self.twenty_four_hours_button.connect('toggled', _on_twenty_four_hours_button_toggled, self) + self.enable_autostart_button.connect('toggled', _on_enable_autostart_button_toggled, self) + self.show_desktop_icons_button.connect('toggled', _on_show_desktop_icons_button_toggled, self) + self.enable_video_wallpapers_button.connect('toggled', _on_enable_video_wallpapers_button_toggled, self) + self.mute_playback_button.connect('toggled', _on_mute_playback_button_toggled, self) + self.pause_playback_button.connect('toggled', _on_pause_playback_button_toggled, self) + self.wallpapers_selector.connect('wallpaper_changed', _on_wallpaper_changed, self) + + # Changes the wallpaper name label + def set_wallpaper_name_label(self): + pretty_name = komorebi.utilities.beautify_wallpaper_name(Settings.wallpaper_name) + self.current_wallpaper_label.set_markup(f"{pretty_name}") + + @GObject.Signal(arg_types=(GObject.TYPE_PYOBJECT,)) + def settings_changed(self, config_key): + pass diff --git a/komorebi/screen.py b/komorebi/screen.py new file mode 100644 index 0000000..2a37d16 --- /dev/null +++ b/komorebi/screen.py @@ -0,0 +1,192 @@ +import logging + +from gi.repository import Clutter, Gdk, GObject, Gtk, GtkClutter + +from komorebi.bubblemenu.menu import BubbleMenu +from komorebi.bubblemenu.item import BubbleMenuItem +import komorebi.utilities + + +class Screen(Gtk.Window): + # Screen information + width = 0 + height = 0 + index = -1 + + # Signal information + signal_handlers = [] + + # Bubble Menu + dimmed = False + bubble_menu = None + + # Bubble Menu Items + change_wallpaper_item = None + settings_item = None + + # Clutter main stage + embed = None + stage = None + + # Root nodes + wallpaper_root = None + overlay_root = None + menu_root = None + + def __init__(self, monitor_index): + logging.debug(f'Initializing background window for monitor {monitor_index}...') + Gtk.Window.__init__(self, title=f'Komorebi - Screen {monitor_index}') + + # Get monitor info + display = Gdk.Display.get_default() + rectangle = display.get_monitor(monitor_index).get_geometry() + + self.width = rectangle.width + self.height = rectangle.height + self.index = monitor_index + if self.width == 0 or self.height == 0: + raise RuntimeError(f"Couldn't get monitor geometry for monitor {monitor_index}") + logging.debug(f'{monitor_index} - Rectangle geometry: x={rectangle.x} y={rectangle.y} ' + f'w={rectangle.width} h={rectangle.height}') + self.set_gravity(Gdk.Gravity.STATIC) + self.move(rectangle.x, rectangle.y) + + # Set window properties + logging.debug(f'{monitor_index} - Setting window properties...') + self.set_size_request(self.width, self.height) + self.set_resizable(False) + self.set_type_hint(Gdk.WindowTypeHint.DESKTOP) + self.set_keep_below(True) + self.set_app_paintable(False) + self.set_skip_pager_hint(True) + self.set_skip_taskbar_hint(True) + self.set_accept_focus(True) + self.stick() + self.set_decorated(False) + self.add_events(Gdk.EventMask.ENTER_NOTIFY_MASK + | Gdk.EventMask.POINTER_MOTION_MASK + | Gdk.EventMask.SMOOTH_SCROLL_MASK) + + # Configure Clutter variables and wallpaper + self.embed = GtkClutter.Embed() + self.stage = self.embed.get_stage() + self.stage.set_background_color(Clutter.Color.from_string('black')[1]) + self.stage.set_size(self.width, self.height) + + # Configure root nodes + self.wallpaper_root = Clutter.Actor() + self.overlay_root = Clutter.Actor() + self.signals_setup() + + # Setup BubbleMenu and items + self.bubble_menu = BubbleMenu(self) + + self.change_wallpaper_item = BubbleMenuItem("Change Wallpaper", self.menu_change_wallpaper) + self.settings_item = BubbleMenuItem("Desktop Preferences", self.menu_open_settings) + + self.bubble_menu.meta_options.add_child(self.change_wallpaper_item) + self.bubble_menu.meta_options.add_child(self.settings_item) + + self.stage.add_child(self.wallpaper_root) + self.stage.add_child(self.overlay_root) + self.stage.add_child(self.bubble_menu) + + self.add(self.embed) + + def signals_setup(self): + def _on_button_press_event(_, e, self): + if e.type == Clutter.EventType.BUTTON_PRESS: + if e.button == Gdk.BUTTON_SECONDARY and not self.dimmed: + self.dim_wallpaper() + self.bubble_menu.fade_in(e) + elif self.dimmed: + self.un_dim_wallpaper() + self.bubble_menu.fade_out() + return True + + self.stage.connect('button_press_event', _on_button_press_event, self) + + def connect_weak(self, detailed_signal, handler, *args): + self.signal_handlers.append(super().connect(detailed_signal, handler, *args)) + + def on_settings_changed(self, setting_key): + # There's only one wallpaper + for wallpaper in self.wallpaper_root.get_children(): + if wallpaper.on_settings_changed(setting_key): + self.wallpaper_root.remove_all_children() + + # Iterate over the children + temp_list = self.overlay_root.get_children() # We have to copy the list, as it might be modified + for overlay in temp_list: + if overlay.on_settings_changed(setting_key): + self.overlay_root.remove_child(overlay) + + # Let utilities handle adding overlays required + new_overlays = komorebi.utilities.on_settings_changed(self, setting_key) + for n_overlay in new_overlays: + self.overlay_root.add_child(n_overlay) + n_overlay.register_menu_actions(self.bubble_menu) + + def menu_change_wallpaper(self, item, e): + logging.debug("Change Wallpaper clicked") + self.emit('settings_requested', True) + return False + + def menu_open_settings(self, item, e): + logging.debug("Open Settings clicked") + self.emit('settings_requested', False) + return False + + def load_wallpaper(self, name): + # Warn all elements of unloading + for wallpaper in self.wallpaper_root.get_children(): + wallpaper.on_unload() + for overlay in self.overlay_root.get_children(): + overlay.on_unload() + + # Disconnect all custom signals to allow proper cleanup + self.bubble_menu.disconnect_all() + for signal in self.signal_handlers: + self.disconnect(signal) + self.signal_handlers = [] + + wallpaper_info = komorebi.utilities.get_wallpaper_config_file(name) + wallpaper = komorebi.utilities.load_wallpaper(self, wallpaper_info) + overlays = komorebi.utilities.load_overlays(self, wallpaper_info) + + self.wallpaper_root.destroy_all_children() + self.overlay_root.destroy_all_children() + + self.wallpaper_root.add_child(wallpaper) + wallpaper.register_menu_actions(self.bubble_menu) + + for overlay in overlays: + self.overlay_root.add_child(overlay) + overlay.register_menu_actions(self.bubble_menu) + + def fade_in(self): + self.show_all() + + def dim_wallpaper(self): + logging.debug("Dim wallpaper") + self.wallpaper_root.save_easing_state() + self.wallpaper_root.set_easing_duration(400) + self.wallpaper_root.set_opacity(100) + self.wallpaper_root.set_easing_mode(Clutter.AnimationMode.EASE_IN_SINE) + self.wallpaper_root.restore_easing_state() + + self.dimmed = True + + def un_dim_wallpaper(self): + logging.debug("Undim wallpaper") + self.wallpaper_root.save_easing_state() + self.wallpaper_root.set_easing_duration(400) + self.wallpaper_root.set_opacity(255) + self.wallpaper_root.set_easing_mode(Clutter.AnimationMode.EASE_IN_SINE) + self.wallpaper_root.restore_easing_state() + + self.dimmed = False + + @GObject.Signal(arg_types=(GObject.TYPE_BOOLEAN,)) + def settings_requested(self, isWallpaper): + pass diff --git a/komorebi/settings.py b/komorebi/settings.py new file mode 100644 index 0000000..685609c --- /dev/null +++ b/komorebi/settings.py @@ -0,0 +1,157 @@ +import logging +import os +from enum import Enum + +from gi.repository import Gio, GLib + +import komorebi + + +class ConfigKeys(Enum): + WALLPAPER_NAME = 'WallpaperName' + TIME_TWENTY_FOUR = 'TimeTwentyFour' + AUTOSTART = 'Autostart' + SHOW_DESKTOP = 'ShowDesktopIcons' + ENABLE_VIDEO = 'EnableVideoWallpapers' + MUTE_PLAYBACK = 'MutePlayback' + PAUSE_PLAYBACK = 'PausePlayback' + + +class Settings: + key_file_group = 'KomorebiProperties' + + # Settings + wallpaper_name = 'foggy_sunny_mountain' + time_twenty_four = True + show_desktop_icons = True + enable_video_wallpapers = True + mute_playback = False + pause_playback = True + autostart = False + + # Internal settings files + _config_key_file = None + _config_file = None + + def _str2bool(string): + if type(string) == bool: + return string + elif type(string) == str: + return string.lower() == 'true' + + def _optional(key, default): + try: + return Settings._config_key_file.get_value(Settings.key_file_group, key) + except GLib.Error as err: + if err.code == GLib.KeyFileError.KEY_NOT_FOUND: + logging.warning(f'Key not found for property "{key}", using default value "{default}"') + return default + + def load_settings(): + logging.info("Loading configuration...") + logging.debug(f'Config dir is "{Settings.get_config_dir()}"') + + config_path = os.path.join(Settings.get_config_dir(), 'komorebi.prop') + Settings._config_file = Gio.File.new_for_path(config_path) + Settings._config_key_file = GLib.KeyFile() + + # If the file doesn't exist, then perform first setup + if not Settings._config_file.query_exists(): + Settings.bootstrap_config_path() + if not Settings._config_file.query_exists(): + logging.info("No configuration file found. Creating a new one...") + Settings.save_configuration_file() + return + + logging.debug("Reading config file...") + + Settings._config_key_file.load_from_file(config_path, GLib.KeyFileFlags.NONE) + + if not Settings._config_key_file.has_group(Settings.key_file_group): + logging.warning('Invalid configuration file found, Fixing...') + Settings.save_configuration_file() + + # Required keys + Settings.wallpaper_name = str(Settings._optional(ConfigKeys.WALLPAPER_NAME.value, 'foggy_sunny_mountain')) + Settings.time_twenty_four = Settings._str2bool(Settings._optional(ConfigKeys.TIME_TWENTY_FOUR.value, True)) + Settings.show_desktop_icons = Settings._str2bool(Settings._optional(ConfigKeys.SHOW_DESKTOP.value, True)) + Settings.enable_video_wallpapers = Settings._str2bool(Settings._optional(ConfigKeys.ENABLE_VIDEO.value, True)) + Settings.mute_playback = Settings._str2bool(Settings._optional(ConfigKeys.MUTE_PLAYBACK.value, False)) + Settings.pause_playback = Settings._str2bool(Settings._optional(ConfigKeys.PAUSE_PLAYBACK.value, True)) + Settings.autostart = Settings._str2bool(Settings._optional(ConfigKeys.AUTOSTART.value, False)) + + Settings.fix_conflicts() + + def fix_conflicts(): + # Disable/Enabled nautilus to fix bug when clicking on another monitor + Gio.Settings.new('org.gnome.desktop.background').set_boolean('show-desktop-icons', False) + + # Check if we have nemo installed + settingsSchemaSource = Gio.SettingsSchemaSource.new_from_directory('/usr/share/glib-2.0/schemas', None, False) + settingsSchema = settingsSchemaSource.lookup('org.nemo.desktop', False) + + if settingsSchema is not None: + # Disable/Enable Nemo's desktop icons + Gio.Settings.new('org.nemo.desktop').set_boolean('show-desktop-icons', False) + + def bootstrap_config_path(): + ''' + Bootstraps the base configuration path if it doesn't exist, and detects older versions of this app + ''' + config_path = Gio.File.new_for_path(os.path.join(Settings.get_config_dir(), 'wallpapers')) + if not config_path.query_exists(): + config_path.make_directory_with_parents() + + old_config_file = Gio.File.new_for_path(os.path.join(GLib.get_home_dir(), '.Komorebi.prop')) + if old_config_file.query_exists(): + logging.info('Found config file from old version, converting it to new one...') + destination_path = Gio.File.new_for_path(os.path.join(Settings.get_config_dir(), 'komorebi.prop')) + old_config_file.copy(destination_path, Gio.FileCopyFlags.NONE) + + Settings._config_file = Gio.File.new_for_path(os.path.join(Settings.get_config_dir(), 'komorebi.prop')) + + def save_configuration_file(): + for group in Settings._config_key_file.get_groups()[0]: + if group != Settings.key_file_group: + Settings._config_key_file.remove_group(group) + + # Sets base properties + Settings._config_key_file.set_string(Settings.key_file_group, ConfigKeys.WALLPAPER_NAME.value, Settings.wallpaper_name) + Settings._config_key_file.set_boolean(Settings.key_file_group, ConfigKeys.TIME_TWENTY_FOUR.value, Settings.time_twenty_four) + Settings._config_key_file.set_boolean(Settings.key_file_group, ConfigKeys.SHOW_DESKTOP.value, Settings.show_desktop_icons) + Settings._config_key_file.set_boolean(Settings.key_file_group, ConfigKeys.ENABLE_VIDEO.value, Settings.enable_video_wallpapers) + Settings._config_key_file.set_boolean(Settings.key_file_group, ConfigKeys.MUTE_PLAYBACK.value, Settings.mute_playback) + Settings._config_key_file.set_boolean(Settings.key_file_group, ConfigKeys.PAUSE_PLAYBACK.value, Settings.pause_playback) + Settings._config_key_file.set_boolean(Settings.key_file_group, ConfigKeys.AUTOSTART.value, Settings.autostart) + + # Delete the file + if Settings._config_file.query_exists(): + Settings._config_file.delete() + + # Save the key file + stream = Gio.DataOutputStream.new(Settings._config_file.create(Gio.FileCreateFlags.NONE)) + stream.put_string(Settings._config_key_file.to_data()[0]) + stream.close() + + def get_config_dir(): + ''' + Returns the path for hosting configuration files and wallpapers + ''' + paths = [ + os.environ.get('XDG_CONFIG_PATH', ''), + os.path.join(GLib.get_home_dir(), '.config'), + GLib.get_home_dir() + ] + + for path in paths: + if path != '': + return os.path.join(path, 'komorebi') + + def get_wallpaper_paths(): + ''' + Returns the list of paths to search for wallpapers + ''' + return [ + os.path.join(Settings.get_config_dir(), 'wallpapers'), + komorebi.__package_datadir__ + ] diff --git a/komorebi/utilities.py b/komorebi/utilities.py new file mode 100644 index 0000000..568969c --- /dev/null +++ b/komorebi/utilities.py @@ -0,0 +1,256 @@ +import logging +import os +from enum import IntEnum + +from gi.repository import Gdk, GdkPixbuf, Gio, GLib, Gtk + +import komorebi +from komorebi.overlays.base import OverlayType +from komorebi.settings import ConfigKeys, Settings +from komorebi.wallpapers.base import WallpaperType + + +# Helper classes to index tuples of information +class MarginIndex(IntEnum): + LEFT = 0 + RIGHT = 1 + TOP = 2 + BOTTOM = 3 + + +class RotationIndex(IntEnum): + X = 0 + Y = 1 + Z = 2 + + +# Global clipboard +clipboard = None + + +def init_clipboard(display): + global clipboard + logging.info("Initializing clipboard...") + + if clipboard is None: + clipboard = Gtk.Clipboard.get_for_display(display, Gdk.SELECTION_CLIPBOARD) + else: + logging.warning("Clipboard is already initialized!") + + +def get_wallpaper_config_file(name): + # Prepare paths + wallpaper_path = '' + wallpaper_config_path = '' + wallpaper_found = False + + # Ensure that wallpaper exists + for path in Settings.get_wallpaper_paths(): + wallpaper_path = os.path.join(path, name) + wallpaper_config_path = os.path.join(wallpaper_path, 'config') + + if (name is None or not Gio.File.new_for_path(wallpaper_path).query_exists() + or not Gio.File.new_for_path(wallpaper_config_path).query_exists()): + continue + + wallpaper_found = True + break + + # If not, fallback to the default type + if not wallpaper_found: + name = 'foggy_sunny_mountain' + wallpaper_path = f'{komorebi.__package_datadir__}/{name}' + wallpaper_config_path = f'{wallpaper_path}/config' + + logging.error(f'got an invalid wallpaper. Setting to default: {name}') + + # Retrieve the wallpaper config + wallpaper_config = GLib.KeyFile.new() + wallpaper_config.load_from_file(wallpaper_config_path, GLib.KeyFileFlags.NONE) + + # Add required keys since the new version; this will later be + # enforced more properly with a file format revision + update_wallpaper(wallpaper_config, wallpaper_path, name) + + return wallpaper_config + + +def update_wallpaper(wallpaper_config, wallpaper_path, name): + # Add a Name section in the metadata + wallpaper_config.set_string('Info', 'Name', name) + + # Add the Path in the metadata + wallpaper_config.set_string('Info', 'Path', wallpaper_path) + + # Set up the Order property, which specifies the order of overlays + order = '' + if wallpaper_config.has_group('Asset'): + order = 'Asset' + if wallpaper_config.has_group('DateTime'): + order = 'Asset,DateTime' if wallpaper_config.get_boolean('DateTime', 'AlwaysOnTop') else 'DateTime,Asset' + elif wallpaper_config.has_group('DateTime'): + order = 'DateTime' + + wallpaper_config.set_string('Info', 'Order', order) + + +def load_wallpaper(screen, wallpaper_config): + wallpaper_type = wallpaper_config.get_string('Info', 'WallpaperType') + if wallpaper_type == WallpaperType.VIDEO.value and not Settings.enable_video_wallpapers: + wallpaper_type = WallpaperType.IMAGE.value + wallpaper = None + if wallpaper_type == WallpaperType.IMAGE.value: + from komorebi.wallpapers.image import ImageWallpaper + wallpaper = ImageWallpaper(screen, wallpaper_config) + elif wallpaper_type == WallpaperType.VIDEO.value: + from komorebi.wallpapers.video import VideoWallpaper + wallpaper = VideoWallpaper(screen, wallpaper_config) + elif wallpaper_type == WallpaperType.WEB.value: + from komorebi.wallpapers.web import WebWallpaper + wallpaper = WebWallpaper(screen, wallpaper_config) + else: + logging.warning(f"Invalid wallpaper type: {wallpaper_type}") + raise RuntimeError("Invalid wallpaper type") + + return wallpaper + + +def load_overlays(screen, wallpaper_config): + overlays = [] + + for overlay in wallpaper_config.get_string('Info', 'Order').split(','): + if overlay == OverlayType.CLOCK.value: + from komorebi.overlays.clock import Clock + overlays.append(Clock(screen, wallpaper_config)) + if overlay == OverlayType.ASSET.value: + from komorebi.overlays.asset import Asset + overlays.append(Asset(screen, wallpaper_config)) + # elif overlay == OverlayType.DESKTOP.value: # This doesn't exist on wallpaper specification *yet* + if Settings.show_desktop_icons: # so for now we simply use this + from komorebi.overlays.desktop import Desktop + overlays.append(Desktop(screen)) + + return overlays + + +def on_settings_changed(screen, setting_key): + overlays = [] + + if (setting_key == ConfigKeys.SHOW_DESKTOP + and Settings.show_desktop_icons): + from komorebi.overlays.desktop import Desktop + overlays.append(Desktop(screen)) + + return overlays + + +def get_icon_from(icon, icon_size): + ''' + Returns an icon detected from file, IconTheme, etc... + ''' + iconPixbuf = None + + if icon is None or icon == '': + return iconPixbuf + + # Try those methods: + # 1- Icon is a file, somewhere in '/'. + # 2- Icon is an icon in a IconTheme. + # 3- Icon isn't in the current IconTheme. + # 4- Icon is not available, use default. + if Gio.File.new_for_path(icon).query_exists(): + iconPixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(icon, icon_size, icon_size, False) + return iconPixbuf + + iconTheme = Gtk.IconTheme.get_default() + iconTheme.prepend_search_path('/usr/share/pixmaps') + + try: + iconPixbuf = iconTheme.load_icon(icon, icon_size, Gtk.IconLookupFlags.FORCE_SIZE) + except GLib.Error: + if iconPixbuf is None: + iconPixbuf = iconTheme.load_icon('application-default-icon', icon_size, Gtk.IconLookupFlags.FORCE_SIZE) + + return iconPixbuf + + +def apply_css(widgets, css): + provider = Gtk.CssProvider() + provider.load_from_data(str.encode(css)) + + for widget in widgets: + widget.get_style_context().add_provider(provider, 800) + + +def apply_alpha(widgets): + for widget in widgets: + widget.set_visual(widget.get_screen().get_rgba_visual() or widget.get_screen().get_system_visual()) + + +def can_play_videos(): + ''' + A dirty way to check if gstreamer is installed + ''' + # FIXME: Horrible way to detect presence of libgstlibav.so + paths = [ + '/usr/lib', + '/usr/lib64', + '/usr/lib/i386-linux-gnu', + '/usr/lib/x86_64-linux-gnu', + '/usr/lib/arm-linux-gnueabihf' + ] + + for path in paths: + if Gio.File.new_for_path(f'{path}/gstreamer-1.0/libgstlibav.so').query_exists(): + return True + + return False + + +def beautify_wallpaper_name(wallpaper_name): + ''' + Beautifies the name of the wallpaper + ''' + result_string = '' + + for word in wallpaper_name.split('_'): + result_string += word.title() + ' ' + + return result_string + + +def toggle_autostart(): + ''' + Toggle autostart for Komorebi + ''' + desktop_file_name = 'org.komorebiteam.komorebi.desktop' + dest_paths = [ + os.environ.get('XDG_CONFIG_HOME', ''), + os.path.join(GLib.get_home_dir(), '.config') + ] + + if Settings.autostart: + # Enable autostart, aka copy the .desktop file to the appropriate folder + desktop_file = Gio.File.new_for_path(os.path.join(komorebi.__datadir__, 'applications', desktop_file_name)) + if not desktop_file.query_exists(): + logging.warning('Desktop file not found, autostart won\'t work!') + return + + for path in dest_paths: + if path == '' or not Gio.File.new_for_path(path).query_exists(): + continue + + dest_file = Gio.File.new_for_path(os.path.join(path, 'autostart', desktop_file_name)) + desktop_file.copy(dest_file, Gio.FileCopyFlags.NONE) + return + + logging.warning('Couldn\'t find any user directory config, autostart won\'t work!') + else: + # Disable autostart, aka delete the .desktop file present on the autostart folder + for path in dest_paths: + if path == '' or not Gio.File.new_for_path(path).query_exists(): + continue + + desktop_file = Gio.File.new_for_path(os.path.join(path, 'autostart', desktop_file_name)) + desktop_file.delete() + return diff --git a/komorebi/wallpaper_creator/pages.py b/komorebi/wallpaper_creator/pages.py new file mode 100644 index 0000000..68188fe --- /dev/null +++ b/komorebi/wallpaper_creator/pages.py @@ -0,0 +1,680 @@ +import os + +from gi.repository import Gdk, GdkPixbuf, Gio, GLib, Gtk + +import komorebi.wallpaper_creator.utilities as utilities +from komorebi.settings import Settings + + +def rgbaToHex(rgba): + return '#{:02x}{:02x}{:02x}'.format(int(rgba.red * 255), + int(rgba.green * 255), + int(rgba.blue * 255)) + + +class InitialPage(Gtk.Box): + # Widgets + about_grid = None + title_box = None + title_lbl = None + about_lbl = None + + name_lbl = None + name_entry = None + + type_lbl = None + type_combo_box = None + + choose_file_lbl = None + location_box = None + location_entry = None + choose_file_btn = None + + revealer = None + thumbnail_box = None + choose_thumbnail_lbl = None + choose_thumbnail_btn = None + + # Filters + image_filter = None + video_filter = None + + def __init__(self): + Gtk.Box.__init__(self, spacing=10, hexpand=True, vexpand=True, + orientation=Gtk.Orientation.VERTICAL, + halign=Gtk.Align.CENTER, + valign=Gtk.Align.CENTER) + + # Initialize elements + self.about_grid = Gtk.Grid(orientation=Gtk.Orientation.VERTICAL, + margin_bottom=30, column_spacing=0, + row_spacing=0) + self.title_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, + spacing=5, margin_top=15, margin_start=10) + self.title_lbl = Gtk.Label(halign=Gtk.Align.START) + self.about_lbl = Gtk.Label(halign=Gtk.Align.START) + + self.name_lbl = Gtk.Label(label='Give your wallpaper a name:') + self.name_entry = Gtk.Entry(placeholder_text='Mountain Summit') + + self.type_lbl = Gtk.Label('My wallpaper is') + self.type_combo_box = Gtk.ComboBoxText() + + self.choose_file_lbl = Gtk.Label('Where is the image located?') + self.location_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10) + self.location_entry = Gtk.Entry(placeholder_text='~/Pictures/my_picture.jpg') + self.choose_file_btn = Gtk.FileChooserButton(title='Choose File', + action=Gtk.FileChooserAction.OPEN, + width_chars=10) + + self.revealer = Gtk.Revealer() + self.thumbnail_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5) + self.choose_thumbnail_lbl = Gtk.Label(label='Where is the thumbnail located?') + self.choose_thumbnail_btn = Gtk.FileChooserButton(title='Choose Thumbnail', + action=Gtk.FileChooserAction.OPEN, + width_chars=10) + + self.image_filter = Gtk.FileFilter() + self.video_filter = Gtk.FileFilter() + + # Setup widgets + self.title_lbl.set_markup("Komorebi Wallpaper Creator") + self.about_lbl.set_markup("by Komorebi Team") + + self.type_combo_box.append('image', 'An image') + self.type_combo_box.append('video', 'A video') + self.type_combo_box.append('web_page', 'A web page') + self.type_combo_box.set_active(0) + + utilities.wallpaper_type = 'image' + + self.image_filter.add_mime_type('image/*') + self.video_filter.add_mime_type('video/*') + + self.choose_file_btn.set_filter(self.image_filter) + self.choose_thumbnail_btn.set_filter(self.image_filter) + + self.location_entry.set_sensitive(False) + + # Setup signals + def _on_name_entry_changed(name_entry): + utilities.wallpaper_name = name_entry.get_text() if len(name_entry.get_text()) > 0 else None + + def _on_type_combo_box_changed(_, self): + utilities.wallpaper_type = self.type_combo_box.get_active_id() + + if utilities.wallpaper_type == 'image': + self.choose_file_lbl.set_label('Where is the image located?') + self.location_entry.set_placeholder_text('~/Pictures/my_picture.jpg') + elif utilities.wallpaper_type == 'web_page': + self.choose_file_lbl.set_label('What is the URL?') + self.location_entry.set_placeholder_text('https://sample.com/random/{{screen_width}}x{{screen_height}}') + else: + self.choose_file_lbl.set_label('Where is the video located?') + self.location_entry.set_placeholder_text('~/my_video.mp4') + self.choose_file_btn.set_filter(self.video_filter if utilities.wallpaper_type == 'video' else self.image_filter) + self.location_entry.set_sensitive(utilities.wallpaper_type == 'web_page') + self.revealer.set_reveal_child(utilities.wallpaper_type == 'web_page' or utilities.wallpaper_type == 'video') + if utilities.wallpaper_type == 'web_page': + self.choose_file_btn.hide() + else: + self.choose_file_btn.show() + + def _on_choose_file_btn_file_set(choose_file_btn): + utilities.file_path = choose_file_btn.get_file().get_path() + + def _on_choose_thumbnail_btn_file_set(choose_thumbnail_btn): + utilities.thumbnail_path = choose_thumbnail_btn.get_file().get_path() + + def _on_location_entry_changed(location_entry): + text = location_entry.get_text() + if '://' in text and (text.startswith('http') or text.startswith('file')): + utilities.web_page_url = text + else: + utilities.web_page_url = None + + self.name_entry.connect('changed', _on_name_entry_changed) + self.type_combo_box.connect('changed', _on_type_combo_box_changed, self) + self.choose_file_btn.connect('file_set', _on_choose_file_btn_file_set) + self.choose_thumbnail_btn.connect('file_set', _on_choose_thumbnail_btn_file_set) + self.location_entry.connect('changed', _on_location_entry_changed) + + # Add widgets + self.title_box.add(self.title_lbl) + self.title_box.add(self.about_lbl) + + self.about_grid.attach(Gtk.Image.new_from_resource('/org/komorebi-team/komorebi/wallpaper_creator.svg'), 0, 0, 1, 1) + self.about_grid.attach(self.title_box, 1, 0, 1, 1) + + self.thumbnail_box.add(self.choose_thumbnail_lbl) + self.thumbnail_box.add(self.choose_thumbnail_btn) + + self.revealer.add(self.thumbnail_box) + + self.location_box.pack_start(self.location_entry, True, True, 0) + self.location_box.add(self.choose_file_btn) + + self.add(self.about_grid) + self.add(self.name_lbl) + self.add(self.name_entry) + + self.add(self.type_lbl) + self.add(self.type_combo_box) + + self.add(self.choose_file_lbl) + self.add(self.location_box) + + self.add(self.revealer) + + +class OptionsPage(Gtk.Box): + # Widgets + wallpaper_box = None + overlay = None + wallpaper_image = None + date_time_box = None + time_lbl = None + date_lbl = None + asset_image = None + + # List of long options + scrolled_window = None + options_box = None + + wallpaper_title_lbl = None + wallpaper_parallax_combo_box = None + + date_time_title_lbl = None + date_time_visible_combo_box = None + date_time_parallax_combo_box = None + date_time_margins_lbl = None + date_time_margins_grid = None + date_time_margin_left_entry = None + date_time_margin_right_entry = None + date_time_margin_top_entry = None + date_time_margin_bottom_entry = None + + date_time_position_lbl = None + date_time_position_combo_box = None + + date_time_alignment_lbl = None + date_time_alignment_combo_box = None + + date_time_always_on_top_combo_box = None + + date_time_color_lbl = None + date_time_color_box = None + date_time_color_btn = None + date_time_alpha_entry = None + + date_time_shadow_color_lbl = None + date_time_shadow_color_box = None + date_time_shadow_color_btn = None + date_time_shadow_alpha_entry = None + + time_font_lbl = None + time_font_btn = None + + date_font_lbl = None + date_font_btn = None + + # Asset (Layer) + asset_title_lbl = None + + asset_visible_combo_box = None + + asset_animation_lbl = None + asset_animation_box = None + asset_mode_combo_box = None + asset_speed_entry = None + + def __init__(self): + Gtk.Box.__init__(self, spacing=10, orientation=Gtk.Orientation.HORIZONTAL, + halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER, + hexpand=False, vexpand=True) + + # Initialize widgets + self.wallpaper_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, + spacing=10, margin_top=20, margin_bottom=20, + margin_start=20, margin_end=0, + valign=Gtk.Align.CENTER, halign=Gtk.Align.START) + self.overlay = Gtk.Overlay() + self.wallpaper_image = Gtk.Image() + self.date_time_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=5, + hexpand=True, vexpand=True, halign=Gtk.Align.CENTER, + valign=Gtk.Align.CENTER) + self.time_lbl = Gtk.Label() + self.date_lbl = Gtk.Label() + self.asset_image = Gtk.Image() + self.scrolled_window = Gtk.ScrolledWindow(hscrollbar_policy=Gtk.PolicyType.NEVER) + self.options_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10, + margin_top=20, margin_bottom=20, margin_end=20, + margin_start=0, halign=Gtk.Align.START, hexpand=True) + self.wallpaper_title_lbl = Gtk.Label() + self.wallpaper_parallax_combo_box = Gtk.ComboBoxText() + self.date_time_title_lbl = Gtk.Label(margin_top=15) + self.date_time_visible_combo_box = Gtk.ComboBoxText() + self.date_time_parallax_combo_box = Gtk.ComboBoxText() + self.date_time_margins_lbl = Gtk.Label(label='Margins:') + self.date_time_margins_grid = Gtk.Grid() + self.date_time_margin_left_entry = Gtk.SpinButton.new_with_range(0, 2000, 5) + self.date_time_margin_right_entry = Gtk.SpinButton.new_with_range(0, 2000, 5) + self.date_time_margin_top_entry = Gtk.SpinButton.new_with_range(0, 2000, 5) + self.date_time_margin_bottom_entry = Gtk.SpinButton.new_with_range(0, 2000, 5) + self.date_time_position_lbl = Gtk.Label('Position:') + self.date_time_position_combo_box = Gtk.ComboBoxText() + self.date_time_alignment_lbl = Gtk.Label('Alignment:') + self.date_time_alignment_combo_box = Gtk.ComboBoxText() + self.date_time_always_on_top_combo_box = Gtk.ComboBoxText() + self.date_time_color_lbl = Gtk.Label('Color and Alpha:') + self.date_time_color_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10) + self.date_time_color_btn = Gtk.ColorButton.new_with_rgba(Gdk.RGBA(222, 222, 222, 255)) + self.date_time_alpha_entry = Gtk.SpinButton.new_with_range(0, 255, 1) + self.date_time_shadow_color_lbl = Gtk.Label(label='Shadow Color and Alpha:') + self.date_time_shadow_color_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10) + self.date_time_shadow_color_btn = Gtk.ColorButton.new_with_rgba(Gdk.RGBA(222, 222, 222, 255)) + self.date_time_shadow_alpha_entry = Gtk.SpinButton.new_with_range(0, 255, 1) + self.time_font_lbl = Gtk.Label(label='Time Font:') + self.time_font_btn = Gtk.FontButton.new_with_font('Lato Light 30') + self.date_font_lbl = Gtk.Label(label='Date Font:') + self.date_font_btn = Gtk.FontButton.new_with_font('Lato Light 20') + self.asset_title_lbl = Gtk.Label(margin_top=15) + self.asset_visible_combo_box = Gtk.ComboBoxText() + self.asset_animation_lbl = Gtk.Label('Animation Mode & Speed:') + self.asset_animation_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=10) + self.asset_mode_combo_box = Gtk.ComboBoxText() + self.asset_speed_entry = Gtk.SpinButton.new_with_range(100, 1000, 1) + + # Setup widgets + self.wallpaper_title_lbl.set_markup("Wallpaper Options:") + self.date_time_title_lbl.set_markup("Date & Time Options:") + self.asset_title_lbl.set_markup("Layer Options:") + + self.date_time_alpha_entry.set_value(255) + self.date_time_shadow_alpha_entry.set_value(255) + self.time_font_btn.set_use_font(True) + self.date_font_btn.set_use_font(True) + + self.date_time_visible_combo_box.append('show', 'Show date & time') + self.date_time_visible_combo_box.append('hide', 'Hide date & time') + self.date_time_visible_combo_box.set_active(0) + + self.wallpaper_parallax_combo_box.append('enable', 'Enable parallax') + self.wallpaper_parallax_combo_box.append('disable', 'Disable parallax') + self.wallpaper_parallax_combo_box.set_active(1) + + self.date_time_parallax_combo_box.append('enable', 'Enable parallax') + self.date_time_parallax_combo_box.append('disable', 'Disable parallax') + self.date_time_parallax_combo_box.set_active(1) + + self.date_time_position_combo_box.append_text('Top Left') + self.date_time_position_combo_box.append_text('Top Center') + self.date_time_position_combo_box.append_text('Top Right') + self.date_time_position_combo_box.append_text('Center Left') + self.date_time_position_combo_box.append_text('Center') + self.date_time_position_combo_box.append_text('Center Right') + self.date_time_position_combo_box.append_text('Bottom Left') + self.date_time_position_combo_box.append_text('Bottom Center') + self.date_time_position_combo_box.append_text('Bottom Right') + self.date_time_position_combo_box.set_active(4) + + self.date_time_alignment_combo_box.append_text('Start') + self.date_time_alignment_combo_box.append_text('Center') + self.date_time_alignment_combo_box.append_text('End') + self.date_time_alignment_combo_box.set_active(1) + + self.date_time_always_on_top_combo_box.append('enable', 'Always show on top') + self.date_time_always_on_top_combo_box.append('disable', 'Show under layer') + self.date_time_always_on_top_combo_box.set_active(0) + + self.asset_visible_combo_box.append('show', 'Show layer') + self.asset_visible_combo_box.append('hide', 'Hide layer') + self.asset_visible_combo_box.set_active(0) + + self.asset_mode_combo_box.append('noanimation', 'No Animation') + self.asset_mode_combo_box.append('light', 'Glowing Light') + self.asset_mode_combo_box.append('clouds', 'Moving Clouds') + self.asset_mode_combo_box.set_active(0) + + # Setup signals + self.wallpaper_parallax_combo_box.connect('changed', self.update_ui, self) + self.date_time_visible_combo_box.connect('changed', self.update_ui, self) + self.date_time_parallax_combo_box.connect('changed', self.update_ui, self) + self.date_time_margin_top_entry.connect('changed', self.update_ui, self) + self.date_time_margin_right_entry.connect('changed', self.update_ui, self) + self.date_time_margin_left_entry.connect('changed', self.update_ui, self) + self.date_time_margin_bottom_entry.connect('changed', self.update_ui, self) + self.date_time_position_combo_box.connect('changed', self.update_ui, self) + self.date_time_alignment_combo_box.connect('changed', self.update_ui, self) + self.date_time_color_btn.connect('color_set', self.update_ui, self) + self.date_time_alpha_entry.connect('changed', self.update_ui, self) + self.time_font_btn.connect('font_set', self.update_ui, self) + self.date_font_btn.connect('font_set', self.update_ui, self) + + # Add widgets + self.date_time_box.add(self.time_lbl) + self.date_time_box.add(self.date_lbl) + + self.overlay.add(self.wallpaper_image) + self.overlay.add_overlay(self.date_time_box) + self.overlay.add_overlay(self.asset_image) + + self.wallpaper_box.add(self.overlay) + + self.date_time_margins_grid.attach(self.date_time_margin_top_entry, 0, 0, 1, 1) + self.date_time_margins_grid.attach(self.date_time_margin_right_entry, 0, 1, 1, 1) + self.date_time_margins_grid.attach(self.date_time_margin_left_entry, 1, 0, 1, 1) + self.date_time_margins_grid.attach(self.date_time_margin_bottom_entry, 1, 1, 1, 1) + + if utilities.wallpaper_type == 'image': + self.options_box.add(self.wallpaper_title_lbl) + self.options_box.add(self.wallpaper_parallax_combo_box) + + self.options_box.add(self.date_time_title_lbl) + + self.options_box.add(self.date_time_visible_combo_box) + self.options_box.add(self.date_time_parallax_combo_box) + + self.options_box.add(self.date_time_position_lbl) + self.options_box.add(self.date_time_position_combo_box) + + self.options_box.add(self.date_time_margins_lbl) + self.options_box.add(self.date_time_margins_grid) + + self.options_box.add(self.date_time_alignment_lbl) + self.options_box.add(self.date_time_alignment_combo_box) + + self.options_box.add(self.date_time_always_on_top_combo_box) + + self.options_box.add(self.date_time_color_lbl) + + self.date_time_color_box.add(self.date_time_color_btn) + self.date_time_color_box.add(self.date_time_alpha_entry) + + self.options_box.add(self.date_time_color_box) + + self.options_box.add(self.date_time_shadow_color_lbl) + + self.date_time_shadow_color_box.add(self.date_time_shadow_color_btn) + self.date_time_shadow_color_box.add(self.date_time_shadow_alpha_entry) + + self.options_box.add(self.date_time_shadow_color_box) + + self.options_box.add(self.time_font_lbl) + self.options_box.add(self.time_font_btn) + + self.options_box.add(self.date_font_lbl) + self.options_box.add(self.date_font_btn) + + if utilities.wallpaper_type == 'image': + self.options_box.add(self.asset_title_lbl) + self.options_box.add(self.asset_visible_combo_box) + self.options_box.add(self.asset_animation_lbl) + self.asset_animation_box.add(self.asset_mode_combo_box) + self.asset_animation_box.add(self.asset_speed_entry) + self.options_box.add(self.asset_animation_box) + + self.scrolled_window.add(self.options_box) + + self.pack_start(self.wallpaper_box, True, True, 0) + self.pack_start(self.scrolled_window, True, True, 0) + + self.set_date_time_label() + + for child in self.options_box.get_children(): + child.set_halign(Gtk.Align.START) + + def update_ui(*args): + self = args[-1] + utilities.wallpaper_parallax = self.wallpaper_parallax_combo_box.get_active_id() == 'enable' + + utilities.show_date_time = self.date_time_visible_combo_box.get_active_id() == 'show' + utilities.date_time_parallax = self.date_time_parallax_combo_box.get_active_id() == 'enable' + + if self.date_time_margin_top_entry.get_text() != '': + utilities.margin_top = int(self.date_time_margin_top_entry.get_text()) + if self.date_time_margin_right_entry.get_text() != '': + utilities.margin_right = int(self.date_time_margin_right_entry.get_text()) + if self.date_time_margin_left_entry.get_text() != '': + utilities.margin_left = int(self.date_time_margin_left_entry.get_text()) + if self.date_time_margin_bottom_entry.get_text() != '': + utilities.margin_bottom = int(self.date_time_margin_bottom_entry.get_text()) + + self.date_time_box.set_opacity(255 * utilities.show_date_time) + self.date_time_box.set_visible(False) + + self.date_time_box.set_margin_top(utilities.margin_top) + self.date_time_box.set_margin_right(utilities.margin_right) + self.date_time_box.set_margin_left(utilities.margin_left) + self.date_time_box.set_margin_bottom(utilities.margin_bottom) + + self.set_position() + self.set_alignment() + + utilities.date_time_always_on_top = self.date_time_always_on_top_combo_box.get_active_id() == 'enable' + + self.set_colors() + self.set_fonts() + self.set_opacity() + + utilities.show_asset = self.asset_visible_combo_box.get_active_id() == 'show' + self.asset_image.set_opacity(255 * utilities.show_asset) + + self.set_animation_mode() + if self.asset_speed_entry.get_text() != '': + utilities.animation_speed = int(self.asset_speed_entry.get_text()) + + self.set_date_time_label(utilities.date_time_color, utilities.time_font, utilities.date_font) + self.show_all() + + def set_position(self): + active = self.date_time_position_combo_box.get_active_text() + utilities.position = active.replace(' ', '_').lower() + if active == 'Top Left': + self.date_time_box.set_halign(Gtk.Align.START) + self.date_time_box.set_valign(Gtk.Align.START) + elif active == 'Top Center': + self.date_time_box.set_halign(Gtk.Align.CENTER) + self.date_time_box.set_valign(Gtk.Align.START) + elif active == 'Top Right': + self.date_time_box.set_halign(Gtk.Align.END) + self.date_time_box.set_valign(Gtk.Align.START) + elif active == 'Center Right': + self.date_time_box.set_halign(Gtk.Align.END) + self.date_time_box.set_valign(Gtk.Align.CENTER) + elif active == 'Center': + self.date_time_box.set_halign(Gtk.Align.CENTER) + self.date_time_box.set_valign(Gtk.Align.CENTER) + elif active == 'Center Left': + self.date_time_box.set_halign(Gtk.Align.START) + self.date_time_box.set_valign(Gtk.Align.CENTER) + elif active == 'Bottom Right': + self.date_time_box.set_halign(Gtk.Align.END) + self.date_time_box.set_valign(Gtk.Align.END) + elif active == 'Bottom Center': + self.date_time_box.set_halign(Gtk.Align.CENTER) + self.date_time_box.set_valign(Gtk.Align.END) + elif active == 'Bottom Left': + self.date_time_box.set_halign(Gtk.Align.START) + self.date_time_box.set_valign(Gtk.Align.END) + + def set_alignment(self): + utilities.alignment = self.date_time_alignment_combo_box.get_active_text().lower() + + if utilities.alignment == 'start': + self.time_lbl.set_halign(Gtk.Align.START) + elif utilities.alignment == 'center': + self.time_lbl.set_halign(Gtk.Align.CENTER) + else: + self.time_lbl.set_halign(Gtk.Align.END) + + def set_colors(self): + rgba = self.date_time_color_btn.get_rgba() + utilities.date_time_color = rgbaToHex(rgba) + + rgba = self.date_time_shadow_color_btn.get_rgba() + utilities.shadow_color = rgbaToHex(rgba) + + def set_fonts(self): + utilities.time_font = self.time_font_btn.get_font_name() + utilities.date_font = self.date_font_btn.get_font_name() + + def set_opacity(self): + if self.date_time_alpha_entry.get_text() != '': + alpha = float(self.date_time_alpha_entry.get_text()) + self.time_lbl.set_opacity(alpha / 255) + self.date_lbl.set_opacity(alpha / 255) + utilities.date_time_alpha = int(alpha) + + if self.date_time_shadow_alpha_entry.get_text() != '': + alpha = int(self.date_time_shadow_alpha_entry.get_text()) + utilities.shadow_alpha = int(alpha) + + def set_image(self, path): + self.wallpaper_image.props.pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(path, 600, 400, True) + + def set_blank(self): + self.wallpaper_image.props.pixbuf = GdkPixbuf.Pixbuf.new_from_resource_at_scale( + '/org/komorebi-team/komorebi/blank.svg', 600, 400, True + ) + + def set_asset(self, path): + self.asset_image.props.pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(path, 600, 400, True) + + def set_animation_mode(self): + utilities.animation_mode = self.asset_mode_combo_box.get_active_id() + + def set_date_time_label(self, color='white', time_font='Lato Light 30', date_font='Lato Light 20'): + self.time_lbl.set_markup(f"10:21 PM") + self.date_lbl.set_markup(f"Sunday, August 22") + + +class FinalPage(Gtk.Box): + # Widgets + logo = None + title_lbl = None + desc_lbl = None + close_btn = None + + def __init__(self): + Gtk.Box.__init__(self, spacing=10, hexpand=True, vexpand=True, + orientation=Gtk.Orientation.VERTICAL, + halign=Gtk.Align.CENTER, valign=Gtk.Align.CENTER) + + # Initialize widgets + self.logo = Gtk.Image.new_from_resource('/org/komorebi-team/komorebi/done.svg') + self.title_lbl = Gtk.Label() + self.desc_lbl = Gtk.Label() + self.close_btn = Gtk.Button(label='Close', margin_top=20, halign=Gtk.Align.CENTER) + + # Setup widgets + self.logo.set_margin_bottom(30) + self.desc_lbl.set_justify(Gtk.Align.CENTER) + self.desc_lbl.set_halign(Gtk.Align.CENTER) + self.desc_lbl.set_hexpand(False) + self.desc_lbl.set_selectable(True) + + utilities.wallpaper_name = utilities.wallpaper_name.replace(" ", "_").replace(".", "_").lower() + + self.title_lbl.set_markup("Done") + + wallpaper_path = os.path.join(Settings.get_config_dir(), 'wallpapers', utilities.wallpaper_name) + self.desc_lbl.set_markup(f"Your wallpaper was copied to:\n{wallpaper_path}\n" + "You can now change the wallpaper in 'Change Wallpaper'.") + + # Setup signals + def _on_close_btn_released(_): + Gtk.main_quit() + + self.close_btn.connect('released', _on_close_btn_released) + + # Add widgets + self.add(self.logo) + self.add(self.title_lbl) + self.add(self.desc_lbl) + self.add(self.close_btn) + + self.create_wallpaper() + + def create_wallpaper(self): + # Create a new directory + utilities.wallpaper_name = utilities.wallpaper_name.replace(' ', '_').replace('.', '_').lower() + + dir_path = os.path.join(Settings.get_config_dir(), 'wallpapers', utilities.wallpaper_name) + Gio.File.new_for_path(dir_path).make_directory_with_parents() + config_path = dir_path + '/config' + config_file = Gio.File.new_for_path(config_path) + + config_key_file = GLib.KeyFile() + + config_key_file.set_string('Info', 'WallpaperType', utilities.wallpaper_type) + + if utilities.wallpaper_type == 'video': + video_file_name = utilities.file_path.split('/')[-1] + config_key_file.set_string('Info', 'VideoFileName', video_file_name) + + # Copy the video into our new dir + Gio.File.new_for_path(utilities.file_path).copy(Gio.File.new_for_path(os.path.join(dir_path, video_file_name)), + Gio.FileCopyFlags.NONE) + elif utilities.wallpaper_type == 'web_page': + config_key_file.set_string('Info', 'WebPageUrl', utilities.web_page_url) + + if utilities.wallpaper_type == 'video' or utilities.wallpaper_type == 'web_page': + # Move the thumbnail + Gio.File.new_for_path(utilities.thumbnail_path).copy( + Gio.File.new_for_path(os.path.join(dir_path, 'wallpaper.jpg')), + Gio.FileCopyFlags.NONE + ) + else: + # Copy the wallpaper into our new dir + Gio.File.new_for_path(utilities.file_path).copy(Gio.File.new_for_path(os.path.join(dir_path, 'wallpaper.jpg')), + Gio.FileCopyFlags.NONE) + + config_key_file.set_boolean('DateTime', 'Visible', utilities.show_date_time) + config_key_file.set_boolean('DateTime', 'Parallax', utilities.date_time_parallax) + + config_key_file.set_integer('DateTime', 'MarginTop', utilities.margin_top) + config_key_file.set_integer('DateTime', 'MarginRight', utilities.margin_right) + config_key_file.set_integer('DateTime', 'MarginLeft', utilities.margin_left) + config_key_file.set_integer('DateTime', 'MarginBottom', utilities.margin_bottom) + + # TODO: Add support for rotations + config_key_file.set_integer('DateTime', 'RotationX', 0) + config_key_file.set_integer('DateTime', 'RotationY', 0) + config_key_file.set_integer('DateTime', 'RotationZ', 0) + + config_key_file.set_string('DateTime', 'Position', utilities.position) + config_key_file.set_string('DateTime', 'Alignment', utilities.alignment) + config_key_file.set_boolean('DateTime', 'AlwaysOnTop', utilities.date_time_always_on_top) + + config_key_file.set_string('DateTime', 'Color', utilities.date_time_color) + config_key_file.set_integer('DateTime', 'Alpha', utilities.date_time_alpha) + + config_key_file.set_string('DateTime', 'ShadowColor', utilities.shadow_color) + config_key_file.set_integer('DateTime', 'ShadowAlpha', utilities.shadow_alpha) + + config_key_file.set_string('DateTime', 'TimeFont', utilities.time_font) + config_key_file.set_string('DateTime', 'DateFont', utilities.date_font) + + if utilities.wallpaper_type == 'image': + config_key_file.set_boolean('Wallpaper', 'Parallax', utilities.wallpaper_parallax) + + if not utilities.asset_path or utilities.asset_path == '': + utilities.show_asset = False + + config_key_file.set_boolean('Asset', 'Visible', utilities.show_asset) + config_key_file.set_string('Asset', 'AnimationMode', utilities.animation_mode) + config_key_file.set_integer('Asset', 'AnimationSpeed', utilities.animation_speed) + + config_key_file.set_integer('Asset', 'Width', 0) + config_key_file.set_integer('Asset', 'Height', 0) + + if utilities.asset_path: + # Move the asset into our new dir + Gio.File.new_for_path(utilities.asset_path).copy(Gio.File.new_for_path(os.path.join(dir_path, 'assets.png')), + Gio.FileCopyFlags.NONE) + + # Save the key file + stream = Gio.DataOutputStream.new(config_file.create(Gio.FileCreateFlags.NONE)) + stream.put_string(config_key_file.to_data()[0]) + stream.close() diff --git a/komorebi/wallpaper_creator/utilities.py b/komorebi/wallpaper_creator/utilities.py new file mode 100644 index 0000000..4de4861 --- /dev/null +++ b/komorebi/wallpaper_creator/utilities.py @@ -0,0 +1,33 @@ +file_path = None +asset_path = None +thumbnail_path = None +web_page_url = None + +wallpaper_name = None +wallpaper_type = None +wallpaper_parallax = None + +show_date_time = None +date_time_parallax = None + +margin_top = None +margin_right = None +margin_left = None +margin_bottom = None + +position = None +alignment = None +date_time_always_on_top = None + +date_time_color = None +date_time_alpha = None + +shadow_color = None +shadow_alpha = None + +time_font = None +date_font = None + +show_asset = None +animation_mode = None +animation_speed = None diff --git a/komorebi/wallpaper_creator/window.py b/komorebi/wallpaper_creator/window.py new file mode 100644 index 0000000..4454716 --- /dev/null +++ b/komorebi/wallpaper_creator/window.py @@ -0,0 +1,217 @@ +import logging + +from gi.repository import Gtk + +import komorebi.wallpaper_creator.utilities as utilities +import komorebi.wallpaper_creator.pages as pages + +from komorebi.utilities import apply_alpha, apply_css + + +class WallpaperWindow(Gtk.Window): + # Main elements + stack = None + layout = None + + # Pages + options_page = None + + # Custom headerbar + header_bar = None + close_btn = None + add_layer_btn = None + next_btn = None + + # Confirmation popover + popover = None + popover_grid = None + confirmation_lbl = None + cancel_btn = None + yes_btn = None + + # Error box + revealer = None + info_bar = None + error_lbl = None + + # CSS definitions + main_css = """ + *{ + background-color: rgba(0, 0, 0, 0.6); + box-shadow: none; + color: white; + border-width: 0px; + } + """ + + header_css = """ + *{ + background-color: rgba(0, 0, 0, 0); + box-shadow: none; + color: white; + border-width: 0px; + } + """ + + def __init__(self): + logging.debug('Loading WallpaperWindow...') + Gtk.Window.__init__(self, title='New Komorebi Wallpaper') + + # Initialize elements + self.stack = Gtk.Stack() + self.layout = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0) + + self.header_bar = Gtk.HeaderBar() + self.close_btn = Gtk.Button(label='Close') + self.add_layer_btn = Gtk.Button(label='Add Layer') + self.next_btn = Gtk.Button(label='Next') + + self.popover = Gtk.Popover() + self.popover_grid = Gtk.Grid() + self.confirmation_lbl = Gtk.Label(label='Are you sure?') + self.cancel_btn = Gtk.Button(label='Cancel') + self.yes_btn = Gtk.Button(label='Yes') + + self.revealer = Gtk.Revealer() + self.info_bar = Gtk.InfoBar(message_type=Gtk.MessageType.ERROR) + self.error_lbl = Gtk.Label() + + # Setup window + self.set_size_request(1050, 700) + self.set_resizable(False) + self.set_position(Gtk.WindowPosition.CENTER) + self.set_titlebar(self.header_bar) + apply_css([self.layout], self.main_css) + apply_css([self.header_bar], self.header_css) + apply_alpha([self]) + + # Setup widgets + self.close_btn.set_margin_top(6) + self.close_btn.set_margin_start(6) + self.close_btn.set_halign(Gtk.Align.START) + + self.add_layer_btn.set_margin_top(6) + self.add_layer_btn.set_margin_start(6) + self.add_layer_btn.set_halign(Gtk.Align.START) + + self.next_btn.set_margin_top(6) + self.next_btn.set_margin_end(6) + + self.popover.set_relative_to(self.close_btn) + + self.popover_grid.set_margin_top(15) + self.popover_grid.set_margin_bottom(15) + self.popover_grid.set_margin_left(15) + self.popover_grid.set_margin_right(15) + self.popover_grid.set_row_spacing(20) + self.popover_grid.set_column_spacing(5) + + self.revealer.set_transition_duration(200) + self.revealer.set_transition_type(Gtk.RevealerTransitionType.SLIDE_DOWN) + + self.stack.set_transition_duration(400) + self.stack.set_transition_type(Gtk.StackTransitionType.SLIDE_LEFT) + + # Setup signals + def _on_close_btn_released(_, self): + self.popover.show_all() + + def _on_add_layer_btn_released(_, self): + file_choose_dialog = Gtk.FileChooserDialog(title='Select an image', parent=self, + action=Gtk.FileChooserAction.OPEN) + file_choose_dialog.add_buttons( + 'Cancel', Gtk.ResponseType.CANCEL, + 'Accept', Gtk.ResponseType.ACCEPT + ) + + file_filter = Gtk.FileFilter() + file_filter.add_mime_type('image/*') + file_choose_dialog.set_filter(file_filter) + + if file_choose_dialog.run() == Gtk.ResponseType.ACCEPT: + utilities.asset_path = file_choose_dialog.get_file().get_path() + self.options_page.set_asset(utilities.asset_path) + + file_choose_dialog.close() + + def _on_next_btn_released(_, self): + current_page = self.stack.get_visible_child_name() + + if current_page == 'initial': + if (utilities.wallpaper_name is None + or (utilities.wallpaper_type == 'image' or utilities.wallpaper_type == 'video') + and utilities.file_path is None): + self.display_error('Please enter a wallpaper name and choose a file') + return True + elif (utilities.wallpaper_name is None or utilities.wallpaper_type == 'web_page' + and utilities.web_page_url is None): + self.display_error('Please enter a wallpaper name, a valid URL, and a thumbnail') + return True + + self.options_page = pages.OptionsPage() + self.add_layer_btn.set_visible(utilities.wallpaper_type == 'image') + if utilities.wallpaper_type == 'image': + self.options_page.set_image(utilities.file_path) + else: + self.options_page.set_blank() + + self.stack.add_named(self.options_page, 'options') + + self.options_page.show_all() + + self.stack.set_visible_child_name('options') + self.revealer.set_reveal_child(False) + else: + self.options_page.update_ui() + self.stack.add_named(pages.FinalPage(), 'final') + + self.show_all() + + self.stack.set_visible_child_name('final') + self.close_btn.set_visible(False) + self.next_btn.set_visible(False) + self.add_layer_btn.set_visible(False) + + def _on_cancel_btn_released(_, self): + self.popover.hide() + + def _on_yes_btn_released(_): + Gtk.main_quit() + + def _on_destroy(self): + Gtk.main_quit() + + self.close_btn.connect('released', _on_close_btn_released, self) + self.add_layer_btn.connect('released', _on_add_layer_btn_released, self) + self.next_btn.connect('released', _on_next_btn_released, self) + self.cancel_btn.connect('released', _on_cancel_btn_released, self) + self.yes_btn.connect('released', _on_yes_btn_released) + self.connect('destroy', _on_destroy) + + # Add widgets + self.header_bar.add(self.close_btn) + self.header_bar.add(self.add_layer_btn) + self.header_bar.pack_end(self.next_btn) + + self.popover_grid.attach(self.confirmation_lbl, 0, 0, 1, 1) + self.popover_grid.attach(self.cancel_btn, 0, 1, 1, 1) + self.popover_grid.attach(self.yes_btn, 1, 1, 1, 1) + + self.popover.add(self.popover_grid) + + self.info_bar.get_content_area().add(self.error_lbl) + self.revealer.add(self.info_bar) + + self.stack.add_named(pages.InitialPage(), 'initial') + + self.layout.add(self.revealer) + self.layout.add(self.stack) + + self.add(self.layout) + self.add_layer_btn.set_visible(False) + + logging.debug('Loaded WindowWallpaper') + + def display_error(self, error_msg): + self.error_lbl.set_label(error_msg) + self.revealer.set_reveal_child(True) diff --git a/komorebi/wallpapers/base.py b/komorebi/wallpapers/base.py new file mode 100644 index 0000000..148ec4b --- /dev/null +++ b/komorebi/wallpapers/base.py @@ -0,0 +1,33 @@ +import enum + +from gi.repository import Clutter + + +class Wallpaper(Clutter.Actor): + # Wallpaper name + name = None + + def __init__(self, screen, config_file): + Clutter.Actor.__init__(self) + + self.name = config_file.get_string('Info', 'Name') + self.set_size(screen.width, screen.height) + + # Called whenever it's time to register behaviour dependent on the menu + def register_menu_actions(self, menu): + pass + + # Called whenever a setting was changed globally. + # Returns if the object is to be removed or not. + def on_settings_changed(self, setting_key): + pass + + # Called when this object is about to be unloaded + def on_unload(self): + pass + + +class WallpaperType(enum.Enum): + IMAGE = 'image' + VIDEO = 'video' + WEB = 'web_page' diff --git a/komorebi/wallpapers/image.py b/komorebi/wallpapers/image.py new file mode 100644 index 0000000..72c3e2a --- /dev/null +++ b/komorebi/wallpapers/image.py @@ -0,0 +1,55 @@ +import logging + +from gi.repository import Cogl, Clutter, GdkPixbuf + +from komorebi.wallpapers.base import Wallpaper + + +class ImageWallpaper(Wallpaper): + # Image content + image = None + + # Wallpaper settings + parallax = None + + def __init__(self, screen, wallpaper_config): + Wallpaper.__init__(self, screen, wallpaper_config) + logging.debug("Loading ImageWallpaper...") + + path = wallpaper_config.get_string('Info', 'Path') + + image_data = GdkPixbuf.Pixbuf.new_from_file_at_scale(f'{path}/wallpaper.jpg', screen.width, screen.height, False) + + self.image = Clutter.Image() + self.image.set_data(image_data.get_pixels(), Cogl.PixelFormat.RGB_888, image_data.get_width(), + image_data.get_height(), image_data.get_rowstride()) + + self.set_content(self.image) + self.set_pivot_point(0.5, 0.5) + if wallpaper_config.has_group('Wallpaper'): + self.parallax = wallpaper_config.get_boolean('Wallpaper', 'Parallax') + + # If this wallpaper features parallax, connect to signals + if self.parallax: + self.set_scale(1.05, 1.05) + self.signals_setup(screen) + + logging.debug("Loaded ImageWallpaper") + + def signals_setup(self, screen): + def _on_motion_notify_event(screen, event, self): + # FIXME: Hardcoded from old code, easily a customizable property + layer_coeff = 70 + + self.set_x((screen.stage.get_width() - self.get_width()) / 2 + - (event.x - screen.stage.get_width() / 2) / layer_coeff) + self.set_y((screen.stage.get_height() - self.get_height()) / 2 + - (event.y - screen.stage.get_height() / 2) / layer_coeff) + + screen.connect_weak('motion_notify_event', _on_motion_notify_event, self) + + def on_unload(self): + logging.debug('Unloading ImageWallpaper...') + + def __del__(self): + logging.debug('Unloaded ImageWallpaper') diff --git a/komorebi/wallpapers/video.py b/komorebi/wallpapers/video.py new file mode 100644 index 0000000..dfd76eb --- /dev/null +++ b/komorebi/wallpapers/video.py @@ -0,0 +1,88 @@ +import logging + +from gi.repository import ClutterGst + +from komorebi.wallpapers.base import Wallpaper +from komorebi.settings import ConfigKeys, Settings + +video_playback = None +video_content = ClutterGst.Content() + + +class VideoWallpaper(Wallpaper): + # Signal + video_progress_handle = None + + def __init__(self, screen, wallpaper_config): + global video_playback + global video_content + Wallpaper.__init__(self, screen, wallpaper_config) + logging.debug("Loading VideoWallpaper...") + + path = wallpaper_config.get_string('Info', 'Path') + + if not video_playback: + video_playback = ClutterGst.Playback() + + video_playback.set_seek_flags(ClutterGst.SeekFlags.ACCURATE) + video_content.set_player(video_playback) + self.video_progress_handle = video_playback.connect('notify::progress', self._on_video_progress_event) + if Settings.mute_playback: + video_playback.set_audio_volume(0) + + video_file_name = wallpaper_config.get_string('Info', 'VideoFileName') + if video_file_name is None: + raise RuntimeError("Wallpaper config doesn't specify video file name") + video_playback.set_uri(f'file://{path}/{video_file_name}') + self.play() + + self.signals_setup(screen) + + self.set_content(video_content) + logging.debug("Loaded VideoWallpaper") + + def on_unload(self): + logging.debug('Unloading VideoWallpaper...') + if self.video_progress_handle: + video_playback.disconnect(self.video_progress_handle) + self.stop() + + def __del__(self): + logging.debug('Unloaded VideoWallpaper') + + def signals_setup(self, screen): + def _on_focus_in_event(_1, _2, self): + if Settings.pause_playback: + self.play() + return False + + def _on_focus_out_event(_1, _2, self): + if Settings.pause_playback: + self.pause() + return False + + # We need the screen as it is the only entity with these focus signals + screen.connect_weak('focus_in_event', _on_focus_in_event, self) + screen.connect_weak('focus_out_event', _on_focus_out_event, self) + + def on_settings_changed(self, setting_key): + if setting_key == ConfigKeys.MUTE_PLAYBACK: + video_playback.set_audio_volume(0 if Settings.mute_playback else 1) + elif setting_key == ConfigKeys.PAUSE_PLAYBACK: + self.pause() if Settings.pause_playback else self.play() + return False + + def _on_video_progress_event(self, playback, _): + if playback.get_progress() >= 1.0: + self.stop() + self.play() + + def play(self): + video_playback.set_playing(True) + + def pause(self): + video_playback.set_playing(False) + + def stop(self): + self.pause() + video_playback.set_progress(0.0) diff --git a/komorebi/wallpapers/web.py b/komorebi/wallpapers/web.py new file mode 100644 index 0000000..aa386f9 --- /dev/null +++ b/komorebi/wallpapers/web.py @@ -0,0 +1,50 @@ +import logging + +from gi.repository import GtkClutter, WebKit2 + +from komorebi.wallpapers.base import Wallpaper +from komorebi.bubblemenu.item import BubbleMenuItem + + +class WebWallpaper(Wallpaper): + # Web content + web_view = None + web_view_embed = None + web_page_url = None + + # Menu options + refresh_item_menu = None + + def __init__(self, screen, wallpaper_config): + Wallpaper.__init__(self, screen, wallpaper_config) + logging.debug("Loading WebWallpaper...") + + self.web_view = WebKit2.WebView() + self.web_view_embed = GtkClutter.Actor.new_with_contents(self.web_view) + self.web_view_embed.set_size(screen.width, screen.height) + + self.web_page_url = wallpaper_config.get_string('Info', 'WebPageUrl') + if self.web_page_url is None: + raise RuntimeError("Wallpaper config doesn't specify web page URL") + self.web_page_url = self.web_page_url.replace('{{screen_width}}', f'{screen.width}') \ + .replace('{{screen_height}}', f'{screen.height}') + self.web_view.load_uri(self.web_page_url) + self.web_view_embed.set_reactive(False) + + self.add_child(self.web_view_embed) + logging.debug("Loaded WebWallpaper") + + def _on_refresh_wallpaper_item(self, item, e): + self.web_view.load_uri(self.web_page_url) + + def on_unload(self): + self.refresh_item_menu.destroy() + logging.debug('Unloading WebWallpaper...') + + def __del__(self): + logging.debug('Unloaded WebWallpaper') + + def register_menu_actions(self, menu): + self.refresh_item_menu = BubbleMenuItem('Refresh Wallpaper', self._on_refresh_wallpaper_item) + + menu.wallpaper_options.add_child(self.refresh_item_menu) diff --git a/meson.build b/meson.build index 7756334..b3f9030 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,7 @@ -project('komorebi', 'vala', 'c', +project('komorebi', version: '2.2.1', - meson_version: '>=0.49', + meson_version: '>=0.50', + default_options: ['prefix=/usr/local'] ) # Internationalisation / Localisation. This is currently only used to configure the .desktop files; @@ -12,60 +13,90 @@ i18n.gettext(meson.project_name(), args: '--directory=' + meson.source_root() ) +py_mod = import('python') +py_installation = py_mod.find_installation('python3') +if not py_installation.found() + error('Couldn\'t find valid Python3 binary') +else + message('Python3 binary found') +endif + # Set some variables prefix = get_option('prefix') bindir = get_option('bindir') datadir = get_option('datadir') pkgdatadir = join_paths(prefix, datadir, meson.project_name()) - -# Configure Komorebi -conf = configuration_data() -conf.set_quoted('PACKAGE_NAME', meson.project_name()) -conf.set_quoted('PACKAGE_VERSION', meson.project_version()) -conf.set_quoted('PKGDATADIR', pkgdatadir) -conf.set_quoted('DATADIR', join_paths(prefix, datadir)) -komorebiconfiguration = configure_file(input: 'config.vala.in', output: 'config.vala', configuration: conf) +py_dir = join_paths(prefix, py_installation.get_install_dir()) # Compile resources (images, etc,) so that they're built into the app. # TODO: Generate separate resource bundles for Komorebi & Wallpaper Creator; # There's enough overlap that I'm not going to do it right now, but it'd be more elegant. gnome = import('gnome') komorebiresources = gnome.compile_resources( - 'as-resources', 'data/resources/komorebi.gresource.xml', + 'komorebi', 'data/resources/komorebi.gresource.xml', source_dir: 'data/resources', - c_name: 'as' + gresource_bundle: true, + install: true, install_dir: pkgdatadir ) dependencies = [ - dependency('glib-2.0', version: '>=2.38'), - dependency('gobject-2.0'), - dependency('gtk+-3.0', version: '>=3.14'), - dependency('gee-0.8'), - dependency('webkit2gtk-4.0'), - dependency('clutter-gtk-1.0'), - dependency('clutter-1.0'), - dependency('clutter-gst-3.0'), + dependency('glib-2.0', version: '>=2.38'), + dependency('gobject-2.0'), + dependency('gtk+-3.0', version: '>=3.14'), + dependency('gee-0.8'), + dependency('webkit2gtk-4.0'), + dependency('clutter-gtk-1.0'), + dependency('clutter-1.0'), + dependency('clutter-gst-3.0'), ] -main_sources = [] -wallpaper_sources = [] - -wallpaper_sources += files('src/Paths.vala') - -subdir('src') -subdir('wallpaper-creator') subdir('data') -# Postinst script needs work. Let's not run it blindly. -# Frankly, I doubt that there's many (any?) users that have yet to update wallpapers to the new format, so maybe do away with it? -#meson.add_install_script('data/Other/postinst') +# Setup install dirs +install_subdir( + 'komorebi', + exclude_files: [ + '__init__.in' + ], + exclude_directories: [ + '__pycache__', + 'bubblemenu/__pycache__', + 'overlays/__pycache__', + 'wallpaper_creator/__pycache__', + 'wallpapers/__pycache__' + ], + install_dir: py_dir +) -executable(meson.project_name(), main_sources, komorebiconfiguration, komorebiresources, - dependencies: dependencies, - install: true +configure_file( + input: 'komorebi.py', + output: 'komorebi', + copy: true, + install_dir: bindir ) -executable(meson.project_name() + '-wallpaper-creator', wallpaper_sources, komorebiconfiguration, komorebiresources, - dependencies: dependencies, - install: true +configure_file( + input: 'komorebi-wallpaper-creator.py', + output: 'komorebi-wallpaper-creator', + copy: true, + install_dir: bindir ) + +# Configure __init__.py +conf = configuration_data() +conf.set_quoted('PACKAGE_NAME', meson.project_name()) +conf.set_quoted('PACKAGE_VERSION', meson.project_version()) +conf.set_quoted('PKGDATADIR', pkgdatadir) +conf.set_quoted('DATADIR', join_paths(prefix, datadir)) + +configure_file( + input: 'komorebi/__init__.in', + output: '__init__.py', + configuration: conf, + install: true, + install_dir: join_paths(py_dir, 'komorebi') +) + +# Postinst script needs work. Let's not run it blindly. +# Frankly, I doubt that there's many (any?) users that have yet to update wallpapers to the new format, so maybe do away with it? +#meson.add_install_script('data/Other/postinst') diff --git a/src/Main.vala b/src/Main.vala deleted file mode 100644 index ae6d314..0000000 --- a/src/Main.vala +++ /dev/null @@ -1,93 +0,0 @@ -// -// Copyright (C) 2020 Komorebi Team Authors -// Copyright (C) 2016-2017 Abraham Masri -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -using Komorebi.OnScreen; -using Komorebi.Utilities; - -namespace Komorebi { - - BackgroundWindow[] backgroundWindows; - - public static bool checkDesktopCompatible() { - - // We're not supporting Wayland at the moment - // due to some restrictions - if(Environment.get_variable ("XDG_SESSION_TYPE").contains("wayland") || - Environment.get_variable ("WAYLAND_DISPLAY") != null) { - return false; - } - - return true; - } - - public static void main (string [] args) { - - string package_name = Config.package_name; - string package_version = Config.package_version; - - print(@"Welcome to $package_name\n"); - - if(args[1] == "--version" || args[1] == "version") { - print(@"Version: $package_version\nMaintained by: Komorebi Team\n\n"); - return; - } - - if(!checkDesktopCompatible()) { - print("[ERROR]: Wayland detected. Not supported (yet) :(\n"); - print("[INFO]: Contribute to Komorebi and add the support! <3\n"); - return; - } - - GtkClutter.init (ref args); - Gtk.init (ref args); - - readConfigurationFile(); - - if(OnScreen.enableVideoWallpapers) { - - print("[INFO]: loading Gst\n"); - Gst.init (ref args); - } - - Gtk.Settings.get_default().gtk_application_prefer_dark_theme = true; - - var screen = Gdk.Screen.get_default (); - int monitorCount = hasArg("--single-screen", args) ? 1 : screen.get_n_monitors(); - - - initializeClipboard(screen); - - readWallpaperFile(); - - backgroundWindows = new BackgroundWindow[monitorCount]; - for (int i = 0; i < monitorCount; ++i) - backgroundWindows[i] = new BackgroundWindow(i); - - - var mainSettings = Gtk.Settings.get_default (); - // mainSettings.set("gtk-xft-dpi", (int) (1042 * 100), null); - mainSettings.set("gtk-xft-antialias", 1, null); - mainSettings.set("gtk-xft-rgba" , "none", null); - mainSettings.set("gtk-xft-hintstyle" , "slight", null); - - for (int i = 0; i < monitorCount; ++i) - backgroundWindows[i].fadeIn(); - - Clutter.main(); - } -} diff --git a/src/OnScreen/AssetActor.vala b/src/OnScreen/AssetActor.vala deleted file mode 100644 index f7d02d2..0000000 --- a/src/OnScreen/AssetActor.vala +++ /dev/null @@ -1,200 +0,0 @@ -// -// Copyright (C) 2020 Komorebi Team Authors -// Copyright (C) 2015-2018 Abraham Masri @cheesecakeufo -// -// This program is free software: you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License version 3, as published -// by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranties of -// MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -// PURPOSE. See the GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License along -// with this program. If not, see - -using Clutter; - -using Komorebi.Utilities; - -namespace Komorebi.OnScreen { - - public class AssetActor : Actor { - - BackgroundWindow parent; - - // Image(Asset) and its pixbuf - Image image = new Image(); - Gdk.Pixbuf pixbuf; - - public uint assetAnimationTimeout; - - // Animation-specific variables - string cloudsDirection = "right"; - string fadeType = "in"; - - public AssetActor (BackgroundWindow parent) { - this.parent = parent; - set_content(image); - } - - public void setAsset() { - - string package_datadir = Config.package_datadir; - - if(!assetVisible) { - pixbuf = null; - image.set_data (pixbuf.get_pixels(), pixbuf.has_alpha ? Cogl.PixelFormat.RGBA_8888 : Cogl.PixelFormat.RGB_888, - pixbuf.get_width(), pixbuf.get_height(), - pixbuf.get_rowstride()); - fadeOut(); - return; - } - - if(assetWidth <= 0) - assetWidth = screenWidth; - if(assetHeight <= 0) - assetHeight = screenHeight; - - var assetPath = @"$package_datadir/$wallpaperName/assets.png"; - - // make sure the asset exists - if(!File.new_for_path(assetPath).query_exists()) { - print(@"[WARNING]: asset with path: $assetPath does not exist\n"); - return; - } - - if(assetWidth != 0 && assetHeight != 0) - pixbuf = new Gdk.Pixbuf.from_file_at_scale(assetPath, assetWidth, assetHeight, false); - else - pixbuf = new Gdk.Pixbuf.from_file(assetPath); - - image.set_data (pixbuf.get_pixels(), pixbuf.has_alpha ? Cogl.PixelFormat.RGBA_8888 : Cogl.PixelFormat.RGB_888, - pixbuf.get_width(), pixbuf.get_height(), - pixbuf.get_rowstride()); - - - x = 0; - y = 0; - opacity = 255; - remove_all_transitions(); - - setMargins(); - - if(shouldAnimate()) - animate(); - else - fadeIn(); - } - - void setMargins() { - - translation_y = 0; - translation_x = 0; - - translation_y += assetMarginTop; - translation_x -= assetMarginRight; - translation_x += assetMarginLeft; - translation_y -= assetMarginBottom; - } - - void animate () { - - if(assetAnimationSpeed <= 10) { - assetAnimationSpeed = 100; - print("[WARNING]: The Asset Animation Speed has been adjusted in this wallpaper. Please consider updating it to at least 100\n"); - } - - - assetAnimationTimeout = Timeout.add(assetAnimationSpeed * 30, () => { - - switch (assetAnimationMode) { - - case "clouds": - if(cloudsDirection == "right") { - - if(x + (width / 2) >= screenWidth) - cloudsDirection = "left"; - else { - save_easing_state (); - set_easing_duration (assetAnimationSpeed * 100); - x += 60; - set_easing_mode (Clutter.AnimationMode.LINEAR); - restore_easing_state (); - } - - } else { - - if(x <= 0) - cloudsDirection = "right"; - else { - save_easing_state (); - set_easing_duration (assetAnimationSpeed * 100); - x -= 60; - set_easing_mode (Clutter.AnimationMode.LINEAR); - restore_easing_state (); - } - } - - break; - - case "light": - - if(fadeType == "in") { - fadeIn(assetAnimationSpeed * 100); - fadeType = "out"; - } else { - fadeOut(assetAnimationSpeed * 100); - fadeType = "in"; - } - - - break; - } - - return true; - }); - } - - public void fadeIn (int custom_duration = 90) { - - save_easing_state (); - set_easing_duration (custom_duration); - opacity = 255; - set_easing_mode (Clutter.AnimationMode.LINEAR); - restore_easing_state (); - } - - public void fadeOut (int custom_duration = 90) { - - save_easing_state (); - set_easing_duration (custom_duration); - opacity = 0; - set_easing_mode (Clutter.AnimationMode.LINEAR); - restore_easing_state (); - } - - public bool shouldAnimate () { - - if(wallpaperType == "video" || - wallpaperType == "web_page" || - assetAnimationMode == "noanimation") { - - if(assetAnimationTimeout > 0) { - - Source.remove(assetAnimationTimeout); - assetAnimationTimeout = 0; - } - - remove_all_transitions(); - fadeOut(); - - return false; - } - - return true; - } - - } -} diff --git a/src/OnScreen/BackgroundWindow.vala b/src/OnScreen/BackgroundWindow.vala deleted file mode 100644 index 9d15a38..0000000 --- a/src/OnScreen/BackgroundWindow.vala +++ /dev/null @@ -1,464 +0,0 @@ -// -// Copyright (C) 2020 Komorebi Team Authors -// Copyright (C) 2017-2018 Abraham Masri @cheesecakeufo -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - - -using Gtk; -using Gdk; -using Gst; -using WebKit; - -using Komorebi.Utilities; - -namespace Komorebi.OnScreen { - - // Global - Name of active wallpaper - string wallpaperName; - - // Global - 24 hr time - bool timeTwentyFour; - - // Global - Show desktop Icons - bool showDesktopIcons; - - // Global - Enable Video Wallpapers - bool enableVideoWallpapers; - - // Global - Mute Playback of video - bool mutePlayback; - - // Global - Pause Playback when unfocused - bool pausePlayback; - - // Global - Whether we can open preferences window - bool canOpenPreferences = true; - - // Global - Clipboard - Gtk.Clipboard clipboard; - - public static void initializeClipboard(Gdk.Screen screen) { - clipboard = Gtk.Clipboard.get_for_display (screen.get_display (), Gdk.SELECTION_CLIPBOARD); - } - - public class BackgroundWindow : Gtk.Window { - - // this webview acts as a wallpaper (if necessary) - WebView webView = new WebView(); - GtkClutter.Actor webViewActor; - - GtkClutter.Embed embed; - - // Main container - public Clutter.Actor mainActor { get; private set; } - - // Video Wallpaper - public ClutterGst.Playback videoPlayback { get; private set; } - ClutterGst.Content videoContent; - - // Wallpaper pixbuf & image - Clutter.Actor wallpaperActor = new Clutter.Actor(); - Pixbuf wallpaperPixbuf; - Clutter.Image wallpaperImage = new Clutter.Image(); - - // Date and time box itself - DateTimeBox dateTimeBox; - - // Asset Actor - AssetActor assetActor; - - // Bubble menu - public BubbleMenu bubbleMenu { get; private set; } - - // Desktop icons - public DesktopIcons desktopIcons { get; private set; } - - // Current animation mode - bool dateTimeBoxParallax = false; - - // Gradient bg animation (if available) - string gradientBackground = ""; - - const TargetEntry[] targets = { - { "text/uri-list", 0, 0} - }; - - - public BackgroundWindow (int monitorIndex) { - - title = "Desktop"; - - // Get current monitor size - getMonitorSize(monitorIndex); - - embed = new GtkClutter.Embed() {width_request = screenWidth, height_request = screenHeight}; - mainActor = embed.get_stage(); - desktopPath = Environment.get_user_special_dir(UserDirectory.DESKTOP); - desktopIcons = monitorIndex == 0 ? new DesktopIcons(this) : null; - bubbleMenu = new BubbleMenu(this); - assetActor = new AssetActor(this); - dateTimeBox = new DateTimeBox(this); - webViewActor = new GtkClutter.Actor.with_contents(webView); - - if(enableVideoWallpapers) { - videoPlayback = new ClutterGst.Playback (); - videoContent = new ClutterGst.Content(); - videoPlayback.set_seek_flags (ClutterGst.SeekFlags.ACCURATE); - - videoContent.player = videoPlayback; - if (mutePlayback) { - muteVolume(); - } - videoPlayback.notify["progress"].connect(() => { - if(videoPlayback.progress >= 1.0 && wallpaperType == "video") { - videoPlayback.progress = 0.0; - videoPlayback.playing = true; - } - }); - } - - - // Setup widgets - set_size_request(screenWidth, screenHeight); - resizable = false; - set_type_hint(WindowTypeHint.DESKTOP); - set_keep_below(true); - app_paintable = false; - skip_pager_hint = true; - skip_taskbar_hint = true; - accept_focus = true; - stick (); - decorated = false; - add_events (EventMask.ENTER_NOTIFY_MASK | EventMask.POINTER_MOTION_MASK | EventMask.SMOOTH_SCROLL_MASK); - Gtk.drag_dest_set (this, Gtk.DestDefaults.MOTION | Gtk.DestDefaults.DROP, targets, Gdk.DragAction.MOVE); - - mainActor.background_color = Clutter.Color.from_string("black"); - - webViewActor.set_size(screenWidth, screenHeight); - wallpaperActor.set_size(screenWidth, screenHeight); - assetActor.set_size(screenWidth, screenHeight); - wallpaperActor.set_pivot_point (0.5f, 0.5f); - - // Add widgets - mainActor.add_child(wallpaperActor); - mainActor.add_child(dateTimeBox); - mainActor.add_child(assetActor); - - if(desktopIcons != null) - mainActor.add_child(desktopIcons); - - mainActor.add_child(bubbleMenu); - - // add the widgets - add(embed); - - initializeConfigFile(); - signalsSetup(); - - } - - public void muteVolume() { - videoContent.get_player().set_audio_volume(0.0); - } - - public void unmuteVolume() { - videoContent.get_player().set_audio_volume(1.0); - } - - void getMonitorSize(int monitorIndex) { - - Rectangle rectangle; - var screen = Gdk.Screen.get_default (); - - screen.get_monitor_geometry (monitorIndex, out rectangle); - - screenHeight = rectangle.height; - screenWidth = rectangle.width; - - set_gravity(Gravity.STATIC); - move(rectangle.x, rectangle.y); - - } - - void signalsSetup () { - - button_release_event.connect((e) => { - - // Hide the bubble menu - if(bubbleMenu.opacity > 0) { - bubbleMenu.fadeOut(); - unDimWallpaper(); - return true; - } - - // Show options - if(e.button == 3) { - - if(bubbleMenu.opacity > 0) - return false; - - if(desktopIcons != null && showDesktopIcons) - if(e.x >= desktopIcons.x && e.x <= (desktopIcons.x + desktopIcons.width) && - e.y >= desktopIcons.y && e.y <= (desktopIcons.y + desktopIcons.height)) - return false; - - bubbleMenu.fadeIn(e.x, e.y, MenuType.DESKTOP); - dimWallpaper(); - } - - return false; - }); - - motion_notify_event.connect((event) => { - - // No parallax when menu is open - if(bubbleMenu.opacity > 0) { - return true; - } - - var layer_coeff = 70; - - if(dateTimeParallax) { - if(dateTimePosition == "center") { - dateTimeBox.x = (float)((mainActor.width - dateTimeBox.width) / 2 - (event.x - (mainActor.width / 2)) / layer_coeff); - dateTimeBox.y = (float)((mainActor.height - dateTimeBox.height) / 2 - (event.y - (mainActor.height / 2)) / layer_coeff); - } - } - - if(wallpaperParallax) { - wallpaperActor.x = (float)((mainActor.width - wallpaperActor.width) / 2 - (event.x - (mainActor.width / 2)) / layer_coeff); - wallpaperActor.y = (float)((mainActor.height - wallpaperActor.height) / 2 - (event.y - (mainActor.height / 2)) / layer_coeff); - } - - return true; - }); - - focus_out_event.connect(() => { - - if (pausePlayback) { - videoPlayback.playing = false; - } - // Hide the bubble menu - if(bubbleMenu.opacity > 0) { - bubbleMenu.fadeOut(); - unDimWallpaper(); - return true; - } - - return true; - }); - - focus_in_event.connect(() => { - if (pausePlayback) { - videoPlayback.playing = true; - } - return true; - }); - - drag_motion.connect(dimWallpaper); - - drag_leave.connect(() => unDimWallpaper()); - - drag_data_received.connect((widget, context, x, y, selectionData, info, time) => { - - foreach(var uri in selectionData.get_uris()) { - - // Path of the file - string filePath = uri.replace("file://","").replace("file:/",""); - filePath = GLib.Uri.unescape_string (filePath); - - // Get the actual GLib file - var file = File.new_for_path(filePath); - var desktopFile = File.new_for_path(desktopPath + "/" + file.get_basename()); - file.copy(desktopFile, FileCopyFlags.NONE, null); - } - - Gtk.drag_finish (context, true, false, time); - }); - - // disable interactions with webView - webView.button_press_event.connect(() => { - return true; - }); - - webView.button_release_event.connect((e) => { - - button_release_event(e); - return true; - }); - } - - public void initializeConfigFile () { - - setWallpaper(); - - if(desktopIcons != null) { - - if(!showDesktopIcons) - desktopIcons.fadeOut(); - else - desktopIcons.fadeIn(); - } - - if(dateTimeVisible) { - - if(dateTimeAlwaysOnTop) - mainActor.set_child_above_sibling(dateTimeBox, assetActor); - else - mainActor.set_child_below_sibling(dateTimeBox, assetActor); - - dateTimeBox.setDateTime(); - - } else - dateTimeBox.fadeOut(); - - if((wallpaperType != "video" && wallpaperType != "web_page") && assetVisible) - assetActor.setAsset(); - else - assetActor.shouldAnimate(); - } - - void setWallpaper() { - - string package_datadir = Config.package_datadir; - - var scaleWidth = screenWidth; - var scaleHeight = screenHeight; - - if(wallpaperParallax) { - - wallpaperActor.scale_y = 1.05f; - wallpaperActor.scale_x = 1.05f; - - } else { - - wallpaperActor.scale_y = 1.00f; - wallpaperActor.scale_x = 1.00f; - } - - if(enableVideoWallpapers) { - - if(wallpaperType == "video") { - - var videoPath = @"file:///$wallpaperPath/$videoFileName"; - videoPlayback.uri = videoPath; - videoPlayback.playing = true; - - wallpaperActor.set_content(videoContent); - - return; - - } else { - - videoPlayback.playing = false; - videoPlayback.uri = ""; - } - } - - if (wallpaperType == "web_page") { - - wallpaperFromUrl(webPageUrl); - - wallpaperActor.set_content(null); - wallpaperPixbuf = null; - - if(webViewActor.get_parent() != wallpaperActor) - wallpaperActor.add_child(webViewActor); - - return; - - } else { - - // remove webViewActor - if(webViewActor.get_parent() == wallpaperActor) - wallpaperActor.remove_child(webViewActor); - } - - wallpaperActor.set_content(wallpaperImage); - - wallpaperPixbuf = new Gdk.Pixbuf.from_file_at_scale(@"$wallpaperPath/wallpaper.jpg", scaleWidth, scaleHeight, false); - - wallpaperImage.set_data (wallpaperPixbuf.get_pixels(), Cogl.PixelFormat.RGB_888, - wallpaperPixbuf.get_width(), wallpaperPixbuf.get_height(), - wallpaperPixbuf.get_rowstride()); - } - - public bool dimWallpaper () { - - wallpaperActor.save_easing_state (); - wallpaperActor.set_easing_duration (400); - wallpaperActor.opacity = 100; - wallpaperActor.set_easing_mode (Clutter.AnimationMode.EASE_IN_SINE); - wallpaperActor.restore_easing_state (); - - assetActor.opacity = 0; - dateTimeBox.opacity = 0; - - return true; - } - - bool unDimWallpaper () { - - wallpaperActor.save_easing_state (); - wallpaperActor.set_easing_duration (400); - wallpaperActor.opacity = 255; - wallpaperActor.set_easing_mode (Clutter.AnimationMode.EASE_IN_SINE); - wallpaperActor.restore_easing_state (); - - if(assetVisible) - assetActor.opacity = 255; - dateTimeBox.fadeIn(200); - - if(desktopIcons != null) { - if(!showDesktopIcons) - desktopIcons.fadeOut(); - else - desktopIcons.fadeIn(); - } - - return true; - } - - // loads a web page from a URL - public void wallpaperFromUrl(owned string url) { - - url = url.replace("{{screen_width}}", @"$screenWidth").replace("{{screen_height}}", @"$screenHeight"); - - webView.load_uri(url); - } - - /* Shows the window */ - public void fadeIn() { - - show_all(); - dateTimeBox.setPosition(); - - if(desktopIcons != null) - desktopIcons.addIconsFromQueue(); - - } - - public bool contains_point(int x, int y) { - int wl, wt, wr, wb; - get_position(out wl, out wt); - get_size(out wr, out wb); - wr += wl; - wb += wt; - - return (x >= wl && y >= wt && x < wr && y < wb); - } - } -} diff --git a/src/OnScreen/BubbleMenu.vala b/src/OnScreen/BubbleMenu.vala deleted file mode 100644 index 344d5fe..0000000 --- a/src/OnScreen/BubbleMenu.vala +++ /dev/null @@ -1,278 +0,0 @@ -// -// Copyright (C) 2020 Komorebi Team Authors -// Copyright (C) 2015-2016 Abraham Masri @cheesecakeufo -// -// This program is free software: you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License version 3, as published -// by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranties of -// MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -// PURPOSE. See the GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License along -// with this program. If not, see - -using Clutter; - -using Komorebi.Utilities; - -namespace Komorebi.OnScreen { - - public enum MenuType { - DESKTOP, - ICON - - } - - public class BubbleMenu : Actor { - - BackgroundWindow parent; - - // Horizontal Box Layout - BoxLayout horizontalBoxLayout = new BoxLayout() {orientation = Orientation.VERTICAL, spacing = 5}; - - // Bubble items (Desktop) - BubbleMenuItem newFolderMenuItem; - BubbleMenuItem refreshMenuItem; - BubbleMenuItem pasteMenuItem; - /*BubbleMenuItem hideAllWindowsMenuItem*/ - BubbleMenuItem changeWallpaperMenuItem; - BubbleMenuItem preferencesMenuItem; - - // Menu Items (Icon) - BubbleMenuItem moveToTrashMenuItem; - BubbleMenuItem copyMenuItem; - BubbleMenuItem makeAliasMenuItem; - BubbleMenuItem getInfoMenuItem; - - // Current icon (when right clicked) - OnScreen.Icon icon; - - // Type of this menu - MenuType menuType; - - construct { - - // Properties - opacity = 0; - - layout_manager = horizontalBoxLayout; - margin_top = 5; - margin_right = 5; - margin_left = 20; - margin_bottom = 5; - - } - - - public BubbleMenu (BackgroundWindow parent) { - this.parent = parent; - - // Desktop items - newFolderMenuItem = new BubbleMenuItem("New Folder"); - refreshMenuItem = new BubbleMenuItem("Refresh Wallpaper"); - pasteMenuItem = new BubbleMenuItem("Paste"); - changeWallpaperMenuItem = new BubbleMenuItem("Change Wallpaper"); - preferencesMenuItem = new BubbleMenuItem("Desktop Preferences"); - - // icon items - moveToTrashMenuItem = new BubbleMenuItem("Move to Trash"); - copyMenuItem = new BubbleMenuItem("Copy Path"); - makeAliasMenuItem = new BubbleMenuItem("Make Alias"); - getInfoMenuItem = new BubbleMenuItem("Get Info"); - - add_child(moveToTrashMenuItem); - add_child(copyMenuItem); - // add_child(makeAliasMenuItem); - add_child(getInfoMenuItem); - add_child(newFolderMenuItem); - add_child(pasteMenuItem); - add_child(refreshMenuItem); - add_child(changeWallpaperMenuItem); - add_child(preferencesMenuItem); - - foreach(Clutter.Actor child in get_children()) - child.visible = false; - - // Signals - signalsSetup(); - } - - void signalsSetup () { - - newFolderMenuItem.button_press_event.connect(() => { - parent.desktopIcons.createNewFolder(); - return true; - }); - - pasteMenuItem.button_press_event.connect(() => { - parent.desktopIcons.copyToDesktop(clipboard.wait_for_text()); - return true; - }); - - - refreshMenuItem.button_press_event.connect(() => { - - this.parent.wallpaperFromUrl(webPageUrl); - - return true; - }); - - changeWallpaperMenuItem.button_press_event.connect(() => { - - if(showDesktopIcons) - parent.desktopIcons.fadeOut(); - - fadeOut(); - - // Check if preferences window is already visible - if(canOpenPreferences) { - - canOpenPreferences = false; - new PreferencesWindow("wallpapers"); - - } - - return true; - }); - - preferencesMenuItem.button_press_event.connect(() => { - - // Check if preferences window is already visible - if(canOpenPreferences) { - - canOpenPreferences = false; - new PreferencesWindow(); - - } - return true; - }); - - - // Icon items - copyMenuItem.button_press_event.connect(() => { - - // Copy file/folder - clipboard.set_text(icon.filePath, icon.filePath.length); - clipboard.store(); - - return true; - }); - - moveToTrashMenuItem.button_press_event.connect(() => { - - icon.trash(); - - // Move file/folder to trash - var sourceFile = File.new_for_path(icon.filePath); - - try { - sourceFile.trash(); - } catch (Error e) { - - print ("Error deleting %s: %s\n", icon.titleName, e.message); - } - - return true; - }); - - getInfoMenuItem.button_press_event.connect(() => { - - // Display a window with file/directory info - infoWindow.setInfoFromPath(icon.filePath); - infoWindow.show_all(); - - return true; - }); - - } - - public void setIcon (OnScreen.Icon icon) { - - this.icon = icon; - - } - - public void fadeIn (double x, double y, MenuType menuType) { - - this.menuType = menuType; - - if(menuType == MenuType.ICON) { - - moveToTrashMenuItem.visible = true; - copyMenuItem.visible = true; - getInfoMenuItem.visible = true; - - } else { - - // Dim all icons - foreach (var icon in parent.desktopIcons.iconsList) - icon.dimIcon(); - - // Check if we have anything in the clipboard, - // if not, disable the 'Paste' menu item - var clipboardText = clipboard.wait_for_text (); - - if(clipboardText == "" || clipboardText == null) { - pasteMenuItem.opacity = 10; - pasteMenuItem.set_reactive(false); - } else { - pasteMenuItem.opacity = 255; - pasteMenuItem.set_reactive(true); - } - - // Hide 'New Folder' and 'Paste' item if we're not showing icons - if(showDesktopIcons) { - newFolderMenuItem.visible = true; - pasteMenuItem.visible = true; - } - - // If we have a web page wallpaper, show the 'refresh wallpaper' menu item - if(wallpaperType == "web_page") - refreshMenuItem.visible = true; - - changeWallpaperMenuItem.visible = true; - preferencesMenuItem.visible = true; - - } - - // Make sure we don't display off the screen - x = double.min(x, screenWidth - (width + 15 * 2)); - y = double.min(y, parent.mainActor.height - (height + 15 * 2)); - - opacity = 0; - this.x = (float)x; - this.y = (float)y; - - save_easing_state (); - set_easing_duration (90); - this.x += 15; - this.y += 15; - opacity = 255; - set_easing_mode (Clutter.AnimationMode.EASE_IN_SINE); - restore_easing_state (); - } - - public void fadeOut () { - - save_easing_state (); - set_easing_duration (90); - scale_x = 0.9f; - scale_y = 0.9f; - opacity = 0; - set_easing_mode (Clutter.AnimationMode.EASE_IN_SINE); - restore_easing_state (); - - foreach(Clutter.Actor child in get_children()) - child.visible = false; - - // Undim all icon - foreach (var icon in parent.desktopIcons.iconsList) - icon.unDimIcon(); - - icon = null; - } - } -} diff --git a/src/OnScreen/BubbleMenuItem.vala b/src/OnScreen/BubbleMenuItem.vala deleted file mode 100644 index 96bf9f8..0000000 --- a/src/OnScreen/BubbleMenuItem.vala +++ /dev/null @@ -1,70 +0,0 @@ -// -// Copyright (C) 2020 Komorebi Team Authors -// Copyright (C) 2015-2016 Abraham Masri @cheesecakeufo -// -// This program is free software: you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License version 3, as published -// by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranties of -// MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -// PURPOSE. See the GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License along -// with this program. If not, see - -using Gdk; -using Clutter; - -namespace Komorebi.OnScreen { - - public class BubbleMenuItem : Actor { - - public Text text = new Text(); - - public BubbleMenuItem (string title) { - - // Properties - set_reactive (true); - x_align = ActorAlign.START; - x_expand = true; - margin_top = 5; - - text.font_name = "Lato 15"; - text.text = title; - text.set_color(Clutter.Color.from_string("white")); - - // Signals - signalsSetup(); - - add_child(text); - - } - - void signalsSetup () { - - - button_press_event.connect((e) => { - - opacity = 100; - - return false; - }); - - motion_event.connect((e) => { - - opacity = 200; - - return false; - }); - - leave_event.connect((e) => { - - opacity = 255; - - return false; - }); - } - } -} diff --git a/src/OnScreen/DateTimeBox.vala b/src/OnScreen/DateTimeBox.vala deleted file mode 100644 index b1f51c7..0000000 --- a/src/OnScreen/DateTimeBox.vala +++ /dev/null @@ -1,276 +0,0 @@ -// -// Copyright (C) 2020 Komorebi Team Authors -// Copyright (C) 2015-2016 Abraham Masri @cheesecakeufo -// -// This program is free software: you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License version 3, as published -// by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranties of -// MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -// PURPOSE. See the GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License along -// with this program. If not, see - -using Gtk; -using Cairo; - -using Komorebi.Utilities; - -namespace Komorebi.OnScreen { - - public class DateTimeBox : Clutter.Actor { - - public Clutter.Actor textContainerActor = new Clutter.Actor(); - public Clutter.Text timeText = new Clutter.Text(); - public Clutter.Text dateText = new Clutter.Text(); - - public Clutter.Actor shadowContainerActor = new Clutter.Actor(); - public Clutter.Text timeShadowText = new Clutter.Text(); - public Clutter.Text dateShadowText = new Clutter.Text(); - - // Vertical Box Layout - Clutter.BoxLayout boxLayout = new Clutter.BoxLayout() {orientation = Clutter.Orientation.VERTICAL}; - - // Time updater - public uint timeout; - - // Time format - string timeFormat = "%l:%M %p"; - - // Ability to drag - Clutter.DragAction dragAction = new Clutter.DragAction(); - - BackgroundWindow parent; - - public DateTimeBox (BackgroundWindow parent) { - - this.parent = parent; - - // Properties - textContainerActor.layout_manager = boxLayout; - shadowContainerActor.layout_manager = boxLayout; - - background_color = {0,0,0,0}; - opacity = 0; - reactive = true; - - textContainerActor.background_color = {0,0,0,0}; - shadowContainerActor.background_color = {0,0,0,0}; - - - timeText.x_expand = true; - timeText.y_expand = true; - - timeShadowText.x_expand = true; - timeShadowText.y_expand = true; - - // Signals - signalsSetup(); - - shadowContainerActor.add_effect(new Clutter.BlurEffect()); - - add_action (dragAction); - - textContainerActor.add_child(timeText); - textContainerActor.add_child(dateText); - - shadowContainerActor.add_child(timeShadowText); - shadowContainerActor.add_child(dateShadowText); - - add_child(shadowContainerActor); - add_child(textContainerActor); - } - - void signalsSetup () { - - dragAction.drag_end.connect ((actor, event_x, event_y) => { - - // Disable Parallax - dateTimeParallax = false; - - // Check if we're at the passing the edge of the screen - if(x < 0) { - moveTo(0); - } else if (x + width > screenWidth) { - moveTo(screenWidth - width, -1); - } - - if(y < 0) { - moveTo(-1, 0); - } else if (y + height > screenHeight) { - moveTo(-1, screenHeight - height); - } - }); - } - - public void setDateTime() { - - setAlignment(); - setRotation(); - - if(opacity < 1) - fadeIn(); - - opacity = dateTimeAlpha; - shadowContainerActor.opacity = dateTimeShadowAlpha; - - setPosition(); - - timeText.notify["width"].connect(() => { - - setPosition(); - setMargins(); - - }); - - if(timeout > 0) - return; // No need to rerun - - timeout = Timeout.add(200, () => { - - if(timeTwentyFour) - timeFormat = "%H:%M"; - else - timeFormat = "%l:%M %p"; - - var glibTime = new GLib.DateTime.now_local().format(timeFormat); - var glibDate = new GLib.DateTime.now_local().format("%A, %B %e"); - - timeText.set_markup(@"$glibTime"); - dateText.set_markup(@"$glibDate"); - - // Apply same to shadows - timeShadowText.set_markup(@"$glibTime"); - dateShadowText.set_markup(@"$glibDate"); - return true; - }); - } - - public void setAlignment() { - - if(dateTimeAlignment == "start") { - timeText.x_align = Clutter.ActorAlign.START; - timeShadowText.x_align = Clutter.ActorAlign.START; - } - else if(dateTimeAlignment == "center") { - timeText.x_align = Clutter.ActorAlign.CENTER; - timeShadowText.x_align = Clutter.ActorAlign.CENTER; - } - else { - timeText.x_align = Clutter.ActorAlign.END; - timeShadowText.x_align = Clutter.ActorAlign.END; - } - } - - public void setRotation() { - - rotation_angle_x = dateTimeRotationX; - rotation_angle_y = dateTimeRotationY; - rotation_angle_z = dateTimeRotationZ; - } - - public void setPosition() { - var mainActor = parent.mainActor; - - switch (dateTimePosition) { - - case "top_right": - x = mainActor.width - width; - y = 0; - break; - - case "top_center": - x = (mainActor.width / 2) - (width / 2); - y = 0; - break; - - case "top_left": - x = 0; - y = 0; - break; - - case "center_right": - x = mainActor.width - width; - y = (mainActor.height / 2) - (height / 2); - break; - - case "center": - x = (mainActor.width / 2) - (width / 2); - y = (mainActor.height / 2) - (height / 2); - break; - - case "center_left": - x = 0; - y = (mainActor.height / 2) - (height / 2); - break; - - case "bottom_right": - x = mainActor.width - width; - y = mainActor.height - height; - break; - - case "bottom_center": - x = (mainActor.width / 2) - (width / 2); - y = mainActor.height - height; - break; - - case "bottom_left": - x = 0; - y = mainActor.height - height; - break; - - default: - break; - } - } - - - public void setMargins() { - - translation_y = 0; - translation_x = 0; - - translation_y += dateTimeMarginTop; - translation_x -= dateTimeMarginRight; - translation_x += dateTimeMarginLeft; - translation_y -= dateTimeMarginBottom; - } - - - private void moveTo(float x = -1, float y = -1) { - - save_easing_state (); - set_easing_duration (90); - if(x != -1) this.x = x; - if(y != -1) this.y = y; - set_easing_mode (Clutter.AnimationMode.EASE_IN_SINE); - restore_easing_state (); - } - - public void fadeIn (int custom_duration = 90) { - - save_easing_state (); - set_easing_duration (90); - opacity = dateTimeAlpha; - set_easing_mode (Clutter.AnimationMode.EASE_IN_SINE); - restore_easing_state (); - - reactive = true; - - } - - public void fadeOut () { - - save_easing_state (); - set_easing_duration (90); - opacity = 0; - set_easing_mode (Clutter.AnimationMode.EASE_IN_SINE); - restore_easing_state (); - - reactive = false; - } - } -} diff --git a/src/OnScreen/DesktopIcons.vala b/src/OnScreen/DesktopIcons.vala deleted file mode 100644 index 2bdfd13..0000000 --- a/src/OnScreen/DesktopIcons.vala +++ /dev/null @@ -1,270 +0,0 @@ -// -// Copyright (C) 2020 Komorebi Team Authors -// Copyright (C) 2012-2017 Abraham Masri -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// -// -// Copied from ManagerForKedos - Abraham Masri -// - -using Gtk; -using Gee; -using Clutter; - -using Komorebi.Utilities; - -using GLib.Environment; - -namespace Komorebi.OnScreen { - - // File/Directory info Window - InfoWindow infoWindow; - - public class DesktopIcons : ResponsiveGrid { - - BackgroundWindow parent; - public BackgroundWindow window { get { return parent; } } - - /* Desktops path */ - string DesktopPath = Environment.get_user_special_dir(UserDirectory.DESKTOP); - - FileMonitor fileMonitor; - - // List of icons (used to make things faster when reloading) - public Gee.ArrayList iconsList { get; private set; } - - public DesktopIcons (BackgroundWindow parent) { - this.parent = parent; - - infoWindow = new InfoWindow(); - iconsList = new Gee.ArrayList(); - - margin_top = 60; - margin_left = 120; - y_expand = true; - iconSize = 64; - - monitorChanges(); - getDesktops(); - } - - /* Watch for Changes */ - void monitorChanges () { - - fileMonitor = File.new_for_path(DesktopPath).monitor(0); - - fileMonitor.changed.connect((e,a,event) => { - if(event == FileMonitorEvent.DELETED || event == FileMonitorEvent.CREATED) { - getDesktops(); - addIconsFromQueue(); - } - - - }); - } - - /* Get .desktop(s) */ - public void getDesktops () { - - iconsList.clear(); - grabDesktopPaths(); - addTrashIcon(); - } - - /* Adds all icons from the queue */ - public void addIconsFromQueue () { - - itemsLimit = (int)Math.round(screenHeight / (83 + verticalLayout.spacing)); - - clearIcons(); - destroy_all_children(); - - foreach (var icon in iconsList) { - append(icon); - icon.unDimIcon(); - } - } - - /* Async get desktop items */ - public void grabDesktopPaths () { - - var desktopFile = File.new_for_path (DesktopPath); - - // Reads all files in the directory - var Enum = desktopFile.enumerate_children ("standard::*", FileQueryInfoFlags.NOFOLLOW_SYMLINKS); - FileInfo info; - - while ((info = Enum.next_file ()) != null) { - - // Location of the file - string FilePath = DesktopPath + "/" + info.get_name (); - - string name = info.get_name(); - Gdk.Pixbuf iconPixbuf = null; - var Path = FilePath; - var DFile = File.new_for_path(FilePath); - OnScreen.Icon icon = null; - - /* Check if the file is .desktop */ - if(DFile.get_basename().has_suffix(".desktop")) { - - var keyFile = new KeyFile(); - keyFile.load_from_file(DFile.get_path(), 0); - - // make sure the keyFile has the required keys - if(!keyFile.has_key(KeyFileDesktop.GROUP, KeyFileDesktop.KEY_NAME) || - !keyFile.has_key(KeyFileDesktop.GROUP, KeyFileDesktop.KEY_ICON) || - !keyFile.has_key(KeyFileDesktop.GROUP, KeyFileDesktop.KEY_EXEC)) - continue; - - name = keyFile.get_string(KeyFileDesktop.GROUP, KeyFileDesktop.KEY_NAME); - - var iconPath = keyFile.get_string(KeyFileDesktop.GROUP, KeyFileDesktop.KEY_ICON); - - iconPixbuf = Utilities.getIconFrom(iconPath, iconSize); - - Path = keyFile.get_string(KeyFileDesktop.GROUP, KeyFileDesktop.KEY_EXEC); - - icon = new Icon(this, name, iconPixbuf, Path, DFile.get_path(), true); - - - - } else { - - string iconPath = LoadIcon(DFile); - - if(iconPath == null) { - if(DFile.query_file_type(FileQueryInfoFlags.NONE) == FileType.DIRECTORY) - iconPath = "folder"; - else { - - var iconQuery = DFile.query_info("standard::icon", 0).get_icon ().to_string().split(" "); - if(iconQuery.length > 1) - iconPath = iconQuery[iconQuery.length - 1]; - } - - iconPixbuf = Utilities.getIconFrom(iconPath, iconSize); - - } else - iconPixbuf = new Gdk.Pixbuf.from_file_at_scale(iconPath, iconSize, iconSize, false); - - - icon = new Icon(this, name, iconPixbuf, "", DFile.get_path(), false); - } - - - iconsList.add(icon); - - } - } - - /* Adds trash icon */ - private void addTrashIcon() { - - iconsList.add(new Icon.Trash(this)); - } - - - /* Creates a new folder */ - public void createNewFolder () { - - var untitledFolder = File.new_for_path(getUntitledFolderName()); - untitledFolder.make_directory_async(); - - } - - /* Pastes a file from a given path to desktop */ - public void copyToDesktop (string path) { - - // Get the actual GLib file - var file = File.new_for_path(path); - var desktopFile = File.new_for_path(desktopPath + "/" + file.get_basename()); - file.copy(desktopFile, FileCopyFlags.NONE, null); - - } - - /* Finds the icon of a file and returns as string */ - string LoadIcon (File file) { - - /* Check if it's a .desktop */ - if(file.get_basename().has_suffix(".desktop")) { - - try { - - var _KeyFile = new KeyFile(); - - _KeyFile.load_from_file(file.get_path(), 0); - - return _KeyFile.get_string(KeyFileDesktop.GROUP, - KeyFileDesktop.KEY_ICON); - - } catch { - - - } - - } - - var Standard = FileAttribute.STANDARD_ICON; - var Thumb = FileAttribute.THUMBNAIL_PATH; - var CustomName = "metadata::custom-icon-name"; - var CustomIcon = "standard::icon"; - - var Query = "%s,%s,%s,%s".printf(Thumb, Standard, CustomIcon, CustomName); - - var Info = file.query_info (Query, 0); - - // look for a thumbnail - var thumb_icon = Info.get_attribute_byte_string (Thumb); - if (thumb_icon != null && thumb_icon != "") - return thumb_icon; - - // otherwise try to get the icon from the fileinfo - return null; - - } - - public void fadeIn () { - - save_easing_state (); - set_easing_duration (200); - opacity = 255; - set_easing_mode (Clutter.AnimationMode.EASE_IN_SINE); - restore_easing_state (); - - } - - public void fadeOut () { - - save_easing_state (); - set_easing_duration (200); - opacity = 0; - set_easing_mode (Clutter.AnimationMode.EASE_IN_SINE); - restore_easing_state (); - - } - - /* Returns a new Untitled Folder name */ - private string getUntitledFolderName(int count = 0) { - - string path = desktopPath + @"/New Folder($(count.to_string()))"; - if(File.new_for_path(path).query_exists()) - path = getUntitledFolderName(count + 1); - - return path; - } - - } -} diff --git a/src/OnScreen/Icon.vala b/src/OnScreen/Icon.vala deleted file mode 100644 index 92b98d6..0000000 --- a/src/OnScreen/Icon.vala +++ /dev/null @@ -1,329 +0,0 @@ -// -// Copyright (C) 2020 Komorebi Team Authors -// Copyright (C) 2017-2018 Abraham Masri @cheesecakeufo -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// -// Copied from ManagerForKedos - Abraham Masri -// - -using Gtk; -using Gdk; -using GtkClutter; -using GLib.Environment; - -using Komorebi.Utilities; - -namespace Komorebi.OnScreen { - - public enum IconType { - NORMAL, - EDIT, - TRASH - } - - public class Icon : Clutter.Actor { - - DesktopIcons parent; - - /* Path of the file */ - public string filePath = ""; - - /* Path of executable path */ - public string execPath = ""; - - /* Title of the file */ - public string titleName = ""; - - Clutter.BoxLayout boxLayout = new Clutter.BoxLayout() {orientation = Clutter.Orientation.VERTICAL}; - - Clutter.Actor mainActor = new Clutter.Actor(); - Clutter.Actor iconActor = new Clutter.Actor(); - Clutter.Image iconImage = new Clutter.Image(); - Clutter.Text titleText = new Clutter.Text(); - - // Ability to drag - Clutter.DragAction dragAction = new Clutter.DragAction(); - - // Wether the path is executable - bool isExecutable = false; - - // Type of this icon - IconType iconType; - - - construct { - - // Properties - layout_manager = boxLayout; - reactive = true; - height = 83; - opacity = 0; - - set_pivot_point (0.5f, 0.5f); - - iconActor.set_size(iconSize, iconSize); - - titleText.set_line_wrap(true); - titleText.set_max_length(10); - titleText.ellipsize = Pango.EllipsizeMode.END; - - setupSignals(); - - // Add widgets - iconActor.add_action(dragAction); - - iconActor.set_content(iconImage); - add_child(iconActor); - add_child(titleText); - - } - - public Icon (DesktopIcons parent, string name, Pixbuf pixbuf, string execPath, string filePath, - bool isExecutable = false) { - this.parent = parent; - this.filePath = filePath; - this.execPath = execPath; - this.titleName = name; - this.isExecutable = isExecutable; - this.iconType = IconType.NORMAL; - - // Setup widgets - iconImage.set_data (pixbuf.get_pixels(), - pixbuf.has_alpha ? Cogl.PixelFormat.RGBA_8888 : Cogl.PixelFormat.RGB_888, - iconSize, iconSize, - pixbuf.get_rowstride()); - - titleText.set_markup(@"$titleName"); - - } - - public Icon.Trash (DesktopIcons parent) { - this.parent = parent; - this.titleName = "Trash"; - var pixbuf = Utilities.getIconFrom("user-trash", 64); - - iconImage.set_data (pixbuf.get_pixels(), - pixbuf.has_alpha ? Cogl.PixelFormat.RGBA_8888 : Cogl.PixelFormat.RGB_888, - iconSize, iconSize, - pixbuf.get_rowstride()); - - titleText.set_markup(@"Trash"); - - this.iconType = IconType.TRASH; - - } - - public Icon.NewFolder (DesktopIcons parent) { - this.parent = parent; - - var pixbuf = Utilities.getIconFrom("folder", 64); - - iconImage.set_data (pixbuf.get_pixels(), - pixbuf.has_alpha ? Cogl.PixelFormat.RGBA_8888 : Cogl.PixelFormat.RGB_888, - iconSize, iconSize, - pixbuf.get_rowstride()); - - this.iconType = IconType.EDIT; - /*mainBox.add(entry);*/ - - /*entry.grab_focus();*/ - } - - /* Setup all signals */ - private void setupSignals () { - - button_press_event.connect((e) => { - - // We don't show animations when right-click button is pressed - if (e.button != 3) { - scaledScale(); - } - - - return true; - }); - - button_release_event.connect ((e) => { - - if(!showDesktopIcons) - return true; - - save_easing_state (); - set_easing_duration (90); - scale_x = 1.0f; - scale_y = 1.0f; - set_easing_mode (Clutter.AnimationMode.EASE_IN_SINE); - restore_easing_state (); - - switch(iconType) { - - case IconType.NORMAL: - - if(e.button == 1) { - - // TODO: Replace event with 2BUTTON_PRESS - if(isExecutable) - AppInfo.create_from_commandline(execPath, null, AppInfoCreateFlags.NONE).launch(null, null); - else - AppInfo.launch_default_for_uri (@"file://$filePath", null); - - } else if(e.button == 3) { // Show the menu - BackgroundWindow backgroundWindow = parent.window; - BubbleMenu bubbleMenu = backgroundWindow.bubbleMenu; - - backgroundWindow.dimWallpaper(); - - bubbleMenu.fadeIn(e.x, e.y, MenuType.ICON); - bubbleMenu.setIcon(this); - - // Dim our text - titleText.opacity = 50; - - // Dim other icons - foreach (var icon in parent.iconsList) { - if(icon.filePath != this.filePath) - icon.dimIcon(); - } - - - } - break; - - case IconType.TRASH: - - // TODO: Replace event with 2BUTTON_PRESS - AppInfo.launch_default_for_uri ("trash://", null); - break; - - } - - - return true; - }); -/* - entry.key_release_event.connect((e) => { - - switch (e.keyval) { - - case Gdk.Key.Return: - case Gdk.Key.KP_Enter: - mainBox.remove(entry); - buttonBox.pack_end(title); - - if(entry.text == "") - titleName = "New Folder"; - else - this.titleName = entry.text; - copyMenuItem.set_label(@"Copy \"$(titleName)\" "); - titleText.set_markup(@"$titleName"); - title.set_markup(@"$titleName"); - title.show_all(); - - // Set the type of the icon back to normal - this.iconType = IconType.NORMAL; - - // Create an actual folder - createNewFolder(titleName); - - break; - - case Gdk.Key.Menu: - entry.grab_focus(); - break; - } - - return false; - }); - - - makeAliasMenuItem.activate.connect(() => { - - // Makes an alias to the file/folder - var sourceFile = File.new_for_path(filePath); - var sourceFileName = sourceFile.get_basename(); - var targetFile = File.new_for_path(desktopPath + "/(Alias) " + sourceFileName); - - targetFile.make_symbolic_link(filePath); - });*/ - - - } - - /* Restores icon's scale to scaled down */ - private bool scaledScale () { - - save_easing_state (); - set_easing_duration (90); - scale_x = 0.9f; - scale_y = 0.9f; - set_easing_mode (Clutter.AnimationMode.EASE_IN_SINE); - restore_easing_state (); - - return true; - } - - /* Trashes the icon */ - public void trash () { - - save_easing_state (); - set_easing_duration (90); - scale_x = 0.9f; - scale_y = 0.9f; - opacity = 0; - set_easing_mode (Clutter.AnimationMode.EASE_IN_SINE); - restore_easing_state (); - - } - - public bool dimIcon () { - - save_easing_state (); - set_easing_duration (400); - opacity = 100; - titleText.opacity = 100; - set_easing_mode (Clutter.AnimationMode.EASE_IN_SINE); - restore_easing_state (); - - return true; - } - - public bool unDimIcon (bool with_scale = false) { - - if(with_scale) { - scale_y = 0.5f; - scale_x = 0.5f; - } - - save_easing_state (); - set_easing_duration (400); - opacity = 255; - if(with_scale) { - scale_y = 1.0f; - scale_x = 1.0f; - } - titleText.opacity = 255; - set_easing_mode (Clutter.AnimationMode.EASE_IN_SINE); - restore_easing_state (); - return true; - } - - /* Activates rename mode */ - public void activateRenameMode () { - - - } - - } -} diff --git a/src/OnScreen/InfoWindow.vala b/src/OnScreen/InfoWindow.vala deleted file mode 100644 index 1db1610..0000000 --- a/src/OnScreen/InfoWindow.vala +++ /dev/null @@ -1,177 +0,0 @@ -// -// Copyright (C) 2020 Komorebi Team Authors -// Copyright (C) 2012-2017 Abraham Masri -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// -// -// Copied from ManagerForKedos - Abraham Masri -// - -using Gtk; -using Komorebi.Utilities; - -using GLib.Environment; - -namespace Komorebi.OnScreen { - - - public class InfoWindow : Gtk.Window { - - // Box containing everything - private Box mainBox = new Box(Orientation.VERTICAL, 0); - - // Box contains close button (acts like HeaderBar) - private Box headerBar = new Box(Orientation.HORIZONTAL, 5); - - // Box contains title label, and size - private Box topBox = new Box(Orientation.VERTICAL, 5); - - // Close/Hide button - private Button closeButton = new Button(); - - // File/Directory title - public Label titleLabel = new Label("No name"); - - // File/Directory size - public Label sizeLabel = new Label("Size unknown"); - - // Separator - private Separator separator = new Separator(Orientation.HORIZONTAL); - - - // Box more file info and properties - private Box fileInfoBox = new Box(Orientation.VERTICAL, 5); - - // Location - public RowLabel locationLabel = new RowLabel("Location"); - - // Type - public RowLabel typeLabel = new RowLabel("Type"); - - // Accessed - public RowLabel accessedLabel = new RowLabel("Accessed"); - - // Modified - public RowLabel modifiedLabel = new RowLabel("Modified"); - - // Owner - public RowLabel ownerLabel = new RowLabel("Owner"); - - string headerBarCSS = "*{ - background-color: rgba(25,25,25,0.7); - border-width: 0px; - box-shadow: none; - border-top-left-radius: 0.6em; - border-top-right-radius: 0.6em; - border-color: @transparent; - }"; - - string windowCSS = "*{ - - background-color: rgba(25,25,25,0.7); - border-width: 0px; - box-shadow: none; - border-bottom-left-radius: 0.6em; - border-bottom-right-radius: 0.6em; - color: white; - }"; - - string separatorCSS = "*{ - color: rgba(51,51,51,0.6); - }"; - public InfoWindow() { - - // Configure the window - set_size_request(340, 390); - resizable = false; - set_titlebar(headerBar); - addAlpha({this}); - applyCSS({this}, windowCSS); - - // Configure widgets - applyCSS({headerBar}, headerBarCSS); - closeButton.set_halign(Align.START); - - titleLabel.set_halign(Align.CENTER); - titleLabel.set_line_wrap(true); - titleLabel.set_max_width_chars(19); - titleLabel.set_ellipsize(Pango.EllipsizeMode.MIDDLE); - titleLabel.set_selectable(true); - - separator.margin_top = 10; - separator.margin_bottom = 10; - applyCSS({separator}, separatorCSS); - - fileInfoBox.margin = 20; - - // Signals - closeButton.button_press_event.connect(() => { - this.hide(); - return true; - }); - - // Add widgets - closeButton.add(new Image.from_resource("/org/komorebi-team/komorebi/close_btn.svg")); - headerBar.pack_start(closeButton, false, false); - - topBox.add(titleLabel); - topBox.add(sizeLabel); - - - fileInfoBox.add(locationLabel); - fileInfoBox.add(typeLabel); - fileInfoBox.add(accessedLabel); - fileInfoBox.add(modifiedLabel); - fileInfoBox.add(ownerLabel); - - mainBox.add(topBox); - mainBox.add(separator); - mainBox.add(fileInfoBox); - add(mainBox); - - closeButton.grab_focus(); - } - - /* Set window information */ - public void setInfoFromPath(string path) { - - File file = File.new_for_path(path); - FileInfo fileInfo = file.query_info("%s,%s,%s,%s,%s,%s".printf( - FileAttribute.STANDARD_SIZE, - FileAttribute.STANDARD_TYPE, - FileAttribute.STANDARD_CONTENT_TYPE, - FileAttribute.TIME_ACCESS, - FileAttribute.TIME_CHANGED, - FileAttribute.OWNER_USER - ) , 0); - - var accessedTime = (int64) fileInfo.get_attribute_uint64(FileAttribute.TIME_ACCESS); - var modifiedTime = (int64) fileInfo.get_attribute_uint64(FileAttribute.TIME_CHANGED); - var owner = fileInfo.get_attribute_string(FileAttribute.OWNER_USER); - - titleLabel.set_markup(@"$(file.get_basename())"); - sizeLabel.set_markup(@"$(GLib.format_size (fileInfo.get_size()))"); - - locationLabel.set_value(path); - typeLabel.set_value(fileInfo.get_content_type()); - accessedLabel.set_value(formatDateTime((new DateTime.from_unix_utc(accessedTime)).to_local())); - modifiedLabel.set_value(formatDateTime((new DateTime.from_unix_utc(modifiedTime)).to_local())); - ownerLabel.set_value(owner); - - } - } - - -} diff --git a/src/OnScreen/PreferencesWindow.vala b/src/OnScreen/PreferencesWindow.vala deleted file mode 100644 index 070afaa..0000000 --- a/src/OnScreen/PreferencesWindow.vala +++ /dev/null @@ -1,345 +0,0 @@ -// -// Copyright (C) 2020 Komorebi Team Authors -// Copyright (C) 2016-2017 Abraham Masri -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - - -using Gtk; -using Gdk; - -using Komorebi.Utilities; - -namespace Komorebi.OnScreen { - - public class PreferencesWindow : Gtk.Window { - - // Custom headerbar - HeaderBar headerBar = new HeaderBar(); - - Button hideButton = new Button.with_label("Hide"); - Button quitButton = new Button.with_label("Quit Komorebi"); - - // Contains two pages (Preferences and Wallpapers) - Gtk.Notebook notebook = new Gtk.Notebook(); - - // Contains preferences page widgets - Gtk.Box preferencesPage = new Box(Orientation.VERTICAL, 5); - - Gtk.Grid aboutGrid = new Gtk.Grid(); - - Box titleBox = new Box(Orientation.VERTICAL, 5); - Label titleLabel = new Label(""); - Label aboutLabel = new Label(""); - - Gtk.CheckButton twentyFourHoursButton = new Gtk.CheckButton.with_label ("Use 24-hour time"); - Gtk.CheckButton enableAutostartButton = new Gtk.CheckButton.with_label ("Launch Komorebi on system startup"); - Gtk.CheckButton showDesktopIconsButton = new Gtk.CheckButton.with_label ("Show desktop icons"); - Gtk.CheckButton enableVideoWallpapersButton = new Gtk.CheckButton.with_label ("Enable Video Wallpapers (Restarting Komorebi is required)"); - Gtk.CheckButton mutePlaybackButton = new Gtk.CheckButton.with_label ("Mute Video playback"); - Gtk.CheckButton pausePlaybackButton = new Gtk.CheckButton.with_label ("Pause Video playback on un-focus"); - - Gtk.Box bottomPreferencesBox = new Box(Orientation.HORIZONTAL, 10); - - Button donateButton = new Button.with_label("Donate"); - Button reportButton = new Button.with_label("Report an issue"); - - // Contains wallpapers page widgets - Gtk.Box wallpapersPage = new Box(Orientation.VERTICAL, 10); - - Gtk.InfoBar infoBar = new Gtk.InfoBar (); - - WallpapersSelector wallpapersSelector = new WallpapersSelector(); - - Gtk.Box bottomWallpapersBox = new Box(Orientation.HORIZONTAL, 10); - - Label currentWallpaperLabel = new Label(""); - - // Triggered when pointer leaves window - bool canDestroy = false; - - - /* Add some style */ - string notebookCSS = " - *{ - background: none; - background-color: rgba(0, 0, 0, 0.60); - box-shadow: none; - color: white; - border-width: 0; - } - .notebook.header { - background-color: rgb(0,0,0); - } - .notebook notebook:focus tab { - background: none; - border-width: 0; - border-radius: 0px; - border-color: transparent; - border-image-width: 0; - border-image: none; - background-color: red; - } - "; - - string headerCSS = " - *{ - background: rgba(0, 0, 0, 0.7); - background-color: rgb(0, 0, 0); - box-shadow: none; - color: white; - border-width: 0px; - box-shadow: none; - border-image: none; - border: none; - } - "; - - string infoBarCSS = " - *{ - background: #f44336; - background-color: #f44336; - box-shadow: none; - color: white; - border-width: 0px; - box-shadow: none; - border-image: none; - border: none; - } - "; - public PreferencesWindow (string selectedTab = "preferences") { - - title = ""; - set_size_request(760, 500); - resizable = false; - window_position = WindowPosition.CENTER; - set_titlebar(headerBar); - applyCSS({this.notebook}, notebookCSS); - applyCSS({this.infoBar}, infoBarCSS); - applyCSS({headerBar, hideButton, quitButton, donateButton, reportButton}, headerCSS); - addAlpha({this}); - - // Setup Widgets - titleLabel.set_markup("Komorebi"); - aboutLabel.set_markup("by Komorebi Team"); - - // showSystemStatsButton.active = showInfoBox; - twentyFourHoursButton.active = timeTwentyFour; - enableAutostartButton.active = autostart; - showDesktopIconsButton.active = showDesktopIcons; - enableVideoWallpapersButton.active = enableVideoWallpapers; - mutePlaybackButton.active = mutePlayback; - pausePlaybackButton.active = pausePlayback; - - setWallpaperNameLabel(); - - // Properties - hideButton.margin_top = 6; - hideButton.margin_start = 6; - hideButton.halign = Align.START; - - quitButton.margin_top = 6; - quitButton.margin_end = 6; - - notebook.expand = true; - - preferencesPage.margin = 20; - preferencesPage.halign = Align.CENTER; - preferencesPage.margin_bottom = 10; - - aboutGrid.halign = Align.CENTER; - aboutGrid.margin_bottom = 30; - aboutGrid.column_spacing = 0; - aboutGrid.row_spacing = 0; - - titleBox.margin_top = 15; - titleBox.margin_start = 10; - titleLabel.halign = Align.START; - - bottomPreferencesBox.margin_top = 10; - - donateButton.valign = Align.CENTER; - reportButton.valign = Align.CENTER; - - infoBar.message_type = MessageType.WARNING; - infoBar.set_show_close_button(false); - - currentWallpaperLabel.selectable = true; - - bottomWallpapersBox.margin = 25; - bottomWallpapersBox.margin_top = 10; - - // Signals - destroy.connect(() => { canOpenPreferences = true;}); - - hideButton.released.connect(() => { destroy(); }); - quitButton.released.connect(() => { - - print("Quitting Komorebi. Good bye :)\n"); - Clutter.main_quit(); - - }); - - donateButton.released.connect(() => { - - print("Thank you <3\n"); - AppInfo.launch_default_for_uri("https://goo.gl/Yr1RQe", null); // Thank you <3 - destroy(); - - }); - - reportButton.released.connect(() => { - - AppInfo.launch_default_for_uri("https://goo.gl/aaJgN7", null); - destroy(); - }); - - - twentyFourHoursButton.toggled.connect (() => { - - timeTwentyFour = twentyFourHoursButton.active; - updateConfigurationFile(); - - }); - - enableAutostartButton.toggled.connect (() => { - autostart = enableAutostartButton.active; - if (enableAutostartButton.active) - enableAutostart(); - else - disableAutostart(); - updateConfigurationFile(); - }); - - showDesktopIconsButton.toggled.connect (() => { - showDesktopIcons = showDesktopIconsButton.active; - updateConfigurationFile(); - - if (showDesktopIcons) { - foreach (BackgroundWindow backgroundWindow in backgroundWindows) - backgroundWindow.desktopIcons.fadeIn(); - } else { - foreach (BackgroundWindow backgroundWindow in backgroundWindows) - backgroundWindow.desktopIcons.fadeOut(); - } - }); - - enableVideoWallpapersButton.toggled.connect (() => { - - enableVideoWallpapers = enableVideoWallpapersButton.active; - updateConfigurationFile(); - - }); - - mutePlaybackButton.toggled.connect(() => { - mutePlayback = mutePlaybackButton.active; - if (mutePlayback) { - foreach (BackgroundWindow backgroundWindow in backgroundWindows) { - backgroundWindow.muteVolume(); - } - } else { - foreach (BackgroundWindow backgroundWindow in backgroundWindows) { - backgroundWindow.unmuteVolume(); - } - } - updateConfigurationFile(); - }); - - pausePlaybackButton.toggled.connect(() => { - pausePlayback = pausePlaybackButton.active; - if (!pausePlayback) { - foreach (BackgroundWindow backgroundWindow in backgroundWindows) { - backgroundWindow.videoPlayback.playing = true; - } - } else { - foreach (BackgroundWindow backgroundWindow in backgroundWindows) { - backgroundWindow.videoPlayback.playing = false; - } - } - updateConfigurationFile(); - }); - - wallpapersSelector.wallpaperChanged.connect(() => { - setWallpaperNameLabel(); - }); - - // Add Widgets - headerBar.add(hideButton); - headerBar.pack_end(quitButton); - - titleBox.add(titleLabel); - titleBox.add(aboutLabel); - - aboutGrid.attach(new Image.from_resource("/org/komorebi-team/komorebi/komorebi.svg"), 0, 0, 1, 1); - aboutGrid.attach(titleBox, 1, 0, 1, 1); - - bottomPreferencesBox.pack_start(donateButton); - bottomPreferencesBox.pack_end(reportButton); - - preferencesPage.add(aboutGrid); - preferencesPage.add(twentyFourHoursButton); - preferencesPage.add(enableAutostartButton); - preferencesPage.add(showDesktopIconsButton); - preferencesPage.add(enableVideoWallpapersButton); - preferencesPage.add(mutePlaybackButton); - preferencesPage.add(pausePlaybackButton); - preferencesPage.pack_end(bottomPreferencesBox); - - bottomWallpapersBox.add(new Image.from_resource("/org/komorebi-team/komorebi/info.svg")); - bottomWallpapersBox.add(currentWallpaperLabel); - - if(!canPlayVideos()) { - - infoBar.get_content_area().add(new Label("gstreamer1.0-libav is missing. You won't be able to set video wallpapers without it.")); - wallpapersPage.add(infoBar); - } - - wallpapersPage.add(wallpapersSelector); - wallpapersPage.add(bottomWallpapersBox); - - - if(selectedTab == "wallpapers") { - notebook.append_page(wallpapersPage, new Label("Wallpapers")); - notebook.append_page(preferencesPage, new Label("Preferences")); - } else { - notebook.append_page(preferencesPage, new Label("Preferences")); - notebook.append_page(wallpapersPage, new Label("Wallpapers")); - } - - - notebook.child_set_property (preferencesPage, "tab-expand", true); - notebook.child_set_property (wallpapersPage, "tab-expand", true); - - add(notebook); - - show_all(); - } - - /* Changes the wallpaper name label */ - private void setWallpaperNameLabel() { - - var prettyName = beautifyWallpaperName(wallpaperName); - currentWallpaperLabel.set_markup(@"$prettyName"); - } - - /* Shows the window */ - public void FadeIn() { - - show_all(); - - } - - } -} diff --git a/src/OnScreen/ResponsiveGrid.vala b/src/OnScreen/ResponsiveGrid.vala deleted file mode 100644 index 053c957..0000000 --- a/src/OnScreen/ResponsiveGrid.vala +++ /dev/null @@ -1,64 +0,0 @@ -// -// Copyright (C) 2020 Komorebi Team Authors -// Copyright (C) 2016-2017 Abarham Masri -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// -// - -using Clutter; - -namespace Komorebi.OnScreen { - - public class ResponsiveGrid : Actor { - - // Limit of items per column - public int itemsLimit = 8; - - // Layouts (HORIZONTAL/VERTICAL) - internal BoxLayout horizontalLayout = new BoxLayout() {orientation = Clutter.Orientation.HORIZONTAL, spacing = 50}; - internal BoxLayout verticalLayout = new BoxLayout() {orientation = Clutter.Orientation.VERTICAL, spacing = 30}; - - public ResponsiveGrid () { - - layout_manager = horizontalLayout; - y_align = ActorAlign.START; - } - - public void append (Actor item) { - - if(last_child != null) - if(last_child.get_n_children() < itemsLimit) { - last_child.add_child (item); - return; - } - - - // Create a new column and add the new item to it - var columnActor = new Actor() {layout_manager = verticalLayout, y_align = ActorAlign.START, y_expand = true}; - - columnActor.add_child(item); - add_child(columnActor); - } - - public void clearIcons () { - - foreach (var child in get_children()) { - child.destroy_all_children(); - remove_child(child); - } - - } - } -} diff --git a/src/OnScreen/RowLabel.vala b/src/OnScreen/RowLabel.vala deleted file mode 100644 index 262d4a9..0000000 --- a/src/OnScreen/RowLabel.vala +++ /dev/null @@ -1,122 +0,0 @@ -// -// Copyright (C) 2020 Komorebi Team Authors -// Copyright (C) 2012-2017 Abraham Masri -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// -// -// Copied from ManagerForKedos - Abraham Masri -// - -using Gtk; -using Gdk; -using Komorebi.Utilities; - -using GLib.Environment; - -namespace Komorebi.OnScreen { - - public class RowLabel : Gtk.EventBox { - - // Switch between mainBox and 'Copied' label - private Stack stack = new Stack(); - - // Contains both labels - private Box mainBox = new Box(Orientation.HORIZONTAL, 20); - - public Label nameLabel = new Label("Row"); - public Label valueLabel = new Label("Value"); - - private Label copiedLabel = new Label("Copied"); - - string CSS = "*, *:disabled { - transition: 150ms ease-in; - - background-color: @transparent; - background-image: none; - border: none; - border-color: @transparent; - box-shadow: inset 1px 2px rgba(0,0,0,0); - border-radius: 3px; - color: white; - text-shadow:0px 2px 3px rgba(0,0,0,0.9); - -gtk-icon-shadow: 0px 1px 4px rgba(0, 0, 0, 0.4); - - } - - .:hover { - transition: 50ms ease-out; - border-style: outset; - background-color: rgba(0, 0, 0, 0.9); - - }"; - - public RowLabel(string nameString) { - - nameLabel.label = nameString; - copiedLabel.label = nameString + " copied"; - - margin = 10; - add_events (EventMask.ALL_EVENTS_MASK); - applyCSS({this}, CSS); - - - stack.set_transition_type(StackTransitionType.CROSSFADE); - stack.set_transition_duration(300); - - valueLabel.set_line_wrap(true); - valueLabel.set_max_width_chars(19); - valueLabel.set_ellipsize(Pango.EllipsizeMode.MIDDLE); - - nameLabel.set_halign(Align.START); - valueLabel.set_halign(Align.END); - - // Signals - button_press_event.connect(() => { - - // Set the clipboard's value - clipboard.set_text (valueLabel.label, -1); - - stack.set_visible_child(copiedLabel); - - Timeout.add(600, () => { - - stack.set_visible_child(mainBox); - - return false; - }); - - return true; - }); - - - mainBox.pack_start(nameLabel); - mainBox.pack_end(valueLabel); - - stack.add_named(mainBox, "mainBox"); - stack.add_named(copiedLabel, "copiedLabel"); - - stack.set_visible_child(mainBox); - - add(stack); - } - - public void set_value(string valueString) { - - valueLabel.label = valueString; - valueLabel.tooltip_text = valueString; - } - } - -} diff --git a/src/OnScreen/Thumbnail.vala b/src/OnScreen/Thumbnail.vala deleted file mode 100644 index 588eac1..0000000 --- a/src/OnScreen/Thumbnail.vala +++ /dev/null @@ -1,102 +0,0 @@ -// -// Copyright (C) 2020 Komorebi Team Authors -// Copyright (C) 2012-2013 Abraham Masri @cheesecakeufo -// -// This program is free software: you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License version 3, as published -// by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, but -// WITHOUT ANY WARRANTY; without even the implied warranties of -// MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR -// PURPOSE. See the GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License along -// with this program. If not, see - -using Gtk; - -using Komorebi.Utilities; - -namespace Komorebi.OnScreen { - - private class Thumbnail : EventBox { - - string name = ""; - - Overlay overlay = new Overlay(); - Image thumbnailImage = new Image(); - Image borderImage = new Image.from_resource("/org/komorebi-team/komorebi/thumbnail_border.svg"); - Revealer revealer = new Revealer(); - - // Signaled when clicked - public signal void clicked (); - - construct { - - add_events (Gdk.EventMask.BUTTON_RELEASE_MASK); - - revealer.set_transition_duration(200); - revealer.set_transition_type(RevealerTransitionType.CROSSFADE); - - - overlay.add(thumbnailImage); - overlay.add_overlay(revealer); - add(overlay); - } - - public Thumbnail (string path, string name) { - - this.name = name; - - thumbnailImage.pixbuf = new Gdk.Pixbuf.from_file_at_scale(GLib.Path.build_filename(path, name, "wallpaper.jpg"), 150, 100, false); - - // Signals - button_release_event.connect(() => { - - wallpaperName = name; - showBorder(); - clicked(); - - readWallpaperFile(); - updateConfigurationFile(); - - foreach (BackgroundWindow backgroundWindow in backgroundWindows) - backgroundWindow.initializeConfigFile(); - - - foreach(var thumbnail in thumbnailsList) - if(thumbnail.name != name) - thumbnail.hideBorder(); - - return true; - }); - - revealer.set_reveal_child((wallpaperName == name)); - - // Add widgets - revealer.add(borderImage); - } - - - public Thumbnail.Add() { - - thumbnailImage.pixbuf = new Gdk.Pixbuf.from_resource_at_scale("/org/komorebi-team/komorebi/thumbnail_add.svg", 150, 100, false); - - } - - - /* Shows the border */ - public void showBorder () { - - revealer.set_reveal_child(true); - - } - - /* Hides the border */ - public void hideBorder () { - - revealer.set_reveal_child(false); - } - } -} diff --git a/src/OnScreen/WallpapersSelector.vala b/src/OnScreen/WallpapersSelector.vala deleted file mode 100644 index 1743ea0..0000000 --- a/src/OnScreen/WallpapersSelector.vala +++ /dev/null @@ -1,135 +0,0 @@ -// -// Copyright (C) 2020 Komorebi Team Authors -// Copyright (C) 2017-2018 Abraham Masri @cheesecakeufo -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -using Gtk; -using Gdk; - -namespace Komorebi.OnScreen { - - List thumbnailsList; - - public class WallpapersSelector : ScrolledWindow { - - public string path = Config.package_datadir + "/"; // Komorebi can't find wallpapers if this variable doesn't have a trailing slash. Hacky, but it works. Fix later on. - - Gtk.Grid grid = new Grid(); - - int row = 0; - int column = 0; - - // Signaled when a thumbnail is clicked - public signal void wallpaperChanged (); - - public WallpapersSelector () { - - thumbnailsList = new List(); - - set_policy(PolicyType.NEVER, PolicyType.AUTOMATIC); - vexpand = true; - margin = 20; - - grid.halign = Align.CENTER; - grid.row_spacing = 5; - grid.column_spacing = 20; - - getWallpapers(); - - // add the 'create new' thumbnail - // var create_new_thumbnail = new Thumbnail.Add(); - - // // Signals - // create_new_thumbnail.clicked.connect(() => wallpaperChanged()); - - // addThumbnail(create_new_thumbnail); - // thumbnailsList.append(create_new_thumbnail); - - add(grid); - } - - - public void getWallpapers () { - - string package_datadir = Config.package_datadir; - - clearGrid(); - - foreach(var thumbnail in thumbnailsList) - thumbnailsList.remove(thumbnail); - - foreach(var path in Komorebi.Paths.getWallpaperPaths()) { - File wallpapersFolder = File.new_for_path(path); - - try { - - var enumerator = wallpapersFolder.enumerate_children ("standard::*", FileQueryInfoFlags.NOFOLLOW_SYMLINKS); - - FileInfo info; - - while ((info = enumerator.next_file ()) != null) - if (info.get_file_type () == FileType.DIRECTORY) { - - var name = info.get_name(); - var fullPath = GLib.Path.build_filename(path, name); - - // Check if we have a valid wallpaper - if (File.new_build_filename(fullPath, "wallpaper.jpg").query_exists() && - File.new_build_filename(fullPath, "config").query_exists()) { - - var thumbnail = new Thumbnail(path, name); - - // Signals - thumbnail.clicked.connect(() => wallpaperChanged()); - - addThumbnail(thumbnail); - thumbnailsList.append(thumbnail); - } else - print(@"[WARNING]: Found an invalid wallpaper with name: $name \n"); - } - - } catch { - print(@"Could not read directory '$path'"); - } - } - } - - /* Adds a thumbnail to the grid */ - private void addThumbnail (Thumbnail thumbnail) { - - grid.attach (thumbnail, column, row, 1, 1); - - if(column >= 3) { - row++; - column = 0; - } else - column++; - - thumbnail.show_all(); - } - - /* Clears the grid */ - private void clearGrid() { - - foreach (var widget in grid.get_children ()) - grid.remove(widget); - - column = 0; - row = 0; - } - - } -} diff --git a/src/Paths.vala b/src/Paths.vala deleted file mode 100644 index 965dd9b..0000000 --- a/src/Paths.vala +++ /dev/null @@ -1,48 +0,0 @@ -// -// Copyright (C) 2020 Komorebi Team Authors -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -namespace Komorebi.Paths { - - string[] wallpaperPaths; - - /* Returns the path for hosting configuration files and wallpapers */ - public string getConfigDir() { - - string basePath = Environment.get_variable ("XDG_CONFIG_HOME"); - - if(basePath == null) { - basePath = GLib.Path.build_filename(Environment.get_home_dir(), ".config"); - - if(basePath == null) - basePath = Environment.get_home_dir(); - } - - return GLib.Path.build_filename(basePath, "komorebi"); - } - - /* Returns the list of paths to search for wallpapers */ - public string[] getWallpaperPaths() { - if(wallpaperPaths == null) { - wallpaperPaths = { - GLib.Path.build_filename(getConfigDir(), "wallpapers"), - Config.package_datadir - }; - } - - return wallpaperPaths; - } -} diff --git a/src/Utilities.vala b/src/Utilities.vala deleted file mode 100644 index c7dace1..0000000 --- a/src/Utilities.vala +++ /dev/null @@ -1,476 +0,0 @@ -// -// Copyright (C) 2020 Komorebi Team Authors -// Copyright (C) 2012-2017 Abraham Masri -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// -// -// Copied from Acis - Abraham Masri -// - -using Gtk; -using Gdk; -using GLib; -using Cairo; - -using Komorebi.OnScreen; -using Komorebi.Paths; - -namespace Komorebi.Utilities { - - // Komorebi variables - string desktopPath; - string configFilePath; - File configFile; - KeyFile configKeyFile; - - // Screen variables - int screenHeight; - int screenWidth; - - // Icons variables - int iconSize; - - // DateTime variables - bool dateTimeParallax; - bool dateTimeVisible; - - int dateTimeMarginTop; - int dateTimeMarginRight; - int dateTimeMarginLeft; - int dateTimeMarginBottom; - - double dateTimeRotationX; - double dateTimeRotationY; - double dateTimeRotationZ; - - string dateTimePosition; - string dateTimeAlignment; - bool dateTimeAlwaysOnTop; - - string dateTimeColor; - int dateTimeAlpha; - - string dateTimeShadowColor; - int dateTimeShadowAlpha; - - string dateTimeTimeFont; - string dateTimeDateFont; - - // Wallpaper variables - KeyFile wallpaperKeyFile; - string wallpaperPath; - string wallpaperType; - string videoFileName; - string webPageUrl; - - bool wallpaperParallax; - - // Asset variables - bool assetVisible; - - int assetWidth; - int assetHeight; - - string assetAnimationMode; - int assetAnimationSpeed; - - string assetPosition; - - int assetMarginTop; - int assetMarginRight; - int assetMarginLeft; - int assetMarginBottom; - - bool autostart; - - /* Returns an icon detected from file, IconTheme, etc .. */ - public Pixbuf getIconFrom (string icon, int size) { - - Pixbuf IconPixbuf = null; - - if(icon == null || icon == "") - return IconPixbuf; - - /* Try those methods: - * 1- Icon is a file, somewhere in '/'. - * 2- Icon is an icon in a IconTheme. - * 3- Icon isn't in the current IconTheme. - * 4- Icon is not available, use default. - */ - if(File.new_for_path(icon).query_exists()) { - IconPixbuf = new Pixbuf.from_file_at_scale(icon, size, size, false); - return IconPixbuf; - } - - - Gtk.IconTheme _IconTheme = Gtk.IconTheme.get_default (); - _IconTheme.prepend_search_path("/usr/share/pixmaps/"); - - - try { - IconPixbuf = _IconTheme.load_icon (icon, size, IconLookupFlags.FORCE_SIZE); - } catch (Error e) { - if(IconPixbuf == null) - IconPixbuf = _IconTheme.load_icon ("application-default-icon", size, IconLookupFlags.FORCE_SIZE); - } - - - return IconPixbuf; - - } - - /* TAKEN FROM ACIS --- Until Acis is public */ - /* Applies CSS theming for specified GTK+ Widget */ - public void applyCSS (Widget[] widgets, string CSS) { - - var Provider = new Gtk.CssProvider (); - Provider.load_from_data (CSS, -1); - - foreach(var widget in widgets) - widget.get_style_context().add_provider(Provider,-1); - - } - - - /* TAKEN FROM ACIS --- Until Acis is public */ - /* Allow alpha layer in the window */ - public void addAlpha (Widget[] widgets) { - - foreach(var widget in widgets) - widget.set_visual (widget.get_screen ().get_rgba_visual () ?? widget.get_screen ().get_system_visual ()); - - } - - /* Formats the date and time into a human read-able version */ - public string formatDateTime (DateTime dateTime) { - - if (OnScreen.timeTwentyFour) - return dateTime.format("%m/%d/%Y %H:%M"); - - return dateTime.format("%m/%d/%Y %l:%M %p"); - } - - /* Reads the .prop file */ - public void readConfigurationFile () { - - // Default values - wallpaperName = "foggy_sunny_mountain"; - timeTwentyFour = true; - showDesktopIcons = true; - enableVideoWallpapers = true; - mutePlayback = false; - pausePlayback = true; - autostart = false; - - if(configFilePath == null) - configFilePath = GLib.Path.build_filename(getConfigDir(), "komorebi.prop"); - - if(configFile == null) - configFile = File.new_for_path(configFilePath); - - if(configKeyFile == null) - configKeyFile = new KeyFile (); - - if(!configFile.query_exists()) { - bootstrapConfigPath(); - if(!configFile.query_exists()) { - print("No configuration file found. Creating one..\n"); - updateConfigurationFile(); - return; - } - } - - print("Reading config file..\n"); - - configKeyFile.load_from_file(configFilePath, KeyFileFlags.NONE); - - var key_file_group = "KomorebiProperties"; - - // make sure the config file has the required values - if(!configKeyFile.has_group(key_file_group) || - !configKeyFile.has_key(key_file_group, "WallpaperName") || - !configKeyFile.has_key(key_file_group, "TimeTwentyFour") || - !configKeyFile.has_key(key_file_group, "ShowDesktopIcons") || - !configKeyFile.has_key(key_file_group, "EnableVideoWallpapers")) { - - print("[WARNING]: invalid configuration file found. Fixing..\n"); - updateConfigurationFile(); - return; - } - - - wallpaperName = configKeyFile.get_string (key_file_group, "WallpaperName"); - timeTwentyFour = configKeyFile.get_boolean (key_file_group, "TimeTwentyFour"); - showDesktopIcons = configKeyFile.get_boolean (key_file_group, "ShowDesktopIcons"); - enableVideoWallpapers = configKeyFile.get_boolean (key_file_group, "EnableVideoWallpapers"); - if (configKeyFile.has_key(key_file_group, "MutePlayback")) { - mutePlayback = configKeyFile.get_boolean(key_file_group, "MutePlayback"); - } else { - mutePlayback = false; - } - if (configKeyFile.has_key(key_file_group, "PausePlayback")) { - pausePlayback = configKeyFile.get_boolean(key_file_group, "PausePlayback"); - } else { - pausePlayback = true; - } - if (configKeyFile.has_key(key_file_group, "Autostart")) { - autostart = configKeyFile.get_boolean(key_file_group, "Autostart"); - } else { - autostart = false; - } - fixConflicts(); - } - - /* Bootstraps the base configuration path if it doesn't exist, and detects older versions of this app */ - public void bootstrapConfigPath() { - File configPath = File.new_build_filename(getConfigDir(), "wallpapers"); - if(!configPath.query_exists()) - configPath.make_directory_with_parents(); - - // If it can find an older config file, copy it to the new directory - File oldConfigFile = File.new_build_filename(Environment.get_home_dir(), ".Komorebi.prop"); - if(oldConfigFile.query_exists()) { - print("Found config file from old version, converting it to new one...\n"); - File destinationPath = File.new_build_filename(getConfigDir(), "komorebi.prop"); - oldConfigFile.copy(destinationPath, FileCopyFlags.NONE); - } - - configFile = File.new_for_path(configFilePath); - } - - /* Updates the .prop file */ - public void updateConfigurationFile () { - - var key_file_group = "KomorebiProperties"; - - configKeyFile.set_string (key_file_group, "WallpaperName", wallpaperName); - configKeyFile.set_boolean (key_file_group, "TimeTwentyFour", timeTwentyFour); - configKeyFile.set_boolean (key_file_group, "ShowDesktopIcons", showDesktopIcons); - configKeyFile.set_boolean (key_file_group, "EnableVideoWallpapers", enableVideoWallpapers); - configKeyFile.set_boolean(key_file_group, "MutePlayback", mutePlayback); - configKeyFile.set_boolean(key_file_group, "PausePlayback", pausePlayback); - configKeyFile.set_boolean(key_file_group, "Autostart", autostart); - - // Delete the file - if(configFile.query_exists()) - configFile.delete(); - - // save the key file - var stream = new DataOutputStream (configFile.create (0)); - stream.put_string (configKeyFile.to_data ()); - stream.close (); - - } - - /* Fixes conflicts with other environmnets */ - void fixConflicts() { - - // Disable/Enabled nautilus to fix bug when clicking on another monitor - new GLib.Settings("org.gnome.desktop.background").set_boolean("show-desktop-icons", false); - - // Check if we have nemo installed - SettingsSchemaSource settingsSchemaSource = new SettingsSchemaSource.from_directory ("/usr/share/glib-2.0/schemas", null, false); - SettingsSchema settingsSchema = settingsSchemaSource.lookup ("org.nemo.desktop", false); - - if (settingsSchema != null) - // Disable/Enable Nemo's desktop icons - new GLib.Settings("org.nemo.desktop").set_boolean("show-desktop-icons", false); - - - } - - void readWallpaperFile () { - - // check if the wallpaper exists - // also, make sure the wallpaper name is valid - string wallpaperConfigPath = ""; - bool wallpaperFound = false; - - // Populates the wallpaper path list - getWallpaperPaths(); - - for(int i = 0; i < wallpaperPaths.length; i++) { - wallpaperPath = @"$(wallpaperPaths[i])/$wallpaperName"; - wallpaperConfigPath = @"$wallpaperPath/config"; - - if(wallpaperName == null || !File.new_for_path(wallpaperPath).query_exists() || - !File.new_for_path(wallpaperConfigPath).query_exists()) - continue; - - wallpaperFound = true; - break; - } - - if(!wallpaperFound) { - wallpaperName = "foggy_sunny_mountain"; - wallpaperPath = @"$(Config.package_datadir)/$wallpaperName"; - wallpaperConfigPath = @"$wallpaperPath/config"; - - print(@"[ERROR]: got an invalid wallpaper. Setting to default: $wallpaperName\n"); - } - - // init the wallpaperKeyFile (if we haven't already) - if(wallpaperKeyFile == null) - wallpaperKeyFile = new KeyFile (); - - // Read the config file - wallpaperKeyFile.load_from_file(wallpaperConfigPath, KeyFileFlags.NONE); - - // Wallpaper Info - wallpaperType = wallpaperKeyFile.get_string("Info", "WallpaperType"); - - // DateTime - dateTimeVisible = wallpaperKeyFile.get_boolean ("DateTime", "Visible"); - dateTimeParallax = wallpaperKeyFile.get_boolean ("DateTime", "Parallax"); - - dateTimeMarginLeft = wallpaperKeyFile.get_integer ("DateTime", "MarginLeft"); - dateTimeMarginTop = wallpaperKeyFile.get_integer ("DateTime", "MarginTop"); - dateTimeMarginBottom = wallpaperKeyFile.get_integer ("DateTime", "MarginBottom"); - dateTimeMarginRight = wallpaperKeyFile.get_integer ("DateTime", "MarginRight"); - - dateTimeRotationX = wallpaperKeyFile.get_double ("DateTime", "RotationX"); - dateTimeRotationY = wallpaperKeyFile.get_double ("DateTime", "RotationY"); - dateTimeRotationZ = wallpaperKeyFile.get_double ("DateTime", "RotationZ"); - - dateTimePosition = wallpaperKeyFile.get_string ("DateTime", "Position"); - dateTimeAlignment = wallpaperKeyFile.get_string ("DateTime", "Alignment"); - dateTimeAlwaysOnTop = wallpaperKeyFile.get_boolean ("DateTime", "AlwaysOnTop"); - - dateTimeColor = wallpaperKeyFile.get_string ("DateTime", "Color"); - dateTimeAlpha = wallpaperKeyFile.get_integer ("DateTime", "Alpha"); - - dateTimeShadowColor = wallpaperKeyFile.get_string ("DateTime", "ShadowColor"); - dateTimeShadowAlpha = wallpaperKeyFile.get_integer ("DateTime", "ShadowAlpha"); - - dateTimeTimeFont = wallpaperKeyFile.get_string ("DateTime", "TimeFont"); - dateTimeDateFont = wallpaperKeyFile.get_string ("DateTime", "DateFont"); - - - if(wallpaperType == "video") { - videoFileName = wallpaperKeyFile.get_string("Info", "VideoFileName"); - wallpaperParallax = assetVisible = false; - return; - } - - if(wallpaperType == "web_page") { - webPageUrl = wallpaperKeyFile.get_string("Info", "WebPageUrl"); - wallpaperParallax = assetVisible = false; - - return; - } - - // Wallpaper base image - wallpaperParallax = wallpaperKeyFile.get_boolean("Wallpaper", "Parallax"); - - // Asset - assetVisible = wallpaperKeyFile.get_boolean ("Asset", "Visible"); - - assetAnimationMode = wallpaperKeyFile.get_string ("Asset", "AnimationMode"); - assetAnimationSpeed = wallpaperKeyFile.get_integer ("Asset", "AnimationSpeed"); - - assetWidth = wallpaperKeyFile.get_integer ("Asset", "Width"); - assetHeight = wallpaperKeyFile.get_integer ("Asset", "Height"); - } - - - /* Creates a new folder in desktop */ - public void createNewFolder(string name, int number = 0) { - - File newFolder; - - if(number > 0) - newFolder = File.new_for_path(desktopPath + @"/$name ($(number.to_string()))"); - else - newFolder = File.new_for_path(desktopPath + @"/$name"); - - if(newFolder.query_exists()) - createNewFolder(name, number + 1); - else - newFolder.make_directory_async(); - - } - - /* Beautifies the name of the wallpaper */ - public string beautifyWallpaperName (string wallpaperName) { - - var resultString = ""; - - foreach(var word in wallpaperName.split("_")) { - resultString += (word.@get(0).to_string().up() + word.substring(1).down() + " "); - } - - return resultString; - - } - - /* A dirty way to check if gstreamer is installed */ - public bool canPlayVideos() { - - if( File.new_for_path("/usr/lib/gstreamer-1.0/libgstlibav.so").query_exists() || - File.new_for_path("/usr/lib64/gstreamer-1.0/libgstlibav.so").query_exists() || - File.new_for_path("/usr/lib/i386-linux-gnu/gstreamer-1.0/libgstlibav.so").query_exists() || - File.new_for_path("/usr/lib/x86_64-linux-gnu/gstreamer-1.0/libgstlibav.so").query_exists() || - File.new_for_path("/usr/lib/arm-linux-gnueabihf/gstreamer-1.0/libgstlibav.so").query_exists()) - return true; - - return false; - } - - public void enableAutostart() { - var desktopFileName = "org.komorebiteam.komorebi.desktop"; - File desktopFile = File.new_build_filename(Config.datadir, "applications", desktopFileName); - if(!desktopFile.query_exists()) { - print("[WARNING] Desktop file not found, autostart won't work!"); - return; - } - - string[] destPaths = {Environment.get_variable("XDG_CONFIG_HOME"), GLib.Path.build_filename(Environment.get_home_dir(), ".config")}; - - foreach(string path in destPaths) { - if(path == null || !File.new_for_path(path).query_exists()) - continue; - - File destFile = File.new_build_filename(path, "autostart", desktopFileName); - desktopFile.copy(destFile, FileCopyFlags.NONE); - return; - } - - print("[WARNING] Couldn't find any user directory config, autostart won't work!"); - } - - public void disableAutostart() { - var desktopFileName = "org.komorebiteam.komorebi.desktop"; - string[] destPaths = {Environment.get_variable("XDG_CONFIG_HOME"), GLib.Path.build_filename(Environment.get_home_dir(), ".config")}; - - foreach(string path in destPaths) { - if(path == null || !File.new_for_path(path).query_exists()) - continue; - - File desktopFile = File.new_build_filename(path, "autostart", desktopFileName); - desktopFile.delete(); - return; - } - } - - /* A quick way to find a given arg from the args list */ - public bool hasArg(string arg, string[] args) { - foreach(string s in args) { - if(s == arg) - return true; - } - - return false; - } -} diff --git a/src/meson.build b/src/meson.build deleted file mode 100644 index 42e8f89..0000000 --- a/src/meson.build +++ /dev/null @@ -1,18 +0,0 @@ -main_sources += files( - 'Main.vala', - 'OnScreen/BackgroundWindow.vala', - 'OnScreen/DateTimeBox.vala', - 'OnScreen/DesktopIcons.vala', - 'OnScreen/ResponsiveGrid.vala', - 'OnScreen/Icon.vala', - 'OnScreen/InfoWindow.vala', - 'OnScreen/RowLabel.vala', - 'OnScreen/WallpapersSelector.vala', - 'OnScreen/Thumbnail.vala', - 'OnScreen/BubbleMenu.vala', - 'OnScreen/BubbleMenuItem.vala', - 'OnScreen/AssetActor.vala', - 'OnScreen/PreferencesWindow.vala', - 'Paths.vala', - 'Utilities.vala' -) diff --git a/wallpaper-creator/Main.vala b/wallpaper-creator/Main.vala deleted file mode 100644 index b0ebb0f..0000000 --- a/wallpaper-creator/Main.vala +++ /dev/null @@ -1,83 +0,0 @@ -// -// Copyright (C) 2020 Komorebi Team Authors -// Copyright (C) 2017-2018 Abraham Masri -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -using WallpaperCreator.OnScreen; - -namespace WallpaperCreator { - - string filePath; - string assetPath; - string thumbnailPath; - string webPageUrl; - - string wallpaperName; - string wallpaperType; // image/video/web_page - bool wallpaperParallax; - - // Properties - bool showDateTime; - bool dateTimeParallax; - - int marginTop; - int marginRight; - int marginLeft; - int marginBottom; - - string position; - string alignment; - bool dateTimeAlwaysOnTop; - - string dateTimeColor; - int dateTimeAlpha; - - string shadowColor; - int shadowAlpha; - - string timeFont; - string dateFont; - - bool showAsset = false; - string animationMode; - int animationSpeed; - - public static void main (string [] args) { - - - string package_name = Config.package_name; - string package_version = Config.package_version; - - print(@"Welcome to $package_name Wallpaper Creator\n"); - - if(args[1] == "--version" || args[1] == "version") { - print(@"Version: $package_version\nMaintained by: Komorebi Team\n\n"); - return; - } - Gtk.init (ref args); - - Gtk.Settings.get_default().gtk_application_prefer_dark_theme = true; - - new NewWallpaperWindow(); - - var mainSettings = Gtk.Settings.get_default (); - mainSettings.set("gtk-xft-antialias", 1, null); - mainSettings.set("gtk-xft-rgba" , "none", null); - mainSettings.set("gtk-xft-hintstyle" , "slight", null); - - Gtk.main(); - } -} diff --git a/wallpaper-creator/OnScreen/FinalPage.vala b/wallpaper-creator/OnScreen/FinalPage.vala deleted file mode 100644 index ca3959b..0000000 --- a/wallpaper-creator/OnScreen/FinalPage.vala +++ /dev/null @@ -1,168 +0,0 @@ -// -// Copyright (C) 2020 Komorebi Team Authors -// Copyright (C) 2016-2017 Abraham Masri -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -using Gtk; -using Komorebi; - -namespace WallpaperCreator.OnScreen { - - public class FinalPage : Box { - - Image logo = new Image.from_resource("/org/komorebi-team/komorebi/done.svg"); - - Label titleLabel = new Label(""); - Label descLabel = new Label(""); - - Button closeButton = new Button.with_label("Close"); - - public FinalPage() { - - spacing = 10; - hexpand = true; - vexpand = true; - orientation = Orientation.VERTICAL; - halign = Align.CENTER; - valign = Align.CENTER; - - logo.margin_bottom = 30; - - descLabel.justify = Justification.CENTER; - descLabel.halign = Align.CENTER; - descLabel.hexpand = false; - descLabel.selectable = true; - - wallpaperName = wallpaperName.replace(" ", "_").replace(".", "_").down(); - - titleLabel.set_markup("Done"); - - var wallpaperPath = GLib.Path.build_filename(Paths.getConfigDir(), "wallpapers", wallpaperName); - - descLabel.set_markup(@"Your wallpaper was copied to:\n$wallpaperPath\nYou can now change the wallpaper in 'Change Wallpaper'."); - - closeButton.margin_top = 20; - closeButton.halign = Align.CENTER; - - // Signals - closeButton.released.connect(() => { - - print("My job is done. Good bye!\n"); - Gtk.main_quit(); - }); - - - add(logo); - add(titleLabel); - add(descLabel); - add(closeButton); - - createWallpaper(); - } - - /* Creates a wallpaper */ - private void createWallpaper() { - - // Create a new directory - var dirPath = GLib.Path.build_filename(Paths.getConfigDir(), "wallpapers", wallpaperName); - File.new_for_path(dirPath).make_directory_with_parents(); - var configPath = GLib.Path.build_filename(dirPath, "config"); - var configFile = File.new_for_path(configPath); - - var configKeyFile = new KeyFile(); - - configKeyFile.set_string("Info", "WallpaperType", wallpaperType); - - if(wallpaperType == "video") { - - var videoFileNameArray = filePath.split("/"); - var videoFileName = videoFileNameArray[videoFileNameArray.length - 1]; - configKeyFile.set_string("Info", "VideoFileName", videoFileName); - - // Copy the video into our new dir - File.new_for_path(filePath).copy(File.new_build_filename(dirPath, videoFileName), FileCopyFlags.NONE); - - - } else if (wallpaperType == "web_page") - configKeyFile.set_string("Info", "WebPageUrl", webPageUrl); - - - if(wallpaperType == "video" || wallpaperType == "web_page") { - - // Move the thumbnail - File.new_for_path(thumbnailPath).copy(File.new_build_filename(dirPath, "wallpaper.jpg"), FileCopyFlags.NONE); - - } else { - - // Copy the wallpaper into our new dir - File.new_for_path(filePath).copy(File.new_build_filename(dirPath, "wallpaper.jpg"), FileCopyFlags.NONE); - } - - configKeyFile.set_boolean("DateTime", "Visible", showDateTime); - configKeyFile.set_boolean("DateTime", "Parallax", dateTimeParallax); - - configKeyFile.set_integer("DateTime", "MarginTop", marginTop); - configKeyFile.set_integer("DateTime", "MarginRight", marginRight); - configKeyFile.set_integer("DateTime", "MarginLeft", marginLeft); - configKeyFile.set_integer("DateTime", "MarginBottom", marginBottom); - - // TODO: Add support for rotations - configKeyFile.set_integer("DateTime", "RotationX", 0); - configKeyFile.set_integer("DateTime", "RotationY", 0); - configKeyFile.set_integer("DateTime", "RotationZ", 0); - - configKeyFile.set_string("DateTime", "Position", position); - configKeyFile.set_string("DateTime", "Alignment", alignment); - configKeyFile.set_boolean("DateTime", "AlwaysOnTop", dateTimeAlwaysOnTop); - - configKeyFile.set_string("DateTime", "Color", dateTimeColor); - configKeyFile.set_integer("DateTime", "Alpha", dateTimeAlpha); - - configKeyFile.set_string("DateTime", "ShadowColor", shadowColor); - configKeyFile.set_integer("DateTime", "ShadowAlpha", shadowAlpha); - - configKeyFile.set_string("DateTime", "TimeFont", timeFont); - configKeyFile.set_string("DateTime", "DateFont", dateFont); - - - if(wallpaperType == "image") { - - configKeyFile.set_boolean("Wallpaper", "Parallax", wallpaperParallax); - - if(assetPath == null || assetPath == "") - showAsset = false; - - configKeyFile.set_boolean("Asset", "Visible", showAsset); - configKeyFile.set_string("Asset", "AnimationMode", animationMode); - configKeyFile.set_integer("Asset", "AnimationSpeed", animationSpeed); - - configKeyFile.set_integer("Asset", "Width", 0); - configKeyFile.set_integer("Asset", "Height", 0); - - if(assetPath != null) { - // Move the asset into our new dir - File.new_for_path(assetPath).copy(File.new_build_filename(dirPath, "assets.png"), FileCopyFlags.NONE); - } - } - - // save the key file - var stream = new DataOutputStream (configFile.create (0)); - stream.put_string (configKeyFile.to_data ()); - stream.close (); - - } - } -} diff --git a/wallpaper-creator/OnScreen/InitialPage.vala b/wallpaper-creator/OnScreen/InitialPage.vala deleted file mode 100644 index 742a84d..0000000 --- a/wallpaper-creator/OnScreen/InitialPage.vala +++ /dev/null @@ -1,189 +0,0 @@ -// -// Copyright (C) 2020 Komorebi Team Authors -// Copyright (C) 2016-2017 Abraham Masri -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -using Gtk; - -namespace WallpaperCreator.OnScreen { - - public class InitialPage : Box { - - Grid aboutGrid = new Grid(); - - Box titleBox = new Box(Orientation.VERTICAL, 5); - Label titleLabel = new Label(""); - Label aboutLabel = new Label(""); - - - Label nameLabel = new Label("Give your wallpaper a name:"); - Entry nameEntry = new Entry() { placeholder_text = "Mountain Summit" }; - - FileFilter imageFilter = new FileFilter (); - FileFilter videoFilter = new FileFilter (); - - Label typeLabel = new Label("My wallpaper is"); - ComboBoxText typeComboBox = new ComboBoxText(); - - Label chooseFileLabel = new Label("Where is the image located?"); - Box locationBox = new Box(Orientation.HORIZONTAL, 10); - Entry locationEntry = new Entry() { placeholder_text = "~/Pictures/my_picture.jpg" }; - FileChooserButton chooseFileButton = new FileChooserButton("Choose File", Gtk.FileChooserAction.OPEN); - - Revealer revealer = new Revealer(); - - Box thumbnailBox = new Box(Orientation.VERTICAL, 5); - Label chooseThumbnailLabel = new Label("Where is the thumbnail located?"); - FileChooserButton chooseThumbnailButton = new FileChooserButton("Choose Thumbnail", Gtk.FileChooserAction.OPEN); - - public InitialPage() { - - spacing = 10; - hexpand = true; - vexpand = true; - orientation = Orientation.VERTICAL; - halign = Align.CENTER; - valign = Align.CENTER; - - aboutGrid.halign = Align.CENTER; - aboutGrid.margin_bottom = 30; - aboutGrid.column_spacing = 0; - aboutGrid.row_spacing = 0; - - titleBox.margin_top = 15; - titleBox.margin_start = 10; - titleLabel.halign = Align.START; - - titleLabel.set_markup("Komorebi Wallpaper Creator"); - aboutLabel.set_markup("by Komorebi Team"); - - aboutLabel.halign = Align.START; - - typeComboBox.append("image", "An image"); - typeComboBox.append("video", "A video"); - typeComboBox.append("web_page", "A web page"); - typeComboBox.active = 0; - - wallpaperType = "image"; - - imageFilter.add_mime_type ("image/*"); - videoFilter.add_mime_type ("video/*"); - - chooseFileButton.set_filter (imageFilter); - chooseFileButton.width_chars = 10; - - chooseThumbnailButton.set_filter (imageFilter); - chooseThumbnailButton.width_chars = 10; - - locationEntry.set_sensitive(false); - - // Signals - nameEntry.changed.connect(() => { - - if(nameEntry.text.length <= 0) - wallpaperName = null; - else - wallpaperName = nameEntry.text; - }); - - typeComboBox.changed.connect(() => { - wallpaperType = typeComboBox.get_active_id(); - - if(wallpaperType == "image") { - - chooseFileButton.set_filter (imageFilter); - chooseFileLabel.label = "Where is the image located?"; - locationEntry.placeholder_text = "~/Pictures/my_picture.jpg"; - locationEntry.set_sensitive(false); - - revealer.set_reveal_child(false); - - chooseFileButton.show(); - - } else if(wallpaperType == "web_page") { - - chooseFileButton.set_filter (imageFilter); - chooseFileLabel.label = "What is the URL?"; - locationEntry.placeholder_text = "https://sample.com/random/{{screen_width}}x{{screen_height}}"; - locationEntry.set_sensitive(true); - - revealer.set_reveal_child(true); - - chooseFileButton.hide(); - - } else { - - chooseFileButton.set_filter (videoFilter); - chooseFileLabel.label = "Where is the video located?"; - locationEntry.placeholder_text = "~/my_video.mp4"; - locationEntry.set_sensitive(false); - - revealer.set_reveal_child(true); - - chooseFileButton.show(); - } - - }); - - chooseFileButton.file_set.connect (() => { - - filePath = chooseFileButton.get_file().get_path(); - - }); - - - chooseThumbnailButton.file_set.connect (() => { - - thumbnailPath = chooseThumbnailButton.get_file().get_path(); - }); - - locationEntry.changed.connect(() => { - - if(locationEntry.text.length <= 0 || !(locationEntry.text.contains("://") - && (locationEntry.text.has_prefix("http") || locationEntry.text.has_prefix("file")))) - webPageUrl = null; - else - webPageUrl = locationEntry.text; - }); - - titleBox.add(titleLabel); - titleBox.add(aboutLabel); - - aboutGrid.attach(new Image.from_resource("/org/komorebi-team/komorebi/wallpaper_creator.svg"), 0, 0, 1, 1); - aboutGrid.attach(titleBox, 1, 0, 1, 1); - - thumbnailBox.add(chooseThumbnailLabel); - thumbnailBox.add(chooseThumbnailButton); - - revealer.add(thumbnailBox); - - locationBox.pack_start(locationEntry); - locationBox.add(chooseFileButton); - - add(aboutGrid); - add(nameLabel); - add(nameEntry); - - add(typeLabel); - add(typeComboBox); - - add(chooseFileLabel); - add(locationBox); - - add(revealer); - } - } -} diff --git a/wallpaper-creator/OnScreen/NewWallpaperWindow.vala b/wallpaper-creator/OnScreen/NewWallpaperWindow.vala deleted file mode 100644 index aa79a07..0000000 --- a/wallpaper-creator/OnScreen/NewWallpaperWindow.vala +++ /dev/null @@ -1,248 +0,0 @@ -// -// Copyright (C) 2020 Komorebi Team Authors -// Copyright (C) 2017-2018 Abraham Masri @cheesecakeufo -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - - -using Gtk; -using Gdk; - - -namespace WallpaperCreator.OnScreen { - - public class NewWallpaperWindow : Gtk.Window { - - // Custom headerbar - HeaderBar headerBar = new HeaderBar(); - - Button closeButton = new Button.with_label("Close"); - Button addLayerButton = new Button.with_label("Add Layer") { visible = false }; - - Button nextButton = new Button.with_label("Next"); - - // Confirmation popover - Popover popover = new Popover(null); - Grid popoverGrid = new Grid(); - Label confirmationLabel = new Label("Are you sure?"); - Button cancelButton = new Button.with_label("Cancel"); - Button yesButton = new Button.with_label("Yes"); - - Gtk.Box mainBox = new Box(Orientation.VERTICAL, 0); - - // Used as a display for errors - Gtk.Revealer revealer = new Revealer(); - Gtk.InfoBar infoBar = new Gtk.InfoBar () { message_type = MessageType.ERROR }; - Gtk.Label errorLabel = new Label(""); - - Stack stack = new Stack(); - - OptionsPage optionsPage; - - /* Add some style */ - string CSS = " - *{ - background-color: rgba(0, 0, 0, 0.6); - box-shadow: none; - color: white; - border-width: 0px; - } - "; - - string headerCSS = " - *{ - background-color: rgba(0, 0, 0, 0); - box-shadow: none; - color: white; - border-width: 0px; - } - "; - - - public NewWallpaperWindow () { - - title = "New Komorebi Wallpaper"; - set_size_request(1050, 700); - resizable = false; - window_position = WindowPosition.CENTER; - set_titlebar(headerBar); - applyCSS({mainBox}, CSS); - applyCSS({headerBar}, headerCSS); - addAlpha({this}); - - // Properties - closeButton.margin_top = 6; - closeButton.margin_start = 6; - closeButton.halign = Align.START; - - addLayerButton.margin_top = 6; - addLayerButton.margin_start = 6; - addLayerButton.halign = Align.START; - - nextButton.margin_top = 6; - nextButton.margin_end = 6; - - popover.set_relative_to(closeButton); - - popoverGrid.margin = 15; - popoverGrid.row_spacing = 20; - popoverGrid.column_spacing = 5; - - revealer.set_transition_duration(200); - revealer.set_transition_type(RevealerTransitionType.SLIDE_DOWN); - - stack.set_transition_duration(400); - stack.set_transition_type(StackTransitionType.SLIDE_LEFT); - - // Signals - closeButton.released.connect(() => { - popover.show_all(); - }); - - addLayerButton.released.connect(() => { - - Gtk.FileChooserDialog fileChooseDialog = new Gtk.FileChooserDialog ( - "Select an image", this, Gtk.FileChooserAction.OPEN, - "Cancel", Gtk.ResponseType.CANCEL, - "Open", Gtk.ResponseType.ACCEPT - ); - - FileFilter filter = new FileFilter(); - filter.add_mime_type ("image/*"); - - fileChooseDialog.set_filter (filter); - - if (fileChooseDialog.run () == Gtk.ResponseType.ACCEPT) { - assetPath = fileChooseDialog.get_file().get_path(); - optionsPage.setAsset(assetPath); - } - - fileChooseDialog.close (); - }); - - nextButton.released.connect(() => { - - var currentPage = stack.get_visible_child_name(); - - if(currentPage == "initial") { - - if(wallpaperName == null || (wallpaperType == "image" || wallpaperType == "video") && filePath == null) { - - displayError("Please enter a wallpaper name and choose a file"); - return; - - } else if (wallpaperName == null || wallpaperType == "web_page" && webPageUrl == null) { - - displayError("Please enter a wallpaper name, a valid URL, and a thumbnail"); - return; - } - - - optionsPage = new OptionsPage(); - - if(wallpaperType == "image") { - - addLayerButton.visible = true; - optionsPage.setImage(filePath); - - } else { - addLayerButton.visible = false; - optionsPage.setBlank(); - } - - stack.add_named(optionsPage, "options"); - - optionsPage.show_all(); - - stack.set_visible_child_name("options"); - revealer.set_reveal_child(false); - } else { - - optionsPage.updateUI(); - stack.add_named(new FinalPage(), "final"); - - show_all(); - - stack.set_visible_child_name("final"); - closeButton.visible = false; - nextButton.visible = false; - addLayerButton.visible = false; - - } - - }); - - cancelButton.released.connect(() => popover.hide()); - yesButton.released.connect(() => Gtk.main_quit()); - - // Add Widgets - headerBar.add(closeButton); - headerBar.add(addLayerButton); - headerBar.pack_end(nextButton); - - popoverGrid.attach(confirmationLabel, 0, 0); - popoverGrid.attach(cancelButton, 0, 1); - popoverGrid.attach(yesButton, 1, 1); - - popover.add(popoverGrid); - - infoBar.get_content_area().add(errorLabel); - revealer.add(infoBar); - - stack.add_named(new InitialPage(), "initial"); - - mainBox.add(revealer); - mainBox.add(stack); - - add(mainBox); - show_all(); - - // Post-Show options - addLayerButton.visible = false; - - } - - private void displayError(string errorMessage) { - - errorLabel.label = errorMessage; - revealer.set_reveal_child(true); - } - - } - - - /* TAKEN FROM ACIS --- Until Acis is public */ - /* Applies CSS theming for specified GTK+ Widget */ - public void applyCSS (Widget[] widgets, string CSS) { - - var Provider = new Gtk.CssProvider (); - Provider.load_from_data (CSS, -1); - - foreach(var widget in widgets) - widget.get_style_context().add_provider(Provider,-1); - - } - - - /* TAKEN FROM ACIS --- Until Acis is public */ - /* Allow alpha layer in the window */ - public void addAlpha (Widget[] widgets) { - - foreach(var widget in widgets) - widget.set_visual (widget.get_screen ().get_rgba_visual () ?? widget.get_screen ().get_system_visual ()); - - } - -} diff --git a/wallpaper-creator/OnScreen/OptionsPage.vala b/wallpaper-creator/OnScreen/OptionsPage.vala deleted file mode 100644 index d77651b..0000000 --- a/wallpaper-creator/OnScreen/OptionsPage.vala +++ /dev/null @@ -1,429 +0,0 @@ -// -// Copyright (C) 2020 Komorebi Team Authors -// Copyright (C) 2017-2018 Abraham Masri @cheesecakeufo -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . -// - -using Gtk; -using Gdk; - -namespace WallpaperCreator.OnScreen { - - public class OptionsPage : Box { - - // Contains the wallpaper image with buttons - Gtk.Box wallpaperBox = new Box(Orientation.VERTICAL, 10); - Overlay overlay = new Overlay(); - Image wallpaperImage = new Image(); - Box dateTimeBox = new Box(Orientation.VERTICAL, 5); - Label timeLabel = new Label(""); - Label dateLabel = new Label(""); - Image assetImage = new Image(); - - // List of long options - ScrolledWindow scrolledWindow = new ScrolledWindow(null, null); - Box optionsBox = new Box(Orientation.VERTICAL, 10); - - Label wallpaperTitleLabel = new Label(""); - - ComboBoxText wallpaperParallaxComboBox = new ComboBoxText(); - - Label dateTimeTitleLabel = new Label("") {margin_top = 15}; - - ComboBoxText dateTimeVisibleComboBox = new ComboBoxText(); - - ComboBoxText dateTimeParallaxComboBox = new ComboBoxText(); - - Label dateTimeMarginsLabel = new Label("Margins:"); - Grid dateTimeMarginsGrid = new Grid(); - SpinButton dateTimeMarginLeftEntry = new SpinButton.with_range(0,2000, 5); - SpinButton dateTimeMarginRightEntry = new SpinButton.with_range(0,2000, 5); - SpinButton dateTimeMarginTopEntry = new SpinButton.with_range(0,2000, 5); - SpinButton dateTimeMarginBottomEntry = new SpinButton.with_range(0,2000, 5); - - Label dateTimePositionLabel = new Label("Position:"); - ComboBoxText dateTimePositionComboBox = new ComboBoxText(); - - Label dateTimeAlignmentLabel = new Label("Alignment:"); - ComboBoxText dateTimeAlignmentComboBox = new ComboBoxText(); - - ComboBoxText dateTimeAlwaysOnTopComboBox = new ComboBoxText(); - - Label dateTimeColorLabel = new Label("Color and Alpha:"); - Box dateTimeColorBox = new Box(Orientation.HORIZONTAL, 10); - ColorButton dateTimeColorButton = new ColorButton.with_rgba({222, 222, 222, 255}); - SpinButton dateTimeAlphaEntry = new SpinButton.with_range(0, 255, 1) { value = 255 }; - - Label dateTimeShadowColorLabel = new Label("Shadow Color and Alpha:"); - Box dateTimeShadowColorBox = new Box(Orientation.HORIZONTAL, 10); - ColorButton dateTimeShadowColorButton = new ColorButton.with_rgba({222, 222, 222, 255}); - SpinButton dateTimeShadowAlphaEntry = new SpinButton.with_range(0, 255, 1) { value = 255 }; - - Label timeFontLabel = new Label("Time Font:"); - FontButton timeFontButton = new FontButton.with_font("Lato Light 30") { use_font = true }; - - Label dateFontLabel = new Label("Date Font:"); - FontButton dateFontButton = new FontButton.with_font("Lato Light 20") { use_font = true }; - - // Asset (Layer) - Label assetTitleLabel = new Label("") {margin_top = 15}; - - ComboBoxText assetVisibleComboBox = new ComboBoxText(); - - Label assetAnimationLabel = new Label("Animation Mode & Speed:"); - Box assetAnimationBox = new Box(Orientation.HORIZONTAL, 10); - ComboBoxText assetModeComboBox = new ComboBoxText(); - SpinButton assetSpeedEntry = new SpinButton.with_range(100, 1000, 1); - - public OptionsPage() { - - spacing = 10; - orientation = Orientation.HORIZONTAL; - halign = Align.CENTER; - valign = Align.CENTER; - hexpand = true; - vexpand = true; - - wallpaperBox.margin = 20; - wallpaperBox.margin_end = 0; - wallpaperBox.valign = Align.CENTER; - wallpaperBox.halign = Align.START; - - dateTimeBox.hexpand = true; - dateTimeBox.vexpand = true; - dateTimeBox.halign = Align.CENTER; - dateTimeBox.valign = Align.CENTER; - - scrolledWindow.hscrollbar_policy = PolicyType.NEVER; - - optionsBox.margin = 20; - optionsBox.margin_start = 0; - optionsBox.halign = Align.START; - optionsBox.hexpand = true; - - wallpaperTitleLabel.set_markup("Wallpaper Options:"); - - wallpaperParallaxComboBox.append("enable", "Enable parallax"); - wallpaperParallaxComboBox.append("disable", "Disable parallax"); - wallpaperParallaxComboBox.active = 1; - - dateTimeTitleLabel.set_markup("Date & Time Options:"); - - dateTimeVisibleComboBox.append("show", "Show date & time"); - dateTimeVisibleComboBox.append("hide", "Hide date & time"); - dateTimeVisibleComboBox.active = 0; - - dateTimeParallaxComboBox.append("enable", "Enable parallax"); - dateTimeParallaxComboBox.append("disable", "Disable parallax"); - dateTimeParallaxComboBox.active = 1; - - dateTimePositionComboBox.append_text("Top Left"); - dateTimePositionComboBox.append_text("Top Center"); - dateTimePositionComboBox.append_text("Top Right"); - dateTimePositionComboBox.append_text("Center Left"); - dateTimePositionComboBox.append_text("Center"); - dateTimePositionComboBox.append_text("Center Right"); - dateTimePositionComboBox.append_text("Bottom Left"); - dateTimePositionComboBox.append_text("Bottom Center"); - dateTimePositionComboBox.append_text("Bottom Right"); - dateTimePositionComboBox.active = 4; - - dateTimeAlignmentComboBox.append_text("Start"); - dateTimeAlignmentComboBox.append_text("Center"); - dateTimeAlignmentComboBox.append_text("End"); - dateTimeAlignmentComboBox.active = 1; - - dateTimeAlwaysOnTopComboBox.append("enable", "Always show on top"); - dateTimeAlwaysOnTopComboBox.append("disable", "Show under layer"); - dateTimeAlwaysOnTopComboBox.active = 0; - - assetTitleLabel.set_markup("Layer Options:"); - - assetVisibleComboBox.append("show", "Show layer"); - assetVisibleComboBox.append("hide", "Hide layer"); - assetVisibleComboBox.active = 0; - - - assetModeComboBox.append("noanimation", "No Animation"); - assetModeComboBox.append("light", "Glowing Light"); - assetModeComboBox.append("clouds", "Moving Clouds"); - assetModeComboBox.active = 0; - - // Signals - wallpaperParallaxComboBox.changed.connect(() => updateUI()); - dateTimeVisibleComboBox.changed.connect(() => updateUI()); - dateTimeParallaxComboBox.changed.connect(() => updateUI()); - dateTimeMarginTopEntry.changed.connect(() => updateUI()); - dateTimeMarginRightEntry.changed.connect(() => updateUI()); - dateTimeMarginLeftEntry.changed.connect(() => updateUI()); - dateTimeMarginBottomEntry.changed.connect(() => updateUI()); - dateTimePositionComboBox.changed.connect(() => updateUI()); - dateTimeAlignmentComboBox.changed.connect(() => updateUI()); - dateTimeColorButton.color_set.connect(() => updateUI()); - dateTimeAlphaEntry.changed.connect(() => updateUI()); - timeFontButton.font_set.connect(() => updateUI()); - dateFontButton.font_set.connect(() => updateUI()); - - // Add widgets - dateTimeBox.add(timeLabel); - dateTimeBox.add(dateLabel); - - overlay.add(wallpaperImage); - overlay.add_overlay(dateTimeBox); - overlay.add_overlay(assetImage); - - wallpaperBox.add(overlay); - - dateTimeMarginsGrid.attach(dateTimeMarginTopEntry, 0, 0); - dateTimeMarginsGrid.attach(dateTimeMarginRightEntry, 0, 1); - dateTimeMarginsGrid.attach(dateTimeMarginLeftEntry, 1, 0); - dateTimeMarginsGrid.attach(dateTimeMarginBottomEntry, 1, 1); - - if(wallpaperType == "image") { - optionsBox.add(wallpaperTitleLabel); - optionsBox.add(wallpaperParallaxComboBox); - } - - optionsBox.add(dateTimeTitleLabel); - - optionsBox.add(dateTimeVisibleComboBox); - optionsBox.add(dateTimeParallaxComboBox); - - optionsBox.add(dateTimePositionLabel); - optionsBox.add(dateTimePositionComboBox); - - optionsBox.add(dateTimeMarginsLabel); - optionsBox.add(dateTimeMarginsGrid); - - optionsBox.add(dateTimeAlignmentLabel); - optionsBox.add(dateTimeAlignmentComboBox); - - optionsBox.add(dateTimeAlwaysOnTopComboBox); - - // Date time - optionsBox.add(dateTimeColorLabel); - - dateTimeColorBox.add(dateTimeColorButton); - dateTimeColorBox.add(dateTimeAlphaEntry); - - optionsBox.add(dateTimeColorBox); - - // Date time shadow - optionsBox.add(dateTimeShadowColorLabel); - - dateTimeShadowColorBox.add(dateTimeShadowColorButton); - dateTimeShadowColorBox.add(dateTimeShadowAlphaEntry); - - optionsBox.add(dateTimeShadowColorBox); - - // Time Font - optionsBox.add(timeFontLabel); - optionsBox.add(timeFontButton); - - // Date Font - optionsBox.add(dateFontLabel); - optionsBox.add(dateFontButton); - - - - if(wallpaperType == "image") { - - optionsBox.add(assetTitleLabel); - optionsBox.add(assetVisibleComboBox); - optionsBox.add(assetAnimationLabel); - assetAnimationBox.add(assetModeComboBox); - assetAnimationBox.add(assetSpeedEntry); - optionsBox.add(assetAnimationBox); - } - - scrolledWindow.add(optionsBox); - - pack_start(wallpaperBox); - pack_start(scrolledWindow); - - // Post-show options - setDateTimeLabel(); - - foreach(var child in optionsBox.get_children()) - child.halign = Align.START; - } - - public void updateUI () { - - - wallpaperParallax = wallpaperParallaxComboBox.get_active_id() == "enable"; - - showDateTime = dateTimeVisibleComboBox.get_active_id() == "show"; - dateTimeParallax = dateTimeParallaxComboBox.get_active_id() == "enable"; - - marginTop = dateTimeMarginTopEntry.text.to_int(); - marginRight = dateTimeMarginRightEntry.text.to_int(); - marginLeft = dateTimeMarginLeftEntry.text.to_int(); - marginBottom = dateTimeMarginBottomEntry.text.to_int(); - - dateTimeBox.opacity = showDateTime ? 255 : 0; - dateTimeBox.visible = false; - - // Margins - dateTimeBox.margin_top = marginTop; - dateTimeBox.margin_end = marginRight; - dateTimeBox.margin_start = marginLeft; - dateTimeBox.margin_bottom = marginBottom; - - setPosition(); - setAlignment(); - - dateTimeAlwaysOnTop = dateTimeAlwaysOnTopComboBox.get_active_id() == "enable"; - - setColor(); - setFonts(); - setOpacity(); - - showAsset = assetVisibleComboBox.get_active_id() == "show"; - assetImage.opacity = showAsset ? 255 : 0; - - setAnimationMode(); - animationSpeed = assetSpeedEntry.text.to_int(); - - setDateTimeLabel(dateTimeColor, timeFont, dateFont); - show_all(); - } - - public void setPosition() { - - var active = dateTimePositionComboBox.get_active_text(); - - position = active.replace(" ", "_").down(); - - switch (active) { - - case "Top Left": - dateTimeBox.halign = Align.START; - dateTimeBox.valign = Align.START; - break; - case "Top Center": - dateTimeBox.halign = Align.CENTER; - dateTimeBox.valign = Align.START; - break; - case "Top Right": - dateTimeBox.halign = Align.END; - dateTimeBox.valign = Align.START; - break; - case "Center Right": - dateTimeBox.halign = Align.END; - dateTimeBox.valign = Align.CENTER; - break; - - case "Center": - dateTimeBox.halign = Align.CENTER; - dateTimeBox.valign = Align.CENTER; - break; - - case "Center Left": - dateTimeBox.halign = Align.START; - dateTimeBox.valign = Align.CENTER; - break; - - case "Bottom Right": - dateTimeBox.halign = Align.END; - dateTimeBox.valign = Align.END; - break; - - case "Bottom Center": - dateTimeBox.halign = Align.CENTER; - dateTimeBox.valign = Align.END; - break; - - case "Bottom Left": - dateTimeBox.halign = Align.START; - dateTimeBox.valign = Align.END; - break; - - default: - break; - } - } - - - public void setAlignment() { - - alignment = dateTimeAlignmentComboBox.get_active_text().down(); - - if(alignment == "start") - timeLabel.halign = Align.START; - else if(alignment == "center") - timeLabel.halign = Align.CENTER; - else - timeLabel.halign = Align.END; - } - - private void setColor() { - - RGBA rgba = dateTimeColorButton.rgba; - dateTimeColor = rgbaToHex(rgba); - - rgba = dateTimeShadowColorButton.rgba; - shadowColor = rgbaToHex(rgba); - } - - private void setFonts() { - - timeFont = timeFontButton.get_font_name (); - dateFont = dateFontButton.get_font_name (); - } - - private void setOpacity() { - - var alpha = dateTimeAlphaEntry.text.to_double(); - timeLabel.opacity = dateLabel.opacity = alpha / 255; - dateTimeAlpha = (int) alpha; - - alpha = dateTimeShadowAlphaEntry.text.to_int(); - shadowAlpha = (int)alpha; - } - - public void setImage(string path) { - - wallpaperImage.pixbuf = new Pixbuf.from_file_at_scale(path, 600, 400, true); - } - - public void setBlank() { - - wallpaperImage.pixbuf = new Pixbuf.from_resource_at_scale("/org/komorebi-team/komorebi/blank.svg", 600, 400, true); - } - - public void setAsset(string path) { - - assetImage.pixbuf = new Pixbuf.from_file_at_scale(path, 600, 400, true); - } - - public void setAnimationMode() { - - animationMode = assetModeComboBox.get_active_id(); - - } - - private void setDateTimeLabel(string color = "white", string timeFont = "Lato Light 30", - string dateFont = "Lato Light 20") { - - timeLabel.set_markup(@"10:21 PM"); - dateLabel.set_markup(@"Sunday, August 22"); - } - - private string rgbaToHex(RGBA rgba) { - return "#%02x%02x%02x".printf((int)(rgba.red*255), (int)(rgba.green*255), (int)(rgba.blue*255)); - } - } -} diff --git a/wallpaper-creator/meson.build b/wallpaper-creator/meson.build deleted file mode 100644 index 872973f..0000000 --- a/wallpaper-creator/meson.build +++ /dev/null @@ -1,7 +0,0 @@ -wallpaper_sources += files( - 'Main.vala', - 'OnScreen/NewWallpaperWindow.vala', - 'OnScreen/InitialPage.vala', - 'OnScreen/OptionsPage.vala', - 'OnScreen/FinalPage.vala', -)