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',
-)