2019-01-31 09:07:06 -05:00
/* exported main */
2019-08-21 13:36:42 -04:00
imports . gi . versions . Gdk = '3.0' ;
imports . gi . versions . Gtk = '3.0' ;
2012-01-18 21:21:56 -05:00
const Gettext = imports . gettext ;
2019-11-29 22:12:54 -05:00
const { Gdk , GLib , Gio , GObject , Gtk } = imports . gi ;
2012-05-04 17:23:08 -04:00
const Format = imports . format ;
2012-01-18 21:21:56 -05:00
const _ = Gettext . gettext ;
2019-11-30 00:51:35 -05:00
const Config = imports . misc . config ;
2012-01-18 21:21:56 -05:00
const ExtensionUtils = imports . misc . extensionUtils ;
2018-09-05 20:55:20 -04:00
const { loadInterfaceXML } = imports . misc . fileUtils ;
2012-01-18 21:21:56 -05:00
2019-11-30 00:06:08 -05:00
const { ExtensionState , ExtensionType } = ExtensionUtils ;
2018-11-01 08:55:17 -04:00
2018-09-05 20:55:20 -04:00
const GnomeShellIface = loadInterfaceXML ( 'org.gnome.Shell.Extensions' ) ;
2012-01-18 21:21:56 -05:00
const GnomeShellProxy = Gio . DBusProxy . makeProxyWrapper ( GnomeShellIface ) ;
function stripPrefix ( string , prefix ) {
if ( string . slice ( 0 , prefix . length ) == prefix )
return string . slice ( prefix . length ) ;
return string ;
}
2019-10-28 14:35:33 -04:00
var Application = GObject . registerClass (
class Application extends Gtk . Application {
2019-05-28 17:22:37 -04:00
_init ( ) {
2012-01-18 21:21:56 -05:00
GLib . set _prgname ( 'gnome-shell-extension-prefs' ) ;
2019-05-28 17:22:37 -04:00
super . _init ( {
2020-01-24 11:00:24 -05:00
application _id : 'org.gnome.Extensions' ,
2019-08-20 17:43:54 -04:00
flags : Gio . ApplicationFlags . HANDLES _COMMAND _LINE ,
2012-01-18 21:21:56 -05:00
} ) ;
2019-11-29 20:48:18 -05:00
}
get shellProxy ( ) {
return this . _shellProxy ;
}
vfunc _activate ( ) {
2020-01-26 18:47:18 -05:00
this . _shellProxy . CheckForUpdatesRemote ( ) ;
2019-11-29 20:48:18 -05:00
this . _window . present ( ) ;
}
vfunc _startup ( ) {
super . vfunc _startup ( ) ;
2020-01-23 20:02:10 -05:00
let provider = new Gtk . CssProvider ( ) ;
let uri = 'resource:///org/gnome/shell/css/application.css' ;
try {
provider . load _from _file ( Gio . File . new _for _uri ( uri ) ) ;
} catch ( e ) {
logError ( e , 'Failed to add application style' ) ;
}
Gtk . StyleContext . add _provider _for _screen ( Gdk . Screen . get _default ( ) ,
provider ,
Gtk . STYLE _PROVIDER _PRIORITY _APPLICATION ) ;
2019-11-29 20:48:18 -05:00
this . _shellProxy = new GnomeShellProxy ( Gio . DBus . session , 'org.gnome.Shell' , '/org/gnome/Shell' ) ;
this . _window = new ExtensionsWindow ( { application : this } ) ;
}
vfunc _command _line ( commandLine ) {
let args = commandLine . get _arguments ( ) ;
if ( args . length ) {
let uuid = args [ 0 ] ;
// Strip off "extension:///" prefix which fakes a URI, if it exists
uuid = stripPrefix ( uuid , 'extension:///' ) ;
this . _window . openPrefs ( uuid ) ;
} else {
this . activate ( ) ;
}
return 0 ;
}
} ) ;
2019-11-29 20:48:18 -05:00
var ExtensionsWindow = GObject . registerClass ( {
GTypeName : 'ExtensionsWindow' ,
Template : 'resource:///org/gnome/shell/ui/extensions-window.ui' ,
InternalChildren : [
2019-11-30 02:08:05 -05:00
'userList' ,
'systemList' ,
2019-11-29 20:48:18 -05:00
'killSwitch' ,
2020-01-29 19:28:02 -05:00
'mainBox' ,
2019-11-29 20:48:18 -05:00
'mainStack' ,
2020-01-29 19:28:02 -05:00
'scrolledWindow' ,
2019-11-30 09:20:04 -05:00
'updatesBar' ,
'updatesLabel' ,
2019-11-29 20:48:18 -05:00
] ,
} , class ExtensionsWindow extends Gtk . ApplicationWindow {
2019-11-29 20:48:18 -05:00
_init ( params ) {
super . _init ( params ) ;
2012-01-18 21:21:56 -05:00
2013-02-28 08:50:56 -05:00
this . _startupUuid = null ;
2014-05-26 19:36:41 -04:00
this . _loaded = false ;
2019-11-29 20:48:18 -05:00
this . _prefsDialog = null ;
2019-11-30 09:20:04 -05:00
this . _updatesCheckId = 0 ;
2019-11-29 20:48:18 -05:00
2020-01-29 19:28:02 -05:00
this . _mainBox . set _focus _vadjustment ( this . _scrolledWindow . vadjustment ) ;
2019-11-30 00:51:35 -05:00
let action ;
action = new Gio . SimpleAction ( { name : 'show-about' } ) ;
action . connect ( 'activate' , this . _showAbout . bind ( this ) ) ;
this . add _action ( action ) ;
2019-11-30 09:20:04 -05:00
action = new Gio . SimpleAction ( { name : 'logout' } ) ;
action . connect ( 'activate' , this . _logout . bind ( this ) ) ;
this . add _action ( action ) ;
2019-11-29 20:48:18 -05:00
this . _settings = new Gio . Settings ( { schema _id : 'org.gnome.shell' } ) ;
this . _settings . bind ( 'disable-user-extensions' ,
this . _killSwitch , 'active' ,
Gio . SettingsBindFlags . DEFAULT | Gio . SettingsBindFlags . INVERT _BOOLEAN ) ;
2019-11-30 02:08:05 -05:00
this . _userList . set _sort _func ( this . _sortList . bind ( this ) ) ;
this . _userList . set _header _func ( this . _updateHeader . bind ( this ) ) ;
this . _systemList . set _sort _func ( this . _sortList . bind ( this ) ) ;
this . _systemList . set _header _func ( this . _updateHeader . bind ( this ) ) ;
2019-11-29 20:48:18 -05:00
this . _shellProxy . connectSignal ( 'ExtensionStateChanged' ,
this . _onExtensionStateChanged . bind ( this ) ) ;
this . _scanExtensions ( ) ;
2018-11-01 08:55:17 -04:00
}
2019-11-29 20:48:18 -05:00
get _shellProxy ( ) {
return this . application . shellProxy ;
}
2019-11-30 00:06:08 -05:00
uninstall ( uuid ) {
let row = this . _findExtensionRow ( uuid ) ;
let dialog = new Gtk . MessageDialog ( {
transient _for : this ,
modal : true ,
text : _ ( 'Remove “%s”?' ) . format ( row . name ) ,
secondary _text : _ ( 'If you remove the extension, you need to return to download it if you want to enable it again' ) ,
} ) ;
dialog . add _button ( _ ( 'Cancel' ) , Gtk . ResponseType . CANCEL ) ;
dialog . add _button ( _ ( 'Remove' ) , Gtk . ResponseType . ACCEPT )
. get _style _context ( ) . add _class ( 'destructive-action' ) ;
dialog . connect ( 'response' , ( dlg , response ) => {
if ( response === Gtk . ResponseType . ACCEPT )
this . _shellProxy . UninstallExtensionRemote ( uuid ) ;
dialog . destroy ( ) ;
} ) ;
dialog . present ( ) ;
}
2019-11-29 20:48:18 -05:00
openPrefs ( uuid ) {
if ( ! this . _loaded )
this . _startupUuid = uuid ;
else if ( ! this . _showPrefs ( uuid ) )
this . present ( ) ;
2017-10-30 21:19:44 -04:00
}
2012-01-18 21:21:56 -05:00
2018-11-01 08:50:30 -04:00
_showPrefs ( uuid ) {
2019-11-29 20:48:18 -05:00
if ( this . _prefsDialog )
return false ;
2019-11-30 02:08:05 -05:00
let row = this . _findExtensionRow ( uuid ) ;
if ( ! row || ! row . hasPrefs )
2012-01-18 21:21:56 -05:00
return false ;
let widget ;
try {
2018-11-01 08:50:30 -04:00
widget = row . prefsModule . buildPrefsWidget ( ) ;
2012-01-18 21:21:56 -05:00
} catch ( e ) {
2018-11-01 08:50:30 -04:00
widget = this . _buildErrorUI ( row , e ) ;
2012-01-18 21:21:56 -05:00
}
2019-11-29 20:48:18 -05:00
this . _prefsDialog = new Gtk . Window ( {
application : this . application ,
default _width : 600 ,
default _height : 400 ,
modal : this . visible ,
2019-08-20 17:43:54 -04:00
type _hint : Gdk . WindowTypeHint . DIALOG ,
2019-11-29 20:48:18 -05:00
window _position : Gtk . WindowPosition . CENTER ,
2018-11-01 08:50:30 -04:00
} ) ;
2019-11-29 20:48:18 -05:00
this . _prefsDialog . set _titlebar ( new Gtk . HeaderBar ( {
2018-11-01 08:50:30 -04:00
show _close _button : true ,
title : row . name ,
2019-08-20 17:43:54 -04:00
visible : true ,
2018-11-01 08:50:30 -04:00
} ) ) ;
2014-05-26 19:36:41 -04:00
2019-11-29 20:48:18 -05:00
if ( this . visible )
this . _prefsDialog . transient _for = this ;
this . _prefsDialog . connect ( 'destroy' , ( ) => {
this . _prefsDialog = null ;
if ( ! this . visible )
this . destroy ( ) ;
} ) ;
2014-05-26 19:36:41 -04:00
2019-11-29 20:48:18 -05:00
this . _prefsDialog . add ( widget ) ;
this . _prefsDialog . show ( ) ;
2019-07-20 18:07:00 -04:00
return true ;
2017-10-30 21:19:44 -04:00
}
2012-01-18 21:21:56 -05:00
2019-11-30 00:51:35 -05:00
_showAbout ( ) {
let aboutDialog = new Gtk . AboutDialog ( {
authors : [
'Florian Müllner <fmuellner@gnome.org>' ,
'Jasper St. Pierre <jstpierre@mecheye.net>' ,
'Didier Roche <didrocks@ubuntu.com>' ,
] ,
translator _credits : _ ( 'translator-credits' ) ,
2020-01-24 11:00:24 -05:00
program _name : _ ( 'Extensions' ) ,
2019-11-30 00:51:35 -05:00
comments : _ ( 'Manage your GNOME Extensions' ) ,
license _type : Gtk . License . GPL _2 _0 ,
logo _icon _name : 'org.gnome.Extensions' ,
version : Config . PACKAGE _VERSION ,
transient _for : this ,
modal : true ,
} ) ;
aboutDialog . present ( ) ;
}
2019-11-30 09:20:04 -05:00
_logout ( ) {
this . application . get _dbus _connection ( ) . call (
'org.gnome.SessionManager' ,
'/org/gnome/SessionManager' ,
'org.gnome.SessionManager' ,
'Logout' ,
new GLib . Variant ( '(u)' , [ 0 ] ) ,
null ,
Gio . DBusCallFlags . NONE ,
- 1 ,
null ,
( o , res ) => {
o . call _finish ( res ) ;
} ) ;
}
2018-11-01 08:50:30 -04:00
_buildErrorUI ( row , exc ) {
2018-08-05 22:15:12 -04:00
let scroll = new Gtk . ScrolledWindow ( {
hscrollbar _policy : Gtk . PolicyType . NEVER ,
2019-08-20 17:43:54 -04:00
propagate _natural _height : true ,
2018-08-05 22:15:12 -04:00
} ) ;
let box = new Gtk . Box ( {
orientation : Gtk . Orientation . VERTICAL ,
spacing : 12 ,
margin : 100 ,
2019-08-20 17:43:54 -04:00
margin _bottom : 60 ,
2018-08-05 22:15:12 -04:00
} ) ;
scroll . add ( box ) ;
2012-01-18 21:21:56 -05:00
let label = new Gtk . Label ( {
2019-02-01 14:11:39 -05:00
label : '<span size="x-large">%s</span>' . format ( _ ( "Something’ s gone wrong" ) ) ,
2019-08-20 17:43:54 -04:00
use _markup : true ,
2018-08-05 22:15:12 -04:00
} ) ;
label . get _style _context ( ) . add _class ( Gtk . STYLE _CLASS _DIM _LABEL ) ;
box . add ( label ) ;
label = new Gtk . Label ( {
label : _ ( "We’ re very sorry, but there’ s been a problem: the settings for this extension can’ t be displayed. We recommend that you report the issue to the extension authors." ) ,
justify : Gtk . Justification . CENTER ,
2019-08-20 17:43:54 -04:00
wrap : true ,
2012-01-18 21:21:56 -05:00
} ) ;
box . add ( label ) ;
2018-08-05 22:15:12 -04:00
let expander = new Expander ( {
label : _ ( "Technical Details" ) ,
2019-08-20 17:43:54 -04:00
margin _top : 12 ,
2018-08-05 22:15:12 -04:00
} ) ;
box . add ( expander ) ;
2012-01-18 21:21:56 -05:00
2020-02-14 10:10:34 -05:00
let errortext = '%s\n\nStack trace:\n' . format ( exc ) ;
// Indent stack trace.
errortext +=
exc . stack . split ( '\n' ) . map ( line => ' %s' . format ( line ) ) . join ( '\n' ) ;
2012-01-18 21:21:56 -05:00
let buffer = new Gtk . TextBuffer ( { text : errortext } ) ;
2018-08-05 22:15:12 -04:00
let textview = new Gtk . TextView ( {
2019-08-19 15:06:04 -04:00
buffer ,
2018-08-05 22:15:12 -04:00
wrap _mode : Gtk . WrapMode . WORD ,
monospace : true ,
editable : false ,
top _margin : 12 ,
bottom _margin : 12 ,
left _margin : 12 ,
2019-08-20 17:43:54 -04:00
right _margin : 12 ,
2018-08-05 22:15:12 -04:00
} ) ;
let toolbar = new Gtk . Toolbar ( ) ;
let provider = new Gtk . CssProvider ( ) ;
provider . load _from _data ( ` * {
border : 0 solid @ borders ;
border - top - width : 1 px ;
} ` );
toolbar . get _style _context ( ) . add _provider (
provider ,
Gtk . STYLE _PROVIDER _PRIORITY _APPLICATION
) ;
let copyButton = new Gtk . ToolButton ( {
icon _name : 'edit-copy-symbolic' ,
2019-08-20 17:43:54 -04:00
tooltip _text : _ ( "Copy Error" ) ,
2018-08-05 22:15:12 -04:00
} ) ;
toolbar . add ( copyButton ) ;
copyButton . connect ( 'clicked' , w => {
let clipboard = Gtk . Clipboard . get _default ( w . get _display ( ) ) ;
2019-02-12 09:16:08 -05:00
// markdown for pasting in gitlab issues
let lines = [
2020-02-14 10:10:34 -05:00
'The settings of extension %s had an error:' . format ( row . uuid ) ,
2019-10-29 09:01:07 -04:00
'```' , // '`' (xgettext throws up on odd number of backticks)
2020-02-14 10:10:34 -05:00
exc . toString ( ) ,
2019-10-29 09:01:07 -04:00
'```' , // '`'
2019-02-12 09:16:08 -05:00
'' ,
'Stack trace:' ,
2019-10-29 09:01:07 -04:00
'```' , // '`'
2019-02-12 09:16:08 -05:00
exc . stack . replace ( /\n$/ , '' ) , // stack without trailing newline
2019-10-29 09:01:07 -04:00
'```' , // '`'
2019-08-20 17:43:54 -04:00
'' ,
2019-02-12 09:16:08 -05:00
] ;
clipboard . set _text ( lines . join ( '\n' ) , - 1 ) ;
2018-08-05 22:15:12 -04:00
} ) ;
2012-01-18 21:21:56 -05:00
2018-08-05 22:15:12 -04:00
let spacing = new Gtk . SeparatorToolItem ( { draw : false } ) ;
toolbar . add ( spacing ) ;
toolbar . child _set _property ( spacing , "expand" , true ) ;
let urlButton = new Gtk . ToolButton ( {
label : _ ( "Homepage" ) ,
tooltip _text : _ ( "Visit extension homepage" ) ,
no _show _all : true ,
2019-11-30 12:11:03 -05:00
visible : row . url !== '' ,
2018-08-05 22:15:12 -04:00
} ) ;
toolbar . add ( urlButton ) ;
urlButton . connect ( 'clicked' , w => {
let context = w . get _display ( ) . get _app _launch _context ( ) ;
2018-11-01 08:50:30 -04:00
Gio . AppInfo . launch _default _for _uri ( row . url , context ) ;
2018-08-05 22:15:12 -04:00
} ) ;
let expandedBox = new Gtk . Box ( {
2019-08-20 17:43:54 -04:00
orientation : Gtk . Orientation . VERTICAL ,
2018-08-05 22:15:12 -04:00
} ) ;
expandedBox . add ( textview ) ;
expandedBox . add ( toolbar ) ;
expander . add ( expandedBox ) ;
scroll . show _all ( ) ;
return scroll ;
2017-10-30 21:19:44 -04:00
}
2012-01-18 21:21:56 -05:00
2017-10-30 20:03:21 -04:00
_sortList ( row1 , row2 ) {
2018-11-01 08:50:30 -04:00
return row1 . name . localeCompare ( row2 . name ) ;
2017-10-30 21:19:44 -04:00
}
2014-05-22 22:49:37 -04:00
2017-10-30 20:03:21 -04:00
_updateHeader ( row , before ) {
2014-05-22 22:49:37 -04:00
if ( ! before || row . get _header ( ) )
return ;
let sep = new Gtk . Separator ( { orientation : Gtk . Orientation . HORIZONTAL } ) ;
row . set _header ( sep ) ;
2017-10-30 21:19:44 -04:00
}
2014-05-22 22:49:37 -04:00
2018-11-01 08:55:17 -04:00
_findExtensionRow ( uuid ) {
2019-11-30 02:08:05 -05:00
return [
... this . _userList . get _children ( ) ,
... this . _systemList . get _children ( ) ,
] . find ( c => c . uuid === uuid ) ;
2018-11-01 08:55:17 -04:00
}
_onExtensionStateChanged ( proxy , senderName , [ uuid , newState ] ) {
2019-11-30 00:01:44 -05:00
let extension = ExtensionUtils . deserializeExtension ( newState ) ;
2018-11-01 08:55:17 -04:00
let row = this . _findExtensionRow ( uuid ) ;
2019-11-30 00:01:44 -05:00
2019-11-30 09:20:04 -05:00
this . _queueUpdatesCheck ( ) ;
2019-11-30 02:08:05 -05:00
// the extension's type changed; remove the corresponding row
// and reset the variable to null so that we create a new row
// below and add it to the appropriate list
if ( row && row . type !== extension . type ) {
row . destroy ( ) ;
row = null ;
}
2018-11-01 08:55:17 -04:00
if ( row ) {
2019-11-30 00:01:44 -05:00
if ( extension . state === ExtensionState . UNINSTALLED )
2018-11-01 08:55:17 -04:00
row . destroy ( ) ;
return ; // we only deal with new and deleted extensions here
}
2019-11-30 00:01:44 -05:00
this . _addExtensionRow ( extension ) ;
2018-11-01 08:55:17 -04:00
}
2017-10-30 20:03:21 -04:00
_scanExtensions ( ) {
2018-11-01 08:55:17 -04:00
this . _shellProxy . ListExtensionsRemote ( ( [ extensionsMap ] , e ) => {
if ( e ) {
if ( e instanceof Gio . DBusError ) {
2020-02-14 10:10:34 -05:00
log ( 'Failed to connect to shell proxy: %s' . format ( e . toString ( ) ) ) ;
2018-11-01 08:55:17 -04:00
this . _mainStack . visible _child _name = 'noshell' ;
2019-08-19 20:51:42 -04:00
} else {
2018-11-01 08:55:17 -04:00
throw e ;
2019-08-19 20:51:42 -04:00
}
2018-11-01 08:55:17 -04:00
return ;
}
for ( let uuid in extensionsMap ) {
let extension = ExtensionUtils . deserializeExtension ( extensionsMap [ uuid ] ) ;
this . _addExtensionRow ( extension ) ;
}
this . _extensionsLoaded ( ) ;
} ) ;
2017-10-30 21:19:44 -04:00
}
2012-01-18 21:21:56 -05:00
2018-11-01 08:55:17 -04:00
_addExtensionRow ( extension ) {
2018-11-01 08:50:30 -04:00
let row = new ExtensionRow ( extension ) ;
2014-05-22 22:49:37 -04:00
row . show _all ( ) ;
2019-11-30 02:08:05 -05:00
if ( row . type === ExtensionType . PER _USER )
this . _userList . add ( row ) ;
else
this . _systemList . add ( row ) ;
2017-10-30 21:19:44 -04:00
}
2012-06-04 17:14:18 -04:00
2019-11-30 09:20:04 -05:00
_queueUpdatesCheck ( ) {
if ( this . _updatesCheckId )
return ;
this . _updatesCheckId = GLib . timeout _add _seconds (
GLib . PRIORITY _DEFAULT , 1 , ( ) => {
this . _checkUpdates ( ) ;
this . _updatesCheckId = 0 ;
return GLib . SOURCE _REMOVE ;
} ) ;
}
_checkUpdates ( ) {
let nUpdates = this . _userList . get _children ( ) . filter ( c => c . hasUpdate ) . length ;
this . _updatesLabel . label = Gettext . ngettext (
'%d extension will be updated on next login.' ,
2020-02-04 12:51:57 -05:00
'%d extensions will be updated on next login.' ,
2019-11-30 09:20:04 -05:00
nUpdates ) . format ( nUpdates ) ;
this . _updatesBar . visible = nUpdates > 0 ;
}
2017-10-30 20:03:21 -04:00
_extensionsLoaded ( ) {
2019-11-30 02:08:05 -05:00
this . _userList . visible = this . _userList . get _children ( ) . length > 0 ;
this . _systemList . visible = this . _systemList . get _children ( ) . length > 0 ;
if ( this . _userList . visible || this . _systemList . visible )
2019-11-29 20:48:18 -05:00
this . _mainStack . visible _child _name = 'main' ;
2018-08-05 20:31:18 -04:00
else
this . _mainStack . visible _child _name = 'placeholder' ;
2019-11-30 09:20:04 -05:00
this . _checkUpdates ( ) ;
2018-11-01 08:50:30 -04:00
if ( this . _startupUuid )
this . _showPrefs ( this . _startupUuid ) ;
2013-02-28 08:50:56 -05:00
this . _startupUuid = null ;
2014-05-26 19:36:41 -04:00
this . _loaded = true ;
2017-10-30 21:19:44 -04:00
}
2019-05-28 17:22:37 -04:00
} ) ;
2012-01-18 21:21:56 -05:00
2018-08-05 22:15:12 -04:00
var Expander = GObject . registerClass ( {
Properties : {
'label' : GObject . ParamSpec . string (
'label' , 'label' , 'label' ,
GObject . ParamFlags . READWRITE ,
null
2019-08-20 17:43:54 -04:00
) ,
} ,
2018-08-05 22:15:12 -04:00
} , class Expander extends Gtk . Box {
_init ( params = { } ) {
this . _labelText = null ;
super . _init ( Object . assign ( params , {
orientation : Gtk . Orientation . VERTICAL ,
2019-08-20 17:43:54 -04:00
spacing : 0 ,
2018-08-05 22:15:12 -04:00
} ) ) ;
this . _frame = new Gtk . Frame ( {
shadow _type : Gtk . ShadowType . IN ,
2019-08-20 17:43:54 -04:00
hexpand : true ,
2018-08-05 22:15:12 -04:00
} ) ;
let eventBox = new Gtk . EventBox ( ) ;
this . _frame . add ( eventBox ) ;
let hbox = new Gtk . Box ( {
spacing : 6 ,
2019-08-20 17:43:54 -04:00
margin : 12 ,
2018-08-05 22:15:12 -04:00
} ) ;
eventBox . add ( hbox ) ;
this . _arrow = new Gtk . Image ( {
2019-08-20 17:43:54 -04:00
icon _name : 'pan-end-symbolic' ,
2018-08-05 22:15:12 -04:00
} ) ;
hbox . add ( this . _arrow ) ;
this . _label = new Gtk . Label ( { label : this . _labelText } ) ;
hbox . add ( this . _label ) ;
this . _revealer = new Gtk . Revealer ( ) ;
this . _childBin = new Gtk . Frame ( {
2019-08-20 17:43:54 -04:00
shadow _type : Gtk . ShadowType . IN ,
2018-08-05 22:15:12 -04:00
} ) ;
this . _revealer . add ( this . _childBin ) ;
// Directly chain up to parent for internal children
super . add ( this . _frame ) ;
super . add ( this . _revealer ) ;
let provider = new Gtk . CssProvider ( ) ;
provider . load _from _data ( '* { border-top-width: 0; }' ) ;
this . _childBin . get _style _context ( ) . add _provider (
provider ,
Gtk . STYLE _PROVIDER _PRIORITY _APPLICATION
) ;
this . _gesture = new Gtk . GestureMultiPress ( {
widget : this . _frame ,
button : 0 ,
2019-08-20 17:43:54 -04:00
exclusive : true ,
2018-08-05 22:15:12 -04:00
} ) ;
this . _gesture . connect ( 'released' , ( gesture , nPress ) => {
if ( nPress == 1 )
this . _revealer . reveal _child = ! this . _revealer . reveal _child ;
} ) ;
this . _revealer . connect ( 'notify::reveal-child' , ( ) => {
if ( this . _revealer . reveal _child )
this . _arrow . icon _name = 'pan-down-symbolic' ;
else
this . _arrow . icon _name = 'pan-end-symbolic' ;
} ) ;
}
get label ( ) {
return this . _labelText ;
}
set label ( text ) {
if ( this . _labelText == text )
return ;
if ( this . _label )
this . _label . label = text ;
this . _labelText = text ;
this . notify ( 'label' ) ;
}
add ( child ) {
// set expanded child
this . _childBin . get _children ( ) . forEach ( c => {
this . _childBin . remove ( c ) ;
} ) ;
if ( child )
this . _childBin . add ( child ) ;
}
} ) ;
2019-11-29 22:12:54 -05:00
var ExtensionRow = GObject . registerClass ( {
GTypeName : 'ExtensionRow' ,
Template : 'resource:///org/gnome/shell/ui/extension-row.ui' ,
InternalChildren : [
'nameLabel' ,
'descriptionLabel' ,
2019-11-30 12:11:03 -05:00
'versionLabel' ,
'authorLabel' ,
2019-11-30 09:20:04 -05:00
'updatesIcon' ,
2020-01-23 20:02:10 -05:00
'revealButton' ,
'revealer' ,
2019-11-29 22:12:54 -05:00
] ,
} , class ExtensionRow extends Gtk . ListBoxRow {
2018-11-01 08:50:30 -04:00
_init ( extension ) {
2017-10-30 21:23:39 -04:00
super . _init ( ) ;
2014-05-22 22:49:37 -04:00
2018-11-01 08:55:17 -04:00
this . _app = Gio . Application . get _default ( ) ;
2018-11-01 08:50:30 -04:00
this . _extension = extension ;
this . _prefsModule = null ;
2014-05-22 22:49:37 -04:00
2019-11-29 22:24:39 -05:00
this . _actionGroup = new Gio . SimpleActionGroup ( ) ;
this . insert _action _group ( 'row' , this . _actionGroup ) ;
2019-11-29 22:12:54 -05:00
2019-11-29 22:24:39 -05:00
let action ;
action = new Gio . SimpleAction ( {
name : 'show-prefs' ,
enabled : this . hasPrefs ,
} ) ;
action . connect ( 'activate' , ( ) => this . get _toplevel ( ) . openPrefs ( this . uuid ) ) ;
this . _actionGroup . add _action ( action ) ;
2019-11-29 22:12:54 -05:00
2019-11-30 12:11:03 -05:00
action = new Gio . SimpleAction ( {
name : 'show-url' ,
enabled : this . url !== '' ,
} ) ;
action . connect ( 'activate' , ( ) => {
Gio . AppInfo . launch _default _for _uri (
this . url , this . get _display ( ) . get _app _launch _context ( ) ) ;
} ) ;
this . _actionGroup . add _action ( action ) ;
2019-11-30 00:06:08 -05:00
action = new Gio . SimpleAction ( {
name : 'uninstall' ,
enabled : this . type === ExtensionType . PER _USER ,
} ) ;
action . connect ( 'activate' , ( ) => this . get _toplevel ( ) . uninstall ( this . uuid ) ) ;
this . _actionGroup . add _action ( action ) ;
2019-11-29 22:24:39 -05:00
action = new Gio . SimpleAction ( {
name : 'enabled' ,
state : new GLib . Variant ( 'b' , false ) ,
} ) ;
action . connect ( 'activate' , ( ) => {
let state = action . get _state ( ) ;
action . change _state ( new GLib . Variant ( 'b' , ! state . get _boolean ( ) ) ) ;
} ) ;
action . connect ( 'change-state' , ( a , state ) => {
if ( state . get _boolean ( ) )
2019-11-29 22:12:54 -05:00
this . _app . shellProxy . EnableExtensionRemote ( this . uuid ) ;
else
this . _app . shellProxy . DisableExtensionRemote ( this . uuid ) ;
} ) ;
2019-11-29 22:24:39 -05:00
this . _actionGroup . add _action ( action ) ;
2020-03-03 18:26:04 -05:00
this . _nameLabel . label = this . name ;
2019-11-29 22:24:39 -05:00
let desc = this . _extension . metadata . description . split ( '\n' ) [ 0 ] ;
this . _descriptionLabel . label = desc ;
2019-09-09 11:06:55 -04:00
2020-01-23 20:02:10 -05:00
this . _revealButton . connect ( 'clicked' , ( ) => {
this . _revealer . reveal _child = ! this . _revealer . reveal _child ;
} ) ;
this . _revealer . connect ( 'notify::reveal-child' , ( ) => {
if ( this . _revealer . reveal _child )
this . _revealButton . get _style _context ( ) . add _class ( 'expanded' ) ;
else
this . _revealButton . get _style _context ( ) . remove _class ( 'expanded' ) ;
} ) ;
2019-11-29 22:12:54 -05:00
this . connect ( 'destroy' , this . _onDestroy . bind ( this ) ) ;
2019-09-09 11:06:55 -04:00
2018-11-01 08:55:17 -04:00
this . _extensionStateChangedId = this . _app . shellProxy . connectSignal (
'ExtensionStateChanged' , ( p , sender , [ uuid , newState ] ) => {
if ( this . uuid !== uuid )
return ;
this . _extension = ExtensionUtils . deserializeExtension ( newState ) ;
2019-11-29 22:12:54 -05:00
this . _updateState ( ) ;
2017-10-30 20:38:18 -04:00
} ) ;
2019-11-29 22:12:54 -05:00
this . _updateState ( ) ;
2017-10-30 21:23:39 -04:00
}
2014-05-22 22:49:37 -04:00
2018-11-01 08:50:30 -04:00
get uuid ( ) {
return this . _extension . uuid ;
}
get name ( ) {
return this . _extension . metadata . name ;
}
get hasPrefs ( ) {
return this . _extension . hasPrefs ;
}
2014-05-22 22:49:37 -04:00
2019-11-30 09:20:04 -05:00
get hasUpdate ( ) {
return this . _extension . hasUpdate || false ;
}
2019-11-30 00:06:08 -05:00
get type ( ) {
return this . _extension . type ;
}
2019-11-30 12:11:03 -05:00
get creator ( ) {
return this . _extension . metadata . creator || '' ;
}
2018-11-01 08:50:30 -04:00
get url ( ) {
2019-11-30 12:11:03 -05:00
return this . _extension . metadata . url || '' ;
}
get version ( ) {
return this . _extension . metadata . version || '' ;
2018-11-01 08:50:30 -04:00
}
2019-11-29 22:12:54 -05:00
_updateState ( ) {
let state = this . _extension . state === ExtensionState . ENABLED ;
2019-11-29 22:24:39 -05:00
let action = this . _actionGroup . lookup ( 'enabled' ) ;
action . set _state ( new GLib . Variant ( 'b' , state ) ) ;
action . enabled = this . _canToggle ( ) ;
2019-11-30 12:11:03 -05:00
2019-11-30 09:20:04 -05:00
this . _updatesIcon . visible = this . hasUpdate ;
2020-02-19 13:25:35 -05:00
this . _versionLabel . label = this . version . toString ( ) ;
2019-11-30 12:11:03 -05:00
this . _versionLabel . visible = this . version !== '' ;
2020-02-19 13:25:35 -05:00
this . _authorLabel . label = this . creator . toString ( ) ;
2019-11-30 12:11:03 -05:00
this . _authorLabel . visible = this . creator !== '' ;
2019-11-29 22:12:54 -05:00
}
2018-11-01 08:55:17 -04:00
_onDestroy ( ) {
if ( ! this . _app . shellProxy )
return ;
if ( this . _extensionStateChangedId )
this . _app . shellProxy . disconnectSignal ( this . _extensionStateChangedId ) ;
this . _extensionStateChangedId = 0 ;
}
_canToggle ( ) {
return this . _extension . canChange ;
2014-05-22 22:49:37 -04:00
}
2018-11-01 08:50:30 -04:00
get prefsModule ( ) {
2019-11-30 13:15:14 -05:00
// give extension prefs access to their own extension object
ExtensionUtils . getCurrentExtension = ( ) => this . _extension ;
2018-11-01 08:50:30 -04:00
if ( ! this . _prefsModule ) {
ExtensionUtils . installImporter ( this . _extension ) ;
this . _prefsModule = this . _extension . imports . prefs ;
this . _prefsModule . init ( this . _extension . metadata ) ;
}
return this . _prefsModule ;
}
2014-05-22 22:49:37 -04:00
} ) ;
2012-01-18 21:21:56 -05:00
function initEnvironment ( ) {
// Monkey-patch in a "global" object that fakes some Shell utilities
// that ExtensionUtils depends on.
window . global = {
2019-02-12 06:24:30 -05:00
log ( ... args ) {
print ( args . join ( ', ' ) ) ;
2012-01-18 21:21:56 -05:00
} ,
2017-10-30 20:03:21 -04:00
logError ( s ) {
2020-02-14 10:10:34 -05:00
log ( 'ERROR: %s' . format ( s ) ) ;
2012-01-18 21:21:56 -05:00
} ,
2019-08-20 17:43:54 -04:00
userdatadir : GLib . build _filenamev ( [ GLib . get _user _data _dir ( ) , 'gnome-shell' ] ) ,
2012-01-18 21:21:56 -05:00
} ;
String . prototype . format = Format . format ;
}
function main ( argv ) {
initEnvironment ( ) ;
2019-05-28 17:22:37 -04:00
new Application ( ) . run ( argv ) ;
2012-01-18 21:21:56 -05:00
}