From d2be035aba150d9c3e73fd1b6df830c3478aa054 Mon Sep 17 00:00:00 2001 From: Fabio Erculiani Date: Fri, 13 Apr 2012 00:24:00 +0200 Subject: [PATCH] [magneto] add Gtk3 frontend --- magneto/src/magneto/gtk3/__init__.py | 0 magneto/src/magneto/gtk3/components.py | 164 +++++++++++++++++++ magneto/src/magneto/gtk3/interfaces.py | 208 +++++++++++++++++++++++++ magneto/src/magneto/gtk3/magneto.glade | 162 +++++++++++++++++++ magneto/src/magneto_app.py | 16 +- 5 files changed, 546 insertions(+), 4 deletions(-) create mode 100644 magneto/src/magneto/gtk3/__init__.py create mode 100644 magneto/src/magneto/gtk3/components.py create mode 100644 magneto/src/magneto/gtk3/interfaces.py create mode 100644 magneto/src/magneto/gtk3/magneto.glade diff --git a/magneto/src/magneto/gtk3/__init__.py b/magneto/src/magneto/gtk3/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/magneto/src/magneto/gtk3/components.py b/magneto/src/magneto/gtk3/components.py new file mode 100644 index 000000000..92493800a --- /dev/null +++ b/magneto/src/magneto/gtk3/components.py @@ -0,0 +1,164 @@ +""" + + @author: Fabio Erculiani + @contact: lxnay@sabayon.org + @copyright: Fabio Erculiani + @license: GPL-2 + + B{Entropy Updates Notification Applet (Magneto) GTK3 components} + +""" + +# System imports +import os + +from gi.repository import GObject, Gtk, GdkPixbuf + +from entropy.i18n import _ + +# Magneto imports +from magneto.core.config import PIXMAPS_PATH, ICON_PATH + +class AppletIconPixbuf: + + def __init__(self): + self.images = {} + + def add_file(self, name, filename): + + if name not in self.images: + self.images[name] = [] + + filename = os.path.join(PIXMAPS_PATH, filename) + if not os.access(filename, os.R_OK): + raise AttributeError("Cannot open image file %s" % filename) + + pixbuf = GdkPixbuf.Pixbuf.new_from_file(filename) + + self.add(name, pixbuf) + + def add(self, name, pixbuf): + self.images[name].append(pixbuf) + + def best_match(self, name, size): + best = None + + for image in self.images[name]: + if not best: + best = image + continue + if abs(size - image.height) < abs(size - best.height): + best = image + + return best + + +class GladeWindow: + + def __init__(self, filename, window_name): + + path = filename + if not os.path.isfile(filename): + path = "/usr/lib/entropy/magneto/magneto/gtk3/%s" % (filename,) + if not os.path.isfile(path): + path = "magneto/gtk3/%s" % (filename,) + + self.filename = path + self.xml = Gtk.Builder() + self.xml.set_translation_domain("entropy") + self.xml.add_from_file(path) + self.window = self.get_widget(window_name) + + def get_widget(self, widget): + return self.xml.get_object(widget) + + +class AppletNoticeWindow(GladeWindow): + + def __init__(self, controller): + GladeWindow.__init__(self, "magneto.glade", "notice_window_2") + + self.__controller = controller + self.window.connect('delete-event', self.on_close) + + self.package_list = self.get_widget('update_clist') + self.package_list.append_column( + Gtk.TreeViewColumn( + _("Application"), Gtk.CellRendererText(), text=0)) + self.package_list.append_column( + Gtk.TreeViewColumn( + _("Latest version"), Gtk.CellRendererText(), text=1)) + self.package_list.get_selection().set_mode(Gtk.SelectionMode.NONE) + + self.notebook = self.get_widget('notice_notebook') + self.critical_tab = None + self.critical_tab_contents = None + + self.package_list_model = Gtk.ListStore(GObject.TYPE_STRING, + GObject.TYPE_STRING) + self.package_list.set_model(self.package_list_model) + + self.xml.connect_signals ( + { + "on_launch_pm_clicked": self.on_pm, + "on_close_clicked": self.on_close, + "on_close": self.on_close, + }) + + message_label = Gtk.Label() + message_label.set_line_wrap(True) + self.message_label = message_label + + + def hide(self): + self.window.hide() + + def show(self): + self.window.show() + + def on_pm(self, button): + self.__controller.launch_package_manager() + + def on_close(self, *args): + self.__controller.trigger_notice_window() + return True + + def __set_critical(self, text): + + if not self.critical_tab_contents: + + vb = Gtk.VBox() + vb.add(self.message_label) + tab_label = Gtk.Label(_("Critical Information")) + + tab_label.show() + self.message_label.show() + vb.show() + + self.critical_tab = self.notebook.prepend_page(vb, tab_label) + self.critical_tab_contents = vb + + self.notebook.set_current_page( + self.notebook.page_num(self.critical_tab_contents)) + + self.message_label.set_markup(text) + + else: + + self.message_label.set_markup(text) + + def __remove_critical(self): + if not self.critical_tab_contents: + return + self.notebook.remove_page( + self.notebook.page_num(self.critical_tab_contents)) + + def populate(self, pkg_data, critical_txt): + self.package_list_model.clear() + for name, avail in pkg_data: + self.package_list_model.append((name, avail,)) + + if critical_txt: + self.__set_critical(critical_txt) + else: + self.__remove_critical() diff --git a/magneto/src/magneto/gtk3/interfaces.py b/magneto/src/magneto/gtk3/interfaces.py new file mode 100644 index 000000000..dca79f310 --- /dev/null +++ b/magneto/src/magneto/gtk3/interfaces.py @@ -0,0 +1,208 @@ +# -*- coding: utf-8 -*- +""" + + @author: Fabio Erculiani + @contact: lxnay@sabayon.org + @copyright: Fabio Erculiani + @license: GPL-2 + + B{Entropy Updates Notification Applet (Magneto) GTK3 application} + +""" + +# sys imports +import os +import sys +import time +import subprocess + +# applet imports +from magneto.core import config +from magneto.core.interfaces import MagnetoCore +from magneto.gtk3.components import AppletNoticeWindow, AppletIconPixbuf + +# Entropy imports +from entropy.i18n import _ +import entropy.dep + +from gi.repository import Gtk, GObject, GLib, Gdk, Notify + +class Magneto(MagnetoCore): + + def __init__(self): + + from dbus.mainloop.glib import DBusGMainLoop + MagnetoCore.__init__(self, icon_loader_class = AppletIconPixbuf, + main_loop_class = DBusGMainLoop) + + self.__setup_gtk_app() + + def __setup_gtk_app(self): + + self.menu = Gtk.Menu() + self.menu_items = {} + for i in self._menu_item_list: + if i is None: + self.menu.add(Gtk.SeparatorMenuItem()) + else: + sid = None + myid = i[0] + if myid == "exit": + sid = "gtk-quit" + if sid: + w = Gtk.ImageMenuItem(stock_id = sid) + else: + w = Gtk.ImageMenuItem(i[1]) + w.set_use_underline(True) + pix = self.get_menu_image(myid) + img = Gtk.Image() + img.set_from_pixbuf(pix) + w.set_image(img) + self.menu_items[myid] = w + w.connect('activate', i[3]) + w.show() + self.menu.add(w) + + self.menu.show_all() + + self.status_icon = Gtk.StatusIcon.new_from_pixbuf( + self.icons.best_match("okay", 22)) + self.status_icon.connect("popup-menu", self.applet_context_menu) + self.status_icon.connect("activate", self.applet_doubleclick) + + def __do_first_check(self): + + def _do_check(): + self.send_check_updates_signal(startup_check = True) + return False + + if self._dbus_service_available: + # after 10 seconds + GObject.timeout_add(10000, _do_check) + + def startup(self): + + self._dbus_service_available = self.setup_dbus() + if config.settings['APPLET_ENABLED'] and \ + self._dbus_service_available: + self.enable_applet(do_check = False) + else: + self.disable_applet() + if not self._dbus_service_available: + GObject.timeout_add(30000, self.show_service_not_available) + else: + GObject.timeout_add(30000, self.show_service_available) + self.__do_first_check() + + # Notice Window instance + self._notice_window = AppletNoticeWindow(self) + + # enter main loop + GLib.threads_init() + Gdk.threads_enter() + Gtk.main() + Gdk.threads_leave() + + def close_service(self): + MagnetoCore.close_service(self) + GObject.timeout_add(0, Gtk.main_quit) + + def change_icon(self, image): + to_image = self.icons.best_match(image, self.applet_size) + self.status_icon.set_from_pixbuf(to_image) + + def disable_applet(self, *args): + MagnetoCore.disable_applet(self) + self.menu_items['disable_applet'].hide() + self.menu_items['enable_applet'].show() + + def enable_applet(self, w = None, do_check = True): + done = MagnetoCore.enable_applet(self, do_check = do_check) + if done: + self.menu_items['disable_applet'].show() + self.menu_items['enable_applet'].hide() + + def applet_doubleclick(self, widget): + return MagnetoCore.applet_doubleclick(self) + + def show_alert(self, title, text, urgency = None, force = False): + + def do_show(): + if ((title, text) == self.last_alert) and not force: + return False + Notify.init(_("System Updates")) + n = Notify.Notification.new( + title, text, "dialog-information") + if urgency == 'critical': + n.set_urgency(Notify.Urgency.CRITICAL) + elif urgency == 'low': + n.set_urgency(Notify.Urgency.LOW) + self.last_alert = (title, text) + try: + # this has been dropped from libnotify 0.7 + n.attach_to_status_icon(self.status_icon) + except AttributeError: + pass + n.show() + return False + + GObject.timeout_add(0, do_show) + + def update_tooltip(self, tip): + self.tooltip_text = tip + self.status_icon.set_tooltip_markup(tip) + + def applet_context_menu(self, icon, button, activate_time): + if button == 3: + self.menu.popup(None, None, None, None, 0, activate_time) + return + + def hide_notice_window(self): + self.notice_window_shown = False + self._notice_window.hide() + + def show_notice_window(self): + + if self.notice_window_shown: + return + if not self.package_updates: + return + + entropy_ver = None + packages = [] + for atom in self.package_updates: + + key = entropy.dep.dep_getkey(atom) + avail_rev = entropy.dep.dep_get_entropy_revision(atom) + avail_tag = entropy.dep.dep_gettag(atom) + my_pkg = entropy.dep.remove_entropy_revision(atom) + my_pkg = entropy.dep.remove_tag(my_pkg) + pkgcat, pkgname, pkgver, pkgrev = entropy.dep.catpkgsplit( + my_pkg) + ver = pkgver + if pkgrev != "r0": + ver += "-%s" % (pkgrev,) + if avail_tag: + ver += "#%s" % (avail_tag,) + if avail_rev: + ver += "~%s" % (avail_tag,) + + if key == "sys-apps/entropy": + entropy_ver = ver + + packages.append((key, ver,)) + + critical_txt = '' + if entropy_ver is not None: + critical_txt = "%s sys-apps/entropy %s, %s %s. %s." % ( + _("Your system currently has an outdated version of"), + _("installed"), + _("the latest available version is"), + entropy_ver, + _("It is recommended that you upgrade to" + " the latest before updating any other packages") + ) + + self._notice_window.populate(packages, critical_txt) + self._notice_window.show() + self.notice_window_shown = True diff --git a/magneto/src/magneto/gtk3/magneto.glade b/magneto/src/magneto/gtk3/magneto.glade new file mode 100644 index 000000000..5ed280b9b --- /dev/null +++ b/magneto/src/magneto/gtk3/magneto.glade @@ -0,0 +1,162 @@ + + + + + + False + Magneto Application Updates Notifier + center + 600 + 300 + dialog + + + + True + False + 8 + + + True + False + end + + + True + True + True + True + False + False + + + + True + False + 0 + 0 + + + True + False + 2 + + + True + False + gtk-apply + + + False + False + 0 + + + + + True + False + _Load Package Manager + True + + + False + False + 1 + + + + + + + + + False + False + 0 + + + + + gtk-close + True + True + False + False + True + + + + False + False + 1 + + + + + False + True + end + 0 + + + + + + + + True + True + True + + + True + False + + + True + False + automatic + in + + + True + False + True + + + + + True + True + 0 + + + + + + + True + False + Available Updates + center + + + False + + + + + True + True + 2 + + + + + + button9 + button10 + + + diff --git a/magneto/src/magneto_app.py b/magneto/src/magneto_app.py index 44ab46220..62e94a15b 100755 --- a/magneto/src/magneto_app.py +++ b/magneto/src/magneto_app.py @@ -47,17 +47,25 @@ def _startup(): from magneto.kde.interfaces import Magneto elif "--gtk" in sys.argv: from magneto.gtk.interfaces import Magneto + elif "--gtk3" in sys.argv: + from magneto.gtk3.interfaces import Magneto else: if kde_env is not None: # this is KDE! try: from magneto.kde.interfaces import Magneto except (ImportError, RuntimeError,): - # try GTK - from magneto.gtk.interfaces import Magneto + # try GTK3, then GTK + try: + from magneto.gtk3.interfaces import Magneto + except ImportError: + from magneto.gtk.interfaces import Magneto else: - # load GTK - from magneto.gtk.interfaces import Magneto + # load GTK3, fallback to GTK2 + try: + from magneto.gtk3.interfaces import Magneto + except ImportError: + from magneto.gtk.interfaces import Magneto import entropy.tools magneto = Magneto()