858 lines
30 KiB
Plaintext
858 lines
30 KiB
Plaintext
|
#!/usr/bin/env python3
|
||
|
#
|
||
|
# by Kendall Weaver <kendall@peppermintos.com>
|
||
|
# for Peppermint OS
|
||
|
# modified by Mark Greaves (PCNetSpec) <mark@peppermintos.com>
|
||
|
# with much appreciated code contributions by rhein
|
||
|
# internationalization (i18n)/gettext support by Kiyohito AOKI
|
||
|
#
|
||
|
# Ice is a simple Site Specific Browser (SSB) manager for Chromium and
|
||
|
# Chrome specifically intended to integrate with the LXDE menu system.
|
||
|
# Unlike the built-in functions in the browsers, Ice boasts the ability
|
||
|
# to remove SSBs, validate addresses, and prevent overwriting existing
|
||
|
# SSBs. Special thanks to Matt Phillips <labratmatt@gmail.com> for the
|
||
|
# excellent pyfav library that is integrated into this application.
|
||
|
# ADDENDUM: Added support for Firefox (via "ice-firefox") and Vivaldi.
|
||
|
|
||
|
import os
|
||
|
import sys
|
||
|
import requests
|
||
|
import urllib.request
|
||
|
import urllib.parse
|
||
|
import urllib.error
|
||
|
import os.path
|
||
|
import string
|
||
|
import gi ## added by MG ##
|
||
|
gi.require_version('Gtk','3.0') ## added by MG ##
|
||
|
from gi.repository import Gtk
|
||
|
from gi.repository.GdkPixbuf import Pixbuf
|
||
|
from urllib.parse import urlparse, urlunparse
|
||
|
from bs4 import BeautifulSoup
|
||
|
|
||
|
import gettext
|
||
|
import locale
|
||
|
|
||
|
_HOME = os.getenv("HOME")
|
||
|
_ICE_DIR = "{0}/.local/share/ice".format(_HOME)
|
||
|
_APPS_DIR = "{0}/.local/share/applications".format(_HOME)
|
||
|
_PROFILES_DIR = "{0}/profiles".format(_ICE_DIR)
|
||
|
_FF_PROFILES_DIR = "{0}/firefox".format(_ICE_DIR)
|
||
|
_ICE_ICON = "/usr/share/pixmaps/ice.png"
|
||
|
_CHROME_BIN = "/usr/bin/google-chrome"
|
||
|
_CHROMIUM_BIN = "/usr/bin/chromium-browser"
|
||
|
_VIVALDI_BIN = "/usr/bin/vivaldi"
|
||
|
_FIREFOX_BIN = "/usr/bin/firefox"
|
||
|
|
||
|
gettext.bindtextdomain('messages', os.path.dirname(__file__)+ '/../share/ice/locale/')
|
||
|
gettext.textdomain('messages')
|
||
|
_ = gettext.gettext
|
||
|
|
||
|
|
||
|
|
||
|
# Requisite dirs
|
||
|
for directory in [ _ICE_DIR, _APPS_DIR, _PROFILES_DIR, _FF_PROFILES_DIR ]:
|
||
|
if not os.path.exists(directory):
|
||
|
os.system("mkdir -p {0}".format(directory))
|
||
|
|
||
|
headers = {
|
||
|
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:64.0) Gecko/20100101 Firefox/64.0',
|
||
|
#'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.152 Safari/537.36'
|
||
|
}
|
||
|
|
||
|
|
||
|
def get_details(app):
|
||
|
a = open(app, 'r', errors='ignore')
|
||
|
nameline = ""
|
||
|
iconline = ""
|
||
|
profile = ""
|
||
|
is_ice = False
|
||
|
is_firefox = False
|
||
|
is_isolated = False
|
||
|
|
||
|
for line in a:
|
||
|
if "Name=" in line:
|
||
|
array = line.replace("=", " ").split()
|
||
|
array.pop(0)
|
||
|
for word in array:
|
||
|
nameline = nameline + word + " "
|
||
|
elif "Icon=" in line:
|
||
|
array = line.replace("=", " ").split()
|
||
|
array.pop(0)
|
||
|
for word in array:
|
||
|
iconline = iconline + word
|
||
|
try:
|
||
|
pixbuf = Pixbuf.new_from_file_at_size(iconline, 16, 16)
|
||
|
except:
|
||
|
pixbuf = Pixbuf.new_from_file_at_size(_ICE_ICON, 16, 16)
|
||
|
elif "StartupWMClass=Chromium" in line:
|
||
|
# for legacy apps
|
||
|
is_ice = True
|
||
|
elif "StartupWMClass=ICE-SSB" in line:
|
||
|
is_ice = True
|
||
|
elif "IceFirefox=" in line:
|
||
|
is_firefox = True
|
||
|
profile = str.replace(line, 'IceFirefox=', '').strip()
|
||
|
elif "X-ICE-SSB-Profile=" in line:
|
||
|
is_isolated = True
|
||
|
profile = str.replace(line, 'X-ICE-SSB-Profile=', '').strip()
|
||
|
|
||
|
if nameline != "" and iconline != "" and is_ice is True:
|
||
|
details = {
|
||
|
'nameline' : nameline,
|
||
|
'profile' : profile,
|
||
|
'is_firefox' : is_firefox,
|
||
|
'is_isolated' : is_isolated,
|
||
|
'pixbuf': pixbuf
|
||
|
}
|
||
|
return details
|
||
|
|
||
|
return None
|
||
|
|
||
|
|
||
|
def normalize(url):
|
||
|
(scheme, netloc, path, _, _, frag) = urlparse(url, "http")
|
||
|
if not netloc and path:
|
||
|
return urlunparse((scheme, path, "", "", "", ""))
|
||
|
|
||
|
return urlunparse((scheme, netloc, path, "", "", ""))
|
||
|
|
||
|
|
||
|
def errortest(url):
|
||
|
try:
|
||
|
urllib.request.urlopen(url)
|
||
|
return True
|
||
|
except (urllib.request.HTTPError, urllib.request.URLError):
|
||
|
return False
|
||
|
|
||
|
|
||
|
def download_favicon(url, file_prefix='', target_dir='/tmp'):
|
||
|
parsed_site_uri = urlparse(url)
|
||
|
|
||
|
if not parsed_site_uri.scheme:
|
||
|
url = 'http://{0}'.format(url)
|
||
|
parsed_site_uri = urlparse(url)
|
||
|
|
||
|
if not parsed_site_uri.scheme or not parsed_site_uri.netloc:
|
||
|
raise Exception(_("Unable to parse URL, {0}").format(url))
|
||
|
|
||
|
favicon_url = get_favicon_url(url)
|
||
|
|
||
|
if not favicon_url:
|
||
|
raise Exception(_("Unable to find favicon for, {0}").format(url))
|
||
|
response = requests.get(favicon_url, headers=headers)
|
||
|
if response.status_code == requests.codes.ok:
|
||
|
parsed_uri = urlparse(favicon_url)
|
||
|
favicon_filepath = parsed_uri.path
|
||
|
favicon_path, favicon_filename = os.path.split(favicon_filepath)
|
||
|
|
||
|
valid_chars = "-_.() %s%s" % (string.ascii_letters, string.digits)
|
||
|
|
||
|
sanitized_filename = "".join([x if valid_chars else "" for x in favicon_filename])
|
||
|
|
||
|
sanitized_filename = os.path.join(target_dir, file_prefix + sanitized_filename)
|
||
|
|
||
|
with open(sanitized_filename, 'wb') as f:
|
||
|
for chunk in response.iter_content(chunk_size=1024):
|
||
|
if chunk: # filter out keep-alive new chunks
|
||
|
f.write(chunk)
|
||
|
f.flush()
|
||
|
|
||
|
return sanitized_filename
|
||
|
|
||
|
|
||
|
def parse_markup_for_favicon(markup, parsed_site_uri):
|
||
|
|
||
|
soup = BeautifulSoup(markup, "lxml")
|
||
|
|
||
|
icon_link = soup.find('link', rel='icon')
|
||
|
|
||
|
if icon_link and icon_link.has_attr('href'):
|
||
|
|
||
|
favicon_url = icon_link['href']
|
||
|
|
||
|
if favicon_url.startswith('//'):
|
||
|
parsed_uri = urlparse(url)
|
||
|
favicon_url = "{0}:{1}".format(parsed_uri.scheme, favicon_url)
|
||
|
|
||
|
elif favicon_url.startswith('/'):
|
||
|
favicon_url = "{0}://{1}{2}".format(parsed_site_uri.scheme, parsed_site_uri.netloc, favicon_url)
|
||
|
|
||
|
elif not favicon_url.startswith('http'):
|
||
|
path, filename = os.path.split(parsed_site_uri.path)
|
||
|
favicon_url = "{0}://{1}/{2}".format(parsed_site_uri.scheme, parsed_site_uri.netloc,
|
||
|
os.path.join(path, favicon_url))
|
||
|
|
||
|
return favicon_url
|
||
|
|
||
|
return None
|
||
|
|
||
|
|
||
|
def get_favicon_url(url):
|
||
|
parsed_site_uri = urlparse(url)
|
||
|
|
||
|
try:
|
||
|
response = requests.get(url, headers=headers)
|
||
|
except:
|
||
|
raise Exception(_("Unable to find URL. Is it valid? {0}").format(url))
|
||
|
|
||
|
if response.status_code == requests.codes.ok:
|
||
|
favicon_url = parse_markup_for_favicon(response.content, parsed_site_uri)
|
||
|
|
||
|
if favicon_url:
|
||
|
return favicon_url
|
||
|
|
||
|
favicon_url = '{uri.scheme}://{uri.netloc}/favicon.ico'.format(uri=parsed_site_uri)
|
||
|
|
||
|
response = requests.get(favicon_url, headers=headers)
|
||
|
if response.status_code == requests.codes.ok:
|
||
|
return favicon_url
|
||
|
|
||
|
return None
|
||
|
|
||
|
|
||
|
def applicate():
|
||
|
title = name.get_text()
|
||
|
address = normalize(url.get_text())
|
||
|
|
||
|
semiformatted = ""
|
||
|
array = filter(str.isalpha, title)
|
||
|
for obj in array:
|
||
|
semiformatted = semiformatted + obj
|
||
|
formatted = semiformatted.lower()
|
||
|
|
||
|
loc = where.get_active_text()
|
||
|
if loc == _("Accessories"):
|
||
|
location = "Utility;"
|
||
|
elif loc == _("Games"):
|
||
|
location = "Game;"
|
||
|
elif loc == _("Graphics"):
|
||
|
location = "Graphics;"
|
||
|
elif loc == _("Internet"):
|
||
|
location = "Network;"
|
||
|
elif loc == _("Office"):
|
||
|
location = "Office;"
|
||
|
elif loc == _("Programming"):
|
||
|
location = "Development;"
|
||
|
elif loc == _("Multimedia"):
|
||
|
location = "AudioVideo;"
|
||
|
elif loc == _("System"):
|
||
|
location = "System;"
|
||
|
|
||
|
global iconpath
|
||
|
iconname = iconpath.replace("/", " ").split()[-1]
|
||
|
iconext = iconname.replace(".", " ").split()[-1]
|
||
|
|
||
|
if os.path.exists("{0}/{1}.desktop".format(_APPS_DIR, formatted)):
|
||
|
DuplicateError(title, formatted, address, iconext, location)
|
||
|
elif len(title) == 0:
|
||
|
EmptyNameError()
|
||
|
else:
|
||
|
writefile(title, formatted, address, iconext, location)
|
||
|
|
||
|
|
||
|
def writefile(title, formatted, address, iconext, location):
|
||
|
global iconpath
|
||
|
os.system("cp --force {0} {1}/{2}.{3}".format(iconpath, _ICE_DIR, formatted, iconext))
|
||
|
appfile = os.path.expanduser("{0}/{1}.desktop".format(_APPS_DIR, formatted))
|
||
|
os.system("touch {0}".format(appfile))
|
||
|
if chrome.get_active() == True:
|
||
|
browser = "google-chrome"
|
||
|
elif chromium.get_active() == True:
|
||
|
browser = "chromium-browser"
|
||
|
elif vivaldi.get_active() == True:
|
||
|
browser = "vivaldi"
|
||
|
elif firefox.get_active() == True:
|
||
|
browser = "firefox"
|
||
|
else:
|
||
|
print(_("ERROR: An unknown browser selection error has occurred."))
|
||
|
sys.exit(1)
|
||
|
|
||
|
with open(appfile, 'w') as appfile1:
|
||
|
global isolate_profile
|
||
|
appfile1.truncate()
|
||
|
|
||
|
appfile1.write("[Desktop Entry]\n")
|
||
|
appfile1.write("Version=1.0\n")
|
||
|
appfile1.write("Name={0}\n".format(title))
|
||
|
appfile1.write("Comment={0} (Ice SSB)\n".format(title))
|
||
|
|
||
|
if (browser == "firefox"):
|
||
|
firefox_profile_path = "{0}/{1}".format(_FF_PROFILES_DIR, formatted)
|
||
|
appfile1.write("Exec={0} --class ICE-SSB-{2} --profile {3} --no-remote {1}\n".format(browser, address, formatted, firefox_profile_path))
|
||
|
appfile1.write("IceFirefox={0}\n".format(formatted))
|
||
|
init_firefox_profile(firefox_profile_path)
|
||
|
else:
|
||
|
if isolate_profile == True:
|
||
|
profile_path = "{0}/{1}".format(_PROFILES_DIR, formatted)
|
||
|
appfile1.write("Exec={0} --app={1} --class=ICE-SSB-{2} --user-data-dir={3}\n".format(browser, address, formatted, profile_path))
|
||
|
appfile1.write("X-ICE-SSB-Profile={0}\n".format(formatted))
|
||
|
else:
|
||
|
appfile1.write("Exec={0} --app={1} --class=ICE-SSB-{2}\n".format(browser, address, formatted))
|
||
|
|
||
|
appfile1.write("Terminal=false\n")
|
||
|
appfile1.write("X-MultipleArgs=false\n")
|
||
|
appfile1.write("Type=Application\n")
|
||
|
appfile1.write("Icon={0}/{1}.{2}\n".format(_ICE_DIR, formatted, iconext))
|
||
|
appfile1.write("Categories=GTK;{0}\n".format(location))
|
||
|
appfile1.write("MimeType=text/html;text/xml;application/xhtml_xml;\n")
|
||
|
appfile1.write("StartupWMClass=ICE-SSB-{0}\n".format(formatted))
|
||
|
appfile1.write("StartupNotify=true\n")
|
||
|
|
||
|
name.set_text("")
|
||
|
url.set_text("")
|
||
|
iconpath = _ICE_ICON
|
||
|
new_icon = Pixbuf.new_from_file_at_size(iconpath, 32, 32)
|
||
|
icon.set_from_pixbuf(new_icon)
|
||
|
details = get_details(appfile)
|
||
|
if details is not None:
|
||
|
liststore.prepend([ details['pixbuf'], details['nameline'] ])
|
||
|
|
||
|
def init_firefox_profile(path):
|
||
|
chromepath = "{0}/chrome".format(path)
|
||
|
settingsfile = "{0}/user.js".format(path)
|
||
|
cssfile = "{0}/userChrome.css".format(chromepath)
|
||
|
|
||
|
os.system('mkdir -p ' + chromepath)
|
||
|
os.system('cp -n /usr/lib/peppermint/ice/search.json.mozlz4 ' + path + '/search.json.mozlz4')
|
||
|
os.system('cp -n /usr/lib/peppermint/ice/places.sqlite ' + path + '/places.sqlite')
|
||
|
os.system("touch {0}".format(cssfile))
|
||
|
with open(cssfile, 'w') as cfile:
|
||
|
cfile.write("#nav-bar, #identity-box, #tabbrowser-tabs, #TabsToolbar { visibility: collapse !important; }")
|
||
|
|
||
|
os.system("touch {0}".format(settingsfile))
|
||
|
with open(settingsfile, 'w') as sfile:
|
||
|
sfile.write('user_pref("browser.cache.disk.enable", false);')
|
||
|
sfile.write('user_pref("browser.cache.disk.capacity", 0);')
|
||
|
sfile.write('user_pref("browser.cache.disk.filesystem_reported", 1);')
|
||
|
sfile.write('user_pref("browser.cache.disk.smart_size.enabled", false);')
|
||
|
sfile.write('user_pref("browser.cache.disk.smart_size.first_run", false);')
|
||
|
sfile.write('user_pref("browser.cache.disk.smart_size.use_old_max", false);')
|
||
|
sfile.write('user_pref("browser.ctrlTab.previews", true);')
|
||
|
sfile.write('user_pref("browser.tabs.warnOnClose", false);')
|
||
|
sfile.write('user_pref("plugin.state.flash", 2);')
|
||
|
sfile.write('user_pref("toolkit.legacyUserProfileCustomizations.stylesheets", true);')
|
||
|
|
||
|
# rhein: do we really need this?
|
||
|
#os.system('rm -rf ' + chromepath + '/cache2')
|
||
|
|
||
|
|
||
|
def delete(button):
|
||
|
a = iconview.get_selected_items()
|
||
|
b = liststore.get_iter(a[0])
|
||
|
c = liststore.get_value(b, 1)
|
||
|
liststore.remove(b)
|
||
|
|
||
|
semiformatted = ""
|
||
|
array = filter(str.isalpha, c)
|
||
|
|
||
|
for obj in array:
|
||
|
semiformatted = semiformatted + obj
|
||
|
|
||
|
formatted = semiformatted.lower()
|
||
|
appfile = "{0}/{1}.desktop".format(_APPS_DIR, formatted)
|
||
|
|
||
|
appfileopen = open(appfile, 'r')
|
||
|
appfilelines = appfileopen.readlines()
|
||
|
appfileopen.close()
|
||
|
|
||
|
for line in appfilelines:
|
||
|
if "IceFirefox=" in line:
|
||
|
profile = str.replace(line, 'IceFirefox=', '')
|
||
|
os.system("rm -rf {0}/{1}".format(_FF_PROFILES_DIR, profile))
|
||
|
|
||
|
if "X-ICE-SSB-Profile=" in line:
|
||
|
profile = str.replace(line, 'X-ICE-SSB-Profile=', '')
|
||
|
os.system("rm -rf {0}/{1}".format(_PROFILES_DIR, profile))
|
||
|
|
||
|
os.system("rm {0}".format(appfile))
|
||
|
|
||
|
|
||
|
def clean_orphaned_profiles(known_apps):
|
||
|
known_profiles = []
|
||
|
for app in known_apps:
|
||
|
a = "{0}/{1}".format(_FF_PROFILES_DIR, app['profile'])
|
||
|
if app['profile'] != "":
|
||
|
# make sure firefox apps have profiles available
|
||
|
if app['is_firefox'] is True and not os.path.isdir(a):
|
||
|
init_firefox_profile(a)
|
||
|
known_profiles.append(app['profile'])
|
||
|
|
||
|
for p_type in ['profiles','firefox']:
|
||
|
for fl in os.listdir("{0}/{1}/".format(_ICE_DIR, p_type)):
|
||
|
a = "{0}/{1}/{2}".format(_ICE_DIR, p_type, fl)
|
||
|
if not os.path.isdir(a) or fl not in known_profiles:
|
||
|
os.system("rm -rf {0}".format(a))
|
||
|
|
||
|
|
||
|
class IconSel(Gtk.FileChooserDialog):
|
||
|
|
||
|
def __init__(self):
|
||
|
|
||
|
def update_image(dialog):
|
||
|
filename = dialog.get_preview_filename()
|
||
|
|
||
|
try:
|
||
|
pixbuf = Pixbuf.new_from_file(filename)
|
||
|
preview.set_from_pixbuf(pixbuf)
|
||
|
valid_preview = True
|
||
|
except:
|
||
|
valid_preview = False
|
||
|
|
||
|
dialog.set_preview_widget_active(valid_preview)
|
||
|
|
||
|
filew = Gtk.FileChooserDialog(
|
||
|
_("Please choose an icon."),
|
||
|
None,
|
||
|
Gtk.FileChooserAction.OPEN,
|
||
|
(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK))
|
||
|
filew.set_filename(_ICE_ICON)
|
||
|
|
||
|
filter1 = Gtk.FileFilter()
|
||
|
filter1.set_name("Icons")
|
||
|
filter1.add_mime_type("image/png")
|
||
|
filter1.add_mime_type("image/jpeg")
|
||
|
filter1.add_mime_type("image/gif")
|
||
|
filter1.add_pattern("*.png")
|
||
|
filter1.add_pattern("*.jpg")
|
||
|
filter1.add_pattern("*.gif")
|
||
|
filter1.add_pattern("*.xpm")
|
||
|
filter1.add_pattern("*.svg")
|
||
|
filew.add_filter(filter1)
|
||
|
|
||
|
preview = Gtk.Image()
|
||
|
filew.set_preview_widget(preview)
|
||
|
filew.connect("update-preview", update_image)
|
||
|
|
||
|
response = filew.run()
|
||
|
if response == Gtk.ResponseType.OK:
|
||
|
global iconpath
|
||
|
iconpath = filew.get_filename()
|
||
|
new_icon = Pixbuf.new_from_file_at_size(iconpath, 32, 32)
|
||
|
icon.set_from_pixbuf(new_icon)
|
||
|
filew.destroy()
|
||
|
elif response == Gtk.ResponseType.CANCEL:
|
||
|
filew.destroy()
|
||
|
|
||
|
|
||
|
class NoBrowserError(Gtk.Window):
|
||
|
|
||
|
def destroy(self, button):
|
||
|
self.close()
|
||
|
|
||
|
def __init__(self):
|
||
|
Gtk.Window.__init__(self, title=_("Browser Error"))
|
||
|
self.set_size_request(250, 130)
|
||
|
self.set_icon_from_file(_ICE_ICON)
|
||
|
|
||
|
print(_("test"))
|
||
|
|
||
|
main_lab = Gtk.Label()
|
||
|
main_lab.set_markup(_("<b>Warning: No Suitable Browser Detected</b>"))
|
||
|
text_lab = Gtk.Label(_("The name of the SSB will cause an existing SSB to\nbe overwritten. To prevent this, change a letter in\nthe name. Continue anyway?"))
|
||
|
text_lab = Gtk.Label(_("Ice requires a system installation of either Google\nChrome or Chromium in order to function. Please\ninstall at least one in order to create SSBs."))
|
||
|
|
||
|
close = Gtk.Button(label=_("Close"))
|
||
|
close.connect("clicked", self.destroy)
|
||
|
void = Gtk.Label()
|
||
|
box = Gtk.HBox()
|
||
|
box.pack_start(void, True, True, 0)
|
||
|
box.pack_start(close, False, False, 0)
|
||
|
|
||
|
main_vbox = Gtk.VBox()
|
||
|
main_vbox.pack_start(main_lab, False, False, 10)
|
||
|
main_vbox.pack_start(text_lab, False, False, 0)
|
||
|
main_vbox.pack_start(box, False, False, 10)
|
||
|
|
||
|
main_hbox = Gtk.HBox()
|
||
|
main_hbox.pack_start(main_vbox, True, True, 10)
|
||
|
self.add(main_hbox)
|
||
|
self.show_all()
|
||
|
|
||
|
|
||
|
class DuplicateError(Gtk.Window):
|
||
|
|
||
|
def destroy(self, button):
|
||
|
self.close()
|
||
|
|
||
|
def okay_clicked(self, button, title, formatted, address, iconext, location):
|
||
|
|
||
|
for item in liststore:
|
||
|
itemiter = item.iter
|
||
|
semiformatted = ""
|
||
|
array = filter(str.isalpha, item[1])
|
||
|
|
||
|
for obj in array:
|
||
|
semiformatted = semiformatted + obj
|
||
|
|
||
|
forma = semiformatted.lower()
|
||
|
|
||
|
if forma == formatted:
|
||
|
liststore.remove(itemiter)
|
||
|
|
||
|
writefile(title, formatted, address, iconext, location)
|
||
|
self.close()
|
||
|
|
||
|
def __init__(self, title, formatted, address, iconext, location):
|
||
|
Gtk.Window.__init__(self, title=_("Duplication Error"))
|
||
|
self.set_size_request(250, 130)
|
||
|
self.set_icon_from_file(_ICE_ICON)
|
||
|
|
||
|
main_lab = Gtk.Label()
|
||
|
main_lab.set_markup(_("<b>Warning: File Duplication Error</b>"))
|
||
|
text_lab = Gtk.Label(_("The name of the SSB will cause an existing SSB to\nbe overwritten. To prevent this, change a letter in\nthe name. Continue anyway?"))
|
||
|
|
||
|
okay = Gtk.Button(label=_("OK"))
|
||
|
okay.connect("clicked", self.okay_clicked, title, formatted, address, iconext, location)
|
||
|
cancel = Gtk.Button(label=_("Cancel"))
|
||
|
cancel.connect("clicked", self.destroy)
|
||
|
void = Gtk.Label()
|
||
|
box = Gtk.HBox()
|
||
|
box.pack_start(void, True, True, 0)
|
||
|
box.pack_start(okay, False, False, 10)
|
||
|
box.pack_start(cancel, False, False, 0)
|
||
|
|
||
|
main_vbox = Gtk.VBox()
|
||
|
main_vbox.pack_start(main_lab, False, False, 10)
|
||
|
main_vbox.pack_start(text_lab, False, False, 0)
|
||
|
main_vbox.pack_start(box, False, False, 10)
|
||
|
|
||
|
main_hbox = Gtk.HBox()
|
||
|
main_hbox.pack_start(main_vbox, True, True, 10)
|
||
|
self.add(main_hbox)
|
||
|
self.show_all()
|
||
|
|
||
|
|
||
|
class AddressError(Gtk.Window):
|
||
|
|
||
|
def destroy(self, button):
|
||
|
self.close()
|
||
|
|
||
|
def okay_clicked(self, button):
|
||
|
applicate()
|
||
|
self.close()
|
||
|
|
||
|
def __init__(self):
|
||
|
Gtk.Window.__init__(self, title=_("Address Error"))
|
||
|
self.set_size_request(250, 130)
|
||
|
self.set_icon_from_file(_ICE_ICON)
|
||
|
|
||
|
main_lab = Gtk.Label()
|
||
|
main_lab.set_markup(_("<b>Warning: HTTP or URL Error</b>"))
|
||
|
text_lab = Gtk.Label(_("An error with the web address has been detected.\nThis is possibly the site being down or unavailable\nright now. Continue anyway?"))
|
||
|
|
||
|
okay = Gtk.Button(label=_("OK"))
|
||
|
okay.connect("clicked", self.okay_clicked)
|
||
|
cancel = Gtk.Button(label=_("Cancel"))
|
||
|
cancel.connect("clicked", self.destroy)
|
||
|
void = Gtk.Label()
|
||
|
box = Gtk.HBox()
|
||
|
box.pack_start(void, True, True, 0)
|
||
|
box.pack_start(okay, False, False, 10)
|
||
|
box.pack_start(cancel, False, False, 0)
|
||
|
|
||
|
main_vbox = Gtk.VBox()
|
||
|
main_vbox.pack_start(main_lab, False, False, 10)
|
||
|
main_vbox.pack_start(text_lab, False, False, 0)
|
||
|
main_vbox.pack_start(box, False, False, 10)
|
||
|
|
||
|
main_hbox = Gtk.HBox()
|
||
|
main_hbox.pack_start(main_vbox, True, True, 10)
|
||
|
self.add(main_hbox)
|
||
|
self.show_all()
|
||
|
|
||
|
class EmptyNameError(Gtk.Window):
|
||
|
|
||
|
def destroy(self, button):
|
||
|
self.close()
|
||
|
|
||
|
def okay_clicked(self, button):
|
||
|
applicate()
|
||
|
self.close()
|
||
|
|
||
|
def __init__(self):
|
||
|
Gtk.Window.__init__(self, title=_("Name Error"))
|
||
|
self.set_size_request(250, 130)
|
||
|
self.set_icon_from_file(_ICE_ICON)
|
||
|
|
||
|
main_lab = Gtk.Label()
|
||
|
main_lab.set_markup(_("<b>Error: No Application Name Entered.</b>"))
|
||
|
text_lab = Gtk.Label(_("Please enter an application name to continue."))
|
||
|
|
||
|
close = Gtk.Button(label=_("Close"))
|
||
|
close.connect("clicked", self.destroy)
|
||
|
void = Gtk.Label()
|
||
|
box = Gtk.HBox()
|
||
|
box.pack_start(void, True, True, 0)
|
||
|
box.pack_start(close, False, False, 0)
|
||
|
|
||
|
main_vbox = Gtk.VBox()
|
||
|
main_vbox.pack_start(main_lab, False, False, 10)
|
||
|
main_vbox.pack_start(text_lab, False, False, 0)
|
||
|
main_vbox.pack_start(box, False, False, 10)
|
||
|
|
||
|
main_hbox = Gtk.HBox()
|
||
|
main_hbox.pack_start(main_vbox, True, True, 10)
|
||
|
self.add(main_hbox)
|
||
|
self.show_all()
|
||
|
|
||
|
|
||
|
class Ice(Gtk.Window):
|
||
|
|
||
|
def destroy(self, button):
|
||
|
Gtk.main_quit()
|
||
|
|
||
|
def icon_select(self, button):
|
||
|
IconSel()
|
||
|
|
||
|
def apply_clicked(self, button):
|
||
|
if errortest(normalize(url.get_text())) is True:
|
||
|
applicate()
|
||
|
elif errortest(normalize(url.get_text())) is False:
|
||
|
AddressError()
|
||
|
elif errortest(normalize(url.get_text())) is None:
|
||
|
print(_("ERROR: An address error has occurred."))
|
||
|
sys.exit(1)
|
||
|
else:
|
||
|
print(_("ERROR: An unknown error has occurred."))
|
||
|
sys.exit(1)
|
||
|
|
||
|
def icon_download(self, button):
|
||
|
appurl = normalize(url.get_text())
|
||
|
global iconpath
|
||
|
try:
|
||
|
download_favicon(appurl)
|
||
|
addr0 = get_favicon_url(appurl)
|
||
|
addr1 = addr0.replace('/', ' ')
|
||
|
addr2 = addr1.split()[-1]
|
||
|
iconpath = "/tmp/{0}".format(addr2)
|
||
|
new_icon = Pixbuf.new_from_file_at_size(iconpath, 32, 32)
|
||
|
icon.set_from_pixbuf(new_icon)
|
||
|
except:
|
||
|
iconpath = _ICE_ICON
|
||
|
new_icon = Pixbuf.new_from_file_at_size(iconpath, 32, 32)
|
||
|
icon.set_from_pixbuf(new_icon)
|
||
|
|
||
|
def isolate_clicked(self, button):
|
||
|
global isolate_profile
|
||
|
isolate_profile=False
|
||
|
if button.get_active() == True:
|
||
|
isolate_profile = True
|
||
|
|
||
|
def __init__(self):
|
||
|
Gtk.Window.__init__(self, title="Ice")
|
||
|
self.current_directory = os.path.realpath(_APPS_DIR)
|
||
|
self.set_size_request(460, 350)
|
||
|
self.set_icon_from_file(_ICE_ICON)
|
||
|
|
||
|
######################
|
||
|
# 'Create' page. #
|
||
|
######################
|
||
|
|
||
|
welcome = Gtk.Label()
|
||
|
welcome.set_markup(_("<b>Welcome to Ice, a simple SSB manager.</b>"))
|
||
|
global name
|
||
|
name = Gtk.Entry()
|
||
|
name.set_placeholder_text(_("Name the application"))
|
||
|
global url
|
||
|
url = Gtk.Entry()
|
||
|
url.set_placeholder_text(_("Enter web address"))
|
||
|
|
||
|
where_store = [_("Accessories"), _("Games"), _("Graphics"), _("Internet"),
|
||
|
_("Office"), _("Programming"), _("Multimedia"), _("System")]
|
||
|
where_lab = Gtk.Label(label=_("Where in the menu?"))
|
||
|
global where
|
||
|
where = Gtk.ComboBoxText()
|
||
|
where.set_entry_text_column(0)
|
||
|
for entry in where_store:
|
||
|
where.append_text(entry)
|
||
|
where.set_active(3)
|
||
|
|
||
|
where_box = Gtk.HBox()
|
||
|
where_void = Gtk.Label()
|
||
|
where_box.pack_start(where_lab, False, False, 0)
|
||
|
where_box.pack_start(where_void, False, False, 10)
|
||
|
where_box.pack_start(where, True, True, 0)
|
||
|
|
||
|
global iconpath
|
||
|
iconpath = _ICE_ICON
|
||
|
icon_pixbuf = Pixbuf.new_from_file_at_size(iconpath, 32, 32)
|
||
|
global icon
|
||
|
icon = Gtk.Image()
|
||
|
icon.set_from_pixbuf(icon_pixbuf)
|
||
|
|
||
|
icon_void = Gtk.Label()
|
||
|
icon_box = Gtk.HBox()
|
||
|
icon_box.pack_start(icon, False, False, 10)
|
||
|
icon_box.pack_start(icon_void, False, False, 10)
|
||
|
|
||
|
choose_icon = Gtk.Button(label=_("Select an icon"))
|
||
|
choose_icon.connect("clicked", self.icon_select)
|
||
|
download_icon = Gtk.Button(label=_("Use site favicon"))
|
||
|
download_icon.connect("clicked", self.icon_download)
|
||
|
|
||
|
icon_vbox = Gtk.VBox()
|
||
|
icon_vbox.pack_start(choose_icon, True, True, 5)
|
||
|
icon_vbox.pack_start(download_icon, True, True, 5)
|
||
|
icon_hbox = Gtk.HBox()
|
||
|
icon_hbox.pack_start(icon_box, False, False, 10)
|
||
|
icon_hbox.pack_start(icon_vbox, True, True, 0)
|
||
|
|
||
|
global firefox
|
||
|
firefox = Gtk.RadioButton.new_with_label_from_widget(None, " Firefox")
|
||
|
|
||
|
if not os.path.exists(_FIREFOX_BIN):
|
||
|
firefox.set_sensitive(False)
|
||
|
|
||
|
if not os.path.exists(_CHROMIUM_BIN) and not \
|
||
|
os.path.exists(_CHROME_BIN) and not \
|
||
|
os.path.exists(_VIVALDI_BIN) and \
|
||
|
os.path.exists(_FIREFOX_BIN):
|
||
|
firefox.set_active(True)
|
||
|
|
||
|
global chrome
|
||
|
chrome = Gtk.RadioButton.new_from_widget(firefox)
|
||
|
chrome.set_label(" Chrome")
|
||
|
|
||
|
if not os.path.exists(_CHROME_BIN):
|
||
|
chrome.set_sensitive(False)
|
||
|
|
||
|
if not os.path.exists(_CHROMIUM_BIN) and not \
|
||
|
os.path.exists(_FIREFOX_BIN) and not \
|
||
|
os.path.exists(_VIVALDI_BIN) and \
|
||
|
os.path.exists(_CHROME_BIN):
|
||
|
chrome.set_active(True)
|
||
|
|
||
|
global vivaldi
|
||
|
vivaldi = Gtk.RadioButton.new_from_widget(chrome)
|
||
|
vivaldi.set_label(" Vivaldi")
|
||
|
|
||
|
if not os.path.exists(_VIVALDI_BIN):
|
||
|
vivaldi.set_sensitive(False)
|
||
|
|
||
|
if not os.path.exists(_CHROMIUM_BIN) and not \
|
||
|
os.path.exists(_FIREFOX_BIN) and not \
|
||
|
os.path.exists(_CHROME_BIN) and \
|
||
|
os.path.exists(_VIVALDI_BIN):
|
||
|
vivaldi.set_active(True)
|
||
|
|
||
|
global chromium
|
||
|
chromium = Gtk.RadioButton.new_from_widget(chrome)
|
||
|
chromium.set_label(" Chromium")
|
||
|
|
||
|
if not os.path.exists(_CHROMIUM_BIN):
|
||
|
chromium.set_sensitive(False)
|
||
|
|
||
|
if not os.path.exists(_CHROME_BIN) and not \
|
||
|
os.path.exists(_FIREFOX_BIN) and not \
|
||
|
os.path.exists(_VIVALDI_BIN) and \
|
||
|
os.path.exists(_CHROMIUM_BIN):
|
||
|
chromium.set_active(True)
|
||
|
|
||
|
global isolate_profile
|
||
|
isolate_profile=False
|
||
|
isolate_box = Gtk.VBox()
|
||
|
isolate_button = Gtk.CheckButton(label=_(" Create the SSB with an isolated browser profile (Note: Firefox SSB's are always isolated)"))
|
||
|
isolate_button.connect("toggled", self.isolate_clicked)
|
||
|
isolate_box.add(isolate_button)
|
||
|
|
||
|
apply_button = Gtk.Button(label=_("Apply"))
|
||
|
apply_button.connect("clicked", self.apply_clicked)
|
||
|
close_button = Gtk.Button(label=_("Close"))
|
||
|
close_button.connect("clicked", self.destroy)
|
||
|
button_void = Gtk.Label()
|
||
|
button_box = Gtk.HBox()
|
||
|
button_box.pack_start(chrome, False, False, 10)
|
||
|
button_box.pack_start(chromium, False, False, 0)
|
||
|
button_box.pack_start(vivaldi, False, False, 10)
|
||
|
button_box.pack_start(firefox, False, False, 0)
|
||
|
button_box.pack_start(button_void, True, True, 0)
|
||
|
button_box.pack_start(close_button, False, False, 20)
|
||
|
button_box.pack_start(apply_button, False, False, 0)
|
||
|
|
||
|
create_vbox = Gtk.VBox()
|
||
|
create_vbox.pack_start(welcome, False, False, 15)
|
||
|
create_vbox.pack_start(name, False, False, 0)
|
||
|
create_vbox.pack_start(url, False, False, 10)
|
||
|
create_vbox.pack_start(where_box, False, False, 10)
|
||
|
create_vbox.pack_start(icon_hbox, False, False, 10)
|
||
|
create_vbox.pack_start(isolate_box, False, False, 10)
|
||
|
create_vbox.pack_start(button_box, False, False, 0)
|
||
|
|
||
|
create_hbox = Gtk.HBox()
|
||
|
create_hbox.pack_start(create_vbox, True, True, 20)
|
||
|
create_lab = Gtk.Label(label=_("Create"))
|
||
|
|
||
|
######################
|
||
|
# 'Remove' page. #
|
||
|
######################
|
||
|
|
||
|
global liststore
|
||
|
known_profiles = []
|
||
|
liststore = Gtk.ListStore(Pixbuf, str)
|
||
|
|
||
|
for fl in os.listdir(_APPS_DIR):
|
||
|
a = "{0}/{1}".format(_APPS_DIR, fl)
|
||
|
if not os.path.isdir(a):
|
||
|
details = get_details(a)
|
||
|
if details is not None:
|
||
|
liststore.append([ details['pixbuf'], details['nameline'] ])
|
||
|
known_profiles.append(details)
|
||
|
|
||
|
clean_orphaned_profiles(known_profiles)
|
||
|
|
||
|
global iconview
|
||
|
iconview = Gtk.IconView()
|
||
|
iconview.set_model(liststore)
|
||
|
iconview.set_pixbuf_column(0)
|
||
|
iconview.set_text_column(1)
|
||
|
iconview.set_selection_mode(1)
|
||
|
|
||
|
scroll = Gtk.ScrolledWindow()
|
||
|
scroll.add(iconview)
|
||
|
|
||
|
remove = Gtk.Button(label=_("Remove"))
|
||
|
remove.connect("clicked", delete)
|
||
|
close = Gtk.Button(label=_("Close"))
|
||
|
close.connect("clicked", self.destroy)
|
||
|
void = Gtk.Label()
|
||
|
buttons = Gtk.HBox()
|
||
|
buttons.pack_start(void, True, True, 0)
|
||
|
buttons.pack_start(close, False, False, 20)
|
||
|
buttons.pack_start(remove, False, False, 0)
|
||
|
|
||
|
remove_vbox = Gtk.VBox()
|
||
|
remove_vbox.pack_start(scroll, True, True, 10)
|
||
|
remove_vbox.pack_start(buttons, False, False, 0)
|
||
|
|
||
|
remove_hbox = Gtk.HBox()
|
||
|
remove_hbox.pack_start(remove_vbox, True, True, 20)
|
||
|
remove_lab = Gtk.Label(label=_("Remove"))
|
||
|
|
||
|
##########################
|
||
|
# Main window stuff. #
|
||
|
##########################
|
||
|
|
||
|
notebook = Gtk.Notebook()
|
||
|
notebook.append_page(create_hbox, create_lab)
|
||
|
notebook.append_page(remove_hbox, remove_lab)
|
||
|
|
||
|
main_vbox = Gtk.VBox()
|
||
|
main_vbox.pack_start(notebook, True, True, 10)
|
||
|
main_hbox = Gtk.HBox()
|
||
|
main_hbox.pack_start(main_vbox, True, True, 10)
|
||
|
self.add(main_hbox)
|
||
|
self.show_all()
|
||
|
|
||
|
if not os.path.exists(_CHROME_BIN) and not \
|
||
|
os.path.exists(_CHROMIUM_BIN) and not \
|
||
|
os.path.exists(_VIVALDI_BIN) and not \
|
||
|
os.path.exists(_FIREFOX_BIN):
|
||
|
apply_button.set_sensitive(False)
|
||
|
NoBrowserError()
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
window = Ice()
|
||
|
window.connect("delete-event", Gtk.main_quit)
|
||
|
Gtk.main()
|