[magneto] add Gtk3 frontend
This commit is contained in:
@@ -0,0 +1,164 @@
|
||||
"""
|
||||
|
||||
@author: Fabio Erculiani <lxnay@sabayon.org>
|
||||
@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()
|
||||
@@ -0,0 +1,208 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
|
||||
@author: Fabio Erculiani <lxnay@sabayon.org>
|
||||
@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 <b>sys-apps/entropy</b> %s, %s <b>%s</b>. %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
|
||||
@@ -0,0 +1,162 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk+" version="2.24"/>
|
||||
<!-- interface-naming-policy toplevel-contextual -->
|
||||
<object class="GtkDialog" id="notice_window_2">
|
||||
<property name="can_focus">False</property>
|
||||
<property name="title" translatable="yes">Magneto Application Updates Notifier</property>
|
||||
<property name="window_position">center</property>
|
||||
<property name="default_width">600</property>
|
||||
<property name="default_height">300</property>
|
||||
<property name="type_hint">dialog</property>
|
||||
<signal name="close" handler="on_close" swapped="no"/>
|
||||
<child internal-child="vbox">
|
||||
<object class="GtkVBox" id="dialog-vbox3">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">8</property>
|
||||
<child internal-child="action_area">
|
||||
<object class="GtkHButtonBox" id="dialog-action_area3">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="layout_style">end</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="button9">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="can_default">True</property>
|
||||
<property name="has_default">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<signal name="clicked" handler="on_launch_pm_clicked" swapped="no"/>
|
||||
<child>
|
||||
<object class="GtkAlignment" id="alignment1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="xscale">0</property>
|
||||
<property name="yscale">0</property>
|
||||
<child>
|
||||
<object class="GtkHBox" id="hbox4">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="spacing">2</property>
|
||||
<child>
|
||||
<object class="GtkImage" id="image1">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="stock">gtk-apply</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkLabel" id="label8">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">_Load Package Manager</property>
|
||||
<property name="use_underline">True</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="button10">
|
||||
<property name="label">gtk-close</property>
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="receives_default">False</property>
|
||||
<property name="use_action_appearance">False</property>
|
||||
<property name="use_stock">True</property>
|
||||
<signal name="clicked" handler="on_close_clicked" swapped="no"/>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">False</property>
|
||||
<property name="position">1</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">False</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="pack_type">end</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
<child>
|
||||
<placeholder/>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkNotebook" id="notice_notebook">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">True</property>
|
||||
<property name="scrollable">True</property>
|
||||
<child>
|
||||
<object class="GtkVBox" id="vbox2">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow" id="checklist_window">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="hscrollbar_policy">automatic</property>
|
||||
<property name="shadow_type">in</property>
|
||||
<child>
|
||||
<object class="GtkTreeView" id="update_clist">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="reorderable">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">0</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child type="tab">
|
||||
<object class="GtkLabel" id="label7">
|
||||
<property name="visible">True</property>
|
||||
<property name="can_focus">False</property>
|
||||
<property name="label" translatable="yes">Available Updates</property>
|
||||
<property name="justify">center</property>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="tab_fill">False</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
<packing>
|
||||
<property name="expand">True</property>
|
||||
<property name="fill">True</property>
|
||||
<property name="position">2</property>
|
||||
</packing>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<action-widgets>
|
||||
<action-widget response="0">button9</action-widget>
|
||||
<action-widget response="0">button10</action-widget>
|
||||
</action-widgets>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user