2011-02-17 14:43:48 -05:00
|
|
|
#!@PYTHON@
|
|
|
|
# -*- mode: Python; indent-tabs-mode: nil; -*-
|
|
|
|
|
|
|
|
import os
|
|
|
|
import re
|
2011-06-22 21:29:20 -04:00
|
|
|
import socket
|
2011-02-17 14:43:48 -05:00
|
|
|
import subprocess
|
|
|
|
import sys
|
|
|
|
import optparse
|
|
|
|
import tempfile
|
|
|
|
try:
|
|
|
|
import json
|
|
|
|
except ImportError:
|
|
|
|
try:
|
|
|
|
import simplejson as json
|
|
|
|
except ImportError:
|
2014-08-29 10:23:56 -04:00
|
|
|
print('The Python simplejson module is required')
|
2011-02-17 14:43:48 -05:00
|
|
|
sys.exit(1)
|
|
|
|
|
2016-10-08 14:23:45 -04:00
|
|
|
from gi.repository import Gio, GLib
|
2011-02-17 14:43:48 -05:00
|
|
|
|
2011-06-22 21:32:08 -04:00
|
|
|
SAMPLE_EXTENSION_FILES = {
|
|
|
|
"extension.js": """
|
|
|
|
const St = imports.gi.St;
|
|
|
|
const Main = imports.ui.main;
|
|
|
|
const Tweener = imports.ui.tweener;
|
|
|
|
|
2011-06-22 21:56:24 -04:00
|
|
|
let text, button;
|
2011-06-22 21:32:08 -04:00
|
|
|
|
|
|
|
function _hideHello() {
|
|
|
|
Main.uiGroup.remove_actor(text);
|
|
|
|
text = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
function _showHello() {
|
|
|
|
if (!text) {
|
|
|
|
text = new St.Label({ style_class: 'helloworld-label', text: "Hello, world!" });
|
|
|
|
Main.uiGroup.add_actor(text);
|
|
|
|
}
|
|
|
|
|
|
|
|
text.opacity = 255;
|
|
|
|
|
|
|
|
let monitor = Main.layoutManager.primaryMonitor;
|
|
|
|
|
2014-07-05 05:20:01 -04:00
|
|
|
text.set_position(monitor.x + Math.floor(monitor.width / 2 - text.width / 2),
|
|
|
|
monitor.y + Math.floor(monitor.height / 2 - text.height / 2));
|
2011-06-22 21:32:08 -04:00
|
|
|
|
|
|
|
Tweener.addTween(text,
|
|
|
|
{ opacity: 0,
|
|
|
|
time: 2,
|
|
|
|
transition: 'easeOutQuad',
|
|
|
|
onComplete: _hideHello });
|
|
|
|
}
|
|
|
|
|
2011-06-22 21:56:24 -04:00
|
|
|
function init() {
|
|
|
|
button = new St.Bin({ style_class: 'panel-button',
|
|
|
|
reactive: true,
|
|
|
|
can_focus: true,
|
|
|
|
x_fill: true,
|
|
|
|
y_fill: false,
|
|
|
|
track_hover: true });
|
2012-05-30 09:58:37 -04:00
|
|
|
let icon = new St.Icon({ icon_name: 'system-run-symbolic',
|
2011-06-22 21:32:08 -04:00
|
|
|
style_class: 'system-status-icon' });
|
|
|
|
|
|
|
|
button.set_child(icon);
|
|
|
|
button.connect('button-press-event', _showHello);
|
2011-06-22 21:56:24 -04:00
|
|
|
}
|
2011-06-22 21:32:08 -04:00
|
|
|
|
2011-06-22 21:56:24 -04:00
|
|
|
function enable() {
|
2012-03-18 02:02:47 -04:00
|
|
|
Main.panel._rightBox.insert_child_at_index(button, 0);
|
2011-06-22 21:32:08 -04:00
|
|
|
}
|
2011-06-22 21:56:24 -04:00
|
|
|
|
|
|
|
function disable() {
|
2012-03-18 02:02:47 -04:00
|
|
|
Main.panel._rightBox.remove_child(button);
|
2011-06-22 21:56:24 -04:00
|
|
|
}
|
2011-06-22 21:32:08 -04:00
|
|
|
""",
|
|
|
|
|
|
|
|
"stylesheet.css": """
|
|
|
|
.helloworld-label {
|
|
|
|
font-size: 36px;
|
|
|
|
font-weight: bold;
|
|
|
|
color: #ffffff;
|
|
|
|
background-color: rgba(10,10,10,0.7);
|
|
|
|
border-radius: 5px;
|
|
|
|
padding: .5em;
|
|
|
|
}
|
|
|
|
""",
|
|
|
|
}
|
|
|
|
|
2011-10-16 14:24:20 -04:00
|
|
|
def create_extension():
|
2014-08-29 10:23:56 -04:00
|
|
|
print()
|
|
|
|
print('''Name should be a very short (ideally descriptive) string.
|
2011-02-17 14:43:48 -05:00
|
|
|
Examples are: "Click To Focus", "Adblock", "Shell Window Shrinker".
|
2014-08-29 10:23:56 -04:00
|
|
|
''')
|
|
|
|
name = input('Name: ').strip()
|
|
|
|
print()
|
|
|
|
print('''Description is a single-sentence explanation of what your extension does.
|
2011-02-17 14:43:48 -05:00
|
|
|
Examples are: "Make windows visible on click", "Block advertisement popups"
|
|
|
|
"Animate windows shrinking on minimize"
|
2014-08-29 10:23:56 -04:00
|
|
|
''')
|
|
|
|
description = input('Description: ').strip()
|
2011-02-17 14:43:48 -05:00
|
|
|
underifier = re.compile('[^A-Za-z]')
|
|
|
|
sample_uuid = underifier.sub('_', name)
|
|
|
|
# TODO use evolution data server
|
2011-06-22 21:29:20 -04:00
|
|
|
hostname = socket.gethostname()
|
2011-02-17 14:43:48 -05:00
|
|
|
sample_uuid = sample_uuid + '@' + hostname
|
|
|
|
|
2014-08-29 10:23:56 -04:00
|
|
|
print()
|
|
|
|
print('''Uuid is a globally-unique identifier for your extension.
|
2011-02-17 14:43:48 -05:00
|
|
|
This should be in the format of an email address (foo.bar@extensions.example.com), but
|
|
|
|
need not be an actual email address, though it's a good idea to base the uuid on your
|
|
|
|
email address. For example, if your email address is janedoe@example.com, you might
|
2014-08-29 10:23:56 -04:00
|
|
|
use an extension title clicktofocus@janedoe.example.com.''')
|
|
|
|
uuid = input('Uuid [%s]: ' % (sample_uuid, )).strip()
|
2011-02-17 14:43:48 -05:00
|
|
|
if uuid == '':
|
|
|
|
uuid = sample_uuid
|
|
|
|
|
|
|
|
extension_path = os.path.join(os.path.expanduser('~/.local'), 'share', 'gnome-shell', 'extensions', uuid)
|
|
|
|
if os.path.exists(extension_path):
|
2014-08-29 10:23:56 -04:00
|
|
|
print("Extension path %r already exists" % (extension_path, ))
|
2011-02-17 14:43:48 -05:00
|
|
|
sys.exit(0)
|
|
|
|
os.makedirs(extension_path)
|
|
|
|
meta = { 'name': name,
|
|
|
|
'description': description,
|
|
|
|
'uuid': uuid,
|
|
|
|
'shell-version': ['@VERSION@'] }
|
|
|
|
f = open(os.path.join(extension_path, 'metadata.json'), 'w')
|
|
|
|
try:
|
|
|
|
json.dump(meta, f)
|
|
|
|
except AttributeError:
|
|
|
|
# For Python versions older than 2.6, try using the json-py module
|
|
|
|
f.write(json.write(meta) + '\n')
|
|
|
|
f.close()
|
|
|
|
|
2014-08-29 10:23:56 -04:00
|
|
|
for filename, contents in SAMPLE_EXTENSION_FILES.items():
|
2011-06-22 21:32:08 -04:00
|
|
|
path = os.path.join(extension_path, filename)
|
|
|
|
f = open(path, 'w')
|
|
|
|
f.write(contents)
|
|
|
|
f.close()
|
2011-02-17 14:43:48 -05:00
|
|
|
|
2014-08-29 10:23:56 -04:00
|
|
|
print("Created extension in %r" % (extension_path, ))
|
2011-10-13 00:46:46 -04:00
|
|
|
extensionjs_path = os.path.join(extension_path, 'extension.js')
|
2011-10-20 12:48:40 -04:00
|
|
|
subprocess.Popen(['xdg-open', extensionjs_path])
|
2011-10-16 14:24:20 -04:00
|
|
|
|
|
|
|
ENABLED_EXTENSIONS_KEY = 'enabled-extensions'
|
|
|
|
|
|
|
|
def enable_extension(uuid):
|
|
|
|
settings = Gio.Settings(schema='org.gnome.shell')
|
|
|
|
extensions = settings.get_strv(ENABLED_EXTENSIONS_KEY)
|
|
|
|
|
|
|
|
if uuid in extensions:
|
2014-08-29 10:23:56 -04:00
|
|
|
print("%r is already enabled." % (uuid,), file=sys.stderr)
|
2011-10-16 14:24:20 -04:00
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
extensions.append(uuid)
|
|
|
|
settings.set_strv(ENABLED_EXTENSIONS_KEY, extensions)
|
2014-08-29 10:23:56 -04:00
|
|
|
print("%r is now enabled." % (uuid,), file=sys.stderr)
|
2011-10-16 14:24:20 -04:00
|
|
|
|
|
|
|
def disable_extension(uuid):
|
|
|
|
settings = Gio.Settings(schema='org.gnome.shell')
|
|
|
|
extensions = settings.get_strv(ENABLED_EXTENSIONS_KEY)
|
|
|
|
|
|
|
|
if uuid not in extensions:
|
2014-08-29 10:23:56 -04:00
|
|
|
print("%r is not enabled or installed." % (uuid,), file=sys.stderr)
|
2011-10-16 14:24:20 -04:00
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
# Use a while loop here to remove *all* mentions instances
|
|
|
|
# of the extension. Some faulty tools like to append more than one.
|
|
|
|
while uuid in extensions:
|
|
|
|
extensions.remove(uuid)
|
|
|
|
|
|
|
|
settings.set_strv(ENABLED_EXTENSIONS_KEY, extensions)
|
2014-08-29 10:23:56 -04:00
|
|
|
print("%r is now disabled." % (uuid,), file=sys.stderr)
|
2011-10-16 14:24:20 -04:00
|
|
|
|
2016-10-08 14:23:45 -04:00
|
|
|
def reload_extension(uuid):
|
|
|
|
settings = Gio.Settings(schema='org.gnome.shell')
|
|
|
|
extensions = settings.get_strv(ENABLED_EXTENSIONS_KEY)
|
|
|
|
|
|
|
|
if uuid not in extensions:
|
|
|
|
print("%r is not enabled or installed." % (uuid,), file=sys.stderr)
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
proxy = Gio.DBusProxy.new_sync(Gio.bus_get_sync(Gio.BusType.SESSION, None),
|
|
|
|
Gio.DBusProxyFlags.NONE,
|
|
|
|
None,
|
|
|
|
'org.gnome.Shell',
|
|
|
|
'/org/gnome/Shell',
|
|
|
|
'org.gnome.Shell.Extensions',
|
|
|
|
None)
|
|
|
|
proxy.call_sync('ReloadExtension',
|
|
|
|
GLib.Variant('(s)', (uuid,)),
|
|
|
|
Gio.DBusCallFlags.NONE,
|
|
|
|
-1,
|
|
|
|
None)
|
|
|
|
|
|
|
|
print("%r reloaded." % (uuid,), file=sys.stderr)
|
|
|
|
|
|
|
|
|
2011-10-16 14:24:20 -04:00
|
|
|
def main():
|
|
|
|
parser = optparse.OptionParser()
|
|
|
|
parser.add_option("-d", "--disable-extension", dest="disable",
|
|
|
|
help="Disable a GNOME Shell extension")
|
|
|
|
parser.add_option("-e", "--enable-extension", dest="enable",
|
|
|
|
help="Enable a GNOME Shell extension")
|
|
|
|
parser.add_option("-c", "--create-extension", dest="create", action="store_true",
|
|
|
|
help="Create a new GNOME Shell extension")
|
2016-10-08 14:23:45 -04:00
|
|
|
parser.add_option("-r", "--reload-extension", dest="reload",
|
|
|
|
help="Reload a GNOME Shell extension")
|
2011-10-16 14:24:20 -04:00
|
|
|
options, args = parser.parse_args()
|
|
|
|
|
|
|
|
if args:
|
|
|
|
parser.print_usage()
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
if options.disable:
|
|
|
|
disable_extension(options.disable)
|
|
|
|
|
|
|
|
elif options.enable:
|
|
|
|
enable_extension(options.enable)
|
|
|
|
|
|
|
|
elif options.create:
|
|
|
|
create_extension()
|
|
|
|
|
2016-10-08 14:23:45 -04:00
|
|
|
elif options.reload:
|
|
|
|
reload_extension(options.reload)
|
|
|
|
|
2011-10-16 14:24:20 -04:00
|
|
|
else:
|
|
|
|
parser.print_usage()
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|