diff --git a/catapult/plugin.py b/catapult/plugin.py
index 5d10425..539056f 100644
--- a/catapult/plugin.py
+++ b/catapult/plugin.py
@@ -16,6 +16,7 @@
# along with this program. If not, see .
import catapult
+import contextlib
from catapult.i18n import _
from threading import Thread
@@ -70,6 +71,12 @@ def read_configuration(cls):
def search(self, query):
raise NotImplementedError
+ @contextlib.contextmanager
+ def spinner(self):
+ window = catapult.app.get_active_window()
+ with window.spinner():
+ yield
+
def update(self):
pass
diff --git a/catapult/window.py b/catapult/window.py
index 6541879..08368cc 100644
--- a/catapult/window.py
+++ b/catapult/window.py
@@ -17,8 +17,10 @@
# along with this program. If not, see .
import catapult
+import contextlib
import itertools
import logging
+import time
from catapult import util
from gi.repository import Gdk
@@ -28,6 +30,20 @@
from gi.repository import Gtk
from gi.repository import Pango
+ICON_NAMES_LOADING = [
+ "content-loading-symbolic",
+ "image-loading-symbolic",
+ "content-loading",
+ "image-loading",
+]
+
+ICON_NAMES_SEARCH = [
+ "system-search-symbolic",
+ "edit-find-symbolic",
+ "system-search",
+ "edit-find",
+]
+
ICON_SIZE = Gtk.IconSize.LARGE
ICON_SIZE_PX = 48
@@ -78,6 +94,7 @@ def __init__(self):
self._icon_theme = Gtk.IconTheme.get_for_display(Gdk.Display.get_default())
self._icon_theme_handler_id = None
self._input_entry = Gtk.Entry()
+ self._input_icon = Gtk.Image()
self._plugins = []
self._position = (0, 0)
self._prev_query = ""
@@ -126,22 +143,16 @@ def _init_signal_handlers(self):
def _init_widgets(self):
screen_width, screen_height = catapult.util.get_screen_size()
- input_icon = Gtk.Image()
- input_icon.set_pixel_size(ICON_SIZE_PX/2)
- input_icon.set_from_icon_name(util.lookup_icon(
- "system-search-symbolic",
- "edit-find-symbolic",
- "system-search",
- "edit-find",
- ) or "")
- input_icon.set_icon_size(Gtk.IconSize.LARGE)
- input_icon.add_css_class("catapult-input-icon")
+ self._input_icon.set_pixel_size(ICON_SIZE_PX/2)
+ self._input_icon.set_from_icon_name(util.lookup_icon(*ICON_NAMES_SEARCH) or "")
+ self._input_icon.set_icon_size(Gtk.IconSize.LARGE)
+ self._input_icon.add_css_class("catapult-input-icon")
self._input_entry.add_css_class("catapult-input-entry")
self._input_entry.set_hexpand(True)
input_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
input_box.add_css_class("catapult-input-box")
input_box.set_hexpand(True)
- input_box.append(input_icon)
+ input_box.append(self._input_icon)
input_box.append(self._input_entry)
self._body = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=0)
self._body.add_css_class("catapult-body")
@@ -410,6 +421,32 @@ def show(self):
self._input_entry.grab_focus()
super().show()
+ def spin_start(self):
+ # XXX: Main context iteration doesn't seem to be enough,
+ # we need to sleep a brief moment for the icon to actually change.
+ icon_name = util.lookup_icon(*ICON_NAMES_LOADING) or ""
+ self._input_icon.set_from_icon_name(icon_name)
+ time.sleep(1/10)
+ main_context = GLib.MainContext.default()
+ while main_context.pending():
+ main_context.iteration()
+
+ def spin_stop(self):
+ # XXX: Main context iteration doesn't seem to be enough,
+ # we need to sleep a brief moment for the icon to actually change.
+ icon_name = util.lookup_icon(*ICON_NAMES_SEARCH) or ""
+ self._input_icon.set_from_icon_name(icon_name)
+ time.sleep(1/10)
+ main_context = GLib.MainContext.default()
+ while main_context.pending():
+ main_context.iteration()
+
+ @contextlib.contextmanager
+ def spinner(self):
+ self.spin_start()
+ yield
+ self.spin_stop()
+
def toggle(self, *args, **kwargs):
self.hide() if self.is_visible() else self.show()