Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7b5f024531 | ||
|
|
7576883744 | ||
|
|
f7e32aabc5 | ||
|
|
757ab0096e | ||
|
|
2b10d99295 |
19
.gitignore
vendored
19
.gitignore
vendored
@@ -1,29 +1,18 @@
|
||||
ABOUT-NLS
|
||||
Makefile
|
||||
Makefile.in
|
||||
Makefile.in.in
|
||||
aclocal.m4
|
||||
autom4te.cache/
|
||||
config/
|
||||
configure
|
||||
config.log
|
||||
config.status
|
||||
data/*.json
|
||||
m4/
|
||||
po/*.header
|
||||
po/*.sed
|
||||
po/*.sin
|
||||
po/Makevars.template
|
||||
po/POTFILES
|
||||
po/Rules-quot
|
||||
aclocal.m4
|
||||
autom4te.cache/
|
||||
po/gnome-shell-extensions.pot
|
||||
po/POTFILES
|
||||
po/stamp-it
|
||||
staging/
|
||||
zip-files/
|
||||
|
||||
*~
|
||||
*.gmo
|
||||
metadata.json
|
||||
*.desktop
|
||||
*.gschema.xml
|
||||
*.gschema.valid
|
||||
*.session
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
image: fedora:latest
|
||||
|
||||
stages:
|
||||
- build
|
||||
|
||||
before_script:
|
||||
- dnf install -y meson gettext mozjs52-devel
|
||||
|
||||
build-shell-extensions:
|
||||
stage: build
|
||||
script:
|
||||
- meson _build .
|
||||
- ninja -C _build test install
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +0,0 @@
|
||||
[submodule "data/gnome-shell-sass"]
|
||||
path = data/gnome-shell-sass
|
||||
url = https://gitlab.gnome.org/GNOME/gnome-shell-sass.git
|
||||
3
COPYING
3
COPYING
@@ -1,7 +1,8 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc. <http://fsf.org>
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
31
HACKING
Normal file
31
HACKING
Normal file
@@ -0,0 +1,31 @@
|
||||
--- Creating a New Extension ---
|
||||
|
||||
To create a new extension, add a subdirectory in extensions.
|
||||
Then create a Makefile.am like the one in example, replacing
|
||||
the EXTENSION_ID with the basename of your extension, which
|
||||
must match the UUID in metadata.json.
|
||||
If you need additional files, add them to EXTENSION_EXTRA.
|
||||
|
||||
Then modify extensions/Makefile.am and configure.ac. It should
|
||||
be pretty self-explanatory.
|
||||
|
||||
Don't forget to add any translatable file to po/POTFILES.in, and
|
||||
then you're done.
|
||||
The Gettext domain you should choose is gnome-shell-extensions,
|
||||
not gnome-shell, unless you're sure there is the string you
|
||||
need in gnome-shell.
|
||||
|
||||
--- Coding Style ---
|
||||
|
||||
Generally, we follow GJS coding style (you can find it at
|
||||
http://git.gnome.org/browse/gjs/tree/doc/Style_Guide.txt), which
|
||||
in short is: indent 4 spaces, no tabs, space after comma, no space
|
||||
after function call.
|
||||
|
||||
The Emacs mode line for this
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
Imports should be at the top, in two groups, one for standard
|
||||
imports (like imports.lang or imports.dbus) and introspection,
|
||||
the other for Shell API. Within the same group, put everything
|
||||
in alphabetic order.
|
||||
31
HACKING.md
31
HACKING.md
@@ -1,31 +0,0 @@
|
||||
## Creating a New Extension
|
||||
|
||||
To create a new extension, add a subdirectory in extensions. Then create
|
||||
a meson.build from the provided [template](extensions/meson.build.template).
|
||||
If you need additional sources, add them to extension_sources. Similarily add
|
||||
GSettings schemas to extension_schemas and other files to extension_data.
|
||||
|
||||
Then modify the [toplevel Meson file](meson.build) to add the new
|
||||
extension name in the appropriate set (that is one of classic_extensions,
|
||||
default_extensions or all_extensions).
|
||||
|
||||
Don't forget to add any translatable file to po/POTFILES.in, and
|
||||
then you're done.
|
||||
The Gettext domain you should choose is gnome-shell-extensions,
|
||||
not gnome-shell, unless you're sure there is the string you
|
||||
need in gnome-shell.
|
||||
|
||||
## Coding Style
|
||||
|
||||
Generally, we follow [GJS coding style][coding-style], which in short is:
|
||||
indent 4 spaces, no tabs, space after comma, no space after function call.
|
||||
|
||||
The Emacs mode line for this
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
Imports should be at the top, in two groups, one for standard
|
||||
imports (like imports.lang or imports.dbus) and introspection,
|
||||
the other for Shell API. Within the same group, put everything
|
||||
in alphabetic order.
|
||||
|
||||
[coding-style]: https://gitlab.gnome.org/GNOME/gjs/blob/master/doc/Style_Guide.md
|
||||
5
Makefile.am
Normal file
5
Makefile.am
Normal file
@@ -0,0 +1,5 @@
|
||||
ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
|
||||
|
||||
SUBDIRS = extensions po
|
||||
|
||||
DISTCHECK_CONFIGURE_FLAGS = --enable-extensions=all
|
||||
773
NEWS
773
NEWS
@@ -1,773 +0,0 @@
|
||||
3.29.2
|
||||
======
|
||||
* Misc. bug fixes [Florian; #69]
|
||||
|
||||
Contributors:
|
||||
Florian Müllner
|
||||
|
||||
3.28.1
|
||||
======
|
||||
* Misc. bug fixes [Xiaoguang, Florian; #59, #62]
|
||||
|
||||
Contributors:
|
||||
Florian Müllner, Xiaoguang Wang
|
||||
|
||||
Translators:
|
||||
Dz Chen [zh_CN]
|
||||
|
||||
3.28.0
|
||||
======
|
||||
|
||||
Contributors:
|
||||
Florian Müllner, Xiaoguang Wang
|
||||
|
||||
Translators:
|
||||
Aman Alam [pa], Bruce Cowan [en_GB]
|
||||
|
||||
3.27.92
|
||||
=======
|
||||
|
||||
Contributors:
|
||||
Florian Müllner
|
||||
|
||||
Translators:
|
||||
Piotr Drąg [es], GNOME Translation Robot [gd], Daniel Șerbănescu [ro]
|
||||
|
||||
3.27.91
|
||||
=======
|
||||
* places-menu: Support unmounting ejectable places [Rémy; #17]
|
||||
* apps-menu: Support separators and custom sort order [Florian; #27]
|
||||
* Port to meson [Florian; #31, #45]
|
||||
* window-list: Fix missing icons on wayland [Florian; #10]
|
||||
* places-menu: Fix terminating gnome-shell with recent gjs [Florian; #44]
|
||||
* auto-move: Make it work with wayland windows [Florian; #33]
|
||||
* Classic theme fixes [Florian, Jonas; #26, #41, #39, #40]
|
||||
* Require sassc for classic styling [Florian; !28]
|
||||
* Misc. bug fixes [Piotr, Florian; #772211, #32, #30]
|
||||
|
||||
Contributors:
|
||||
Jeremy Bicha, Piotr Drąg, Jonas Kümmerlin, Rémy Lefevre, Iñigo Martínez,
|
||||
Florian Müllner
|
||||
|
||||
Translators:
|
||||
Matej Urbančič [sl], Kjartan Maraas [nb]
|
||||
|
||||
3.27.1
|
||||
======
|
||||
* updated translations (ca@valencia)
|
||||
|
||||
3.26.1
|
||||
======
|
||||
* native-window-placement: Adjust to gnome-shell changes
|
||||
* updated translations: el, fa, ru, sv
|
||||
|
||||
3.26.0
|
||||
======
|
||||
* updated translations (be, bg, ca, da, eu, fi, is, it, ko, lv, ml,
|
||||
nl, pt_BR, vi, zh_TW)
|
||||
|
||||
3.25.91
|
||||
=======
|
||||
* updated translations (ca, fr, it, pl, pt_BR, sr, sr@latin, tr)
|
||||
|
||||
3.25.90
|
||||
=======
|
||||
* updated translations (es, gl, hr, hu, kk, sl, sv, sv)
|
||||
|
||||
3.25.4
|
||||
======
|
||||
* screenshot-window-sizer: Fix backward cycling
|
||||
* updated translations (ar, be, ca, cs, de, fur, id, lt, pl, sk)
|
||||
|
||||
3.25.3
|
||||
======
|
||||
* places-menu: Use mount operation if necessary
|
||||
* window-list: Respect MWM hints
|
||||
* updated translations (es, fur, kk)
|
||||
|
||||
3.25.2
|
||||
======
|
||||
* places-menu: Make URI launching asynchronous
|
||||
* updated translations (de, fur, hr, hu, id, sl)
|
||||
|
||||
3.25.1
|
||||
======
|
||||
* apps-menu: Mark copied launchers as trusted
|
||||
* places-menu: Make icon lookup asynchronous
|
||||
* updated translations (hr)
|
||||
|
||||
3.24.1
|
||||
======
|
||||
* apps-menu: Allow creating desktop launchers via DND
|
||||
* updated translations (el, vi)
|
||||
|
||||
3.24.0
|
||||
======
|
||||
* updated translations (lv, tr)
|
||||
|
||||
3.23.92
|
||||
=======
|
||||
* update classic theme
|
||||
* updated translations (be, ko, ca, da, cs, ru, lt)
|
||||
|
||||
3.23.91
|
||||
=======
|
||||
* updated translations (de, es, eu, fi, fr, fur, gl, hu, id, it, kk, nb, pl, pt_BR,
|
||||
sk, sr, sr@latin, sv, uk, zh_TW)
|
||||
|
||||
3.23.90
|
||||
=======
|
||||
* window-list: Improve styling
|
||||
* window-list: Hide workspace indicator when there's a single (static) workspace
|
||||
* new translation (be)
|
||||
|
||||
3.23.2
|
||||
======
|
||||
* alternateTab: Don't take over 'switch-group' shortcut
|
||||
* updated translations (zh_CN)
|
||||
|
||||
3.22.1
|
||||
======
|
||||
* window-list: Update icon on app changes
|
||||
|
||||
3.22.0
|
||||
======
|
||||
* updated translations (en_GB)
|
||||
|
||||
3.21.92
|
||||
=======
|
||||
* update style
|
||||
* updated translations (pl, vi)
|
||||
|
||||
3.21.91
|
||||
=======
|
||||
* updated translations (pl)
|
||||
|
||||
3.21.90
|
||||
=======
|
||||
* updated translations (es, gu)
|
||||
|
||||
3.21.4
|
||||
======
|
||||
* apps-menu: Fix entries from non-standard AppDir directories
|
||||
|
||||
3.21.3
|
||||
======
|
||||
* adjust to gnome-shell changes
|
||||
* updated translations (oc)
|
||||
|
||||
3.21.2
|
||||
======
|
||||
* version bump, nothing to see here
|
||||
|
||||
3.20.1
|
||||
======
|
||||
* update classic style
|
||||
* updated translations (gd, oc)
|
||||
|
||||
3.20.0
|
||||
======
|
||||
* version bump, nothing to see here
|
||||
|
||||
3.19.92
|
||||
=======
|
||||
* version bump, nothing to see here
|
||||
|
||||
3.19.91
|
||||
=======
|
||||
* updated translations (oc)
|
||||
|
||||
3.19.90
|
||||
=======
|
||||
* version bump, nothing to see here
|
||||
|
||||
3.19.4
|
||||
======
|
||||
* screenshot-window-sizer: HiDPI support
|
||||
* Fix gnome-shell component in classic session
|
||||
* updated translations (lt)
|
||||
|
||||
3.19.3
|
||||
======
|
||||
* native-window-placement: Don't let border overlap title
|
||||
* apps-menu: Fix handling of .desktop files in subdirectories
|
||||
* updated translations (is)
|
||||
|
||||
3.19.2
|
||||
======
|
||||
* updated translations (gd)
|
||||
|
||||
3.19.1
|
||||
======
|
||||
* Fix some theme issues
|
||||
|
||||
3.18.1
|
||||
======
|
||||
* window-list: Fix accessibility of window buttons
|
||||
* apps-menu: Fix unreliable highlight
|
||||
* updated translations (ar)
|
||||
|
||||
3.18.0
|
||||
======
|
||||
* Bump version
|
||||
|
||||
3.17.92
|
||||
=======
|
||||
* places: Include DESKTOP when desktop icons are enabled
|
||||
* updated translations (fa)
|
||||
|
||||
3.17.91
|
||||
=======
|
||||
* updated translations (nl, pl, zh_TW)
|
||||
|
||||
3.17.90
|
||||
=======
|
||||
* window-list: Improve application ordering
|
||||
* workspace-indicator: Use consistent workspace numbering
|
||||
|
||||
3.17.4
|
||||
======
|
||||
* updated translations (fur)
|
||||
|
||||
3.17.3
|
||||
======
|
||||
* window-list: Adjust with text-scaling-factor
|
||||
* classic style updates
|
||||
* updated translations (pt, ro)
|
||||
|
||||
3.17.2
|
||||
======
|
||||
* updated translations (oc, pt, zh_CN)
|
||||
|
||||
3.17.1
|
||||
======
|
||||
* style updates
|
||||
* updated translations (oc)
|
||||
|
||||
3.16.1
|
||||
======
|
||||
* window-list: Fix workspace indicators popup menu position
|
||||
* apps-menu: Fix taking over panel-main-menu shortcut
|
||||
* updated translations (et, ja, lv)
|
||||
|
||||
3.16.0
|
||||
======
|
||||
* updated translations (ca)
|
||||
|
||||
3.15.92
|
||||
=======
|
||||
* classic: Update theme
|
||||
* update for mutter API changes
|
||||
* updated translations (bg, bs, da, fi, pa, ru, sr, sr@latin, tg)
|
||||
|
||||
3.15.91
|
||||
=======
|
||||
* classic: Update theme
|
||||
* systemMonitor extension was removed, as the message tray where it
|
||||
put its indicator no longer exists
|
||||
* window-list: Adjust for gnome-shell changes
|
||||
* updated translations (gl, it, kk, ko, lt, pl, sk, uk, zh_TW)
|
||||
|
||||
3.15.90
|
||||
=======
|
||||
* classic: Visual refresh based on new shell theme
|
||||
* window-list: Adjust for gnome-shell changes
|
||||
* updated translations (an, el, eo, eu, fr, he, is, sv, tr)
|
||||
|
||||
3.15.4
|
||||
======
|
||||
* window-list: Improve interaction with system modal dialogs
|
||||
* updated translations (cs, de, es, eu, fur, hu, id, nb, pt_BR, ru, sl, vi)
|
||||
|
||||
3.15.3.1
|
||||
========
|
||||
* adjust to gnome-shell change
|
||||
|
||||
3.15.3
|
||||
======
|
||||
* classic-mode: Add high-contrast theme variant, drop .desktop file
|
||||
* places-menu: Fix error when XDG user directories are not set up
|
||||
* window-list: Add option to show on all monitors
|
||||
* updated translations (eu, hu, kk, ro, tr)
|
||||
|
||||
3.15.2
|
||||
======
|
||||
* removable-drive, user-theme, window-list: Update for gnome-shell changes
|
||||
* apps-menu: Fix some visual glitches
|
||||
* Fix classic mode style
|
||||
* updated translations (an, cs, he, vi)
|
||||
|
||||
3.15.1
|
||||
======
|
||||
* updated translations (es, nb)
|
||||
|
||||
3.14.1
|
||||
======
|
||||
* alternateTab: Fix dismissing popup with Escape
|
||||
* some improvements to the window-list
|
||||
(spacing in app buttons, no flash when closing windows with auto-grouping)
|
||||
* updated translations (lv, it, pt, bg)
|
||||
|
||||
3.14.0
|
||||
======
|
||||
* updated translations (bn_IN, hi, kn, sr, sr@latin, uk)
|
||||
|
||||
3.13.92
|
||||
=======
|
||||
* new extension: screenshot-window-sizer
|
||||
* window-list: Don't add sticky windows more than once
|
||||
* updated translations (da, de, fi, ko, mr, ms, ne, pa, pl, sk, sv, ta, te, tr)
|
||||
|
||||
3.13.91
|
||||
=======
|
||||
* window-list: restore fitts'ability of workspace button
|
||||
* updated for gnome-shell changes
|
||||
* updated translations (cs, kk, fr, or, fa, ja, gu, id)
|
||||
|
||||
3.13.90
|
||||
=======
|
||||
* updated translations (as, ca, eu, nl, zh_CN, zh_HK, zh_TW)
|
||||
|
||||
3.13.4
|
||||
======
|
||||
* Updated for gnome-shell changes
|
||||
* updated translations (el, gl, ru)
|
||||
|
||||
3.13.3
|
||||
======
|
||||
* Tweak preference UIs some more
|
||||
* Fix classic mode schema overrides
|
||||
* updated translations (es, he, hu, lt, nb, pt_BR, sl, tr)
|
||||
|
||||
3.13.2
|
||||
======
|
||||
* Fix sorting of grouped buttons in window list
|
||||
* Tweak preference UIs
|
||||
* updated translations (en_GB)
|
||||
|
||||
3.13.1
|
||||
======
|
||||
* add DesktopNames key to the classic session file
|
||||
* classic theme: remove rounded corners from tile previews
|
||||
* window-list: don't shift message tray on other monitors
|
||||
* auto-move-windows: several fixes and updates for api changes
|
||||
* launch-new-instances: updates for api changes
|
||||
* updated translations (ja, km)
|
||||
|
||||
3.12.0
|
||||
======
|
||||
* updated translations (zh_HK, zh_TW)
|
||||
|
||||
3.11.92
|
||||
=======
|
||||
* nothing to see here, move on
|
||||
|
||||
3.11.91
|
||||
=======
|
||||
* updated translations (ko, fur)
|
||||
|
||||
3.11.90
|
||||
=======
|
||||
* several fixes and improvements to the window-list
|
||||
(can be scrolled, works correctly with the OSD
|
||||
keyboard, filters skip-taskbar windows, does not
|
||||
force all notifications to bold)
|
||||
* drive-menu fixed not to show shadowed mounts
|
||||
* updates for gnome-shell changes (launch-new-instance,
|
||||
auto-move-windows, places-menu)
|
||||
* build system fixes for systems without /bin/bash
|
||||
* updated translations (or, tr, uk)
|
||||
|
||||
3.11.5
|
||||
======
|
||||
* updates for gnome-shell changes
|
||||
* updated translations (kn)
|
||||
|
||||
3.11.4
|
||||
======
|
||||
* classic mode now supports session saving
|
||||
* updates for gnome-shell changes
|
||||
* updated translations (ar, kn)
|
||||
|
||||
3.11.3
|
||||
======
|
||||
* workspace-indicator is vertically aligned now
|
||||
* updated translations (ar, eo, ta, te)
|
||||
|
||||
3.11.2
|
||||
======
|
||||
* updated translations (zh_CN)
|
||||
|
||||
3.11.1
|
||||
======
|
||||
* ignore shadowed mounts in drive-menu extension
|
||||
* updates for gnome-shell/gjs changes
|
||||
* updated translations (el, th)
|
||||
|
||||
3.10.1
|
||||
======
|
||||
* updated translations (af, ca, ca@valencia, de, et, eu, fa,
|
||||
hu, lt, lv, nb, nl, pa, pt, sk, sr, sr@latin, tr)
|
||||
|
||||
3.10.0
|
||||
======
|
||||
* updated translations (as, cs, da, es, et, fi, fr, gl,
|
||||
he, id, it, kk, lt, lv, pa, pl, pt, pt_BR, ru, sl, tg,
|
||||
uk, zh_HK, zh_TW)
|
||||
|
||||
3.9.92
|
||||
======
|
||||
* more updates and fixes for gnome-shell master changes
|
||||
and regressions (systemMonitor, window-list, apps-menu)
|
||||
* lots of updated translations (ar, as, cs, da, de, el, es,
|
||||
eu, fi, gl, he, hu, it, ja, kk, ko, lv, nb, nl, pa, pl,
|
||||
pt_BR, ru, sk, sr, sr@latin, ta, tg)
|
||||
|
||||
3.9.91
|
||||
======
|
||||
* update the classic mode session and theme to work with the
|
||||
new system menu
|
||||
* the usual round of updates and fixes for gnome-shell
|
||||
API changes
|
||||
* updated translations (de, it, lt, nl, pl, pt_BR, sk,
|
||||
zh_HK, zh_TW)
|
||||
|
||||
3.9.90
|
||||
======
|
||||
* xrandr-indicator was removed, as the implementation
|
||||
was incompatible with the new DisplayConfig mutter API
|
||||
* various extensions were updated for the 3.9.90 gnome-shell API
|
||||
* updated translations (cs, es, fur, gl, he, hu, id, ja, sl, tg,
|
||||
zh_CN, zh_HK, zh_TW)
|
||||
|
||||
3.9.5
|
||||
=====
|
||||
* alternative-status-menu was removed entirely, as
|
||||
it does not fit in the designs of the new unified
|
||||
status menu
|
||||
* updated translations (as, gu, it, ru)
|
||||
|
||||
3.9.4
|
||||
=====
|
||||
* apps-menu: fixed handling of hot corner in case
|
||||
of screen reconfiguration
|
||||
* alternative-status-menu now correctly honors polkit
|
||||
for hibernation
|
||||
* user-menu now loads themes from $XDG_DATA_HOME too
|
||||
* translation updates (de, id, pt_BR, vi, zh_CN, ml)
|
||||
|
||||
3.9.3
|
||||
=====
|
||||
* classic mode mini extensions were replaced with a
|
||||
GSettings override specified in the .json file
|
||||
* styling of classic mode improved
|
||||
* native-window-placement is back working on 3.9
|
||||
* misc bug fixes
|
||||
* traslation updates (an, cs, el, es, gl, nb, pl, sk, tg)
|
||||
|
||||
3.9.2
|
||||
=====
|
||||
* apps-menu: appearance of the scrollbars was improved
|
||||
* window-list is a little taller in classic mode (to account
|
||||
for the workspace switcher)
|
||||
* alternative-status-menu honors again the dconf configuration
|
||||
* translation updates (sr)
|
||||
|
||||
3.9.1
|
||||
=====
|
||||
* updates to window-list, xrandr-indicator,
|
||||
workspace-indicator, windowsNavigator for gnome-shell
|
||||
changes
|
||||
* translation updates (cs, es, lt, pl, pt_BR, sl)
|
||||
|
||||
3.8.1
|
||||
=====
|
||||
* many improvements to window-list:
|
||||
- windows are activated by DND over them
|
||||
- window buttons now have the right size,
|
||||
even if the text is smaller or larger
|
||||
than the ideal
|
||||
- window buttons can be grouped automatically
|
||||
when the panel becomes crowded
|
||||
- added a workspace switcher menu
|
||||
* added keyboard navigation to apps-menu
|
||||
* small tweaks to classic-mode theme, in particular
|
||||
for menus
|
||||
* translation updates (gl, ko, sr)
|
||||
|
||||
3.8.0
|
||||
=====
|
||||
* translation updates (hu, ja, fi, it)
|
||||
|
||||
3.7.92
|
||||
======
|
||||
* misc bug fixes to app-menu and window-list
|
||||
* translation updates (de, sl, pt_BR, ru)
|
||||
|
||||
3.7.91
|
||||
======
|
||||
* various updates for shell changes
|
||||
* update window-list to always use application icons
|
||||
* update apps-menu to not load subdirectories as
|
||||
separate categories
|
||||
* translation updates (lt, zh_CN)
|
||||
|
||||
3.7.90
|
||||
======
|
||||
* various fixes to make places-menu behave more
|
||||
like Nautilus, including showing the machine
|
||||
name in place of File System
|
||||
* various updates for shell changes
|
||||
* alternative-status-menu no longer supports
|
||||
ConsoleKit systems, you need to install logind
|
||||
to have suspend or hibernate
|
||||
* translation updates (es, cz, pl, sr)
|
||||
|
||||
3.7.5.1
|
||||
=======
|
||||
* new extension forgotten in previous NEWS entry:
|
||||
windows-list
|
||||
* also forgotten previously: classic mode got a new
|
||||
GNOME2 style
|
||||
* build fixes
|
||||
|
||||
3.7.5
|
||||
=====
|
||||
* places-menu is back in the classic extensions, with
|
||||
a new old GNOME-2 look
|
||||
* classic mode moved the date menu to right, where we
|
||||
all know it rightly belongs
|
||||
* apps-menu received a face-lift, with the inclusion
|
||||
of a reduced form of AxeMenu
|
||||
* new extension in the classic set: launch-new-instance,
|
||||
which modifies the behavior of clicking in the dash
|
||||
and app launcher
|
||||
* alternate-tab, native-window-placement and windowsNavigator
|
||||
updated for gnome-shell changes
|
||||
* translation updates (es, cz, pl)
|
||||
|
||||
3.7.4
|
||||
=====
|
||||
* a separate configure switch has been added to enable
|
||||
classic mode session definitions
|
||||
* places-menu is no longer part of the classic-mode
|
||||
extension set
|
||||
* updated translations (ar, gl, hu, lt, pt_BR, sr)
|
||||
|
||||
3.7.3
|
||||
=====
|
||||
* new extensions: default-min-max, static-workspaces
|
||||
* alternate-tab now uses the built-in window switcher and just
|
||||
takes over the switch-application keybinding
|
||||
* workspace-indicator: is no longer part of classic-mode
|
||||
* we now install classic-mode data files for gdm, gnome-session
|
||||
and gnome-shell, so if you enable classic-mode you get a new
|
||||
session option in GDM
|
||||
* updated translations (ar, es, pl, ru, sl, zh_HK, zh_TW)
|
||||
|
||||
3.7.2
|
||||
=====
|
||||
* fixed crashes with places-menu, windowsNavigator, alternate-tab
|
||||
and native-window-placement
|
||||
* alternate-tab now hides attached modal dialogs
|
||||
* places-menu has restored support for Nautilus 3.4
|
||||
* the default for hibernate is now to show in alternative-status-menu
|
||||
* some extensions are now tagged as "classic", and can be chosen with
|
||||
--enable-extensions=classic-mode
|
||||
* dock and gajim were removed at the beginning of the 3.7.1 cycle,
|
||||
as they were buggy and unmaintained
|
||||
* updated translations (ar, cs, de, el, es, gl, id, lt, lv, pa, pl
|
||||
ru, sk, sl, sr, sr@latin)
|
||||
|
||||
3.6.1
|
||||
=====
|
||||
* fixed alternative-status-menu for the new lock screen
|
||||
* squashed some alternate-tab warnings
|
||||
* drive-menu now works with 3.6 again
|
||||
* updated translations (ar, cs, el, es, gl, id, lv, pl, sl)
|
||||
|
||||
3.6.0
|
||||
=====
|
||||
* major rework in places menu, to make it work without
|
||||
removed supporting code in the shell and to make it look like
|
||||
the nautilus sidebar
|
||||
(similar work would be needed for drive-menu, not done yet)
|
||||
* updated translations (ca, cs, de, el, en_GB, es, fi, hu, id, lt,
|
||||
pl, pt_BR, ru, sl, sr)
|
||||
|
||||
3.5.91
|
||||
======
|
||||
* various crashers were fixed in alternative-tab
|
||||
* auto-move-windows now can be made to work with static workspaces
|
||||
* place-menu is now on the left and uses symbolic icons like Files
|
||||
* StIconType usage was removed from all extensions, after it was
|
||||
removed in core
|
||||
* systemMonitor, xrandr-indicator, apps-menu, places-menu,
|
||||
alternative-status-menu were updated for the newer shell
|
||||
* updated translations (es, gl, it, pl, sl)
|
||||
|
||||
3.5.90
|
||||
======
|
||||
* alternate-tab has been reworked again, the old mode switch
|
||||
was removed and the all&thumbnails code extended to handle
|
||||
icons and filtering to the workspace
|
||||
* alternate-tab thumbnails now reflect the aspect ratio of the windows
|
||||
* systemMonitor now shows a tooltip above the indicator
|
||||
* native-window-placement, systemMonitor and windowsNavigator have been updated
|
||||
for the newer shell
|
||||
* updated translations (es, pa)
|
||||
|
||||
3.5.5
|
||||
=====
|
||||
* convenience module has been relicensed to BSD,
|
||||
for compatibility with GPLv3 extensions
|
||||
* alternate-tab has been refactored and seen various
|
||||
improvements to all&thumbnails mode, including a new
|
||||
overlaid application icon
|
||||
* updated translations (lt, id, sr)
|
||||
|
||||
3.5.4
|
||||
=====
|
||||
* updated translations (de, es, ar, sl, lv, zh_CN)
|
||||
|
||||
3.5.2
|
||||
=====
|
||||
* removable-drive-menu is now a11y friendly
|
||||
* the dock can now be placed on any monitor, not just the primary
|
||||
* dock is now clipped to its monitor
|
||||
* alternative-status-menu now exposes GSettings for Suspend
|
||||
and Hibernate visibility - no UI yet
|
||||
* more gnome-shell API changes (places-menu, removable-drive-menu,
|
||||
alternative-status-menu)
|
||||
* miscellaneous bug fixes (native-window-placement, gajim,
|
||||
auto-move-windows)
|
||||
* updated translations
|
||||
|
||||
3.4.0
|
||||
=====
|
||||
* build system improvements
|
||||
* updated translations (ar, cs, fr)
|
||||
|
||||
3.3.92
|
||||
======
|
||||
* various updates for gnome-shell API changes (dock,
|
||||
native-window-placement)
|
||||
* local-install is now a make rule, not a shell script
|
||||
* updated translations (zh, es, sw, ga, hu, it, no, pt_BR, de, sl,
|
||||
pl, la, fi, sr)
|
||||
|
||||
3.3.90
|
||||
======
|
||||
* system wide installation via "make install" is possible
|
||||
again
|
||||
* alternate-tab can now pre-activate the selected window
|
||||
* auto-move-windows, workspace-indicator and example gained
|
||||
new preference dialogs
|
||||
* workspace-indicator: fixed a bug wrt focus stealing prevention
|
||||
* updated translations (es, pt_BR, it, sl, gl, sr)
|
||||
|
||||
3.3.5
|
||||
=====
|
||||
* improvements to the build system and convenience module,
|
||||
making it easier for other extensions to use, and bringing
|
||||
it up to date with gnome-shell changes
|
||||
* all extensions were ported to the Lang.Class framework
|
||||
(except xrandr-indicator, which is pending GDBus merge)
|
||||
* alternate-tab and dock were slightly refactored to clean up
|
||||
some old code
|
||||
|
||||
3.3.4
|
||||
=====
|
||||
* improved styling of windowsNavigator tooltips
|
||||
* fixed windowsNavigator when used with the numeric keypad
|
||||
* fixed native-window-placement with custom button layout
|
||||
* updated translations (pt_BR, cz)
|
||||
|
||||
3.3.3
|
||||
=====
|
||||
* windowsNavigator was fixed to work with azerty keyboards
|
||||
* drive-menu was changed to use media-eject icon instead of media-optical
|
||||
* dock: the default value of hide-effect is now move
|
||||
* dock: if autohide is disabled, now it pushes maximized windows aside
|
||||
* dock was updated to match current core shell styling
|
||||
* native-window-placement: position stategy setting was removed
|
||||
* alternative-status-menu no longer conflicts with other extensions
|
||||
in the user menu
|
||||
* various other minor bug fixes
|
||||
* updated translations (zh, uk, es, it, cz, sl, sk, fi)
|
||||
|
||||
3.3.2
|
||||
=====
|
||||
* all extensions are now self-contained, including l10n and settings
|
||||
* introduce a convenience module that can be shared among all extensions
|
||||
* you can know build an installable zip file with make zip-file
|
||||
* apps-menu no longer shows NoDisplay apps
|
||||
* alternative-status-menu, alternate-tab: fix for master shell
|
||||
|
||||
3.2.1
|
||||
=====
|
||||
* dock: added "move" hide effect
|
||||
* systemMonitor: now it enables/disables properly
|
||||
* systemMonitor: improved styling
|
||||
* alternate-tab: both modes now work with gnome-shell 3.2
|
||||
* various other bug fixes
|
||||
* updated translations
|
||||
|
||||
3.2.0
|
||||
=====
|
||||
|
||||
* various: update for gnome-shell API changes
|
||||
|
||||
3.1.91
|
||||
======
|
||||
|
||||
* gajim: update for gnome-shell API changes
|
||||
|
||||
3.1.90
|
||||
======
|
||||
|
||||
* All extensions have been ported to the new extension
|
||||
system (including live enable/disable)
|
||||
* Updated translations
|
||||
* xrandr-indicator no longer requires a specific gjs version
|
||||
* windowsNavigator fixed for more than 2 workspaces
|
||||
|
||||
3.1.4
|
||||
=====
|
||||
|
||||
* New extension: a menu for changing workspace (workspace-indicator)
|
||||
* systemMonitor: lower the requirement on libgtop
|
||||
* auto-move-windows: open overview when last window on
|
||||
last workspace is closed
|
||||
* dock: implement autohiding, with various configurable
|
||||
effects
|
||||
* alternate-tab: more configurable implementations available
|
||||
* native-window-placement: don't rearrange the windows when
|
||||
the workspace switcher is shown/hidden
|
||||
* update for gnome-shell 3.1.4 API changes
|
||||
|
||||
3.1.3
|
||||
=====
|
||||
|
||||
* New extension: a menu for removable drives (drive-menu
|
||||
* New extensions: GNOME 2 like menus for apps and places
|
||||
(apps-menu, places-menu)
|
||||
* New extension: additional configurability for the window
|
||||
layout in the overview, including a mechanism similar to
|
||||
KDE4 (native-window-placement)
|
||||
* New extension: a message tray indicator for CPU and memory
|
||||
usage (uses libgtop) (systemMonitor)
|
||||
* user-theme: fixed resetting theme
|
||||
* user-theme: support themes installed in /usr/share/themes
|
||||
* alternative-status-menu: ported to gnome-shell master
|
||||
* dock: ported to gnome-shell master
|
||||
* dock: make position configurable (can be left or right)
|
||||
* Updated translations
|
||||
|
||||
3.0.2
|
||||
=====
|
||||
|
||||
* Updated translations.
|
||||
* Fixed bug #647386 (reverting of user-theme to default)
|
||||
* Fixed bug #647599 (support globally installed themes)
|
||||
* Added license and README
|
||||
71
README
Normal file
71
README
Normal file
@@ -0,0 +1,71 @@
|
||||
GNOME Shell Extensions is a collection of extensions providing additional
|
||||
and optional functionality to GNOME Shell.
|
||||
Since GNOME Shell is not API stable, extensions work only against a very
|
||||
specific version of the shell, usually the same as this package (see
|
||||
"configure --version"). Also, since extensions are built from many
|
||||
individual contributors, we cannot guarantee stability or quality for any
|
||||
specific extension.
|
||||
For these reasons, distributions are advised to avoid installing or packaging
|
||||
this module by defaul.
|
||||
|
||||
For more information about GNOME Shell Extensions
|
||||
http://live.gnome.org/GnomeShell/Extensions
|
||||
|
||||
For general information about GNOME Shell
|
||||
http://live.gnome.org/GnomeShell
|
||||
|
||||
Bugs should be reported at http://bugzilla.gnome.org against the 'gnome-shell'
|
||||
product, with the 'extensions' component.
|
||||
|
||||
Extensions
|
||||
==========
|
||||
|
||||
alternate-tab
|
||||
|
||||
Lets you use classic Alt+Tab (window-based instead of app-based) in GNOME Shell.
|
||||
|
||||
alternative-status-menu
|
||||
|
||||
For those who want a power off item visible at all the time, replaces GNOME Shell
|
||||
status menu with one featuring separate Suspend and Power Off. Adds the ability to
|
||||
hibernate as well.
|
||||
|
||||
auto-move-windows
|
||||
|
||||
Lets you manage your workspaces more easily, assigning a specific workspace to
|
||||
each application as soon as it creates a window, in a manner configurable with a
|
||||
GSettings key.
|
||||
|
||||
dock
|
||||
|
||||
Shows a dock-style task switcher on the right side of the screen.
|
||||
|
||||
example
|
||||
|
||||
A minimal example illustrating how to write extensions.
|
||||
|
||||
gajim
|
||||
|
||||
Integration with Gajim, a Jabber/XMPP instant messaging client.
|
||||
|
||||
user-theme
|
||||
|
||||
Loads a shell theme from ~/.themes/<name>/gnome-shell.
|
||||
|
||||
windowsNavigator
|
||||
|
||||
Allow keyboard selection of windows and workspaces in overlay mode.
|
||||
|
||||
xrandr-indicator
|
||||
|
||||
Replace the GTK+ based indicator from gnome-settings-daemon with
|
||||
a native one. Lets the user rotate the laptop monitor and open
|
||||
display preferences quickly.
|
||||
|
||||
License
|
||||
=======
|
||||
GNOME Shell Extensions are distributed under the terms of the GNU General Public License,
|
||||
version 2 or later. See the COPYING file for details.
|
||||
Individual extensions may be licensed under different terms, see each source
|
||||
file for details.
|
||||
|
||||
84
README.md
84
README.md
@@ -1,84 +0,0 @@
|
||||
# GNOME Shell Extensions
|
||||
|
||||
GNOME Shell Extensions is a collection of extensions providing additional
|
||||
and optional functionality to GNOME Shell.
|
||||
|
||||
Since GNOME Shell is not API stable, extensions work only against a very
|
||||
specific version of the shell, usually the same as this package (see
|
||||
"configure --version"). The extensions in this package are supported by GNOME
|
||||
and will be updated to reflect future API changes in GNOME Shell.
|
||||
|
||||
The GNOME wiki has more information about [GNOME Shell Extensions][project-page],
|
||||
as well as some general information about [GNOME Shell][shell-page].
|
||||
|
||||
Bugs should be reported to the GNOME [bug tracking system][bug-tracker].
|
||||
|
||||
## Extensions
|
||||
|
||||
* alternate-tab
|
||||
|
||||
Lets you use classic Alt+Tab (window-based instead of app-based) in GNOME Shell.
|
||||
|
||||
* apps-menu
|
||||
|
||||
Lets you reach an application using gnome 2.x style menu on the panel.
|
||||
|
||||
* auto-move-windows
|
||||
|
||||
Lets you manage your workspaces more easily, assigning a specific workspace to
|
||||
each application as soon as it creates a window, in a manner configurable with a
|
||||
GSettings key.
|
||||
|
||||
* drive-menu
|
||||
|
||||
Shows a status menu for rapid unmount and power off of external storage devices
|
||||
(i.e. pendrives)
|
||||
|
||||
* example
|
||||
|
||||
A minimal example illustrating how to write extensions.
|
||||
|
||||
* launch-new-instance
|
||||
|
||||
Changes application icons to always launch a new instance when activated.
|
||||
|
||||
* native-window-placement
|
||||
|
||||
An alternative algorithm for layouting the thumbnails in the windows overview, that
|
||||
more closely reflects the actual positions and sizes.
|
||||
|
||||
* places-menu
|
||||
|
||||
Shows a status Indicator for navigating to Places.
|
||||
|
||||
* screenshot-window-sizer
|
||||
|
||||
Adds a shortcut for resizing the focus window to a size that is suitable for GNOME Software screenshots
|
||||
|
||||
* user-theme
|
||||
|
||||
Loads a shell theme from ~/.themes/<name>/gnome-shell.
|
||||
|
||||
* window-list
|
||||
|
||||
Adds a bottom panel with a traditional window list.
|
||||
|
||||
* windowsNavigator
|
||||
|
||||
Allow keyboard selection of windows and workspaces in overlay mode.
|
||||
|
||||
* workspace-indicator
|
||||
|
||||
Adds a simple workspace switcher to the top bar.
|
||||
|
||||
## License
|
||||
|
||||
GNOME Shell Extensions are distributed under the terms of the GNU General
|
||||
Public License, version 2 or later. See the [COPYING file][license] for details.
|
||||
Individual extensions may be licensed under different terms, see each source
|
||||
file for details.
|
||||
|
||||
[project-page]: https://wiki.gnome.org/Projects/GnomeShell/Extensions
|
||||
[shell-page]: https://wiki.gnome.org/Projects/GnomeShell
|
||||
[bug-tracker]: https://gitlab.gnome.org/GNOME/gnome-shell-extensions/issues
|
||||
[license]: COPYING
|
||||
20
autogen.sh
Executable file
20
autogen.sh
Executable file
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
# Run this to generate all the initial makefiles, etc.
|
||||
|
||||
srcdir=`dirname $0`
|
||||
test -z "$srcdir" && srcdir=.
|
||||
|
||||
PKG_NAME="gnome-shell-extensions"
|
||||
|
||||
test -f $srcdir/configure.ac || {
|
||||
echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
|
||||
echo " top-level gnome-shell-extensions directory"
|
||||
exit 1
|
||||
}
|
||||
|
||||
which gnome-autogen.sh || {
|
||||
echo "You need to install gnome-common from GNOME Git (or from"
|
||||
echo "your OS vendor's package manager)."
|
||||
exit 1
|
||||
}
|
||||
. gnome-autogen.sh
|
||||
3
config/.gitignore
vendored
Normal file
3
config/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
install-sh
|
||||
mkinstalldirs
|
||||
missing
|
||||
77
configure.ac
Normal file
77
configure.ac
Normal file
@@ -0,0 +1,77 @@
|
||||
AC_PREREQ(2.63)
|
||||
AC_INIT([gnome-shell-extensions],[3.0.2],[https://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell&component=extensions])
|
||||
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_AUX_DIR([config])
|
||||
|
||||
AM_INIT_AUTOMAKE([1.10 dist-bzip2 no-dist-gzip foreign tar-ustar])
|
||||
|
||||
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
|
||||
|
||||
GETTEXT_PACKAGE=gnome-shell-extensions
|
||||
AC_SUBST(GETTEXT_PACKAGE)
|
||||
AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE",
|
||||
[The prefix for our gettext translation domains.])
|
||||
IT_PROG_INTLTOOL(0.26)
|
||||
|
||||
PKG_PROG_PKG_CONFIG([0.22])
|
||||
|
||||
GLIB_GSETTINGS
|
||||
|
||||
ADDITIONAL_PACKAGES=
|
||||
|
||||
dnl keep this in sync with extensions/Makefile.am
|
||||
ALL_EXTENSIONS="example alternate-tab xrandr-indicator windowsNavigator auto-move-windows dock user-theme alternative-status-menu gajim"
|
||||
DEFAULT_EXTENSIONS="alternate-tab windowsNavigator dock alternative-status-menu"
|
||||
AC_ARG_ENABLE([extensions],
|
||||
[AS_HELP_STRING([--enable-extensions],[Space separated list of extensions to enable.
|
||||
The default is to build all extensions that can be installed in the home directory and have no external depedencies.
|
||||
Use "all" to enable all available extensions.])],
|
||||
[],
|
||||
[enable_extensions=$DEFAULT_EXTENSIONS]
|
||||
)
|
||||
if test x$enable_extensions = xall; then
|
||||
enable_extensions="$ALL_EXTENSIONS"
|
||||
fi
|
||||
|
||||
ADDITIONAL_PACKAGES=
|
||||
ENABLED_EXTENSIONS=
|
||||
for e in $enable_extensions; do
|
||||
case $e in
|
||||
xrandr-indicator)
|
||||
ENABLED_EXTENSIONS="$ENABLED_EXTENSIONS $e"
|
||||
ADDITIONAL_PACKAGES="$ADDITIONAL_PAGKAGES gnome-desktop-3.0 >= 2.91.6"
|
||||
;;
|
||||
alternate-tab|example|windowsNavigator|auto-move-windows|dock|user-theme|alternative-status-menu|gajim)
|
||||
ENABLED_EXTENSIONS="$ENABLED_EXTENSIONS $e"
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR([invalid extension $e])
|
||||
esac
|
||||
done
|
||||
|
||||
AC_SUBST(ENABLED_EXTENSIONS, [$ENABLED_EXTENSIONS])
|
||||
|
||||
dnl We don't really need cflags or libdirs, we just check
|
||||
dnl to ensure we don't fail at runtime.
|
||||
|
||||
if test "x$ADDITIONAL_PACKAGES" != x; then
|
||||
PKG_CHECK_MODULES(ADDITIONAL, [$ADDITIONAL_PACKAGES])
|
||||
fi
|
||||
|
||||
dnl Please keep this sorted alphabetically
|
||||
AC_CONFIG_FILES([
|
||||
extensions/alternate-tab/Makefile
|
||||
extensions/alternative-status-menu/Makefile
|
||||
extensions/auto-move-windows/Makefile
|
||||
extensions/dock/Makefile
|
||||
extensions/example/Makefile
|
||||
extensions/windowsNavigator/Makefile
|
||||
extensions/gajim/Makefile
|
||||
extensions/xrandr-indicator/Makefile
|
||||
extensions/user-theme/Makefile
|
||||
extensions/Makefile
|
||||
Makefile
|
||||
po/Makefile.in
|
||||
])
|
||||
AC_OUTPUT
|
||||
@@ -1,2 +0,0 @@
|
||||
To update the gnome-shell-sass submodule to latest upstream commit:
|
||||
git submodule update --rebase
|
||||
@@ -1,178 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="24"
|
||||
height="24"
|
||||
id="svg10621"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="calendar-today.svg">
|
||||
<defs
|
||||
id="defs10623">
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient34508-1-3"
|
||||
id="radialGradient99561-1"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
|
||||
cx="51"
|
||||
cy="30"
|
||||
fx="51"
|
||||
fy="30"
|
||||
r="42" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient34508-1-3">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop34510-1-9" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop34512-4-5" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
r="42"
|
||||
fy="30"
|
||||
fx="51"
|
||||
cy="30"
|
||||
cx="51"
|
||||
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient10592"
|
||||
xlink:href="#linearGradient34508-1-3"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient34508-1-3"
|
||||
id="radialGradient3770"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
|
||||
cx="51"
|
||||
cy="30"
|
||||
fx="51"
|
||||
fy="30"
|
||||
r="42" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient34508-1-3"
|
||||
id="radialGradient3001"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
|
||||
cx="51"
|
||||
cy="30"
|
||||
fx="51"
|
||||
fy="30"
|
||||
r="42" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient34508-1-3"
|
||||
id="radialGradient3007"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
|
||||
cx="51"
|
||||
cy="30"
|
||||
fx="51"
|
||||
fy="30"
|
||||
r="42" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient34508-1-3"
|
||||
id="radialGradient3067"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
|
||||
cx="51"
|
||||
cy="30"
|
||||
fx="51"
|
||||
fy="30"
|
||||
r="42" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient34508-1-3"
|
||||
id="radialGradient3072"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
|
||||
cx="51"
|
||||
cy="30"
|
||||
fx="51"
|
||||
fy="30"
|
||||
r="42" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient34508-1-3"
|
||||
id="radialGradient2997"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.72146227,0,0,0.27484277,14.205424,21.754717)"
|
||||
cx="51"
|
||||
cy="30"
|
||||
fx="51"
|
||||
fy="30"
|
||||
r="42" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#d3d3d3"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="8"
|
||||
inkscape:cx="-55.349829"
|
||||
inkscape:cy="-31.442864"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:window-width="2133"
|
||||
inkscape:window-height="1241"
|
||||
inkscape:window-x="238"
|
||||
inkscape:window-y="89"
|
||||
inkscape:window-maximized="0"
|
||||
borderlayer="true"
|
||||
inkscape:showpageshadow="false">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3109"
|
||||
empspacing="5"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata10626">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(-469.08263,-537.99307)">
|
||||
<circle
|
||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#555753;fill-opacity:0.23756906;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
id="path7305"
|
||||
cx="481.57138"
|
||||
cy="559.4649"
|
||||
r="1.5" />
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 5.6 KiB |
File diff suppressed because it is too large
Load Diff
|
Before Width: | Height: | Size: 100 KiB |
@@ -1,262 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="65"
|
||||
height="22"
|
||||
id="svg10865"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="classic-toggle-off-intl.svg">
|
||||
<defs
|
||||
id="defs10867">
|
||||
<linearGradient
|
||||
id="linearGradient62852-6-5">
|
||||
<stop
|
||||
id="stop62854-6-7"
|
||||
offset="0"
|
||||
style="stop-color:#ffffff;stop-opacity:1" />
|
||||
<stop
|
||||
style="stop-color:#eeeeec;stop-opacity:1"
|
||||
offset="0.97726452"
|
||||
id="stop62858-8-0" />
|
||||
<stop
|
||||
id="stop62860-5-3"
|
||||
offset="1"
|
||||
style="stop-color:#f5f5f4;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<inkscape:path-effect
|
||||
is_visible="true"
|
||||
id="path-effect62989-8-0"
|
||||
effect="spiro" />
|
||||
<linearGradient
|
||||
id="linearGradient62821-5-8">
|
||||
<stop
|
||||
id="stop62823-2-4"
|
||||
offset="0"
|
||||
style="stop-color:#d1d3d1;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop62825-3-8"
|
||||
offset="1"
|
||||
style="stop-color:#ebebeb;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient62852-6-5-3">
|
||||
<stop
|
||||
id="stop62854-6-7-6"
|
||||
offset="0"
|
||||
style="stop-color:#ffffff;stop-opacity:1" />
|
||||
<stop
|
||||
style="stop-color:#eeeeec;stop-opacity:1"
|
||||
offset="0.97726452"
|
||||
id="stop62858-8-0-3" />
|
||||
<stop
|
||||
id="stop62860-5-3-9"
|
||||
offset="1"
|
||||
style="stop-color:#f5f5f4;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<inkscape:path-effect
|
||||
effect="spiro"
|
||||
id="path-effect62829-6-8-0"
|
||||
is_visible="true" />
|
||||
<linearGradient
|
||||
id="linearGradient62821-5-8-1">
|
||||
<stop
|
||||
id="stop62823-2-4-2"
|
||||
offset="0"
|
||||
style="stop-color:#d1d3d1;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop62825-3-8-9"
|
||||
offset="1"
|
||||
style="stop-color:#ebebeb;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="507.42715"
|
||||
x2="702.58966"
|
||||
y1="484.49405"
|
||||
x1="702.58966"
|
||||
gradientTransform="matrix(1.3066667,0,0,1,-841.64667,-483)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient11647"
|
||||
xlink:href="#linearGradient62821-5-8-1"
|
||||
inkscape:collect="always" />
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath65663">
|
||||
<rect
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#729fcf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:new"
|
||||
id="rect65665"
|
||||
width="96.999924"
|
||||
height="24.292892"
|
||||
x="708.71954"
|
||||
y="406.96973"
|
||||
rx="3.1139846"
|
||||
ry="1.9595497"
|
||||
inkscape:export-filename="/home/lapo.fedora/SparkleShare/gnome-mockups/content selection/content-selection.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
</clipPath>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient5378-2-5-9-9-0-80-7-6-8-4-5-7-3-6-2-9"
|
||||
id="linearGradient65582"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.5250827,0,0,0.72144839,620.16092,156.4917)"
|
||||
x1="207.17195"
|
||||
y1="497.39584"
|
||||
x2="207.17195"
|
||||
y2="531.48669" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient5378-2-5-9-9-0-80-7-6-8-4-5-7-3-6-2-9">
|
||||
<stop
|
||||
style="stop-color:#f4f6f4;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop5380-6-1-1-9-3-6-3-6-45-6-4-4-9-9-8-9" />
|
||||
<stop
|
||||
style="stop-color:#d7dad7;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop5382-06-3-6-4-2-4-6-8-0-9-6-8-7-7-6-7" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient65584">
|
||||
<stop
|
||||
style="stop-color:#f1f1f1;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop65586" />
|
||||
<stop
|
||||
style="stop-color:#a7aba7;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop65588" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient5378-2-5-9-9-0-80-7-6-8-4-5-7-3-6-2-9"
|
||||
id="linearGradient65582-5"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.5250827,0,0,0.72144839,-75.348673,-359.16458)"
|
||||
x1="207.17195"
|
||||
y1="497.39584"
|
||||
x2="207.17195"
|
||||
y2="531.48669" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient65584"
|
||||
id="linearGradient65590-6"
|
||||
x1="716.62506"
|
||||
y1="537.23358"
|
||||
x2="716.62506"
|
||||
y2="535.23358"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.0139469,0,0,1.0139469,-705.52354,-521.99915)" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="23.565368"
|
||||
inkscape:cy="19.596892"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="g62929"
|
||||
showgrid="false"
|
||||
borderlayer="true"
|
||||
inkscape:showpageshadow="false"
|
||||
inkscape:snap-nodes="false"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:snap-others="false"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1342"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="28"
|
||||
inkscape:window-maximized="1"
|
||||
showborder="false">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid11512" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata10870">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-1030.3622)">
|
||||
<g
|
||||
inkscape:export-ydpi="90"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-filename="/home/lapo.fedora/SparkleShare/gnome-mockups/system-settings/network/network-panel-summary.png"
|
||||
style="display:inline"
|
||||
id="g62929"
|
||||
transform="translate(-643.91421,517.29894)">
|
||||
<g
|
||||
transform="translate(0,30)"
|
||||
id="g62931">
|
||||
<rect
|
||||
style="fill:#cecece;fill-opacity:1;stroke:#a7a7a7;stroke-width:1;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;color:#000000;color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill-rule:nonzero;stroke-linejoin:miter;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:new;clip-rule:nonzero;opacity:1;isolation:auto;mix-blend-mode:normal;solid-color:#000000;solid-opacity:1;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;filter-blend-mode:normal;filter-gaussianBlur-deviation:0;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto"
|
||||
id="rect62935"
|
||||
width="63.856125"
|
||||
height="21.093594"
|
||||
x="644.5"
|
||||
y="483.5"
|
||||
rx="2"
|
||||
ry="2" />
|
||||
<rect
|
||||
style="fill:url(#linearGradient65582);fill-opacity:1;stroke:#a7a7a7;stroke-width:0.97313344;stroke-linecap:butt;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline;color:#000000;clip-rule:nonzero;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill-rule:nonzero;stroke-linejoin:miter;stroke-dashoffset:0;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;filter-blend-mode:normal;filter-gaussianBlur-deviation:0;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
id="rect62937"
|
||||
width="29.97398"
|
||||
height="17.022524"
|
||||
x="646.55896"
|
||||
y="485.61429"
|
||||
rx="1"
|
||||
ry="1" />
|
||||
<g
|
||||
transform="translate(-38.048674,-1.9445437)"
|
||||
id="g62939" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:original-d="m 647.78241,486.57192 27.73523,0"
|
||||
inkscape:path-effect="#path-effect62989-8-0"
|
||||
id="path62947"
|
||||
d="m 647.78241,486.57192 27.73523,0"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</g>
|
||||
<g
|
||||
id="g11665"
|
||||
transform="matrix(0.78906097,0,0,0.78906097,178.78814,111.57844)" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
id="path3016"
|
||||
sodipodi:cx="50.375"
|
||||
sodipodi:cy="11.875"
|
||||
sodipodi:rx="4.625"
|
||||
sodipodi:ry="4.625"
|
||||
d="M 55,11.875 A 4.625,4.625 0 0 1 50.375,16.5 4.625,4.625 0 0 1 45.75,11.875 4.625,4.625 0 0 1 50.375,7.25 4.625,4.625 0 0 1 55,11.875 Z"
|
||||
transform="translate(642.41421,512.02037)"
|
||||
style="fill:none;stroke:#2e3436;stroke-width:2;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 9.5 KiB |
@@ -1,222 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="65"
|
||||
height="22"
|
||||
id="svg10865"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="classic-toggle-off-us.svg">
|
||||
<defs
|
||||
id="defs10867">
|
||||
<linearGradient
|
||||
id="linearGradient62852-6-5">
|
||||
<stop
|
||||
id="stop62854-6-7"
|
||||
offset="0"
|
||||
style="stop-color:#ffffff;stop-opacity:1" />
|
||||
<stop
|
||||
style="stop-color:#eeeeec;stop-opacity:1"
|
||||
offset="0.97726452"
|
||||
id="stop62858-8-0" />
|
||||
<stop
|
||||
id="stop62860-5-3"
|
||||
offset="1"
|
||||
style="stop-color:#f5f5f4;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<inkscape:path-effect
|
||||
is_visible="true"
|
||||
id="path-effect62989-8-0"
|
||||
effect="spiro" />
|
||||
<linearGradient
|
||||
id="linearGradient62821-5-8">
|
||||
<stop
|
||||
id="stop62823-2-4"
|
||||
offset="0"
|
||||
style="stop-color:#d1d3d1;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop62825-3-8"
|
||||
offset="1"
|
||||
style="stop-color:#ebebeb;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient62852-6-5-3">
|
||||
<stop
|
||||
id="stop62854-6-7-6"
|
||||
offset="0"
|
||||
style="stop-color:#ffffff;stop-opacity:1" />
|
||||
<stop
|
||||
style="stop-color:#eeeeec;stop-opacity:1"
|
||||
offset="0.97726452"
|
||||
id="stop62858-8-0-3" />
|
||||
<stop
|
||||
id="stop62860-5-3-9"
|
||||
offset="1"
|
||||
style="stop-color:#f5f5f4;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<inkscape:path-effect
|
||||
effect="spiro"
|
||||
id="path-effect62829-6-8-0"
|
||||
is_visible="true" />
|
||||
<linearGradient
|
||||
id="linearGradient62821-5-8-1">
|
||||
<stop
|
||||
id="stop62823-2-4-2"
|
||||
offset="0"
|
||||
style="stop-color:#d1d3d1;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop62825-3-8-9"
|
||||
offset="1"
|
||||
style="stop-color:#ebebeb;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
y2="507.42715"
|
||||
x2="702.58966"
|
||||
y1="484.49405"
|
||||
x1="702.58966"
|
||||
gradientTransform="matrix(1.3066667,0,0,1,-841.64667,-483)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="linearGradient11647"
|
||||
xlink:href="#linearGradient62821-5-8-1"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient5378-2-5-9-9-0-80-7-6-8-4-5-7-3-6-2-9"
|
||||
id="linearGradient65582"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.5250827,0,0,0.72144839,620.16092,156.4917)"
|
||||
x1="207.17195"
|
||||
y1="497.39584"
|
||||
x2="207.17195"
|
||||
y2="531.48669" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient5378-2-5-9-9-0-80-7-6-8-4-5-7-3-6-2-9">
|
||||
<stop
|
||||
style="stop-color:#f4f6f4;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop5380-6-1-1-9-3-6-3-6-45-6-4-4-9-9-8-9" />
|
||||
<stop
|
||||
style="stop-color:#d7dad7;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop5382-06-3-6-4-2-4-6-8-0-9-6-8-7-7-6-7" />
|
||||
</linearGradient>
|
||||
<inkscape:path-effect
|
||||
is_visible="true"
|
||||
id="path-effect62989-8-0-6"
|
||||
effect="spiro" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="78.222729"
|
||||
inkscape:cy="-3.6620078"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="g62929"
|
||||
showgrid="false"
|
||||
borderlayer="true"
|
||||
inkscape:showpageshadow="false"
|
||||
inkscape:snap-nodes="false"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:snap-others="false"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1342"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="28"
|
||||
inkscape:window-maximized="1"
|
||||
showborder="false">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid11512" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata10870">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-1030.3622)">
|
||||
<g
|
||||
inkscape:export-ydpi="90"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-filename="/home/lapo.fedora/SparkleShare/gnome-mockups/system-settings/network/network-panel-summary.png"
|
||||
style="display:inline"
|
||||
id="g62929"
|
||||
transform="translate(-643.91421,517.29894)">
|
||||
<g
|
||||
style="display:inline"
|
||||
transform="translate(0,30)"
|
||||
id="g62931">
|
||||
<rect
|
||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#cecece;fill-opacity:1;fill-rule:nonzero;stroke:#a7a7a7;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:new"
|
||||
id="rect62935"
|
||||
width="63.856125"
|
||||
height="21.093594"
|
||||
x="644.5"
|
||||
y="483.5"
|
||||
rx="2"
|
||||
ry="2" />
|
||||
<rect
|
||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#linearGradient65582);fill-opacity:1;fill-rule:nonzero;stroke:#a7a7a7;stroke-width:0.97313344;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
id="rect62937"
|
||||
width="29.97398"
|
||||
height="17.022524"
|
||||
x="646.55896"
|
||||
y="485.61429"
|
||||
rx="1"
|
||||
ry="1" />
|
||||
<g
|
||||
transform="translate(-38.048674,-1.9445437)"
|
||||
id="g62939" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:original-d="m 647.78241,486.57192 27.73523,0"
|
||||
inkscape:path-effect="#path-effect62989-8-0-6"
|
||||
id="path62947"
|
||||
d="m 647.78241,486.57192 27.73523,0"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</g>
|
||||
<g
|
||||
id="g11665"
|
||||
transform="matrix(0.78906097,0,0,0.78906097,167.78814,111.57844)">
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:12.69556618px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#2e3436;fill-opacity:1;stroke:none;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold"
|
||||
x="644.46393"
|
||||
y="533.87158"
|
||||
id="text62949"
|
||||
sodipodi:linespacing="125%"
|
||||
transform="scale(1.0113976,0.98873084)"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan62951"
|
||||
x="644.46393"
|
||||
y="533.87158">OFF</tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 8.0 KiB |
@@ -1,175 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="65"
|
||||
height="22"
|
||||
id="svg10865"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="classic-toggle-on-intl.svg">
|
||||
<defs
|
||||
id="defs10867">
|
||||
<linearGradient
|
||||
id="linearGradient62852-6-5">
|
||||
<stop
|
||||
id="stop62854-6-7"
|
||||
offset="0"
|
||||
style="stop-color:#ffffff;stop-opacity:1" />
|
||||
<stop
|
||||
style="stop-color:#eeeeec;stop-opacity:1"
|
||||
offset="0.97726452"
|
||||
id="stop62858-8-0" />
|
||||
<stop
|
||||
id="stop62860-5-3"
|
||||
offset="1"
|
||||
style="stop-color:#f5f5f4;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<inkscape:path-effect
|
||||
is_visible="true"
|
||||
id="path-effect62989-8-0"
|
||||
effect="spiro" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient38513"
|
||||
id="linearGradient38519"
|
||||
x1="690"
|
||||
y1="506.25049"
|
||||
x2="690"
|
||||
y2="480.93414"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient38513">
|
||||
<stop
|
||||
style="stop-color:#729fcf;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop38515" />
|
||||
<stop
|
||||
style="stop-color:#6f9ccd;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop38517" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient62852-6-5"
|
||||
id="linearGradient62981-1-1"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.85639946,0,0,0.81059641,57.747905,92.132229)"
|
||||
x1="740"
|
||||
y1="486.10501"
|
||||
x2="740"
|
||||
y2="505.3204" />
|
||||
<inkscape:path-effect
|
||||
is_visible="true"
|
||||
id="path-effect62989-8-0-8"
|
||||
effect="spiro" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="9.3225163"
|
||||
inkscape:cy="-0.1588306"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="g62929"
|
||||
showgrid="false"
|
||||
borderlayer="true"
|
||||
inkscape:showpageshadow="false"
|
||||
inkscape:snap-nodes="false"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:snap-others="false"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1342"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="28"
|
||||
inkscape:window-maximized="1"
|
||||
showborder="false">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid11512" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata10870">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-1030.3622)">
|
||||
<g
|
||||
inkscape:export-ydpi="90"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-filename="/home/lapo.fedora/SparkleShare/gnome-mockups/system-settings/network/network-panel-summary.png"
|
||||
style="display:inline"
|
||||
id="g62929"
|
||||
transform="translate(-643.91421,517.29894)">
|
||||
<g
|
||||
style="display:inline"
|
||||
transform="translate(0,30)"
|
||||
id="g62931">
|
||||
<rect
|
||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:url(#linearGradient38519);fill-opacity:1;fill-rule:nonzero;stroke:#3465a4;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
id="rect62935"
|
||||
width="63.856125"
|
||||
height="21.093594"
|
||||
x="644.5"
|
||||
y="483.5"
|
||||
rx="2"
|
||||
ry="2" />
|
||||
<rect
|
||||
style="display:inline;fill:url(#linearGradient62981-1-1);fill-opacity:1;stroke:#3465a4;stroke-width:1;stroke-linecap:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect62937"
|
||||
width="29.97398"
|
||||
height="17.022524"
|
||||
x="676.49646"
|
||||
y="485.67679"
|
||||
rx="1"
|
||||
ry="1" />
|
||||
<g
|
||||
transform="translate(-7.9861743,-1.9445437)"
|
||||
id="g62939" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:original-d="m 677.59874,486.57192 27.94632,0"
|
||||
inkscape:path-effect="#path-effect62989-8-0-8"
|
||||
id="path62947"
|
||||
d="m 677.59874,486.57192 27.94632,0"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</g>
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4444"
|
||||
d="m 661.91421,522.09451 0,7"
|
||||
style="fill:#3465a4;stroke:#3465a4;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;color:#000000;fill-opacity:1;fill-rule:nonzero;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
|
||||
<path
|
||||
style="fill:none;stroke:#ffffff;stroke-width:2;stroke-linecap:square;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
d="m 18,7.96875 0,7"
|
||||
id="path3922"
|
||||
inkscape:connector-curvature="0"
|
||||
transform="translate(643.91421,513.06326)" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 6.2 KiB |
@@ -1,209 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="65"
|
||||
height="22"
|
||||
id="svg10865"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="classic-toggle-on-us.svg">
|
||||
<defs
|
||||
id="defs10867">
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient62852-6-5"
|
||||
id="linearGradient62981-1-1"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.85639946,0,0,0.81059641,57.747905,92.132229)"
|
||||
x1="740"
|
||||
y1="486.10501"
|
||||
x2="740"
|
||||
y2="505.3204" />
|
||||
<linearGradient
|
||||
id="linearGradient62852-6-5">
|
||||
<stop
|
||||
id="stop62854-6-7"
|
||||
offset="0"
|
||||
style="stop-color:#ffffff;stop-opacity:1" />
|
||||
<stop
|
||||
style="stop-color:#eeeeec;stop-opacity:1"
|
||||
offset="0.97726452"
|
||||
id="stop62858-8-0" />
|
||||
<stop
|
||||
id="stop62860-5-3"
|
||||
offset="1"
|
||||
style="stop-color:#f5f5f4;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
<inkscape:path-effect
|
||||
is_visible="true"
|
||||
id="path-effect62989-8-0"
|
||||
effect="spiro" />
|
||||
<clipPath
|
||||
clipPathUnits="userSpaceOnUse"
|
||||
id="clipPath65663">
|
||||
<rect
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#729fcf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;enable-background:new"
|
||||
id="rect65665"
|
||||
width="96.999924"
|
||||
height="24.292892"
|
||||
x="708.71954"
|
||||
y="406.96973"
|
||||
rx="3.1139846"
|
||||
ry="1.9595497"
|
||||
inkscape:export-filename="/home/lapo.fedora/SparkleShare/gnome-mockups/content selection/content-selection.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
</clipPath>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient38513"
|
||||
id="linearGradient38519"
|
||||
x1="690"
|
||||
y1="506.25049"
|
||||
x2="690"
|
||||
y2="480.93414"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient38513">
|
||||
<stop
|
||||
style="stop-color:#729fcf;stop-opacity:1"
|
||||
offset="0"
|
||||
id="stop38515" />
|
||||
<stop
|
||||
style="stop-color:#6f9ccd;stop-opacity:1"
|
||||
offset="1"
|
||||
id="stop38517" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientTransform="translate(-644,-483)"
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient38513"
|
||||
id="linearGradient38519-3"
|
||||
x1="690"
|
||||
y1="506.25049"
|
||||
x2="690"
|
||||
y2="480.93414"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1"
|
||||
inkscape:cx="20.775745"
|
||||
inkscape:cy="7.0434022"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="g62929"
|
||||
showgrid="false"
|
||||
borderlayer="true"
|
||||
inkscape:showpageshadow="false"
|
||||
inkscape:snap-nodes="false"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:snap-others="false"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1342"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="28"
|
||||
inkscape:window-maximized="1"
|
||||
showborder="false">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid11512" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata10870">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-1030.3622)">
|
||||
<g
|
||||
inkscape:export-ydpi="90"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-filename="/home/lapo.fedora/SparkleShare/gnome-mockups/system-settings/network/network-panel-summary.png"
|
||||
style="display:inline"
|
||||
id="g62929"
|
||||
transform="translate(-643.91421,517.29894)">
|
||||
<g
|
||||
transform="translate(0,30)"
|
||||
id="g62931">
|
||||
<rect
|
||||
style="fill:url(#linearGradient38519);fill-opacity:1;stroke:#3465a4;stroke-width:1;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill-rule:nonzero;stroke-linejoin:miter;stroke-dashoffset:0;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;filter-blend-mode:normal;filter-gaussianBlur-deviation:0;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
id="rect62935"
|
||||
width="63.856125"
|
||||
height="21.093594"
|
||||
x="644.5"
|
||||
y="483.5"
|
||||
rx="2"
|
||||
ry="2" />
|
||||
<rect
|
||||
style="fill:url(#linearGradient62981-1-1);fill-opacity:1;stroke:#3465a4;stroke-width:1;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
|
||||
id="rect62937"
|
||||
width="29.97398"
|
||||
height="17.022524"
|
||||
x="676.49646"
|
||||
y="485.67679"
|
||||
rx="1"
|
||||
ry="1" />
|
||||
<g
|
||||
transform="translate(-7.9861743,-1.9445437)"
|
||||
id="g62939" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:original-d="m 677.59874,486.57192 27.94632,0"
|
||||
inkscape:path-effect="#path-effect62989-8-0"
|
||||
id="path62947"
|
||||
d="m 677.59874,486.57192 27.94632,0"
|
||||
style="fill:none;stroke:#ffffff;stroke-width:1px;stroke-linecap:round;stroke-linejoin:miter;stroke-opacity:1" />
|
||||
</g>
|
||||
<text
|
||||
transform="scale(1.0113976,0.98873084)"
|
||||
sodipodi:linespacing="125%"
|
||||
id="text62949-7"
|
||||
y="534.96918"
|
||||
x="646.71399"
|
||||
style="font-size:10.01104736px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#3465a4;fill-opacity:1;stroke:none;display:inline;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold;"
|
||||
xml:space="preserve"><tspan
|
||||
y="534.96918"
|
||||
x="646.71399"
|
||||
id="tspan62951-7"
|
||||
sodipodi:role="line">ON</tspan></text>
|
||||
<text
|
||||
transform="scale(1.0113976,0.98873084)"
|
||||
sodipodi:linespacing="125%"
|
||||
id="text62949"
|
||||
y="533.94482"
|
||||
x="646.71399"
|
||||
style="font-size:10.01104736px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;font-family:Cantarell;-inkscape-font-specification:Cantarell Bold"
|
||||
xml:space="preserve"><tspan
|
||||
y="533.94482"
|
||||
x="646.71399"
|
||||
id="tspan62951"
|
||||
sodipodi:role="line">ON</tspan></text>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 7.5 KiB |
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"parentMode": "user",
|
||||
"stylesheetName": "gnome-classic.css",
|
||||
"enabledExtensions": [@CLASSIC_EXTENSIONS@],
|
||||
"panel": { "left": ["activities", "appMenu"],
|
||||
"center": [],
|
||||
"right": ["a11y", "keyboard", "dateMenu", "aggregateMenu"]
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
@import url("gnome-classic.css");
|
||||
|
||||
stage {
|
||||
-st-icon-style: symbolic;
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Name=GNOME Classic
|
||||
Comment=This session logs you into GNOME Classic
|
||||
Exec=env GNOME_SHELL_SESSION_MODE=classic gnome-session --session gnome-classic
|
||||
TryExec=gnome-session
|
||||
Type=Application
|
||||
DesktopNames=GNOME-Classic;GNOME;
|
||||
@@ -1,105 +0,0 @@
|
||||
/* Use the gnome-shell theme, but with light colors */
|
||||
$variant: 'light';
|
||||
|
||||
@import "gnome-shell-sass/_colors"; //use gtk colors
|
||||
@import "gnome-shell-sass/_drawing";
|
||||
@import "gnome-shell-sass/_common";
|
||||
|
||||
/* Overrides */
|
||||
|
||||
#panel, #panel.solid {
|
||||
font-weight: normal;
|
||||
background-color: $bg_color;
|
||||
background-gradient-direction: vertical;
|
||||
background-gradient-end: darken($bg_color,5%);
|
||||
border-top-color: #666; /* we don't support non-uniform border-colors and
|
||||
use the top border color for any border, so we
|
||||
need to set it even if all we want is a bottom
|
||||
border */
|
||||
border-bottom: 1px solid #666;
|
||||
app-icon-bottom-clip: 0px;
|
||||
&:overview {
|
||||
background-color: #000;
|
||||
background-gradient-end: #000;
|
||||
border-top-color: #000;
|
||||
border-bottom: 1px solid #000;
|
||||
.panel-button { color: #fff; }
|
||||
}
|
||||
|
||||
.panel-button {
|
||||
-natural-hpadding: 8px;
|
||||
-minimum-hpadding: 4px;
|
||||
font-weight: normal;
|
||||
color: $fg_color;
|
||||
text-shadow: none;
|
||||
&:active, &:overview, &:focus, &:checked {
|
||||
// Trick due to St limitations. It needs a background to draw
|
||||
// a box-shadow
|
||||
background-color: $selected_bg_color !important;
|
||||
color: $selected_fg_color !important;
|
||||
box-shadow: none;
|
||||
& > .system-status-icon { icon-shadow: none; }
|
||||
}
|
||||
&:hover {
|
||||
text-shadow: none;
|
||||
& .system-status-icon { icon-shadow: none; }
|
||||
}
|
||||
.app-menu-icon { width: 0; height: 0; margin: 0; } // shell's display:none; :D
|
||||
|
||||
.system-status-icon {
|
||||
icon-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.panel-corner,
|
||||
.panel-corner:active,
|
||||
.panel-corner:overview,
|
||||
.panel-corner:focus {
|
||||
-panel-corner-radius: 0;
|
||||
}
|
||||
&.lock-screen,
|
||||
&.unlock-screen,
|
||||
&.login-screen {
|
||||
background-color: transparentize($_bubble_bg_color, 0.5);
|
||||
background-gradient-start: transparentize($_bubble_bg_color, 0.5);
|
||||
background-gradient-end: transparentize($_bubble_bg_color, 0.5);
|
||||
border-bottom: none;
|
||||
.panel-button { color: $osd_fg_color; }
|
||||
}
|
||||
.popup-menu-arrow { width: 0; height: 0; } // shell's display: none;
|
||||
}
|
||||
|
||||
#appMenu {
|
||||
padding: 0 8px 0 8px;
|
||||
spinner-image: url("classic-process-working.svg");
|
||||
}
|
||||
.tile-preview-left.on-primary,
|
||||
.tile-preview-right.on-primary,
|
||||
.tile-preview-left.tile-preview-right.on-primary {
|
||||
/* keep in sync with -panel-corner-radius */
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
@each $v in us, intl {
|
||||
.toggle-switch-#{$v} {
|
||||
background-image: url("classic-toggle-off-#{$v}.svg");
|
||||
&:checked { background-image: url("classic-toggle-on-#{$v}.svg"); }
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-day-with-events {
|
||||
background-image: url("calendar-today.svg");
|
||||
}
|
||||
|
||||
.message-list-clear-button.button {
|
||||
color: $fg_color
|
||||
}
|
||||
|
||||
.notification-banner {
|
||||
background-color: $bg_color !important;
|
||||
color: $fg_color;
|
||||
.notification-button {
|
||||
background-color: darken($bg_color,5%);
|
||||
&:hover, &focus { background-color: darken($bg_color,2%); }
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
[GNOME Session]
|
||||
Name=GNOME Classic
|
||||
RequiredComponents=org.gnome.Shell;org.gnome.SettingsDaemon.A11ySettings;org.gnome.SettingsDaemon.Clipboard;org.gnome.SettingsDaemon.Color;org.gnome.SettingsDaemon.Datetime;org.gnome.SettingsDaemon.Housekeeping;org.gnome.SettingsDaemon.Keyboard;org.gnome.SettingsDaemon.MediaKeys;org.gnome.SettingsDaemon.Mouse;org.gnome.SettingsDaemon.Power;org.gnome.SettingsDaemon.PrintNotifications;org.gnome.SettingsDaemon.Rfkill;org.gnome.SettingsDaemon.ScreensaverProxy;org.gnome.SettingsDaemon.Sharing;org.gnome.SettingsDaemon.Smartcard;org.gnome.SettingsDaemon.Sound;org.gnome.SettingsDaemon.Wacom;org.gnome.SettingsDaemon.XSettings;
|
||||
Submodule data/gnome-shell-sass deleted from 6cd1fc7f4a
@@ -1,63 +0,0 @@
|
||||
sessions = [
|
||||
['gnome-classic.session.desktop.in', sessiondir],
|
||||
['gnome-classic.desktop.in', xsessiondir]
|
||||
]
|
||||
foreach s : sessions
|
||||
name_array = s[0].split('.')
|
||||
i18n.merge_file('',
|
||||
input: s[0],
|
||||
output: '.'.join([name_array[0], name_array[1]]),
|
||||
po_dir: '../po',
|
||||
install: true,
|
||||
install_dir: s[1],
|
||||
type: 'desktop'
|
||||
)
|
||||
endforeach
|
||||
|
||||
classic_uuids = []
|
||||
foreach e : classic_extensions
|
||||
classic_uuids += e + uuid_suffix
|
||||
endforeach
|
||||
|
||||
mode_conf = configuration_data()
|
||||
mode_conf.set('CLASSIC_EXTENSIONS', '"' + '", "'.join(classic_uuids) + '"')
|
||||
|
||||
mode_file = 'classic.json'
|
||||
configure_file(
|
||||
input: mode_file + '.in',
|
||||
output: mode_file,
|
||||
configuration: mode_conf,
|
||||
install_dir: modedir
|
||||
)
|
||||
|
||||
theme_sources = files(
|
||||
'gnome-shell-sass/_colors.scss',
|
||||
'gnome-shell-sass/_common.scss',
|
||||
'gnome-shell-sass/_drawing.scss',
|
||||
'gnome-shell-sass/_high-contrast-colors.scss'
|
||||
)
|
||||
|
||||
theme_data = [
|
||||
'calendar-today.svg',
|
||||
'classic-process-working.svg',
|
||||
'classic-toggle-off-intl.svg',
|
||||
'classic-toggle-off-us.svg',
|
||||
'classic-toggle-on-intl.svg',
|
||||
'classic-toggle-on-us.svg',
|
||||
'gnome-classic-high-contrast.css'
|
||||
]
|
||||
|
||||
style = 'gnome-classic'
|
||||
custom_target(style + '.css',
|
||||
input: style + '.scss',
|
||||
output: style + '.css',
|
||||
depend_files: theme_sources,
|
||||
command: [sassc, '-a', '@INPUT@', '@OUTPUT@'],
|
||||
install: true,
|
||||
install_dir: themedir
|
||||
)
|
||||
|
||||
install_data(theme_data, install_dir: themedir)
|
||||
|
||||
classic_schema = 'org.gnome.shell.extensions.classic-overrides.gschema.xml'
|
||||
install_data(classic_schema, install_dir: schemadir)
|
||||
@@ -1,46 +0,0 @@
|
||||
<schemalist>
|
||||
<schema id="org.gnome.shell.extensions.classic-overrides"
|
||||
path="/org/gnome/shell/extensions/classic-overrides/"
|
||||
gettext-domain="gnome-shell-extensions">
|
||||
<key name="attach-modal-dialogs" type="b">
|
||||
<default>true</default>
|
||||
<summary>Attach modal dialog to the parent window</summary>
|
||||
<description>
|
||||
This key overrides the key in org.gnome.mutter when running
|
||||
GNOME Shell.
|
||||
</description>
|
||||
</key>
|
||||
|
||||
<key name="button-layout" type="s">
|
||||
<default>"appmenu:minimize,maximize,close"</default>
|
||||
<summary>Arrangement of buttons on the titlebar</summary>
|
||||
<description>
|
||||
This key overrides the key in org.gnome.desktop.wm.preferences when running GNOME Shell.
|
||||
</description>
|
||||
</key>
|
||||
|
||||
<key name="edge-tiling" type="b">
|
||||
<default>true</default>
|
||||
<summary>Enable edge tiling when dropping windows on screen edges</summary>
|
||||
<description>
|
||||
This key overrides the key in org.gnome.mutter when running GNOME Shell.
|
||||
</description>
|
||||
</key>
|
||||
|
||||
<key name="workspaces-only-on-primary" type="b">
|
||||
<default>true</default>
|
||||
<summary>Workspaces only on primary monitor</summary>
|
||||
<description>
|
||||
This key overrides the key in org.gnome.mutter when running GNOME Shell.
|
||||
</description>
|
||||
</key>
|
||||
|
||||
<key name="focus-change-on-pointer-rest" type="b">
|
||||
<default>true</default>
|
||||
<summary>Delay focus changes in mouse mode until the pointer stops moving</summary>
|
||||
<description>
|
||||
This key overrides the key in org.gnome.mutter when running GNOME Shell.
|
||||
</description>
|
||||
</key>
|
||||
</schema>
|
||||
</schemalist>
|
||||
@@ -1,37 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
srcdir=`dirname $0`
|
||||
srcdir=`(cd $srcdir && pwd)`
|
||||
|
||||
builddir=`mktemp -p $srcdir -d _build.XXXXXX` || exit 1
|
||||
installdir=`mktemp -p $srcdir -d _install.XXXXXX` || exit 1
|
||||
|
||||
meson setup --prefix=$installdir -Dextension_set=all $srcdir $builddir
|
||||
ninja -C$builddir install
|
||||
|
||||
rm -rf $srcdir/zip-files
|
||||
mkdir $srcdir/zip-files
|
||||
|
||||
extensiondir=$installdir/share/gnome-shell/extensions
|
||||
schemadir=$installdir/share/glib-2.0/schemas
|
||||
localedir=$installdir/share/locale
|
||||
|
||||
for f in $extensiondir/*; do
|
||||
name=`basename ${f%%@*}`
|
||||
uuid=$name@gnome-shell-extensions.gcampax.github.com
|
||||
schema=$schemadir/org.gnome.shell.extensions.$name.gschema.xml
|
||||
|
||||
cp $srcdir/NEWS $srcdir/COPYING $f
|
||||
cp -r $localedir $f
|
||||
|
||||
if [ -f $schema ]; then
|
||||
mkdir $f/schemas
|
||||
cp $schema $f/schemas;
|
||||
glib-compile-schemas $f/schemas
|
||||
fi
|
||||
|
||||
(cd $f && zip -rmq $srcdir/zip-files/$uuid.shell-extension.zip .)
|
||||
done
|
||||
|
||||
rm -rf $builddir
|
||||
rm -rf $installdir
|
||||
22
extension.mk
Normal file
22
extension.mk
Normal file
@@ -0,0 +1,22 @@
|
||||
extensionurl = http://git.gnome.org/gnome-shell-extensions
|
||||
|
||||
# Change these to modify how installation is performed
|
||||
topextensiondir = $(datadir)/gnome-shell/extensions
|
||||
extensionbase = @gnome-shell-extensions.gnome.org
|
||||
|
||||
uuid = $(EXTENSION_ID)$(extensionbase)
|
||||
|
||||
extensiondir = $(topextensiondir)/$(uuid)
|
||||
|
||||
dist_extension_DATA = extension.js stylesheet.css
|
||||
nodist_extension_DATA = metadata.json $(EXTRA_EXTENSION)
|
||||
|
||||
EXTRA_DIST = metadata.json.in
|
||||
|
||||
metadata.json: metadata.json.in $(top_builddir)/config.status
|
||||
$(AM_V_GEN) sed -e "s|[@]LOCALEDIR@|$(datadir)/locale|" \
|
||||
-e "s|[@]uuid@|$(uuid)|" \
|
||||
-e "s|[@]shell_current@|$(PACKAGE_VERSION)|" \
|
||||
-e "s|[@]url@|$(extensionurl)|" $< > $@
|
||||
|
||||
CLEANFILES = metadata.json
|
||||
3
extensions/Makefile.am
Normal file
3
extensions/Makefile.am
Normal file
@@ -0,0 +1,3 @@
|
||||
DIST_SUBDIRS = example alternate-tab xrandr-indicator windowsNavigator auto-move-windows dock user-theme alternative-status-menu gajim
|
||||
|
||||
SUBDIRS = $(ENABLED_EXTENSIONS)
|
||||
3
extensions/alternate-tab/Makefile.am
Normal file
3
extensions/alternate-tab/Makefile.am
Normal file
@@ -0,0 +1,3 @@
|
||||
EXTENSION_ID = alternate-tab
|
||||
|
||||
include ../../extension.mk
|
||||
@@ -1,62 +1,237 @@
|
||||
/* -*- mode: js; js-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Shell= imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const AltTab = imports.ui.altTab;
|
||||
const AltTab=imports.ui.altTab;
|
||||
const Main = imports.ui.main;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const WindowManager = imports.ui.windowManager;
|
||||
|
||||
let injections = {};
|
||||
|
||||
function init(metadata) {
|
||||
function AltTabPopup2() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
function setKeybinding(name, func) {
|
||||
Main.wm.setCustomKeybindingHandler(name, Shell.ActionMode.NORMAL, func);
|
||||
}
|
||||
AltTabPopup2.prototype = {
|
||||
__proto__ : AltTab.AltTabPopup.prototype,
|
||||
|
||||
function enable() {
|
||||
injections['_keyPressHandler'] = AltTab.WindowSwitcherPopup.prototype._keyPressHandler;
|
||||
AltTab.WindowSwitcherPopup.prototype._keyPressHandler = function(keysym, action) {
|
||||
switch(action) {
|
||||
case Meta.KeyBindingAction.SWITCH_APPLICATIONS:
|
||||
action = Meta.KeyBindingAction.SWITCH_WINDOWS;
|
||||
break;
|
||||
case Meta.KeyBindingAction.SWITCH_APPLICATIONS_BACKWARD:
|
||||
action = Meta.KeyBindingAction.SWITCH_WINDOWS_BACKWARD;
|
||||
break;
|
||||
_init : function() {
|
||||
this.actor = new Shell.GenericContainer({ name: 'altTabPopup',
|
||||
reactive: true });
|
||||
|
||||
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
||||
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
||||
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
|
||||
this._haveModal = false;
|
||||
|
||||
this._currentApp = 0;
|
||||
this._currentWindow = -1;
|
||||
this._thumbnailTimeoutId = 0;
|
||||
this._motionTimeoutId = 0;
|
||||
|
||||
// Initially disable hover so we ignore the enter-event if
|
||||
// the switcher appears underneath the current pointer location
|
||||
this._disableHover();
|
||||
|
||||
this.show();
|
||||
Main.uiGroup.add_actor(this.actor);
|
||||
},
|
||||
|
||||
show : function(backward) {
|
||||
let windows = global.get_window_actors();
|
||||
|
||||
let list = '';
|
||||
let normal_windows= [];
|
||||
let appIcons = [];
|
||||
let tracker = Shell.WindowTracker.get_default();
|
||||
let apps = tracker.get_running_apps ('');
|
||||
|
||||
for (let w = windows.length-1; w >= 0; w--) {
|
||||
let win = windows[w].get_meta_window();
|
||||
if (win.window_type == 0) {
|
||||
normal_windows.push(win);
|
||||
}
|
||||
}
|
||||
normal_windows.sort(Lang.bind(this, this._sortWindows));
|
||||
|
||||
let win_on_top = normal_windows.shift();
|
||||
normal_windows.push(win_on_top);
|
||||
windows = normal_windows;
|
||||
for (let w = 0; w < windows.length; w++) {
|
||||
let win = windows[w];
|
||||
|
||||
let ap1 = null;
|
||||
for (let i = 0;i < apps.length; i++) {
|
||||
let app_wins = apps[i].get_windows();
|
||||
for (let j = 0;j < app_wins.length; j++) {
|
||||
if (app_wins[j] == win)
|
||||
ap1 = new AltTab.AppIcon(apps[i]);
|
||||
}
|
||||
}
|
||||
ap1.cachedWindows = [win];
|
||||
appIcons.push(ap1);
|
||||
}
|
||||
|
||||
if (!windows.length)
|
||||
return false;
|
||||
|
||||
if (!Main.pushModal(this.actor))
|
||||
return false;
|
||||
this._haveModal = true;
|
||||
|
||||
this.actor.connect('key-press-event', Lang.bind(this, this._keyPressEvent));
|
||||
this.actor.connect('key-release-event', Lang.bind(this, this._keyReleaseEvent));
|
||||
|
||||
this.actor.connect('button-press-event', Lang.bind(this, this._clickedOutside));
|
||||
this.actor.connect('scroll-event', Lang.bind(this, this._onScroll));
|
||||
|
||||
this._appSwitcher = new WindowList(windows);
|
||||
this._appSwitcher._altTabPopup=this;
|
||||
this._appSwitcher.highlight(0,false);
|
||||
this.actor.add_actor(this._appSwitcher.actor);
|
||||
this._appSwitcher.connect('item-activated', Lang.bind(this, this._appActivated));
|
||||
this._appSwitcher.connect('item-entered', Lang.bind(this, this._appEntered));
|
||||
|
||||
this._appIcons = appIcons;
|
||||
|
||||
return true
|
||||
},
|
||||
|
||||
_keyPressEvent : function(actor, event) {
|
||||
let keysym = event.get_key_symbol();
|
||||
let shift = (Shell.get_event_state(event) & Clutter.ModifierType.SHIFT_MASK);
|
||||
// X allows servers to represent Shift+Tab in two different ways
|
||||
if (shift && keysym == Clutter.Tab)
|
||||
keysym = Clutter.ISO_Left_Tab;
|
||||
|
||||
this._disableHover();
|
||||
|
||||
if (keysym == Clutter.grave)
|
||||
this._select(this._currentApp, this._nextWindow());
|
||||
else if (keysym == Clutter.asciitilde)
|
||||
this._select(this._currentApp, this._previousWindow());
|
||||
else if (keysym == Clutter.Escape)
|
||||
this.destroy();
|
||||
else if (this._thumbnailsFocused) {
|
||||
if (keysym == Clutter.Tab) {
|
||||
if (this._currentWindow == this._appIcons[this._currentApp].cachedWindows.length - 1)
|
||||
this._select(this._nextApp());
|
||||
else
|
||||
this._select(this._currentApp, this._nextWindow());
|
||||
} else if (keysym == Clutter.ISO_Left_Tab) {
|
||||
if (this._currentWindow == 0 || this._currentWindow == -1)
|
||||
this._select(this._previousApp());
|
||||
else
|
||||
this._select(this._currentApp, this._previousWindow());
|
||||
} else if (keysym == Clutter.Left)
|
||||
this._select(this._currentApp, this._previousWindow());
|
||||
else if (keysym == Clutter.Right)
|
||||
this._select(this._currentApp, this._nextWindow());
|
||||
else if (keysym == Clutter.Up)
|
||||
this._select(this._currentApp, null, true);
|
||||
} else {
|
||||
if (keysym == Clutter.Tab)
|
||||
this._select(this._nextApp());
|
||||
else if (keysym == Clutter.ISO_Left_Tab)
|
||||
this._select(this._previousApp());
|
||||
else if (keysym == Clutter.Left)
|
||||
this._select(this._previousApp());
|
||||
else if (keysym == Clutter.Right)
|
||||
this._select(this._nextApp());
|
||||
}
|
||||
return injections['_keyPressHandler'].call(this, keysym, action);
|
||||
};
|
||||
|
||||
Main.wm._forcedWindowSwitcher = function(display, screen, window, binding) {
|
||||
/* prevent a corner case where both popups show up at once */
|
||||
if (this._workspaceSwitcherPopup != null)
|
||||
this._workspaceSwitcherPopup.destroy();
|
||||
return true;
|
||||
},
|
||||
|
||||
let tabPopup = new AltTab.WindowSwitcherPopup();
|
||||
_sortWindows : function(win1,win2) {
|
||||
let t1 = win1.get_user_time();
|
||||
let t2 = win2.get_user_time();
|
||||
if (t2 > t1) return 1;
|
||||
else return -1;
|
||||
},
|
||||
|
||||
if (!tabPopup.show(binding.is_reversed(), binding.get_name(), binding.get_mask()))
|
||||
tabPopup.destroy();
|
||||
};
|
||||
_appActivated : function(thumbnailList, n) {
|
||||
let appIcon = this._appIcons[this._currentApp];
|
||||
Main.activateWindow(appIcon.cachedWindows[0]);
|
||||
this.destroy();
|
||||
},
|
||||
|
||||
setKeybinding('switch-applications',
|
||||
Main.wm._forcedWindowSwitcher.bind(Main.wm));
|
||||
setKeybinding('switch-applications-backward',
|
||||
Main.wm._forcedWindowSwitcher.bind(Main.wm));
|
||||
_finish : function() {
|
||||
let app = this._appIcons[this._currentApp];
|
||||
Main.activateWindow(app.cachedWindows[0]);
|
||||
this.destroy();
|
||||
},
|
||||
};
|
||||
|
||||
function WindowList(windows) {
|
||||
this._init(windows);
|
||||
}
|
||||
|
||||
function disable() {
|
||||
var prop;
|
||||
WindowList.prototype = {
|
||||
__proto__ : AltTab.AppSwitcher.prototype,
|
||||
|
||||
setKeybinding('switch-applications',
|
||||
Main.wm._startSwitcher.bind(Main.wm));
|
||||
setKeybinding('switch-applications-backward',
|
||||
Main.wm._startSwitcher.bind(Main.wm));
|
||||
_init : function(windows) {
|
||||
AltTab.AppSwitcher.prototype._init.call(this, []);
|
||||
|
||||
for (prop in injections)
|
||||
AltTab.WindowSwitcherPopup.prototype[prop] = injections[prop];
|
||||
delete Main.wm._forcedWindowSwitcher;
|
||||
let activeWorkspace = global.screen.get_active_workspace();
|
||||
this._labels = new Array();
|
||||
this._thumbnailBins = new Array();
|
||||
this._clones = new Array();
|
||||
this._windows = windows;
|
||||
this._arrows= new Array();
|
||||
this.icons= new Array();
|
||||
for (let w = 0; w < windows.length; w++) {
|
||||
let arrow = new St.DrawingArea({ style_class: 'switcher-arrow' });
|
||||
arrow.connect('repaint', Lang.bind(this, function (area) {
|
||||
Shell.draw_box_pointer(area, Shell.PointerDirection.DOWN);
|
||||
}));
|
||||
this._list.add_actor(arrow);
|
||||
this._arrows.push(arrow);
|
||||
|
||||
arrow.hide();
|
||||
|
||||
let win=windows[w];
|
||||
|
||||
let tracker = Shell.WindowTracker.get_default();
|
||||
let apps = tracker.get_running_apps ('');
|
||||
let ap1 = null;
|
||||
for (let i = 0; i < apps.length; i++) {
|
||||
let app_wins = apps[i].get_windows();
|
||||
for (let j = 0; j < app_wins.length; j++) {
|
||||
if (app_wins[j] == win) {
|
||||
ap1 = new AltTab.AppIcon(apps[i]);
|
||||
let mutterWindow = win.get_compositor_private();
|
||||
let windowTexture = mutterWindow.get_texture ();
|
||||
let [width, height] = windowTexture.get_size();
|
||||
let scale = Math.min(1.0, 128 / width, 128 / height);
|
||||
|
||||
let clone = new Clutter.Clone ({ source: windowTexture, reactive: true, width: width * scale, height: height * scale });
|
||||
ap1.icon = ap1.app.create_icon_texture(128);
|
||||
ap1._iconBin.set_size(128,128);
|
||||
ap1._iconBin.child=clone;
|
||||
|
||||
ap1.label.text=win.get_title();
|
||||
}
|
||||
}
|
||||
}
|
||||
ap1.cachedWindows = [win];
|
||||
this._addIcon(ap1);
|
||||
}
|
||||
},
|
||||
|
||||
addSeparator: function () {
|
||||
this._separator=null;
|
||||
}
|
||||
};
|
||||
|
||||
function main() {
|
||||
Main.wm.setKeybindingHandler('switch_windows', function() {
|
||||
let alpopup = new AltTabPopup2();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
extension_data += configure_file(
|
||||
input: metadata_name + '.in',
|
||||
output: metadata_name,
|
||||
configuration: metadata_conf
|
||||
)
|
||||
|
||||
extension_sources += files('prefs.js')
|
||||
@@ -1,11 +1,9 @@
|
||||
{
|
||||
"extension-id": "@extension_id@",
|
||||
"uuid": "@uuid@",
|
||||
"settings-schema": "@gschemaname@",
|
||||
"gettext-domain": "@gettext_domain@",
|
||||
"name": "AlternateTab",
|
||||
"description": "Substitute Alt-Tab with a window based switcher that does not group by application.\nThis extension is part of Classic Mode and is officially supported by GNOME. Please do not report bugs using the form below, use GNOME's GitLab instance instead.",
|
||||
"original-authors": [ "jw@bargsten.org", "thomas.bouffon@gmail.com" ],
|
||||
"shell-version": [ "@shell_current@" ],
|
||||
"description": "A replacement for Alt-Tab, allows to cycle between windows and does not group by application",
|
||||
"original-author": "thomas.bouffon@gmail.com",
|
||||
"shell-version": [ "3.0" ],
|
||||
"localedir": "@LOCALEDIR@",
|
||||
"url": "@url@"
|
||||
}
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Gio = imports.gi.Gio;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const GObject = imports.gi.GObject;
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell-extensions');
|
||||
const _ = Gettext.gettext;
|
||||
const N_ = e => e;
|
||||
|
||||
const ExtensionUtils = imports.misc.extensionUtils;
|
||||
const Me = ExtensionUtils.getCurrentExtension();
|
||||
const Convenience = Me.imports.convenience;
|
||||
|
||||
const SETTINGS_APP_ICON_MODE = 'app-icon-mode';
|
||||
const SETTINGS_CURRENT_WORKSPACE_ONLY = 'current-workspace-only';
|
||||
|
||||
const MODES = {
|
||||
'thumbnail-only': N_("Thumbnail only"),
|
||||
'app-icon-only': N_("Application icon only"),
|
||||
'both': N_("Thumbnail and application icon"),
|
||||
};
|
||||
|
||||
const AltTabSettingsWidget = GObject.registerClass(
|
||||
class AltTabSettingsWidget extends Gtk.Grid {
|
||||
_init(params) {
|
||||
super._init(params);
|
||||
this.margin = 24;
|
||||
this.row_spacing = 6;
|
||||
this.orientation = Gtk.Orientation.VERTICAL;
|
||||
|
||||
this._settings = new Gio.Settings({ schema_id: 'org.gnome.shell.window-switcher' });
|
||||
|
||||
let presentLabel = '<b>' + _("Present windows as") + '</b>';
|
||||
this.add(new Gtk.Label({ label: presentLabel, use_markup: true,
|
||||
halign: Gtk.Align.START }));
|
||||
|
||||
let align = new Gtk.Alignment({ left_padding: 12 });
|
||||
this.add(align);
|
||||
|
||||
let grid = new Gtk.Grid({ orientation: Gtk.Orientation.VERTICAL,
|
||||
row_spacing: 6,
|
||||
column_spacing: 6 });
|
||||
align.add(grid);
|
||||
|
||||
let radio = null;
|
||||
let currentMode = this._settings.get_string(SETTINGS_APP_ICON_MODE);
|
||||
for (let mode in MODES) {
|
||||
// copy the mode variable because it has function scope, not block scope
|
||||
// so cannot be used in a closure
|
||||
let modeCapture = mode;
|
||||
let name = Gettext.gettext(MODES[mode]);
|
||||
|
||||
radio = new Gtk.RadioButton({ group: radio, label: name, valign: Gtk.Align.START });
|
||||
radio.connect('toggled', widget => {
|
||||
if (widget.active)
|
||||
this._settings.set_string(SETTINGS_APP_ICON_MODE, modeCapture);
|
||||
});
|
||||
grid.add(radio);
|
||||
|
||||
if (mode == currentMode)
|
||||
radio.active = true;
|
||||
}
|
||||
|
||||
let check = new Gtk.CheckButton({ label: _("Show only windows in the current workspace"),
|
||||
margin_top: 6 });
|
||||
this._settings.bind(SETTINGS_CURRENT_WORKSPACE_ONLY, check, 'active', Gio.SettingsBindFlags.DEFAULT);
|
||||
this.add(check);
|
||||
}
|
||||
});
|
||||
|
||||
function init() {
|
||||
Convenience.initTranslations();
|
||||
}
|
||||
|
||||
function buildPrefsWidget() {
|
||||
let widget = new AltTabSettingsWidget();
|
||||
widget.show_all();
|
||||
|
||||
return widget;
|
||||
}
|
||||
3
extensions/alternative-status-menu/Makefile.am
Normal file
3
extensions/alternative-status-menu/Makefile.am
Normal file
@@ -0,0 +1,3 @@
|
||||
EXTENSION_ID = alternative-status-menu
|
||||
|
||||
include ../../extension.mk
|
||||
112
extensions/alternative-status-menu/extension.js
Normal file
112
extensions/alternative-status-menu/extension.js
Normal file
@@ -0,0 +1,112 @@
|
||||
/* -*- mode: js2 - indent-tabs-mode: nil - js2-basic-offset: 4 -*- */
|
||||
const Lang = imports.lang;
|
||||
const St = imports.gi.St;
|
||||
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const GnomeSession = imports.misc.gnomeSession;
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
function updateSuspendOrHibernate(object, pspec, item) {
|
||||
let canSuspend = this._upClient.get_can_suspend();
|
||||
let canHibernate = this._upClient.get_can_hibernate();
|
||||
|
||||
if (!canSuspend && !canHibernate) {
|
||||
item.actor.hide();
|
||||
return;
|
||||
} else
|
||||
item.actor.show();
|
||||
if (!canSuspend && canHibernate) {
|
||||
item.updateText(_("Hibernate"), null);
|
||||
return;
|
||||
}
|
||||
let suspendText = _("Suspend");
|
||||
let hibernateText = canHibernate ? _("Hibernate") : null;
|
||||
item.updateText(suspendText, hibernateText);
|
||||
}
|
||||
|
||||
function onSuspendOrHibernateActivate(item) {
|
||||
Main.overview.hide();
|
||||
|
||||
let haveSuspend = this._upClient.get_can_suspend();
|
||||
let haveHibernate = this._upClient.get_can_hibernate();
|
||||
|
||||
if (haveSuspend &&
|
||||
item.state == PopupMenu.PopupAlternatingMenuItemState.DEFAULT) {
|
||||
this._screenSaverProxy.LockRemote(Lang.bind(this, function() {
|
||||
this._upClient.suspend_sync(null);
|
||||
}));
|
||||
} else {
|
||||
this._screenSaverProxy.LockRemote(Lang.bind(this, function() {
|
||||
this._upClient.hibernate_sync(null);
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
function createSubMenu() {
|
||||
let item;
|
||||
|
||||
item = new PopupMenu.PopupImageMenuItem(_("Available"), 'user-available');
|
||||
item.connect('activate', Lang.bind(this, this._setPresenceStatus, GnomeSession.PresenceStatus.AVAILABLE));
|
||||
this.menu.addMenuItem(item);
|
||||
this._presenceItems[GnomeSession.PresenceStatus.AVAILABLE] = item;
|
||||
|
||||
item = new PopupMenu.PopupImageMenuItem(_("Busy"), 'user-busy');
|
||||
item.connect('activate', Lang.bind(this, this._setPresenceStatus, GnomeSession.PresenceStatus.BUSY));
|
||||
this.menu.addMenuItem(item);
|
||||
this._presenceItems[GnomeSession.PresenceStatus.BUSY] = item;
|
||||
|
||||
item = new PopupMenu.PopupSeparatorMenuItem();
|
||||
this.menu.addMenuItem(item);
|
||||
|
||||
item = new PopupMenu.PopupMenuItem(_("My Account"));
|
||||
item.connect('activate', Lang.bind(this, this._onMyAccountActivate));
|
||||
this.menu.addMenuItem(item);
|
||||
|
||||
item = new PopupMenu.PopupMenuItem(_("System Settings"));
|
||||
item.connect('activate', Lang.bind(this, this._onPreferencesActivate));
|
||||
this.menu.addMenuItem(item);
|
||||
|
||||
item = new PopupMenu.PopupSeparatorMenuItem();
|
||||
this.menu.addMenuItem(item);
|
||||
|
||||
item = new PopupMenu.PopupMenuItem(_("Lock Screen"));
|
||||
item.connect('activate', Lang.bind(this, this._onLockScreenActivate));
|
||||
this.menu.addMenuItem(item);
|
||||
|
||||
item = new PopupMenu.PopupMenuItem(_("Switch User"));
|
||||
item.connect('activate', Lang.bind(this, this._onLoginScreenActivate));
|
||||
this.menu.addMenuItem(item);
|
||||
this._loginScreenItem = item;
|
||||
|
||||
item = new PopupMenu.PopupMenuItem(_("Log Out..."));
|
||||
item.connect('activate', Lang.bind(this, this._onQuitSessionActivate));
|
||||
this.menu.addMenuItem(item);
|
||||
|
||||
item = new PopupMenu.PopupSeparatorMenuItem();
|
||||
this.menu.addMenuItem(item);
|
||||
|
||||
item = new PopupMenu.PopupAlternatingMenuItem(_("Suspend"),
|
||||
_("Hibernate"));
|
||||
this.menu.addMenuItem(item);
|
||||
item.connect('activate', Lang.bind(this, onSuspendOrHibernateActivate));
|
||||
this._upClient.connect('notify::can-suspend', Lang.bind(this, updateSuspendOrHibernate, item));
|
||||
this._upClient.connect('notify::can-hibernate', Lang.bind(this, updateSuspendOrHibernate, item));
|
||||
updateSuspendOrHibernate.call(this, null, null, item);
|
||||
|
||||
item = new PopupMenu.PopupMenuItem(_("Power Off..."));
|
||||
item.connect('activate', Lang.bind(this, function() {
|
||||
this._session.ShutdownRemote();
|
||||
}));
|
||||
this.menu.addMenuItem(item);
|
||||
}
|
||||
|
||||
// Put your extension initialization code here
|
||||
function main(metadata) {
|
||||
let statusMenu = Main.panel._statusmenu;
|
||||
statusMenu.menu.removeAll();
|
||||
createSubMenu.call(statusMenu);
|
||||
}
|
||||
8
extensions/alternative-status-menu/metadata.json.in
Normal file
8
extensions/alternative-status-menu/metadata.json.in
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"uuid": "@uuid@",
|
||||
"name": "Alternative Status Menu",
|
||||
"description": "Replaces GNOME Shell Status Menu with one showing Suspend/Hibernate and Power Off as separate items",
|
||||
"shell-version": [ "3.0" ],
|
||||
"localedir": "@LOCALEDIR@",
|
||||
"url": "@url@"
|
||||
}
|
||||
3
extensions/alternative-status-menu/stylesheet.css
Normal file
3
extensions/alternative-status-menu/stylesheet.css
Normal file
@@ -0,0 +1,3 @@
|
||||
.popup-alternating-menu-item:alternate {
|
||||
font-weight: normal !important;
|
||||
}
|
||||
@@ -1,767 +0,0 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Atk = imports.gi.Atk;
|
||||
const DND = imports.ui.dnd;
|
||||
const GMenu = imports.gi.GMenu;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Main = imports.ui.main;
|
||||
const Meta = imports.gi.Meta;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Signals = imports.signals;
|
||||
const Pango = imports.gi.Pango;
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell-extensions');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const ExtensionUtils = imports.misc.extensionUtils;
|
||||
const Me = ExtensionUtils.getCurrentExtension();
|
||||
const Convenience = Me.imports.convenience;
|
||||
|
||||
const appSys = Shell.AppSystem.get_default();
|
||||
|
||||
const APPLICATION_ICON_SIZE = 32;
|
||||
const HORIZ_FACTOR = 5;
|
||||
const MENU_HEIGHT_OFFSET = 132;
|
||||
const NAVIGATION_REGION_OVERSHOOT = 50;
|
||||
|
||||
class ActivitiesMenuItem extends PopupMenu.PopupBaseMenuItem {
|
||||
constructor(button) {
|
||||
super();
|
||||
this._button = button;
|
||||
this.actor.add_child(new St.Label({ text: _("Activities Overview") }));
|
||||
}
|
||||
|
||||
activate(event) {
|
||||
this._button.menu.toggle();
|
||||
Main.overview.toggle();
|
||||
super.activate(event);
|
||||
}
|
||||
};
|
||||
|
||||
class ApplicationMenuItem extends PopupMenu.PopupBaseMenuItem {
|
||||
constructor(button, app) {
|
||||
super();
|
||||
this._app = app;
|
||||
this._button = button;
|
||||
|
||||
this._iconBin = new St.Bin();
|
||||
this.actor.add_child(this._iconBin);
|
||||
|
||||
let appLabel = new St.Label({ text: app.get_name(), y_expand: true,
|
||||
y_align: Clutter.ActorAlign.CENTER });
|
||||
this.actor.add_child(appLabel);
|
||||
this.actor.label_actor = appLabel;
|
||||
|
||||
let textureCache = St.TextureCache.get_default();
|
||||
let iconThemeChangedId = textureCache.connect('icon-theme-changed',
|
||||
this._updateIcon.bind(this));
|
||||
this.actor.connect('destroy', () => {
|
||||
textureCache.disconnect(iconThemeChangedId);
|
||||
});
|
||||
this._updateIcon();
|
||||
|
||||
this.actor._delegate = this;
|
||||
let draggable = DND.makeDraggable(this.actor);
|
||||
|
||||
let maybeStartDrag = draggable._maybeStartDrag;
|
||||
draggable._maybeStartDrag = (event) => {
|
||||
if (this._dragEnabled)
|
||||
return maybeStartDrag.call(draggable, event);
|
||||
return false;
|
||||
};
|
||||
|
||||
draggable.connect('drag-begin', () => {
|
||||
Shell.util_set_hidden_from_pick(Main.legacyTray.actor, true);
|
||||
});
|
||||
draggable.connect('drag-end', () => {
|
||||
Shell.util_set_hidden_from_pick(Main.legacyTray.actor, false);
|
||||
});
|
||||
}
|
||||
|
||||
activate(event) {
|
||||
this._app.open_new_window(-1);
|
||||
this._button.selectCategory(null, null);
|
||||
this._button.menu.toggle();
|
||||
super.activate(event);
|
||||
}
|
||||
|
||||
setActive(active, params) {
|
||||
if (active)
|
||||
this._button.scrollToButton(this);
|
||||
super.setActive(active, params);
|
||||
}
|
||||
|
||||
setDragEnabled(enable) {
|
||||
this._dragEnabled = enable;
|
||||
}
|
||||
|
||||
getDragActor() {
|
||||
return this._app.create_icon_texture(APPLICATION_ICON_SIZE);
|
||||
}
|
||||
|
||||
getDragActorSource() {
|
||||
return this._iconBin;
|
||||
}
|
||||
|
||||
_updateIcon() {
|
||||
this._iconBin.set_child(this.getDragActor());
|
||||
}
|
||||
};
|
||||
|
||||
class CategoryMenuItem extends PopupMenu.PopupBaseMenuItem {
|
||||
constructor(button, category) {
|
||||
super();
|
||||
this._category = category;
|
||||
this._button = button;
|
||||
|
||||
this._oldX = -1;
|
||||
this._oldY = -1;
|
||||
|
||||
let name;
|
||||
if (this._category)
|
||||
name = this._category.get_name();
|
||||
else
|
||||
name = _("Favorites");
|
||||
|
||||
this.actor.add_child(new St.Label({ text: name }));
|
||||
this.actor.connect('motion-event', this._onMotionEvent.bind(this));
|
||||
}
|
||||
|
||||
activate(event) {
|
||||
this._button.selectCategory(this._category, this);
|
||||
this._button.scrollToCatButton(this);
|
||||
super.activate(event);
|
||||
}
|
||||
|
||||
_isNavigatingSubmenu([x, y]) {
|
||||
let [posX, posY] = this.actor.get_transformed_position();
|
||||
|
||||
if (this._oldX == -1) {
|
||||
this._oldX = x;
|
||||
this._oldY = y;
|
||||
return true;
|
||||
}
|
||||
|
||||
let deltaX = Math.abs(x - this._oldX);
|
||||
let deltaY = Math.abs(y - this._oldY);
|
||||
|
||||
this._oldX = x;
|
||||
this._oldY = y;
|
||||
|
||||
// If it lies outside the x-coordinates then it is definitely outside.
|
||||
if (posX > x || posX + this.actor.width < x)
|
||||
return false;
|
||||
|
||||
// If it lies inside the menu item then it is definitely inside.
|
||||
if (posY <= y && posY + this.actor.height >= y)
|
||||
return true;
|
||||
|
||||
// We want the keep-up triangle only if the movement is more
|
||||
// horizontal than vertical.
|
||||
if (deltaX * HORIZ_FACTOR < deltaY)
|
||||
return false;
|
||||
|
||||
// Check whether the point lies inside triangle ABC, and a similar
|
||||
// triangle on the other side of the menu item.
|
||||
//
|
||||
// +---------------------+
|
||||
// | menu item |
|
||||
// A +---------------------+ C
|
||||
// P |
|
||||
// B
|
||||
|
||||
// Ensure that the point P always lies below line AC so that we can
|
||||
// only check for triangle ABC.
|
||||
if (posY > y) {
|
||||
let offset = posY - y;
|
||||
y = posY + this.actor.height + offset;
|
||||
}
|
||||
|
||||
// Ensure that A is (0, 0).
|
||||
x -= posX;
|
||||
y -= posY + this.actor.height;
|
||||
|
||||
// Check which side of line AB the point P lies on by taking the
|
||||
// cross-product of AB and AP. See:
|
||||
// http://stackoverflow.com/questions/3461453/determine-which-side-of-a-line-a-point-lies
|
||||
if (((this.actor.width * y) - (NAVIGATION_REGION_OVERSHOOT * x)) <= 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
_onMotionEvent(actor, event) {
|
||||
if (!Clutter.get_pointer_grab()) {
|
||||
this._oldX = -1;
|
||||
this._oldY = -1;
|
||||
Clutter.grab_pointer(this.actor);
|
||||
}
|
||||
this.actor.hover = true;
|
||||
|
||||
if (this._isNavigatingSubmenu(event.get_coords()))
|
||||
return true;
|
||||
|
||||
this._oldX = -1;
|
||||
this._oldY = -1;
|
||||
this.actor.hover = false;
|
||||
Clutter.ungrab_pointer();
|
||||
|
||||
let source = event.get_source();
|
||||
if (source instanceof St.Widget)
|
||||
source.sync_hover();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
setActive(active, params) {
|
||||
if (active) {
|
||||
this._button.selectCategory(this._category, this);
|
||||
this._button.scrollToCatButton(this);
|
||||
}
|
||||
super.setActive(active, params);
|
||||
}
|
||||
};
|
||||
|
||||
class ApplicationsMenu extends PopupMenu.PopupMenu {
|
||||
constructor(sourceActor, arrowAlignment, arrowSide, button) {
|
||||
super(sourceActor, arrowAlignment, arrowSide);
|
||||
this._button = button;
|
||||
}
|
||||
|
||||
isEmpty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
open(animate) {
|
||||
this._button.hotCorner.setBarrierSize(0);
|
||||
if (this._button.hotCorner.actor) // fallback corner
|
||||
this._button.hotCorner.actor.hide();
|
||||
super.open(animate);
|
||||
}
|
||||
|
||||
close(animate) {
|
||||
let size = Main.layoutManager.panelBox.height;
|
||||
this._button.hotCorner.setBarrierSize(size);
|
||||
if (this._button.hotCorner.actor) // fallback corner
|
||||
this._button.hotCorner.actor.show();
|
||||
super.close(animate);
|
||||
}
|
||||
|
||||
toggle() {
|
||||
if (this.isOpen) {
|
||||
this._button.selectCategory(null, null);
|
||||
} else {
|
||||
if (Main.overview.visible)
|
||||
Main.overview.hide();
|
||||
}
|
||||
super.toggle();
|
||||
}
|
||||
};
|
||||
|
||||
class DesktopTarget {
|
||||
constructor() {
|
||||
this._desktop = null;
|
||||
this._desktopDestroyedId = 0;
|
||||
|
||||
this._windowAddedId =
|
||||
global.window_group.connect('actor-added',
|
||||
this._onWindowAdded.bind(this));
|
||||
|
||||
global.get_window_actors().forEach(a => {
|
||||
this._onWindowAdded(a.get_parent(), a);
|
||||
});
|
||||
}
|
||||
|
||||
get hasDesktop() {
|
||||
return this._desktop != null;
|
||||
}
|
||||
|
||||
_onWindowAdded(group, actor) {
|
||||
if (!(actor instanceof Meta.WindowActor))
|
||||
return;
|
||||
|
||||
if (actor.meta_window.get_window_type() == Meta.WindowType.DESKTOP)
|
||||
this._setDesktop(actor);
|
||||
}
|
||||
|
||||
_setDesktop(desktop) {
|
||||
if (this._desktop) {
|
||||
this._desktop.disconnect(this._desktopDestroyedId);
|
||||
this._desktopDestroyedId = 0;
|
||||
|
||||
delete this._desktop._delegate;
|
||||
}
|
||||
|
||||
this._desktop = desktop;
|
||||
this.emit('desktop-changed');
|
||||
|
||||
if (this._desktop) {
|
||||
this._desktopDestroyedId = this._desktop.connect('destroy', () => {
|
||||
this._setDesktop(null);
|
||||
});
|
||||
this._desktop._delegate = this;
|
||||
}
|
||||
}
|
||||
|
||||
_getSourceAppInfo(source) {
|
||||
if (!(source instanceof ApplicationMenuItem))
|
||||
return null;
|
||||
return source._app.app_info;
|
||||
}
|
||||
|
||||
_touchFile(file) {
|
||||
let queryFlags = Gio.FileQueryInfoFlags.NONE;
|
||||
let ioPriority = GLib.PRIORITY_DEFAULT;
|
||||
|
||||
let info = new Gio.FileInfo();
|
||||
info.set_attribute_uint64(Gio.FILE_ATTRIBUTE_TIME_ACCESS,
|
||||
GLib.get_real_time());
|
||||
file.set_attributes_async (info, queryFlags, ioPriority, null,
|
||||
(o, res) => {
|
||||
try {
|
||||
o.set_attributes_finish(res);
|
||||
} catch(e) {
|
||||
log('Failed to update access time: ' + e.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_markTrusted(file) {
|
||||
let modeAttr = Gio.FILE_ATTRIBUTE_UNIX_MODE;
|
||||
let trustedAttr = 'metadata::trusted';
|
||||
let queryFlags = Gio.FileQueryInfoFlags.NONE;
|
||||
let ioPriority = GLib.PRIORITY_DEFAULT;
|
||||
|
||||
file.query_info_async(modeAttr, queryFlags, ioPriority, null,
|
||||
(o, res) => {
|
||||
try {
|
||||
let info = o.query_info_finish(res);
|
||||
let mode = info.get_attribute_uint32(modeAttr) | 0o100;
|
||||
|
||||
info.set_attribute_uint32(modeAttr, mode);
|
||||
info.set_attribute_string(trustedAttr, 'yes');
|
||||
file.set_attributes_async (info, queryFlags, ioPriority, null,
|
||||
(o, res) => {
|
||||
o.set_attributes_finish(res);
|
||||
|
||||
// Hack: force nautilus to reload file info
|
||||
this._touchFile(file);
|
||||
});
|
||||
} catch(e) {
|
||||
log('Failed to mark file as trusted: ' + e.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (this._windowAddedId)
|
||||
global.window_group.disconnect(this._windowAddedId);
|
||||
this._windowAddedId = 0;
|
||||
|
||||
this._setDesktop(null);
|
||||
}
|
||||
|
||||
handleDragOver(source, actor, x, y, time) {
|
||||
let appInfo = this._getSourceAppInfo(source);
|
||||
if (!appInfo)
|
||||
return DND.DragMotionResult.CONTINUE;
|
||||
|
||||
return DND.DragMotionResult.COPY_DROP;
|
||||
}
|
||||
|
||||
acceptDrop(source, actor, x, y, time) {
|
||||
let appInfo = this._getSourceAppInfo(source);
|
||||
if (!appInfo)
|
||||
return false;
|
||||
|
||||
this.emit('app-dropped');
|
||||
|
||||
let desktop = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DESKTOP);
|
||||
|
||||
let src = Gio.File.new_for_path(appInfo.get_filename());
|
||||
let dst = Gio.File.new_for_path(GLib.build_filenamev([desktop, src.get_basename()]));
|
||||
|
||||
try {
|
||||
// copy_async() isn't introspectable :-(
|
||||
src.copy(dst, Gio.FileCopyFlags.OVERWRITE, null, null);
|
||||
this._markTrusted(dst);
|
||||
} catch(e) {
|
||||
log('Failed to copy to desktop: ' + e.message);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(DesktopTarget.prototype);
|
||||
|
||||
class ApplicationsButton extends PanelMenu.Button {
|
||||
constructor() {
|
||||
super(1.0, null, false);
|
||||
|
||||
this.setMenu(new ApplicationsMenu(this.actor, 1.0, St.Side.TOP, this));
|
||||
Main.panel.menuManager.addMenu(this.menu);
|
||||
|
||||
// At this moment applications menu is not keyboard navigable at
|
||||
// all (so not accessible), so it doesn't make sense to set as
|
||||
// role ATK_ROLE_MENU like other elements of the panel.
|
||||
this.actor.accessible_role = Atk.Role.LABEL;
|
||||
|
||||
let hbox = new St.BoxLayout({ style_class: 'panel-status-menu-box' });
|
||||
|
||||
this._label = new St.Label({ text: _("Applications"),
|
||||
y_expand: true,
|
||||
y_align: Clutter.ActorAlign.CENTER });
|
||||
hbox.add_child(this._label);
|
||||
hbox.add_child(PopupMenu.arrowIcon(St.Side.BOTTOM));
|
||||
|
||||
this.actor.add_actor(hbox);
|
||||
this.actor.name = 'panelApplications';
|
||||
this.actor.label_actor = this._label;
|
||||
|
||||
this.actor.connect('captured-event', this._onCapturedEvent.bind(this));
|
||||
this.actor.connect('destroy', this._onDestroy.bind(this));
|
||||
|
||||
this._showingId = Main.overview.connect('showing', () => {
|
||||
this.actor.add_accessible_state (Atk.StateType.CHECKED);
|
||||
});
|
||||
this._hidingId = Main.overview.connect('hiding', () => {
|
||||
this.actor.remove_accessible_state (Atk.StateType.CHECKED);
|
||||
});
|
||||
Main.layoutManager.connect('startup-complete',
|
||||
this._setKeybinding.bind(this));
|
||||
this._setKeybinding();
|
||||
|
||||
this._desktopTarget = new DesktopTarget();
|
||||
this._desktopTarget.connect('app-dropped', () => {
|
||||
this.menu.close();
|
||||
});
|
||||
this._desktopTarget.connect('desktop-changed', () => {
|
||||
this._applicationsButtons.forEach(item => {
|
||||
item.setDragEnabled(this._desktopTarget.hasDesktop);
|
||||
});
|
||||
});
|
||||
|
||||
this._tree = new GMenu.Tree({ menu_basename: 'applications.menu' });
|
||||
this._treeChangedId = this._tree.connect('changed',
|
||||
this._onTreeChanged.bind(this));
|
||||
|
||||
this._applicationsButtons = new Map();
|
||||
this.reloadFlag = false;
|
||||
this._createLayout();
|
||||
this._display();
|
||||
this._installedChangedId = appSys.connect('installed-changed',
|
||||
this._onTreeChanged.bind(this));
|
||||
}
|
||||
|
||||
_onTreeChanged() {
|
||||
if (this.menu.isOpen) {
|
||||
this._redisplay();
|
||||
this.mainBox.show();
|
||||
} else {
|
||||
this.reloadFlag = true;
|
||||
}
|
||||
}
|
||||
|
||||
get hotCorner() {
|
||||
return Main.layoutManager.hotCorners[Main.layoutManager.primaryIndex];
|
||||
}
|
||||
|
||||
_createVertSeparator() {
|
||||
let separator = new St.DrawingArea({ style_class: 'calendar-vertical-separator',
|
||||
pseudo_class: 'highlighted' });
|
||||
separator.connect('repaint', this._onVertSepRepaint.bind(this));
|
||||
return separator;
|
||||
}
|
||||
|
||||
_onDestroy() {
|
||||
Main.overview.disconnect(this._showingId);
|
||||
Main.overview.disconnect(this._hidingId);
|
||||
appSys.disconnect(this._installedChangedId);
|
||||
this._tree.disconnect(this._treeChangedId);
|
||||
this._tree = null;
|
||||
|
||||
Main.wm.setCustomKeybindingHandler('panel-main-menu',
|
||||
Shell.ActionMode.NORMAL |
|
||||
Shell.ActionMode.OVERVIEW,
|
||||
Main.sessionMode.hasOverview ?
|
||||
Main.overview.toggle.bind(Main.overview) :
|
||||
null);
|
||||
|
||||
this._desktopTarget.destroy();
|
||||
}
|
||||
|
||||
_onCapturedEvent(actor, event) {
|
||||
if (event.type() == Clutter.EventType.BUTTON_PRESS) {
|
||||
if (!Main.overview.shouldToggleByCornerOrButton())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
_onMenuKeyPress(actor, event) {
|
||||
let symbol = event.get_key_symbol();
|
||||
if (symbol == Clutter.KEY_Left || symbol == Clutter.KEY_Right) {
|
||||
let direction = symbol == Clutter.KEY_Left ? Gtk.DirectionType.LEFT
|
||||
: Gtk.DirectionType.RIGHT;
|
||||
if (this.menu.actor.navigate_focus(global.stage.key_focus, direction, false))
|
||||
return true;
|
||||
}
|
||||
return super._onMenuKeyPress(actor, event);
|
||||
}
|
||||
|
||||
_onVertSepRepaint(area) {
|
||||
let cr = area.get_context();
|
||||
let themeNode = area.get_theme_node();
|
||||
let [width, height] = area.get_surface_size();
|
||||
let stippleColor = themeNode.get_color('-stipple-color');
|
||||
let stippleWidth = themeNode.get_length('-stipple-width');
|
||||
let x = Math.floor(width/2) + 0.5;
|
||||
cr.moveTo(x, 0);
|
||||
cr.lineTo(x, height);
|
||||
Clutter.cairo_set_source_color(cr, stippleColor);
|
||||
cr.setDash([1, 3], 1); // Hard-code for now
|
||||
cr.setLineWidth(stippleWidth);
|
||||
cr.stroke();
|
||||
}
|
||||
|
||||
_onOpenStateChanged(menu, open) {
|
||||
if (open) {
|
||||
if (this.reloadFlag) {
|
||||
this._redisplay();
|
||||
this.reloadFlag = false;
|
||||
}
|
||||
this.mainBox.show();
|
||||
}
|
||||
super._onOpenStateChanged(menu, open);
|
||||
}
|
||||
|
||||
_setKeybinding() {
|
||||
Main.wm.setCustomKeybindingHandler('panel-main-menu',
|
||||
Shell.ActionMode.NORMAL |
|
||||
Shell.ActionMode.OVERVIEW,
|
||||
() => { this.menu.toggle(); });
|
||||
}
|
||||
|
||||
_redisplay() {
|
||||
this.applicationsBox.destroy_all_children();
|
||||
this.categoriesBox.destroy_all_children();
|
||||
this._display();
|
||||
}
|
||||
|
||||
_loadCategory(categoryId, dir) {
|
||||
let iter = dir.iter();
|
||||
let nextType;
|
||||
while ((nextType = iter.next()) != GMenu.TreeItemType.INVALID) {
|
||||
if (nextType == GMenu.TreeItemType.ENTRY) {
|
||||
let entry = iter.get_entry();
|
||||
let id;
|
||||
try {
|
||||
id = entry.get_desktop_file_id(); // catch non-UTF8 filenames
|
||||
} catch(e) {
|
||||
continue;
|
||||
}
|
||||
let app = appSys.lookup_app(id);
|
||||
if (!app)
|
||||
app = new Shell.App({ app_info: entry.get_app_info() });
|
||||
if (app.get_app_info().should_show())
|
||||
this.applicationsByCategory[categoryId].push(app);
|
||||
} else if (nextType == GMenu.TreeItemType.SEPARATOR) {
|
||||
this.applicationsByCategory[categoryId].push('separator');
|
||||
} else if (nextType == GMenu.TreeItemType.DIRECTORY) {
|
||||
let subdir = iter.get_directory();
|
||||
if (!subdir.get_is_nodisplay())
|
||||
this._loadCategory(categoryId, subdir);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scrollToButton(button) {
|
||||
let appsScrollBoxAdj = this.applicationsScrollBox.get_vscroll_bar().get_adjustment();
|
||||
let appsScrollBoxAlloc = this.applicationsScrollBox.get_allocation_box();
|
||||
let currentScrollValue = appsScrollBoxAdj.get_value();
|
||||
let boxHeight = appsScrollBoxAlloc.y2 - appsScrollBoxAlloc.y1;
|
||||
let buttonAlloc = button.actor.get_allocation_box();
|
||||
let newScrollValue = currentScrollValue;
|
||||
if (currentScrollValue > buttonAlloc.y1 - 10)
|
||||
newScrollValue = buttonAlloc.y1 - 10;
|
||||
if (boxHeight + currentScrollValue < buttonAlloc.y2 + 10)
|
||||
newScrollValue = buttonAlloc.y2 - boxHeight + 10;
|
||||
if (newScrollValue != currentScrollValue)
|
||||
appsScrollBoxAdj.set_value(newScrollValue);
|
||||
}
|
||||
|
||||
scrollToCatButton(button) {
|
||||
let catsScrollBoxAdj = this.categoriesScrollBox.get_vscroll_bar().get_adjustment();
|
||||
let catsScrollBoxAlloc = this.categoriesScrollBox.get_allocation_box();
|
||||
let currentScrollValue = catsScrollBoxAdj.get_value();
|
||||
let boxHeight = catsScrollBoxAlloc.y2 - catsScrollBoxAlloc.y1;
|
||||
let buttonAlloc = button.actor.get_allocation_box();
|
||||
let newScrollValue = currentScrollValue;
|
||||
if (currentScrollValue > buttonAlloc.y1 - 10)
|
||||
newScrollValue = buttonAlloc.y1 - 10;
|
||||
if (boxHeight + currentScrollValue < buttonAlloc.y2 + 10)
|
||||
newScrollValue = buttonAlloc.y2 - boxHeight + 10;
|
||||
if (newScrollValue != currentScrollValue)
|
||||
catsScrollBoxAdj.set_value(newScrollValue);
|
||||
}
|
||||
|
||||
_createLayout() {
|
||||
let section = new PopupMenu.PopupMenuSection();
|
||||
this.menu.addMenuItem(section);
|
||||
this.mainBox = new St.BoxLayout({ vertical: false });
|
||||
this.leftBox = new St.BoxLayout({ vertical: true });
|
||||
this.applicationsScrollBox = new St.ScrollView({ x_fill: true, y_fill: false,
|
||||
y_align: St.Align.START,
|
||||
style_class: 'apps-menu vfade' });
|
||||
this.applicationsScrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
|
||||
let vscroll = this.applicationsScrollBox.get_vscroll_bar();
|
||||
vscroll.connect('scroll-start', () => {
|
||||
this.menu.passEvents = true;
|
||||
});
|
||||
vscroll.connect('scroll-stop', () => {
|
||||
this.menu.passEvents = false;
|
||||
});
|
||||
this.categoriesScrollBox = new St.ScrollView({ x_fill: true, y_fill: false,
|
||||
y_align: St.Align.START,
|
||||
style_class: 'vfade' });
|
||||
this.categoriesScrollBox.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
|
||||
vscroll = this.categoriesScrollBox.get_vscroll_bar();
|
||||
vscroll.connect('scroll-start', () => { this.menu.passEvents = true; });
|
||||
vscroll.connect('scroll-stop', () => { this.menu.passEvents = false; });
|
||||
this.leftBox.add(this.categoriesScrollBox, { expand: true,
|
||||
x_fill: true, y_fill: true,
|
||||
y_align: St.Align.START });
|
||||
|
||||
let activities = new ActivitiesMenuItem(this);
|
||||
this.leftBox.add(activities.actor, { expand: false,
|
||||
x_fill: true, y_fill: false,
|
||||
y_align: St.Align.START });
|
||||
|
||||
this.applicationsBox = new St.BoxLayout({ vertical: true });
|
||||
this.applicationsScrollBox.add_actor(this.applicationsBox);
|
||||
this.categoriesBox = new St.BoxLayout({ vertical: true });
|
||||
this.categoriesScrollBox.add_actor(this.categoriesBox);
|
||||
|
||||
this.mainBox.add(this.leftBox);
|
||||
this.mainBox.add(this._createVertSeparator(), { expand: false, x_fill: false, y_fill: true});
|
||||
this.mainBox.add(this.applicationsScrollBox, { expand: true, x_fill: true, y_fill: true });
|
||||
section.actor.add_actor(this.mainBox);
|
||||
}
|
||||
|
||||
_display() {
|
||||
this._applicationsButtons.clear();
|
||||
this.mainBox.style=('width: 35em;');
|
||||
this.mainBox.hide();
|
||||
|
||||
//Load categories
|
||||
this.applicationsByCategory = {};
|
||||
this._tree.load_sync();
|
||||
let root = this._tree.get_root_directory();
|
||||
let categoryMenuItem = new CategoryMenuItem(this, null);
|
||||
this.categoriesBox.add_actor(categoryMenuItem.actor);
|
||||
let iter = root.iter();
|
||||
let nextType;
|
||||
while ((nextType = iter.next()) != GMenu.TreeItemType.INVALID) {
|
||||
if (nextType == GMenu.TreeItemType.DIRECTORY) {
|
||||
let dir = iter.get_directory();
|
||||
if (!dir.get_is_nodisplay()) {
|
||||
let categoryId = dir.get_menu_id();
|
||||
this.applicationsByCategory[categoryId] = [];
|
||||
this._loadCategory(categoryId, dir);
|
||||
if (this.applicationsByCategory[categoryId].length > 0) {
|
||||
let categoryMenuItem = new CategoryMenuItem(this, dir);
|
||||
this.categoriesBox.add_actor(categoryMenuItem.actor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Load applications
|
||||
this._displayButtons(this._listApplications(null));
|
||||
|
||||
let height = this.categoriesBox.height + MENU_HEIGHT_OFFSET + 'px';
|
||||
this.mainBox.style+=('height: ' + height);
|
||||
}
|
||||
|
||||
selectCategory(dir, categoryMenuItem) {
|
||||
this.applicationsBox.get_children().forEach(c => {
|
||||
if (c._delegate instanceof PopupMenu.PopupSeparatorMenuItem)
|
||||
c._delegate.destroy();
|
||||
else
|
||||
this.applicationsBox.remove_actor(c);
|
||||
});
|
||||
|
||||
if (dir)
|
||||
this._displayButtons(this._listApplications(dir.get_menu_id()));
|
||||
else
|
||||
this._displayButtons(this._listApplications(null));
|
||||
}
|
||||
|
||||
_displayButtons(apps) {
|
||||
if (apps) {
|
||||
for (let i = 0; i < apps.length; i++) {
|
||||
let app = apps[i];
|
||||
let item;
|
||||
if (app instanceof Shell.App)
|
||||
item = this._applicationsButtons.get(app);
|
||||
else
|
||||
item = new PopupMenu.PopupSeparatorMenuItem();
|
||||
if (!item) {
|
||||
item = new ApplicationMenuItem(this, app);
|
||||
item.setDragEnabled(this._desktopTarget.hasDesktop);
|
||||
this._applicationsButtons.set(app, item);
|
||||
}
|
||||
if (!item.actor.get_parent())
|
||||
this.applicationsBox.add_actor(item.actor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_listApplications(category_menu_id) {
|
||||
let applist;
|
||||
|
||||
if (category_menu_id) {
|
||||
applist = this.applicationsByCategory[category_menu_id];
|
||||
} else {
|
||||
applist = new Array();
|
||||
let favorites = global.settings.get_strv('favorite-apps');
|
||||
for (let i = 0; i < favorites.length; i++) {
|
||||
let app = appSys.lookup_app(favorites[i]);
|
||||
if (app)
|
||||
applist.push(app);
|
||||
}
|
||||
}
|
||||
|
||||
return applist;
|
||||
}
|
||||
|
||||
destroy() {
|
||||
super.destroy();
|
||||
}
|
||||
};
|
||||
|
||||
let appsMenuButton;
|
||||
let activitiesButton;
|
||||
|
||||
function enable() {
|
||||
activitiesButton = Main.panel.statusArea['activities'];
|
||||
activitiesButton.container.hide();
|
||||
appsMenuButton = new ApplicationsButton();
|
||||
Main.panel.addToStatusArea('apps-menu', appsMenuButton, 1, 'left');
|
||||
}
|
||||
|
||||
function disable() {
|
||||
Main.panel.menuManager.removeMenu(appsMenuButton.menu);
|
||||
appsMenuButton.destroy();
|
||||
activitiesButton.container.show();
|
||||
}
|
||||
|
||||
function init(metadata) {
|
||||
Convenience.initTranslations();
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
extension_data += configure_file(
|
||||
input: metadata_name + '.in',
|
||||
output: metadata_name,
|
||||
configuration: metadata_conf
|
||||
)
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"extension-id": "@extension_id@",
|
||||
"uuid": "@uuid@",
|
||||
"gettext-domain": "@gettext_domain@",
|
||||
"name": "Applications Menu",
|
||||
"description": "Add a category-based menu for applications.\nThis extension is part of Classic Mode and is officially supported by GNOME. Please do not report bugs using the form below, use GNOME's GitLab instance instead.",
|
||||
"original-authors": [ "e2002@bk.ru", "debarshir@gnome.org" ],
|
||||
"shell-version": [ "@shell_current@" ],
|
||||
"url": "@url@"
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
.apps-menu:ltr {
|
||||
padding-right: 3px;
|
||||
}
|
||||
|
||||
.apps-menu:rtl {
|
||||
padding-left: 3px;
|
||||
}
|
||||
14
extensions/auto-move-windows/Makefile.am
Normal file
14
extensions/auto-move-windows/Makefile.am
Normal file
@@ -0,0 +1,14 @@
|
||||
EXTENSION_ID = auto-move-windows
|
||||
|
||||
include ../../extension.mk
|
||||
|
||||
gschemas_in = org.gnome.shell.extensions.auto-move-windows.gschema.xml.in
|
||||
|
||||
@INTLTOOL_XML_NOMERGE_RULE@
|
||||
|
||||
gsettings_SCHEMAS = $(gschemas_in:.xml.in=.xml)
|
||||
|
||||
@GSETTINGS_RULES@
|
||||
|
||||
CLEANFILES += $(gschemas_in:.xml.in=.valid) $(gsettings_SCHEMAS)
|
||||
EXTRA_DIST += $(gschemas_in)
|
||||
@@ -1,145 +1,109 @@
|
||||
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
|
||||
// Start apps on custom workspaces
|
||||
|
||||
const Glib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
|
||||
const ExtensionUtils = imports.misc.extensionUtils;
|
||||
const Me = ExtensionUtils.getCurrentExtension();
|
||||
const Convenience = Me.imports.convenience;
|
||||
const SETTINGS_SCHEMA = 'org.gnome.shell.extensions.auto-move-windows';
|
||||
const SETTINGS_KEY = 'application-list';
|
||||
|
||||
class WindowMover {
|
||||
constructor() {
|
||||
this._settings = Convenience.getSettings();
|
||||
this._appSystem = Shell.AppSystem.get_default();
|
||||
this._appConfigs = new Map();
|
||||
this._appData = new Map();
|
||||
function WindowMover() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
this._appsChangedId =
|
||||
this._appSystem.connect('installed-changed',
|
||||
this._updateAppData.bind(this));
|
||||
WindowMover.prototype = {
|
||||
_init: function() {
|
||||
this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
|
||||
this._windowTracker = Shell.WindowTracker.get_default();
|
||||
|
||||
this._settings.connect('changed', this._updateAppConfigs.bind(this));
|
||||
this._updateAppConfigs();
|
||||
}
|
||||
let display = global.screen.get_display();
|
||||
// Connect after so the handler from ShellWindowTracker has already run
|
||||
display.connect_after('window-created', Lang.bind(this, this._findAndMove));
|
||||
},
|
||||
|
||||
_updateAppConfigs() {
|
||||
this._appConfigs.clear();
|
||||
|
||||
this._settings.get_strv('application-list').forEach(v => {
|
||||
let [appId, num] = v.split(':');
|
||||
this._appConfigs.set(appId, parseInt(num) - 1);
|
||||
});
|
||||
|
||||
this._updateAppData();
|
||||
}
|
||||
|
||||
_updateAppData() {
|
||||
let ids = [...this._appConfigs.keys()];
|
||||
let removedApps = [...this._appData.keys()].filter(
|
||||
a => !ids.includes(a.id)
|
||||
);
|
||||
removedApps.forEach(app => {
|
||||
app.disconnect(this._appData.get(app).windowsChangedId);
|
||||
this._appData.delete(app);
|
||||
});
|
||||
|
||||
let addedApps = ids.map(id => this._appSystem.lookup_app(id)).filter(
|
||||
app => app != null && !this._appData.has(app)
|
||||
);
|
||||
addedApps.forEach(app => {
|
||||
let data = {
|
||||
windowsChangedId: app.connect('windows-changed',
|
||||
this._appWindowsChanged.bind(this)),
|
||||
moveWindowsId: 0,
|
||||
windows: app.get_windows()
|
||||
}
|
||||
this._appData.set(app, data);
|
||||
});
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (this._appsChangedId) {
|
||||
this._appSystem.disconnect(this._appsChangedId);
|
||||
this._appsChangedId = 0;
|
||||
}
|
||||
|
||||
if (this._settings) {
|
||||
this._settings.run_dispose();
|
||||
this._settings = null;
|
||||
}
|
||||
|
||||
this._appConfigs.clear();
|
||||
this._updateAppData();
|
||||
}
|
||||
|
||||
_moveWindow(window, workspaceNum) {
|
||||
if (window.skip_taskbar)
|
||||
return;
|
||||
|
||||
// ensure we have the required number of workspaces
|
||||
for (let i = global.screen.n_workspaces; i <= workspaceNum; i++) {
|
||||
window.change_workspace_by_index(i - 1, false);
|
||||
_ensureAtLeastWorkspaces: function(num, window) {
|
||||
for (let j = global.screen.n_workspaces; j <= num; j++) {
|
||||
window.change_workspace_by_index(j-1, false, global.get_current_time());
|
||||
global.screen.append_new_workspace(false, 0);
|
||||
}
|
||||
},
|
||||
|
||||
window.change_workspace_by_index(workspaceNum, false);
|
||||
_findAndMove: function(display, window, noRecurse) {
|
||||
if (!this._windowTracker.is_window_interesting(window))
|
||||
return;
|
||||
|
||||
let spaces = this._settings.get_strv(SETTINGS_KEY);
|
||||
|
||||
let app = this._windowTracker.get_window_app(window);
|
||||
if (!app) {
|
||||
if (!noRecurse) {
|
||||
// window is not tracked yet
|
||||
Mainloop.idle_add(Lang.bind(this, function() {
|
||||
this._findAndMove(display, window, true);
|
||||
return false;
|
||||
}));
|
||||
} else
|
||||
log ('Cannot find application for window');
|
||||
return;
|
||||
}
|
||||
let app_id = app.get_id();
|
||||
for ( let j = 0 ; j < spaces.length; j++ ) {
|
||||
let apps_to_space = spaces[j].split(":");
|
||||
// Match application id
|
||||
if (apps_to_space[0] == app_id) {
|
||||
let workspace_num = parseInt(apps_to_space[1]) - 1;
|
||||
|
||||
if (workspace_num >= global.screen.n_workspaces)
|
||||
this._ensureAtLeastWorkspaces(workspace_num, window);
|
||||
|
||||
window.change_workspace_by_index(workspace_num, false, global.get_current_time());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_appWindowsChanged(app) {
|
||||
let data = this._appData.get(app);
|
||||
let windows = app.get_windows();
|
||||
|
||||
// If get_compositor_private() returns non-NULL on a removed windows,
|
||||
// the window still exists and is just moved to a different workspace
|
||||
// or something; assume it'll be added back immediately, so keep it
|
||||
// to avoid moving it again
|
||||
windows.push(...data.windows.filter(
|
||||
w => !windows.includes(w) && w.get_compositor_private() != null
|
||||
));
|
||||
|
||||
let workspaceNum = this._appConfigs.get(app.id);
|
||||
windows.filter(w => !data.windows.includes(w)).forEach(window => {
|
||||
this._moveWindow(window, workspaceNum);
|
||||
});
|
||||
data.windows = windows;
|
||||
}
|
||||
};
|
||||
|
||||
let prevCheckWorkspaces;
|
||||
let winMover;
|
||||
|
||||
function init() {
|
||||
Convenience.initTranslations();
|
||||
}
|
||||
|
||||
function myCheckWorkspaces() {
|
||||
let keepAliveWorkspaces = [];
|
||||
let foundNonEmpty = false;
|
||||
for (let i = this._workspaces.length - 1; i >= 0; i--) {
|
||||
if (!foundNonEmpty)
|
||||
foundNonEmpty = this._workspaces[i].list_windows().length > 0;
|
||||
else if (!this._workspaces[i]._keepAliveId)
|
||||
keepAliveWorkspaces.push(this._workspaces[i]);
|
||||
}
|
||||
function main(extensionMeta) {
|
||||
Main._checkWorkspaces = function() {
|
||||
let i;
|
||||
let emptyWorkspaces = new Array(Main._workspaces.length);
|
||||
|
||||
// make sure the original method only removes empty workspaces at the end
|
||||
keepAliveWorkspaces.forEach(ws => { ws._keepAliveId = 1; });
|
||||
prevCheckWorkspaces.call(this);
|
||||
keepAliveWorkspaces.forEach(ws => { delete ws._keepAliveId; });
|
||||
for (i = 0; i < Main._workspaces.length; i++)
|
||||
emptyWorkspaces[i] = true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function enable() {
|
||||
prevCheckWorkspaces = Main.wm._workspaceTracker._checkWorkspaces;
|
||||
Main.wm._workspaceTracker._checkWorkspaces = myCheckWorkspaces;
|
||||
|
||||
winMover = new WindowMover();
|
||||
}
|
||||
|
||||
function disable() {
|
||||
Main.wm._workspaceTracker._checkWorkspaces = prevCheckWorkspaces;
|
||||
winMover.destroy();
|
||||
let windows = global.get_window_actors();
|
||||
for (i = 0; i < windows.length; i++) {
|
||||
let win = windows[i];
|
||||
|
||||
if (win.get_meta_window().is_on_all_workspaces())
|
||||
continue;
|
||||
|
||||
let workspaceIndex = win.get_workspace();
|
||||
emptyWorkspaces[workspaceIndex] = false;
|
||||
}
|
||||
|
||||
// If we don't have an empty workspace at the end, add one
|
||||
if (!emptyWorkspaces[emptyWorkspaces.length -1]) {
|
||||
global.screen.append_new_workspace(false, global.get_current_time());
|
||||
emptyWorkspaces.push(false);
|
||||
}
|
||||
|
||||
// Delete other empty workspaces; do it from the end to avoid index changes
|
||||
for (i = emptyWorkspaces.length - 2; i >= 0; i--) {
|
||||
if (emptyWorkspaces[i])
|
||||
global.screen.remove_workspace(Main._workspaces[i], global.get_current_time());
|
||||
else
|
||||
break;
|
||||
}
|
||||
Main._checkWorkspacesId = 0;
|
||||
return false;
|
||||
|
||||
};
|
||||
|
||||
new WindowMover();
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
extension_data += configure_file(
|
||||
input: metadata_name + '.in',
|
||||
output: metadata_name,
|
||||
configuration: metadata_conf
|
||||
)
|
||||
|
||||
extension_sources += files('prefs.js')
|
||||
extension_schemas += files(metadata_conf.get('gschemaname') + '.gschema.xml')
|
||||
@@ -1,11 +1,9 @@
|
||||
{
|
||||
"extension-id": "@extension_id@",
|
||||
"uuid": "@uuid@",
|
||||
"settings-schema": "@gschemaname@",
|
||||
"gettext-domain": "@gettext_domain@",
|
||||
"name": "Auto Move Windows",
|
||||
"description": "Move applications to specific workspaces when they create windows.",
|
||||
"shell-version": [ "@shell_current@" ],
|
||||
"description": "Move applications to specific workspaces when they create windows",
|
||||
"shell-version": [ "3.0.0", "3.0.1", "3.0.2" ],
|
||||
"localedir": "@LOCALEDIR@",
|
||||
"original-authors": [ "alessandro.crismani@gmail.com", "thomas.bouffon@gmail.com" ],
|
||||
"url": "@url@"
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
<key name="application-list" type="as">
|
||||
<!-- FIXME: should be a(su), when JS supports more of GVariant -->
|
||||
<default>[ ]</default>
|
||||
<summary>Application and workspace list</summary>
|
||||
<description>A list of strings, each containing an application id (desktop file name), followed by a colon and the workspace number</description>
|
||||
<_summary>Application and workspace list</_summary>
|
||||
<_description>A list of strings, each containing an application id (desktop file name), followed by a colon and the workspace number</_description>
|
||||
</key>
|
||||
</schema>
|
||||
</schemalist>
|
||||
@@ -1,260 +0,0 @@
|
||||
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
|
||||
// Start apps on custom workspaces
|
||||
|
||||
const Gio = imports.gi.Gio;
|
||||
const GObject = imports.gi.GObject;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell-extensions');
|
||||
const _ = Gettext.gettext;
|
||||
const N_ = e => e;
|
||||
|
||||
const ExtensionUtils = imports.misc.extensionUtils;
|
||||
const Me = ExtensionUtils.getCurrentExtension();
|
||||
const Convenience = Me.imports.convenience;
|
||||
|
||||
const SETTINGS_KEY = 'application-list';
|
||||
|
||||
const WORKSPACE_MAX = 36; // compiled in limit of mutter
|
||||
|
||||
const Columns = {
|
||||
APPINFO: 0,
|
||||
DISPLAY_NAME: 1,
|
||||
ICON: 2,
|
||||
WORKSPACE: 3,
|
||||
ADJUSTMENT: 4
|
||||
};
|
||||
|
||||
const Widget = GObject.registerClass({
|
||||
GTypeName: 'AutoMoveWindowsPrefsWidget',
|
||||
}, class Widget extends Gtk.Grid {
|
||||
_init(params) {
|
||||
super._init(params);
|
||||
this.set_orientation(Gtk.Orientation.VERTICAL);
|
||||
|
||||
this._settings = Convenience.getSettings();
|
||||
this._settings.connect('changed', this._refresh.bind(this));
|
||||
this._changedPermitted = false;
|
||||
|
||||
this._store = new Gtk.ListStore();
|
||||
this._store.set_column_types([Gio.AppInfo, GObject.TYPE_STRING, Gio.Icon, GObject.TYPE_INT,
|
||||
Gtk.Adjustment]);
|
||||
|
||||
let scrolled = new Gtk.ScrolledWindow({ shadow_type: Gtk.ShadowType.IN});
|
||||
scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
|
||||
this.add(scrolled);
|
||||
|
||||
|
||||
this._treeView = new Gtk.TreeView({ model: this._store,
|
||||
hexpand: true, vexpand: true });
|
||||
this._treeView.get_selection().set_mode(Gtk.SelectionMode.SINGLE);
|
||||
|
||||
let appColumn = new Gtk.TreeViewColumn({ expand: true, sort_column_id: Columns.DISPLAY_NAME,
|
||||
title: _("Application") });
|
||||
let iconRenderer = new Gtk.CellRendererPixbuf;
|
||||
appColumn.pack_start(iconRenderer, false);
|
||||
appColumn.add_attribute(iconRenderer, "gicon", Columns.ICON);
|
||||
let nameRenderer = new Gtk.CellRendererText;
|
||||
appColumn.pack_start(nameRenderer, true);
|
||||
appColumn.add_attribute(nameRenderer, "text", Columns.DISPLAY_NAME);
|
||||
this._treeView.append_column(appColumn);
|
||||
|
||||
let workspaceColumn = new Gtk.TreeViewColumn({ title: _("Workspace"),
|
||||
sort_column_id: Columns.WORKSPACE });
|
||||
let workspaceRenderer = new Gtk.CellRendererSpin({ editable: true });
|
||||
workspaceRenderer.connect('edited', this._workspaceEdited.bind(this));
|
||||
workspaceColumn.pack_start(workspaceRenderer, true);
|
||||
workspaceColumn.add_attribute(workspaceRenderer, "adjustment", Columns.ADJUSTMENT);
|
||||
workspaceColumn.add_attribute(workspaceRenderer, "text", Columns.WORKSPACE);
|
||||
this._treeView.append_column(workspaceColumn);
|
||||
|
||||
scrolled.add(this._treeView);
|
||||
|
||||
let toolbar = new Gtk.Toolbar({ icon_size: Gtk.IconSize.SMALL_TOOLBAR });
|
||||
toolbar.get_style_context().add_class(Gtk.STYLE_CLASS_INLINE_TOOLBAR);
|
||||
this.add(toolbar);
|
||||
|
||||
let newButton = new Gtk.ToolButton({ icon_name: 'bookmark-new-symbolic',
|
||||
label: _("Add Rule"),
|
||||
is_important: true });
|
||||
newButton.connect('clicked', this._createNew.bind(this));
|
||||
toolbar.add(newButton);
|
||||
|
||||
let delButton = new Gtk.ToolButton({ icon_name: 'edit-delete-symbolic' });
|
||||
delButton.connect('clicked', this._deleteSelected.bind(this));
|
||||
toolbar.add(delButton);
|
||||
|
||||
let selection = this._treeView.get_selection();
|
||||
selection.connect('changed', () => {
|
||||
delButton.sensitive = selection.count_selected_rows() > 0;
|
||||
});
|
||||
delButton.sensitive = selection.count_selected_rows() > 0;
|
||||
|
||||
this._changedPermitted = true;
|
||||
this._refresh();
|
||||
}
|
||||
|
||||
_createNew() {
|
||||
let dialog = new Gtk.Dialog({ title: _("Create new matching rule"),
|
||||
transient_for: this.get_toplevel(),
|
||||
use_header_bar: true,
|
||||
modal: true });
|
||||
dialog.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL);
|
||||
let addButton = dialog.add_button(_("Add"), Gtk.ResponseType.OK);
|
||||
dialog.set_default_response(Gtk.ResponseType.OK);
|
||||
|
||||
let grid = new Gtk.Grid({ column_spacing: 10,
|
||||
row_spacing: 15,
|
||||
margin: 10 });
|
||||
dialog._appChooser = new Gtk.AppChooserWidget({ show_all: true });
|
||||
dialog._appChooser.connect('application-selected', (w, appInfo) => {
|
||||
addButton.sensitive = appInfo && this._checkId(appInfo.get_id());
|
||||
});
|
||||
let appInfo = dialog._appChooser.get_app_info();
|
||||
addButton.sensitive = appInfo && this._checkId(appInfo.get_id());
|
||||
|
||||
grid.attach(dialog._appChooser, 0, 0, 2, 1);
|
||||
grid.attach(new Gtk.Label({ label: _("Workspace"),
|
||||
halign: Gtk.Align.END }), 0, 1, 1, 1);
|
||||
let adjustment = new Gtk.Adjustment({ lower: 1,
|
||||
upper: WORKSPACE_MAX,
|
||||
step_increment: 1
|
||||
});
|
||||
dialog._spin = new Gtk.SpinButton({ adjustment: adjustment,
|
||||
snap_to_ticks: true });
|
||||
dialog._spin.set_value(1);
|
||||
grid.attach(dialog._spin, 1, 1, 1, 1);
|
||||
dialog.get_content_area().add(grid);
|
||||
|
||||
dialog.connect('response', (dialog, id) => {
|
||||
if (id != Gtk.ResponseType.OK) {
|
||||
dialog.destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
let appInfo = dialog._appChooser.get_app_info();
|
||||
if (!appInfo)
|
||||
return;
|
||||
let index = Math.floor(dialog._spin.value);
|
||||
if (isNaN(index) || index < 0)
|
||||
index = 1;
|
||||
|
||||
this._changedPermitted = false;
|
||||
this._appendItem(appInfo.get_id(), index);
|
||||
this._changedPermitted = true;
|
||||
|
||||
let iter = this._store.append();
|
||||
let adj = new Gtk.Adjustment({ lower: 1,
|
||||
upper: WORKSPACE_MAX,
|
||||
step_increment: 1,
|
||||
value: index });
|
||||
this._store.set(iter,
|
||||
[Columns.APPINFO, Columns.ICON, Columns.DISPLAY_NAME, Columns.WORKSPACE, Columns.ADJUSTMENT],
|
||||
[appInfo, appInfo.get_icon(), appInfo.get_display_name(), index, adj]);
|
||||
|
||||
dialog.destroy();
|
||||
});
|
||||
dialog.show_all();
|
||||
}
|
||||
|
||||
_deleteSelected() {
|
||||
let [any, model, iter] = this._treeView.get_selection().get_selected();
|
||||
|
||||
if (any) {
|
||||
let appInfo = this._store.get_value(iter, Columns.APPINFO);
|
||||
|
||||
this._changedPermitted = false;
|
||||
this._removeItem(appInfo.get_id());
|
||||
this._changedPermitted = true;
|
||||
this._store.remove(iter);
|
||||
}
|
||||
}
|
||||
|
||||
_workspaceEdited(renderer, pathString, text) {
|
||||
let index = parseInt(text);
|
||||
if (isNaN(index) || index < 0)
|
||||
index = 1;
|
||||
let path = Gtk.TreePath.new_from_string(pathString);
|
||||
let [model, iter] = this._store.get_iter(path);
|
||||
let appInfo = this._store.get_value(iter, Columns.APPINFO);
|
||||
|
||||
this._changedPermitted = false;
|
||||
this._changeItem(appInfo.get_id(), index);
|
||||
this._store.set_value(iter, Columns.WORKSPACE, index);
|
||||
this._changedPermitted = true;
|
||||
}
|
||||
|
||||
_refresh() {
|
||||
if (!this._changedPermitted)
|
||||
// Ignore this notification, model is being modified outside
|
||||
return;
|
||||
|
||||
this._store.clear();
|
||||
|
||||
let currentItems = this._settings.get_strv(SETTINGS_KEY);
|
||||
let validItems = [ ];
|
||||
for (let i = 0; i < currentItems.length; i++) {
|
||||
let [id, index] = currentItems[i].split(':');
|
||||
let appInfo = Gio.DesktopAppInfo.new(id);
|
||||
if (!appInfo)
|
||||
continue;
|
||||
validItems.push(currentItems[i]);
|
||||
|
||||
let iter = this._store.append();
|
||||
let adj = new Gtk.Adjustment({ lower: 1,
|
||||
upper: WORKSPACE_MAX,
|
||||
step_increment: 1,
|
||||
value: index });
|
||||
this._store.set(iter,
|
||||
[Columns.APPINFO, Columns.ICON, Columns.DISPLAY_NAME, Columns.WORKSPACE, Columns.ADJUSTMENT],
|
||||
[appInfo, appInfo.get_icon(), appInfo.get_display_name(), parseInt(index), adj]);
|
||||
}
|
||||
|
||||
if (validItems.length != currentItems.length) // some items were filtered out
|
||||
this._settings.set_strv(SETTINGS_KEY, validItems);
|
||||
}
|
||||
|
||||
_checkId(id) {
|
||||
let items = this._settings.get_strv(SETTINGS_KEY);
|
||||
return !items.some(i => i.startsWith(id + ':'));
|
||||
}
|
||||
|
||||
_appendItem(id, workspace) {
|
||||
let currentItems = this._settings.get_strv(SETTINGS_KEY);
|
||||
currentItems.push(id + ':' + workspace);
|
||||
this._settings.set_strv(SETTINGS_KEY, currentItems);
|
||||
}
|
||||
|
||||
_removeItem(id) {
|
||||
let currentItems = this._settings.get_strv(SETTINGS_KEY);
|
||||
let index = currentItems.map(el => el.split(':')[0]).indexOf(id);
|
||||
|
||||
if (index < 0)
|
||||
return;
|
||||
currentItems.splice(index, 1);
|
||||
this._settings.set_strv(SETTINGS_KEY, currentItems);
|
||||
}
|
||||
|
||||
_changeItem(id, workspace) {
|
||||
let currentItems = this._settings.get_strv(SETTINGS_KEY);
|
||||
let index = currentItems.map(el => el.split(':')[0]).indexOf(id);
|
||||
|
||||
if (index < 0)
|
||||
currentItems.push(id + ':' + workspace);
|
||||
else
|
||||
currentItems[index] = id + ':' + workspace;
|
||||
this._settings.set_strv(SETTINGS_KEY, currentItems);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
function init() {
|
||||
Convenience.initTranslations();
|
||||
}
|
||||
|
||||
function buildPrefsWidget() {
|
||||
let widget = new Widget({ margin: 12 });
|
||||
widget.show_all();
|
||||
|
||||
return widget;
|
||||
}
|
||||
3
extensions/dock/Makefile.am
Normal file
3
extensions/dock/Makefile.am
Normal file
@@ -0,0 +1,3 @@
|
||||
EXTENSION_ID = dock
|
||||
|
||||
include ../../extension.mk
|
||||
456
extensions/dock/extension.js
Normal file
456
extensions/dock/extension.js
Normal file
@@ -0,0 +1,456 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Pango = imports.gi.Pango;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
const Mainloop = imports.mainloop;
|
||||
|
||||
const AppFavorites = imports.ui.appFavorites;
|
||||
const DND = imports.ui.dnd;
|
||||
const Main = imports.ui.main;
|
||||
const Overview = imports.ui.overview;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const Search = imports.ui.search;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const Workspace = imports.ui.workspace;
|
||||
const AppDisplay = imports.ui.appDisplay;
|
||||
const AltTab = imports.ui.altTab;
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell-extensions');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const DOCKICON_SIZE = 48;
|
||||
const DND_RAISE_APP_TIMEOUT = 500;
|
||||
|
||||
function Dock() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
Dock.prototype = {
|
||||
_init : function() {
|
||||
this._placeholderText = null;
|
||||
this._menus = [];
|
||||
this._menuDisplays = [];
|
||||
|
||||
this._favorites = [];
|
||||
|
||||
this._spacing = 4;
|
||||
this._item_size = DOCKICON_SIZE;
|
||||
|
||||
this.actor = new St.BoxLayout({ name: 'dock', vertical: true, reactive: true });
|
||||
|
||||
this._grid = new Shell.GenericContainer();
|
||||
this.actor.add(this._grid, { expand: true, y_align: St.Align.START });
|
||||
this.actor.connect('style-changed', Lang.bind(this, this._onStyleChanged));
|
||||
|
||||
this._grid.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
||||
this._grid.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||
this._grid.connect('allocate', Lang.bind(this, this._allocate));
|
||||
|
||||
this._workId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._redisplay));
|
||||
|
||||
this._tracker = Shell.WindowTracker.get_default();
|
||||
this._appSystem = Shell.AppSystem.get_default();
|
||||
|
||||
this._appSystem.connect('installed-changed', Lang.bind(this, this._queueRedisplay));
|
||||
AppFavorites.getAppFavorites().connect('changed', Lang.bind(this, this._queueRedisplay));
|
||||
this._tracker.connect('app-state-changed', Lang.bind(this, this._queueRedisplay));
|
||||
|
||||
Main.chrome.addActor(this.actor, { visibleInOverview: false });
|
||||
this.actor.lower_bottom();
|
||||
},
|
||||
|
||||
_appIdListToHash: function(apps) {
|
||||
let ids = {};
|
||||
for (let i = 0; i < apps.length; i++)
|
||||
ids[apps[i].get_id()] = apps[i];
|
||||
return ids;
|
||||
},
|
||||
|
||||
_queueRedisplay: function () {
|
||||
Main.queueDeferredWork(this._workId);
|
||||
},
|
||||
|
||||
_redisplay: function () {
|
||||
this.removeAll();
|
||||
|
||||
let favorites = AppFavorites.getAppFavorites().getFavoriteMap();
|
||||
|
||||
/* hardcode here pending some design about how exactly desktop contexts behave */
|
||||
let contextId = '';
|
||||
|
||||
let running = this._tracker.get_running_apps(contextId);
|
||||
let runningIds = this._appIdListToHash(running);
|
||||
|
||||
let icons = 0;
|
||||
|
||||
let nFavorites = 0;
|
||||
for (let id in favorites) {
|
||||
let app = favorites[id];
|
||||
let display = new DockIcon(app);
|
||||
this.addItem(display.actor);
|
||||
nFavorites++;
|
||||
icons++;
|
||||
}
|
||||
|
||||
for (let i = 0; i < running.length; i++) {
|
||||
let app = running[i];
|
||||
if (app.get_id() in favorites)
|
||||
continue;
|
||||
let display = new DockIcon(app);
|
||||
icons++;
|
||||
this.addItem(display.actor);
|
||||
}
|
||||
if (this._placeholderText) {
|
||||
this._placeholderText.destroy();
|
||||
this._placeholderText = null;
|
||||
}
|
||||
|
||||
if (running.length == 0 && nFavorites == 0) {
|
||||
this._placeholderText = new St.Label({ text: _("Drag here to add favorites") });
|
||||
this.actor.add_actor(this._placeholderText);
|
||||
}
|
||||
|
||||
let primary = global.get_primary_monitor();
|
||||
let height = (icons)*(this._item_size + this._spacing) + 2*this._spacing;
|
||||
this.actor.set_size(this._item_size + 4*this._spacing, height);
|
||||
this.actor.set_position(primary.width-this._item_size-this._spacing-2, (primary.height-height)/2);
|
||||
},
|
||||
|
||||
_getPreferredWidth: function (grid, forHeight, alloc) {
|
||||
alloc.min_size = this._item_size;
|
||||
alloc.natural_size = this._item_size + this._spacing;
|
||||
},
|
||||
|
||||
_getPreferredHeight: function (grid, forWidth, alloc) {
|
||||
let children = this._grid.get_children();
|
||||
let nRows = children.length;
|
||||
let totalSpacing = Math.max(0, nRows - 1) * this._spacing;
|
||||
let height = nRows * this._item_size + totalSpacing;
|
||||
alloc.min_size = height;
|
||||
alloc.natural_size = height;
|
||||
},
|
||||
|
||||
_allocate: function (grid, box, flags) {
|
||||
let children = this._grid.get_children();
|
||||
|
||||
let x = box.x1 + this._spacing;
|
||||
let y = box.y1 + this._spacing;
|
||||
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
let childBox = new Clutter.ActorBox();
|
||||
childBox.x1 = x;
|
||||
childBox.y1 = y;
|
||||
childBox.x2 = childBox.x1 + this._item_size;
|
||||
childBox.y2 = childBox.y1 + this._item_size;
|
||||
children[i].allocate(childBox, flags);
|
||||
y += this._item_size + this._spacing;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
_onStyleChanged: function() {
|
||||
let themeNode = this.actor.get_theme_node();
|
||||
let [success, len] = themeNode.get_length('spacing', false);
|
||||
if (success)
|
||||
this._spacing = len;
|
||||
[success, len] = themeNode.get_length('-shell-grid-item-size', false);
|
||||
if (success)
|
||||
this._item_size = len;
|
||||
this._grid.queue_relayout();
|
||||
},
|
||||
|
||||
removeAll: function () {
|
||||
this._grid.get_children().forEach(Lang.bind(this, function (child) {
|
||||
child.destroy();
|
||||
}));
|
||||
},
|
||||
|
||||
addItem: function(actor) {
|
||||
this._grid.add_actor(actor);
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(Dock.prototype);
|
||||
|
||||
function DockIcon(app) {
|
||||
this._init(app);
|
||||
}
|
||||
|
||||
DockIcon.prototype = {
|
||||
_init : function(app) {
|
||||
this.app = app;
|
||||
this.actor = new St.Button({ style_class: 'dock-app',
|
||||
button_mask: St.ButtonMask.ONE | St.ButtonMask.TWO,
|
||||
reactive: true,
|
||||
x_fill: true,
|
||||
y_fill: true });
|
||||
this.actor._delegate = this;
|
||||
this.actor.set_size(DOCKICON_SIZE, DOCKICON_SIZE);
|
||||
|
||||
this._icon = this.app.create_icon_texture(DOCKICON_SIZE);
|
||||
this.actor.set_child(this._icon);
|
||||
|
||||
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
||||
|
||||
this._menu = null;
|
||||
this._menuManager = new PopupMenu.PopupMenuManager(this);
|
||||
|
||||
this._has_focus = false;
|
||||
|
||||
let tracker = Shell.WindowTracker.get_default();
|
||||
tracker.connect('notify::focus-app', Lang.bind(this, this._onStateChanged));
|
||||
|
||||
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
this.actor.connect('notify::hover', Lang.bind(this, this._hoverChanged));
|
||||
|
||||
this._menuTimeoutId = 0;
|
||||
this._stateChangedId = this.app.connect('notify::state',
|
||||
Lang.bind(this, this._onStateChanged));
|
||||
this._onStateChanged();
|
||||
},
|
||||
|
||||
_onDestroy: function() {
|
||||
if (this._stateChangedId > 0)
|
||||
this.app.disconnect(this._stateChangedId);
|
||||
this._stateChangedId = 0;
|
||||
this._removeMenuTimeout();
|
||||
},
|
||||
|
||||
_removeMenuTimeout: function() {
|
||||
if (this._menuTimeoutId > 0) {
|
||||
Mainloop.source_remove(this._menuTimeoutId);
|
||||
this._menuTimeoutId = 0;
|
||||
}
|
||||
},
|
||||
|
||||
_hoverChanged: function(actor) {
|
||||
if (actor != this.actor)
|
||||
this._has_focus = false;
|
||||
else
|
||||
this._has_focus = true;
|
||||
return false;
|
||||
},
|
||||
|
||||
_onStateChanged: function() {
|
||||
let tracker = Shell.WindowTracker.get_default();
|
||||
let focusedApp = tracker.focus_app;
|
||||
if (this.app.state != Shell.AppState.STOPPED) {
|
||||
this.actor.add_style_class_name('running');
|
||||
if (this.app == focusedApp) {
|
||||
this.actor.add_style_class_name('focused');
|
||||
} else {
|
||||
this.actor.remove_style_class_name('focused');
|
||||
}
|
||||
} else {
|
||||
this.actor.remove_style_class_name('focused');
|
||||
this.actor.remove_style_class_name('running');
|
||||
}
|
||||
},
|
||||
|
||||
_onButtonPress: function(actor, event) {
|
||||
let button = event.get_button();
|
||||
if (button == 1) {
|
||||
this._removeMenuTimeout();
|
||||
this._menuTimeoutId = Mainloop.timeout_add(AppDisplay.MENU_POPUP_TIMEOUT, Lang.bind(this, function() {
|
||||
this.popupMenu();
|
||||
}));
|
||||
} else if (button == 3) {
|
||||
this.popupMenu();
|
||||
}
|
||||
},
|
||||
|
||||
_onClicked: function(actor, button) {
|
||||
this._removeMenuTimeout();
|
||||
|
||||
if (button == 1) {
|
||||
this._onActivate(Clutter.get_current_event());
|
||||
} else if (button == 2) {
|
||||
// Last workspace is always empty
|
||||
let launchWorkspace = global.screen.get_workspace_by_index(global.screen.n_workspaces - 1);
|
||||
launchWorkspace.activate(global.get_current_time());
|
||||
this.emit('launching');
|
||||
this.app.open_new_window(-1);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
getId: function() {
|
||||
return this.app.get_id();
|
||||
},
|
||||
|
||||
popupMenu: function() {
|
||||
this._removeMenuTimeout();
|
||||
this.actor.fake_release();
|
||||
|
||||
if (!this._menu) {
|
||||
this._menu = new DockIconMenu(this);
|
||||
this._menu.connect('activate-window', Lang.bind(this, function (menu, window) {
|
||||
this.activateWindow(window);
|
||||
}));
|
||||
this._menu.connect('popup', Lang.bind(this, function (menu, isPoppedUp) {
|
||||
if (!isPoppedUp)
|
||||
this._onMenuPoppedDown();
|
||||
}));
|
||||
|
||||
this._menuManager.addMenu(this._menu, true);
|
||||
}
|
||||
|
||||
this._menu.popup();
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
activateWindow: function(metaWindow) {
|
||||
if (metaWindow) {
|
||||
this._didActivateWindow = true;
|
||||
Main.activateWindow(metaWindow);
|
||||
}
|
||||
},
|
||||
|
||||
setSelected: function (isSelected) {
|
||||
this._selected = isSelected;
|
||||
if (this._selected)
|
||||
this.actor.add_style_class_name('selected');
|
||||
else
|
||||
this.actor.remove_style_class_name('selected');
|
||||
},
|
||||
|
||||
_onMenuPoppedDown: function() {
|
||||
this.actor.sync_hover();
|
||||
},
|
||||
|
||||
_getRunning: function() {
|
||||
return this.app.state != Shell.AppState.STOPPED;
|
||||
},
|
||||
|
||||
_onActivate: function (event) {
|
||||
this.emit('launching');
|
||||
let modifiers = Shell.get_event_state(event);
|
||||
|
||||
if (modifiers & Clutter.ModifierType.CONTROL_MASK
|
||||
&& this.app.state == Shell.AppState.RUNNING) {
|
||||
let current_workspace = global.screen.get_active_workspace().index();
|
||||
this.app.open_new_window(current_workspace);
|
||||
} else {
|
||||
let tracker = Shell.WindowTracker.get_default();
|
||||
let focusedApp = tracker.focus_app;
|
||||
|
||||
if (this.app == focusedApp) {
|
||||
let windows = this.app.get_windows();
|
||||
let current_workspace = global.screen.get_active_workspace();
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
let w = windows[i];
|
||||
if (w.get_workspace() == current_workspace)
|
||||
w.minimize();
|
||||
}
|
||||
} else {
|
||||
this.app.activate(-1);
|
||||
}
|
||||
}
|
||||
Main.overview.hide();
|
||||
},
|
||||
|
||||
shellWorkspaceLaunch : function() {
|
||||
this.app.open_new_window();
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(DockIcon.prototype);
|
||||
|
||||
function DockIconMenu(source) {
|
||||
this._init(source);
|
||||
}
|
||||
|
||||
DockIconMenu.prototype = {
|
||||
__proto__: AppDisplay.AppIconMenu.prototype,
|
||||
|
||||
_init: function(source) {
|
||||
PopupMenu.PopupMenu.prototype._init.call(this, source.actor, St.Align.MIDDLE, St.Side.RIGHT, 0);
|
||||
|
||||
this._source = source;
|
||||
|
||||
this.connect('activate', Lang.bind(this, this._onActivate));
|
||||
this.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged));
|
||||
|
||||
this.actor.add_style_class_name('dock-menu');
|
||||
|
||||
// Chain our visibility and lifecycle to that of the source
|
||||
source.actor.connect('notify::mapped', Lang.bind(this, function () {
|
||||
if (!source.actor.mapped)
|
||||
this.close();
|
||||
}));
|
||||
source.actor.connect('destroy', Lang.bind(this, function () { this.actor.destroy(); }));
|
||||
|
||||
Main.chrome.addActor(this.actor);
|
||||
},
|
||||
|
||||
_redisplay: function() {
|
||||
this.removeAll();
|
||||
|
||||
let windows = this._source.app.get_windows();
|
||||
|
||||
// Display the app windows menu items and the separator between windows
|
||||
// of the current desktop and other windows.
|
||||
let activeWorkspace = global.screen.get_active_workspace();
|
||||
let separatorShown = windows.length > 0 && windows[0].get_workspace() != activeWorkspace;
|
||||
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
if (!separatorShown && windows[i].get_workspace() != activeWorkspace) {
|
||||
this._appendSeparator();
|
||||
separatorShown = true;
|
||||
}
|
||||
let item = this._appendMenuItem(windows[i].title);
|
||||
item._window = windows[i];
|
||||
}
|
||||
|
||||
if (windows.length > 0)
|
||||
this._appendSeparator();
|
||||
|
||||
let isFavorite = AppFavorites.getAppFavorites().isFavorite(this._source.app.get_id());
|
||||
|
||||
this._newWindowMenuItem = windows.length > 0 ? this._appendMenuItem(_("New Window")) : null;
|
||||
|
||||
this._quitAppMenuItem = windows.length >0 ? this._appendMenuItem(_("Quit Application")) : null;
|
||||
|
||||
if (windows.length > 0)
|
||||
this._appendSeparator();
|
||||
this._toggleFavoriteMenuItem = this._appendMenuItem(isFavorite ?
|
||||
_("Remove from Favorites")
|
||||
: _("Add to Favorites"));
|
||||
|
||||
this._highlightedItem = null;
|
||||
},
|
||||
|
||||
_onActivate: function (actor, child) {
|
||||
if (child._window) {
|
||||
let metaWindow = child._window;
|
||||
this.emit('activate-window', metaWindow);
|
||||
} else if (child == this._newWindowMenuItem) {
|
||||
let current_workspace = global.screen.get_active_workspace().index();
|
||||
this._source.app.open_new_window(current_workspace);
|
||||
this.emit('activate-window', null);
|
||||
} else if (child == this._quitAppMenuItem) {
|
||||
this._source.app.request_quit();
|
||||
} else if (child == this._toggleFavoriteMenuItem) {
|
||||
let favs = AppFavorites.getAppFavorites();
|
||||
let isFavorite = favs.isFavorite(this._source.app.get_id());
|
||||
if (isFavorite)
|
||||
favs.removeFavorite(this._source.app.get_id());
|
||||
else
|
||||
favs.addFavorite(this._source.app.get_id());
|
||||
}
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
|
||||
function main(extensionMeta) {
|
||||
imports.gettext.bindtextdomain('gnome-shell-extensions', extensionMeta.localedir);
|
||||
|
||||
let dock = new Dock();
|
||||
}
|
||||
9
extensions/dock/metadata.json.in
Normal file
9
extensions/dock/metadata.json.in
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"uuid": "@uuid@",
|
||||
"name": "Dock",
|
||||
"description": "A dock for the GNOME Shell -- displays favorite and running applications",
|
||||
"original-author": "tclaesson@gmail.com",
|
||||
"shell-version": [ "3.0" ],
|
||||
"localedir": "@LOCALEDIR@",
|
||||
"url": "@url@"
|
||||
}
|
||||
54
extensions/dock/stylesheet.css
Normal file
54
extensions/dock/stylesheet.css
Normal file
@@ -0,0 +1,54 @@
|
||||
#dock {
|
||||
border-radius: 9px;
|
||||
background-color: rgba(0,0,0,0.9);
|
||||
border-width: 2px;
|
||||
border-color: #5f5f5f;
|
||||
}
|
||||
/* Panel */
|
||||
.dock-app {
|
||||
padding: 4px;
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
border-radius: 4px;
|
||||
transition-duration: 100;
|
||||
}
|
||||
|
||||
.dock-app.running {
|
||||
padding: 3px;
|
||||
border: 1px solid #181818;
|
||||
background-gradient-direction: vertical;
|
||||
background-gradient-start: #3d3d3d;
|
||||
background-gradient-end: #181818;
|
||||
}
|
||||
|
||||
.dock-app.selected {
|
||||
padding: 3px;
|
||||
border: 1px solid #666666;
|
||||
}
|
||||
|
||||
.dock-app.focused {
|
||||
padding: 3px;
|
||||
border: 1px solid #5f5f5f;
|
||||
background-gradient-direction: vertical;
|
||||
background-gradient-start: rgba(61,61,61,0.8);
|
||||
background-gradient-end: rgba(24,24,24,0.2);
|
||||
}
|
||||
|
||||
.dock-app:hover {
|
||||
padding: 3px;
|
||||
border: 1px solid #666666;
|
||||
background-gradient-direction: vertical;
|
||||
background-gradient-start: rgba(61,61,61,0.8);
|
||||
background-gradient-end: rgba(24,24,24,0.2);
|
||||
transition-duration: 100;
|
||||
}
|
||||
|
||||
.dock-app:active {
|
||||
padding: 3px;
|
||||
background-color: #1e1e1e;
|
||||
border: 1px solid #5f5f5f;
|
||||
}
|
||||
|
||||
.dock-menu {
|
||||
font-size: 12px
|
||||
}
|
||||
@@ -1,202 +0,0 @@
|
||||
// Drive menu extension
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gio = imports.gi.Gio;
|
||||
const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell-extensions');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const Panel = imports.ui.panel;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const ShellMountOperation = imports.ui.shellMountOperation;
|
||||
|
||||
const ExtensionUtils = imports.misc.extensionUtils;
|
||||
const Me = ExtensionUtils.getCurrentExtension();
|
||||
const Convenience = Me.imports.convenience;
|
||||
|
||||
class MountMenuItem extends PopupMenu.PopupBaseMenuItem {
|
||||
constructor(mount) {
|
||||
super();
|
||||
|
||||
this.label = new St.Label({ text: mount.get_name() });
|
||||
this.actor.add(this.label, { expand: true });
|
||||
this.actor.label_actor = this.label;
|
||||
|
||||
this.mount = mount;
|
||||
|
||||
let ejectIcon = new St.Icon({ icon_name: 'media-eject-symbolic',
|
||||
style_class: 'popup-menu-icon ' });
|
||||
let ejectButton = new St.Button({ child: ejectIcon });
|
||||
ejectButton.connect('clicked', this._eject.bind(this));
|
||||
this.actor.add(ejectButton);
|
||||
|
||||
this._changedId = mount.connect('changed', this._syncVisibility.bind(this));
|
||||
this._syncVisibility();
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (this._changedId) {
|
||||
this.mount.disconnect(this._changedId);
|
||||
this._changedId = 0;
|
||||
}
|
||||
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
_isInteresting() {
|
||||
if (!this.mount.can_eject() && !this.mount.can_unmount())
|
||||
return false;
|
||||
if (this.mount.is_shadowed())
|
||||
return false;
|
||||
|
||||
let volume = this.mount.get_volume();
|
||||
|
||||
if (volume == null) {
|
||||
// probably a GDaemonMount, could be network or
|
||||
// local, but we can't tell; assume it's local for now
|
||||
return true;
|
||||
}
|
||||
|
||||
return volume.get_identifier('class') != 'network';
|
||||
}
|
||||
|
||||
_syncVisibility() {
|
||||
this.actor.visible = this._isInteresting();
|
||||
}
|
||||
|
||||
_eject() {
|
||||
let mountOp = new ShellMountOperation.ShellMountOperation(this.mount);
|
||||
|
||||
if (this.mount.can_eject())
|
||||
this.mount.eject_with_operation(Gio.MountUnmountFlags.NONE,
|
||||
mountOp.mountOp,
|
||||
null, // Gio.Cancellable
|
||||
this._ejectFinish.bind(this));
|
||||
else
|
||||
this.mount.unmount_with_operation(Gio.MountUnmountFlags.NONE,
|
||||
mountOp.mountOp,
|
||||
null, // Gio.Cancellable
|
||||
this._unmountFinish.bind(this));
|
||||
}
|
||||
|
||||
_unmountFinish(mount, result) {
|
||||
try {
|
||||
mount.unmount_with_operation_finish(result);
|
||||
} catch(e) {
|
||||
this._reportFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
_ejectFinish(mount, result) {
|
||||
try {
|
||||
mount.eject_with_operation_finish(result);
|
||||
} catch(e) {
|
||||
this._reportFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
_reportFailure(exception) {
|
||||
// TRANSLATORS: %s is the filesystem name
|
||||
let msg = _("Ejecting drive “%s” failed:").format(this.mount.get_name());
|
||||
Main.notifyError(msg, exception.message);
|
||||
}
|
||||
|
||||
activate(event) {
|
||||
let context = global.create_app_launch_context(event.get_time(), -1);
|
||||
Gio.AppInfo.launch_default_for_uri(this.mount.get_root().get_uri(),
|
||||
context);
|
||||
|
||||
super.activate(event);
|
||||
}
|
||||
};
|
||||
|
||||
class DriveMenu extends PanelMenu.Button {
|
||||
constructor() {
|
||||
super(0.0, _("Removable devices"));
|
||||
|
||||
let hbox = new St.BoxLayout({ style_class: 'panel-status-menu-box' });
|
||||
let icon = new St.Icon({ icon_name: 'media-eject-symbolic',
|
||||
style_class: 'system-status-icon' });
|
||||
|
||||
hbox.add_child(icon);
|
||||
hbox.add_child(PopupMenu.arrowIcon(St.Side.BOTTOM));
|
||||
this.actor.add_child(hbox);
|
||||
|
||||
this._monitor = Gio.VolumeMonitor.get();
|
||||
this._addedId = this._monitor.connect('mount-added', (monitor, mount) => {
|
||||
this._addMount(mount);
|
||||
this._updateMenuVisibility();
|
||||
});
|
||||
this._removedId = this._monitor.connect('mount-removed', (monitor, mount) => {
|
||||
this._removeMount(mount);
|
||||
this._updateMenuVisibility();
|
||||
});
|
||||
|
||||
this._mounts = [ ];
|
||||
|
||||
this._monitor.get_mounts().forEach(this._addMount.bind(this));
|
||||
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
this.menu.addAction(_("Open Files"), event => {
|
||||
let appSystem = Shell.AppSystem.get_default();
|
||||
let app = appSystem.lookup_app('org.gnome.Nautilus.desktop');
|
||||
app.activate_full(-1, event.get_time());
|
||||
});
|
||||
|
||||
this._updateMenuVisibility();
|
||||
}
|
||||
|
||||
_updateMenuVisibility() {
|
||||
if (this._mounts.filter(i => i.actor.visible).length > 0)
|
||||
this.actor.show();
|
||||
else
|
||||
this.actor.hide();
|
||||
}
|
||||
|
||||
_addMount(mount) {
|
||||
let item = new MountMenuItem(mount);
|
||||
this._mounts.unshift(item);
|
||||
this.menu.addMenuItem(item, 0);
|
||||
}
|
||||
|
||||
_removeMount(mount) {
|
||||
for (let i = 0; i < this._mounts.length; i++) {
|
||||
let item = this._mounts[i];
|
||||
if (item.mount == mount) {
|
||||
item.destroy();
|
||||
this._mounts.splice(i, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
log ('Removing a mount that was never added to the menu');
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (this._addedId) {
|
||||
this._monitor.disconnect(this._addedId);
|
||||
this._monitor.disconnect(this._removedId);
|
||||
this._addedId = 0;
|
||||
this._removedId = 0;
|
||||
}
|
||||
|
||||
super.destroy();
|
||||
}
|
||||
};
|
||||
|
||||
function init() {
|
||||
Convenience.initTranslations();
|
||||
}
|
||||
|
||||
let _indicator;
|
||||
|
||||
function enable() {
|
||||
_indicator = new DriveMenu;
|
||||
Main.panel.addToStatusArea('drive-menu', _indicator);
|
||||
}
|
||||
|
||||
function disable() {
|
||||
_indicator.destroy();
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
extension_data += configure_file(
|
||||
input: metadata_name + '.in',
|
||||
output: metadata_name,
|
||||
configuration: metadata_conf
|
||||
)
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"extension-id": "@extension_id@",
|
||||
"uuid": "@uuid@",
|
||||
"settings-schema": "@gschemaname@",
|
||||
"gettext-domain": "@gettext_domain@",
|
||||
"name": "Removable Drive Menu",
|
||||
"description": "A status menu for accessing and unmounting removable devices.",
|
||||
"shell-version": [ "@shell_current@" ],
|
||||
"url": "@url@"
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
/* This extensions requires no custom styling */
|
||||
3
extensions/example/Makefile.am
Normal file
3
extensions/example/Makefile.am
Normal file
@@ -0,0 +1,3 @@
|
||||
EXTENSION_ID = example
|
||||
|
||||
include ../../extension.mk
|
||||
@@ -1,4 +1,3 @@
|
||||
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
|
||||
// Sample extension code, makes clicking on the panel show a message
|
||||
const St = imports.gi.St;
|
||||
const Mainloop = imports.mainloop;
|
||||
@@ -8,42 +7,18 @@ const _ = Gettext.gettext;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
|
||||
const ExtensionUtils = imports.misc.extensionUtils;
|
||||
const Me = ExtensionUtils.getCurrentExtension();
|
||||
const Convenience = Me.imports.convenience;
|
||||
|
||||
function _showHello() {
|
||||
let settings = Convenience.getSettings();
|
||||
let text = settings.get_string('hello-text') || _("Hello, world!");
|
||||
|
||||
let label = new St.Label({ style_class: 'helloworld-label', text: text });
|
||||
let monitor = Main.layoutManager.primaryMonitor;
|
||||
global.stage.add_actor(label);
|
||||
label.set_position(Math.floor (monitor.width / 2 - label.width / 2), Math.floor(monitor.height / 2 - label.height / 2));
|
||||
Mainloop.timeout_add(3000, () => { label.destroy(); });
|
||||
let text = new St.Label({ style_class: 'helloworld-label', text: _("Hello, world!") });
|
||||
let monitor = global.get_primary_monitor();
|
||||
global.stage.add_actor(text);
|
||||
text.set_position(Math.floor (monitor.width / 2 - text.width / 2), Math.floor(monitor.height / 2 - text.height / 2));
|
||||
Mainloop.timeout_add(3000, function () { text.destroy(); });
|
||||
}
|
||||
|
||||
// Put your extension initialization code here
|
||||
function init(metadata) {
|
||||
log ('Example extension initalized');
|
||||
|
||||
Convenience.initTranslations();
|
||||
}
|
||||
|
||||
let signalId;
|
||||
|
||||
function enable() {
|
||||
log ('Example extension enabled');
|
||||
function main(metadata) {
|
||||
imports.gettext.bindtextdomain('gnome-shell-extensions', metadata.localedir);
|
||||
|
||||
Main.panel.actor.reactive = true;
|
||||
signalId = Main.panel.actor.connect('button-release-event', _showHello);
|
||||
}
|
||||
|
||||
function disable() {
|
||||
log ('Example extension disabled');
|
||||
|
||||
if (signalId) {
|
||||
Main.panel.actor.disconnect(signalId);
|
||||
signalId = 0;
|
||||
}
|
||||
Main.panel.actor.connect('button-release-event', _showHello);
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
extension_data += configure_file(
|
||||
input: metadata_name + '.in',
|
||||
output: metadata_name,
|
||||
configuration: metadata_conf
|
||||
)
|
||||
|
||||
extension_sources += files('prefs.js')
|
||||
extension_schemas += files(metadata_conf.get('gschemaname') + '.gschema.xml')
|
||||
@@ -1,10 +1,8 @@
|
||||
{
|
||||
"extension-id": "@extension_id@",
|
||||
"uuid": "@uuid@",
|
||||
"settings-schema": "@gschemaname@",
|
||||
"gettext-domain": "@gettext_domain@",
|
||||
"name": "Hello, World!",
|
||||
"description": "An example extension to show how it works. Shows Hello, world when clicking on the top panel.",
|
||||
"shell-version": [ "@shell_current@" ],
|
||||
"shell-version": [ "3.0" ],
|
||||
"localedir": "@LOCALEDIR@",
|
||||
"url": "@url@"
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
<schemalist gettext-domain="gnome-shell-extensions">
|
||||
<schema id="org.gnome.shell.extensions.example" path="/org/gnome/shell/extensions/example/">
|
||||
<key name="hello-text" type="s">
|
||||
<default>''</default>
|
||||
<summary>Alternative greeting text.</summary>
|
||||
<description>If not empty, it contains the text that will be shown when clicking on the panel.</description>
|
||||
</key>
|
||||
</schema>
|
||||
</schemalist>
|
||||
@@ -1,54 +0,0 @@
|
||||
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
|
||||
|
||||
const GLib = imports.gi.GLib;
|
||||
const GObject = imports.gi.GObject;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell-extensions');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const ExtensionUtils = imports.misc.extensionUtils;
|
||||
const Me = ExtensionUtils.getCurrentExtension();
|
||||
const Convenience = Me.imports.convenience;
|
||||
|
||||
function init() {
|
||||
Convenience.initTranslations();
|
||||
}
|
||||
|
||||
const ExamplePrefsWidget = GObject.registerClass(
|
||||
class ExamplePrefsWidget extends Gtk.Grid {
|
||||
_init(params) {
|
||||
super._init(params);
|
||||
this.margin = 12;
|
||||
this.row_spacing = this.column_spacing = 6;
|
||||
this.set_orientation(Gtk.Orientation.VERTICAL);
|
||||
|
||||
this.add(new Gtk.Label({ label: '<b>' + _("Message") + '</b>',
|
||||
use_markup: true,
|
||||
halign: Gtk.Align.START }));
|
||||
|
||||
let entry = new Gtk.Entry({ hexpand: true,
|
||||
margin_bottom: 12 });
|
||||
this.add(entry);
|
||||
|
||||
this._settings = Convenience.getSettings();
|
||||
this._settings.bind('hello-text', entry, 'text', Gio.SettingsBindFlags.DEFAULT);
|
||||
|
||||
// TRANSLATORS: Example is the name of the extension, should not be
|
||||
// translated
|
||||
let primaryText = _("Example aims to show how to build well behaved \
|
||||
extensions for the Shell and as such it has little functionality on its own.\n\
|
||||
Nevertheless it’s possible to customize the greeting message.");
|
||||
|
||||
this.add(new Gtk.Label({ label: primaryText,
|
||||
wrap: true, xalign: 0 }));
|
||||
}
|
||||
});
|
||||
|
||||
function buildPrefsWidget() {
|
||||
let widget = new ExamplePrefsWidget();
|
||||
widget.show_all();
|
||||
|
||||
return widget;
|
||||
}
|
||||
3
extensions/gajim/Makefile.am
Normal file
3
extensions/gajim/Makefile.am
Normal file
@@ -0,0 +1,3 @@
|
||||
EXTENSION_ID = gajim
|
||||
|
||||
include ../../extension.mk
|
||||
313
extensions/gajim/extension.js
Normal file
313
extensions/gajim/extension.js
Normal file
@@ -0,0 +1,313 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const DBus = imports.dbus;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
const Tp = imports.gi.TelepathyGLib;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const Mainloop = imports.mainloop;
|
||||
const MessageTray = imports.ui.messageTray;
|
||||
const Shell = imports.gi.Shell;
|
||||
const TelepathyClient = imports.ui.telepathyClient;
|
||||
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
// http://ntt.cc/ext/base64-Encoding-Decoding.html
|
||||
const keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
|
||||
function decode64(input) {
|
||||
let output = "";
|
||||
let chr1, chr2, chr3;
|
||||
let enc1, enc2, enc3, enc4;
|
||||
let i = 0;
|
||||
|
||||
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
|
||||
|
||||
do {
|
||||
enc1 = keyStr.indexOf(input.charAt(i++));
|
||||
enc2 = keyStr.indexOf(input.charAt(i++));
|
||||
enc3 = keyStr.indexOf(input.charAt(i++));
|
||||
enc4 = keyStr.indexOf(input.charAt(i++));
|
||||
|
||||
chr1 = (enc1 << 2) | (enc2 >> 4);
|
||||
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
|
||||
chr3 = ((enc3 & 3) << 6) | enc4;
|
||||
|
||||
output = output + String.fromCharCode(chr1);
|
||||
|
||||
if (enc3 != 64) {
|
||||
output = output + String.fromCharCode(chr2);
|
||||
}
|
||||
if (enc4 != 64) {
|
||||
output = output + String.fromCharCode(chr3);
|
||||
}
|
||||
|
||||
chr1 = chr2 = chr3 = "";
|
||||
enc1 = enc2 = enc3 = enc4 = "";
|
||||
|
||||
} while (i < input.length);
|
||||
|
||||
return unescape(output);
|
||||
}
|
||||
|
||||
function wrappedText(text, sender, timestamp, direction) {
|
||||
return {
|
||||
messageType: Tp.ChannelTextMessageType.NORMAL,
|
||||
text: text,
|
||||
sender: sender,
|
||||
timestamp: timestamp,
|
||||
direction: direction
|
||||
};
|
||||
}
|
||||
|
||||
function Source(gajimClient, accountName, author, initialMessage) {
|
||||
this._init(gajimClient, accountName, author, initialMessage);
|
||||
}
|
||||
|
||||
Source.prototype = {
|
||||
__proto__: MessageTray.Source.prototype,
|
||||
|
||||
_init: function(gajimClient, accountName, author, initialMessage) {
|
||||
MessageTray.Source.prototype._init.call(this, author);
|
||||
this.isChat = true;
|
||||
this._author = author;
|
||||
this._gajimClient = gajimClient;
|
||||
this._accountName = accountName;
|
||||
this._initialMessage = initialMessage;
|
||||
this._iconUri = null;
|
||||
this._presence = "online";
|
||||
|
||||
this._notification = new TelepathyClient.Notification(this);
|
||||
this._notification.setUrgency(MessageTray.Urgency.HIGH);
|
||||
|
||||
let jid = author.split('/')[0];
|
||||
let proxy = this._gajimClient.proxy();
|
||||
proxy.contact_infoRemote(jid, Lang.bind(this, this._gotContactInfos));
|
||||
this._statusChangeId = proxy.connect('ContactStatus',
|
||||
Lang.bind(this, this._onStatusChange));
|
||||
this._contactAbsenceId = proxy.connect('ContactAbsence',
|
||||
Lang.bind(this, this._onStatusChange));
|
||||
this._chatStateId = proxy.connect('ChatState',
|
||||
Lang.bind(this, this._onChatState));
|
||||
this._messageSentId = proxy.connect('MessageSent',
|
||||
Lang.bind(this, this._messageSent));
|
||||
this._newMessageId = proxy.connect('NewMessage',
|
||||
Lang.bind(this, this._messageReceived));
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
let proxy = this._gajimClient.proxy();
|
||||
proxy.disconnect(this._statusChangeId);
|
||||
proxy.disconnect(this._contactAbsenceId);
|
||||
proxy.disconnect(this._chatStateId);
|
||||
proxy.disconnect(this._messageSentId);
|
||||
proxy.disconnect(this._newMessageId);
|
||||
MessageTray.Source.prototype.destroy.call(this);
|
||||
},
|
||||
|
||||
_gotContactInfos: function(result, excp) {
|
||||
this.title = result['FN'];
|
||||
|
||||
let avatarUri = null;
|
||||
if (result['PHOTO']) {
|
||||
let mimeType = result['PHOTO']['TYPE'];
|
||||
let avatarData = decode64(result['PHOTO']['BINVAL']);
|
||||
let sha = result['PHOTO']['SHA'];
|
||||
avatarUri = this._gajimClient.cacheAvatar(mimeType, sha, avatarData);
|
||||
}
|
||||
|
||||
this._iconUri = avatarUri;
|
||||
this._setSummaryIcon(this.createNotificationIcon());
|
||||
|
||||
let message = wrappedText(this._initialMessage, this._author, null, TelepathyClient.NotificationDirection.RECEIVED);
|
||||
this._notification.appendMessage(message, false);
|
||||
|
||||
if (!Main.messageTray.contains(this))
|
||||
Main.messageTray.add(this);
|
||||
|
||||
this.notify(this._notification);
|
||||
},
|
||||
|
||||
createNotificationIcon: function() {
|
||||
let iconBox = new St.Bin({ style_class: 'avatar-box' });
|
||||
iconBox._size = this.ICON_SIZE;
|
||||
|
||||
if (!this._iconUri) {
|
||||
iconBox.child = new St.Icon({ icon_name: 'avatar-default',
|
||||
icon_type: St.IconType.FULLCOLOR,
|
||||
icon_size: iconBox._size });
|
||||
} else {
|
||||
let textureCache = St.TextureCache.get_default();
|
||||
iconBox.child = textureCache.load_uri_async(this._iconUri, iconBox._size, iconBox._size);
|
||||
}
|
||||
return iconBox;
|
||||
},
|
||||
|
||||
open: function(notification) {
|
||||
// Lookup for the messages window and display it. In the case where it's not o
|
||||
// opened yet fallback to the roster window.
|
||||
let windows = global.get_window_actors();
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
let metaWindow = windows[i].metaWindow;
|
||||
if (metaWindow.get_wm_class_instance() == "gajim" &&
|
||||
metaWindow.get_role() == "messages") {
|
||||
Main.activateWindow(metaWindow);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let app = Shell.AppSystem.get_default().get_app('gajim.desktop');
|
||||
app.activate_window(null, global.get_current_time());
|
||||
},
|
||||
|
||||
_onChatState: function(emitter, data) {
|
||||
let chatstate = data[1][5];
|
||||
if (chatstate == 'gone')
|
||||
this.destroy();
|
||||
},
|
||||
|
||||
_messageReceived: function(emitter, data) {
|
||||
let author = data[1][0];
|
||||
let text = data[1][1];
|
||||
if (text && (author == this._author)) {
|
||||
let message = wrappedText(text, this._author, null, TelepathyClient.NotificationDirection.RECEIVED);
|
||||
this._notification.appendMessage(message, false);
|
||||
this.notify(this._notification);
|
||||
}
|
||||
},
|
||||
|
||||
_messageSent: function(emitter, data) {
|
||||
let text = data[1][1];
|
||||
let chatstate = data[1][3];
|
||||
|
||||
if (text) {
|
||||
let message = wrappedText(text, this._author, null, TelepathyClient.NotificationDirection.SENT);
|
||||
this._notification.appendMessage(message, false);
|
||||
} else if (chatstate == 'gone')
|
||||
this.destroy();
|
||||
},
|
||||
|
||||
notify: function() {
|
||||
|
||||
MessageTray.Source.prototype.notify.call(this, this._notification);
|
||||
},
|
||||
|
||||
respond: function(text) {
|
||||
let jid = this._author;
|
||||
let keyID = ""; // unencrypted.
|
||||
this._gajimClient.proxy().send_chat_messageRemote(jid, text, keyID, this._accountName);
|
||||
},
|
||||
|
||||
_onStatusChange: function(emitter, data) {
|
||||
if (!this.title)
|
||||
return;
|
||||
|
||||
let jid = data[1][0];
|
||||
let presence = data[1][1];
|
||||
let message = data[1][2];
|
||||
|
||||
if (jid != this._author.split('/')[0])
|
||||
return;
|
||||
|
||||
let presenceMessage, shouldNotify, title;
|
||||
title = GLib.markup_escape_text(this.title, -1);
|
||||
if (presence == "away") {
|
||||
presenceMessage = _("%s is away.").format(title);
|
||||
shouldNotify = false;
|
||||
} else if (presence == "offline") {
|
||||
presenceMessage = _("%s is offline.").format(title);
|
||||
shouldNotify = (this._presence != "offline");
|
||||
} else if (presence == "online") {
|
||||
presenceMessage = _("%s is online.").format(title);
|
||||
shouldNotify = (this._presence == "offline");
|
||||
} else if (presence == "dnd") {
|
||||
presenceMessage = _("%s is busy.").format(title);
|
||||
shouldNotify = false;
|
||||
} else
|
||||
return;
|
||||
|
||||
this._presence = presence;
|
||||
|
||||
if (message)
|
||||
presenceMessage += ' <i>(' + GLib.markup_escape_text(message, -1) + ')</i>';
|
||||
|
||||
this._notification.appendPresence(presenceMessage, shouldNotify);
|
||||
if (shouldNotify)
|
||||
this.notify(this._notification);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const GajimIface = {
|
||||
name: 'org.gajim.dbus.RemoteInterface',
|
||||
properties: [],
|
||||
methods: [{ name: 'send_chat_message', inSignature: 'ssss', outSignature: 'b'},
|
||||
{ name: 'contact_info', inSignature: 's', outSignature: 'a{sv}'}],
|
||||
signals: [{ name: 'NewMessage', inSignature: 'av' },
|
||||
{ name: 'ChatState', inSignature: 'av' },
|
||||
{ name: 'ContactStatus', inSignature: 'av' },
|
||||
{ name: 'ContactAbsence', inSignature: 'av' },
|
||||
{ name: 'MessageSent', inSignature: 'av' }]
|
||||
};
|
||||
|
||||
let Gajim = DBus.makeProxyClass(GajimIface);
|
||||
|
||||
function GajimClient() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
GajimClient.prototype = {
|
||||
_init: function() {
|
||||
this._sources = {};
|
||||
this._cacheDir = GLib.get_user_cache_dir() + '/gnome-shell/gajim-avatars';
|
||||
GLib.mkdir_with_parents(this._cacheDir, 0x1c0); // 0x1c0 = octal 0700
|
||||
|
||||
this._proxy = new Gajim(DBus.session, 'org.gajim.dbus', '/org/gajim/dbus/RemoteObject');
|
||||
this._proxy.connect('NewMessage', Lang.bind(this, this._messageReceived));
|
||||
},
|
||||
|
||||
proxy : function() {
|
||||
return this._proxy;
|
||||
},
|
||||
|
||||
_messageReceived : function(emitter, data) {
|
||||
let author = data[1][0];
|
||||
let message = data[1][1];
|
||||
let account = data[0];
|
||||
let source = this._sources[author];
|
||||
if (!source) {
|
||||
source = new Source(this, account, author, message);
|
||||
source.connect('destroy', Lang.bind(this,
|
||||
function() {
|
||||
delete this._sources[author];
|
||||
}));
|
||||
this._sources[author] = source;
|
||||
}
|
||||
},
|
||||
|
||||
cacheAvatar : function(mimeType, sha, avatarData) {
|
||||
let ext = mimeType.split('/')[1];
|
||||
let file = this._cacheDir + '/' + sha + '.' + ext;
|
||||
let uri = GLib.filename_to_uri(file, null);
|
||||
|
||||
if (GLib.file_test(file, GLib.FileTest.EXISTS))
|
||||
return uri;
|
||||
|
||||
let success = false;
|
||||
try {
|
||||
success = GLib.file_set_contents(file, avatarData, avatarData.length);
|
||||
} catch (e) {
|
||||
logError(e, 'Error caching avatar data');
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
function main() {
|
||||
let client = new GajimClient();
|
||||
}
|
||||
8
extensions/gajim/metadata.json.in
Normal file
8
extensions/gajim/metadata.json.in
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"uuid": "@uuid@",
|
||||
"name": "Gajim IM integration",
|
||||
"description": "Display Gajim incoming chats as notifications in the Shell message tray.",
|
||||
"shell-version": [ "3.0" ],
|
||||
"localedir": "@LOCALEDIR@",
|
||||
"url": "http://base-art.net"
|
||||
}
|
||||
0
extensions/gajim/stylesheet.css
Normal file
0
extensions/gajim/stylesheet.css
Normal file
@@ -1,17 +0,0 @@
|
||||
const AppDisplay = imports.ui.appDisplay;
|
||||
|
||||
let _activateOriginal = null;
|
||||
|
||||
function init() {
|
||||
}
|
||||
|
||||
function enable() {
|
||||
_activateOriginal = AppDisplay.AppIcon.prototype.activate;
|
||||
AppDisplay.AppIcon.prototype.activate = function() {
|
||||
_activateOriginal.call(this, 2);
|
||||
};
|
||||
}
|
||||
|
||||
function disable() {
|
||||
AppDisplay.AppIcon.prototype.activate = _activateOriginal;
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
extension_data += configure_file(
|
||||
input: metadata_name + '.in',
|
||||
output: metadata_name,
|
||||
configuration: metadata_conf
|
||||
)
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"extension-id": "@extension_id@",
|
||||
"uuid": "@uuid@",
|
||||
"settings-schema": "@gschemaname@",
|
||||
"gettext-domain": "@gettext_domain@",
|
||||
"name": "Launch new instance",
|
||||
"description": "Always launch a new instance when clicking in the dash or the application view.\nThis extension is part of Classic Mode and is officially supported by GNOME. Please do not report bugs using the form below, use GNOME's GitLab instance instead.",
|
||||
"shell-version": [ "@shell_current@" ],
|
||||
"url": "@url@"
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
/* This extensions requires no special styling */
|
||||
@@ -1,45 +0,0 @@
|
||||
extension_schemas = []
|
||||
js_sources = extensionlib
|
||||
|
||||
metadata_name = 'metadata.json'
|
||||
|
||||
foreach e : all_extensions
|
||||
uuid = e + uuid_suffix
|
||||
|
||||
metadata_conf = configuration_data()
|
||||
metadata_conf.set('extension_id', e)
|
||||
metadata_conf.set('uuid', uuid)
|
||||
metadata_conf.set('gschemaname', 'org.gnome.shell.extensions.' + e)
|
||||
metadata_conf.set('gettext_domain', gettext_domain)
|
||||
metadata_conf.set('shell_current', shell_version)
|
||||
metadata_conf.set('url', 'https://gitlab.gnome.org/GNOME/gnome-shell-extensions')
|
||||
|
||||
extension_sources = files(e + '/extension.js')
|
||||
extension_data = files(e + '/stylesheet.css')
|
||||
|
||||
subdir(e)
|
||||
|
||||
js_sources += extension_sources
|
||||
|
||||
if (enabled_extensions.contains(e))
|
||||
install_data (extension_sources + extension_data + extensionlib,
|
||||
install_dir: join_paths(extensiondir, uuid)
|
||||
)
|
||||
endif
|
||||
endforeach
|
||||
|
||||
install_data (extension_schemas,
|
||||
install_dir: schemadir
|
||||
)
|
||||
|
||||
foreach js_source : js_sources
|
||||
if (js52.found())
|
||||
path_array = '@0@'.format(js_source).split('/')
|
||||
name = join_paths(path_array[-2], path_array[-1])
|
||||
|
||||
test('Checking syntax of ' + name, js52,
|
||||
args: ['-s', '-c', js_source],
|
||||
workdir: meson.current_source_dir()
|
||||
)
|
||||
endif
|
||||
endforeach
|
||||
@@ -1,8 +0,0 @@
|
||||
extension_data += configure_file(
|
||||
input: metadata_name + '.in',
|
||||
output: metadata_name,
|
||||
configuration: metadata_conf
|
||||
)
|
||||
|
||||
# extension_sources += files('prefs.js')
|
||||
# extension_schemas += files(metadata_conf.get('gschemaname') + '.gschema.xml')
|
||||
@@ -1,299 +0,0 @@
|
||||
// -*- mode: js2; indent-tabs-mode: nil; js2-basic-offset: 4 -*-
|
||||
const Workspace = imports.ui.workspace;
|
||||
|
||||
const ExtensionUtils = imports.misc.extensionUtils;
|
||||
const Me = ExtensionUtils.getCurrentExtension();
|
||||
const Convenience = Me.imports.convenience;
|
||||
|
||||
// testing settings for natural window placement strategy:
|
||||
const WINDOW_PLACEMENT_NATURAL_FILLGAPS = true; // enlarge windows at the end to fill gaps // not implemented yet
|
||||
const WINDOW_PLACEMENT_NATURAL_GRID_FALLBACK = true; // fallback to grid mode if all windows have the same size and positions. // not implemented yet
|
||||
const WINDOW_PLACEMENT_NATURAL_ACCURACY = 20; // accuracy of window translate moves (KDE-default: 20)
|
||||
const WINDOW_PLACEMENT_NATURAL_GAPS = 5; // half of the minimum gap between windows
|
||||
const WINDOW_PLACEMENT_NATURAL_MAX_TRANSLATIONS = 5000; // safety limit for preventing endless loop if something is wrong in the algorithm
|
||||
|
||||
class Rect {
|
||||
constructor(x, y, width, height) {
|
||||
[this.x, this.y, this.width, this.height] = [x, y, width, height];
|
||||
}
|
||||
|
||||
/**
|
||||
* used in _calculateWindowTransformationsNatural to replace Meta.Rectangle that is too slow.
|
||||
*/
|
||||
copy() {
|
||||
return new Rect(this.x, this.y, this.width, this.height);
|
||||
}
|
||||
|
||||
union(rect2) {
|
||||
let dest = this.copy();
|
||||
if (rect2.x < dest.x)
|
||||
{
|
||||
dest.width += dest.x - rect2.x;
|
||||
dest.x = rect2.x;
|
||||
}
|
||||
if (rect2.y < dest.y)
|
||||
{
|
||||
dest.height += dest.y - rect2.y;
|
||||
dest.y = rect2.y;
|
||||
}
|
||||
if (rect2.x + rect2.width > dest.x + dest.width)
|
||||
dest.width = rect2.x + rect2.width - dest.x;
|
||||
if (rect2.y + rect2.height > dest.y + dest.height)
|
||||
dest.height = rect2.y + rect2.height - dest.y;
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
adjusted(dx, dy, dx2, dy2) {
|
||||
let dest = this.copy();
|
||||
dest.x += dx;
|
||||
dest.y += dy;
|
||||
dest.width += -dx + dx2;
|
||||
dest.height += -dy + dy2;
|
||||
return dest;
|
||||
}
|
||||
|
||||
overlap(rect2) {
|
||||
return !((this.x + this.width <= rect2.x) ||
|
||||
(rect2.x + rect2.width <= this.x) ||
|
||||
(this.y + this.height <= rect2.y) ||
|
||||
(rect2.y + rect2.height <= this.y));
|
||||
}
|
||||
|
||||
center() {
|
||||
return [this.x + this.width / 2, this.y + this.height / 2];
|
||||
}
|
||||
|
||||
translate(dx, dy) {
|
||||
this.x += dx;
|
||||
this.y += dy;
|
||||
}
|
||||
};
|
||||
|
||||
class NaturalLayoutStrategy extends Workspace.LayoutStrategy {
|
||||
constructor(settings) {
|
||||
super();
|
||||
this._settings = settings;
|
||||
}
|
||||
|
||||
computeLayout(windows, layout) {
|
||||
layout.windows = windows;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns clones with matching target coordinates and scales to arrange windows in a natural way that no overlap exists and relative window size is preserved.
|
||||
* This function is almost a 1:1 copy of the function
|
||||
* PresentWindowsEffect::calculateWindowTransformationsNatural() from KDE, see:
|
||||
* https://projects.kde.org/projects/kde/kdebase/kde-workspace/repository/revisions/master/entry/kwin/effects/presentwindows/presentwindows.cpp
|
||||
*/
|
||||
computeWindowSlots(layout, area) {
|
||||
// As we are using pseudo-random movement (See "slot") we need to make sure the list
|
||||
// is always sorted the same way no matter which window is currently active.
|
||||
|
||||
let area_rect = new Rect(area.x, area.y, area.width, area.height);
|
||||
let bounds = area_rect.copy();
|
||||
let clones = layout.windows;
|
||||
|
||||
let direction = 0;
|
||||
let directions = [];
|
||||
let rects = [];
|
||||
for (let i = 0; i < clones.length; i++) {
|
||||
// save rectangles into 4-dimensional arrays representing two corners of the rectangular: [left_x, top_y, right_x, bottom_y]
|
||||
let rect = clones[i].metaWindow.get_frame_rect();
|
||||
rects[i] = new Rect(rect.x, rect.y, rect.width, rect.height);
|
||||
bounds = bounds.union(rects[i]);
|
||||
|
||||
// This is used when the window is on the edge of the screen to try to use as much screen real estate as possible.
|
||||
directions[i] = direction;
|
||||
direction++;
|
||||
if (direction == 4) {
|
||||
direction = 0;
|
||||
}
|
||||
}
|
||||
|
||||
let loop_counter = 0;
|
||||
let overlap;
|
||||
do {
|
||||
overlap = false;
|
||||
for (let i = 0; i < rects.length; i++) {
|
||||
for (let j = 0; j < rects.length; j++) {
|
||||
if (i != j && rects[i].adjusted(-WINDOW_PLACEMENT_NATURAL_GAPS, -WINDOW_PLACEMENT_NATURAL_GAPS,
|
||||
WINDOW_PLACEMENT_NATURAL_GAPS, WINDOW_PLACEMENT_NATURAL_GAPS).overlap(
|
||||
rects[j].adjusted(-WINDOW_PLACEMENT_NATURAL_GAPS, -WINDOW_PLACEMENT_NATURAL_GAPS,
|
||||
WINDOW_PLACEMENT_NATURAL_GAPS, WINDOW_PLACEMENT_NATURAL_GAPS))) {
|
||||
loop_counter++;
|
||||
overlap = true;
|
||||
|
||||
// TODO: something like a Point2D would be nicer here:
|
||||
|
||||
// Determine pushing direction
|
||||
let i_center = rects[i].center();
|
||||
let j_center = rects[j].center();
|
||||
let diff = [j_center[0] - i_center[0], j_center[1] - i_center[1]];
|
||||
|
||||
// Prevent dividing by zero and non-movement
|
||||
if (diff[0] == 0 && diff[1] == 0)
|
||||
diff[0] = 1;
|
||||
// Try to keep screen/workspace aspect ratio
|
||||
if ( bounds.height / bounds.width > area_rect.height / area_rect.width )
|
||||
diff[0] *= 2;
|
||||
else
|
||||
diff[1] *= 2;
|
||||
|
||||
// Approximate a vector of between 10px and 20px in magnitude in the same direction
|
||||
let length = Math.sqrt(diff[0] * diff[0] + diff[1] * diff[1]);
|
||||
diff[0] = diff[0] * WINDOW_PLACEMENT_NATURAL_ACCURACY / length;
|
||||
diff[1] = diff[1] * WINDOW_PLACEMENT_NATURAL_ACCURACY / length;
|
||||
|
||||
// Move both windows apart
|
||||
rects[i].translate(-diff[0], -diff[1]);
|
||||
rects[j].translate(diff[0], diff[1]);
|
||||
|
||||
|
||||
if (this._settings.get_boolean('use-more-screen')) {
|
||||
// Try to keep the bounding rect the same aspect as the screen so that more
|
||||
// screen real estate is utilised. We do this by splitting the screen into nine
|
||||
// equal sections, if the window center is in any of the corner sections pull the
|
||||
// window towards the outer corner. If it is in any of the other edge sections
|
||||
// alternate between each corner on that edge. We don't want to determine it
|
||||
// randomly as it will not produce consistant locations when using the filter.
|
||||
// Only move one window so we don't cause large amounts of unnecessary zooming
|
||||
// in some situations. We need to do this even when expanding later just in case
|
||||
// all windows are the same size.
|
||||
// (We are using an old bounding rect for this, hopefully it doesn't matter)
|
||||
let xSection = Math.round((rects[i].x - bounds.x) / (bounds.width / 3));
|
||||
let ySection = Math.round((rects[i].y - bounds.y) / (bounds.height / 3));
|
||||
|
||||
let i_center = rects[i].center();
|
||||
diff[0] = 0;
|
||||
diff[1] = 0;
|
||||
if (xSection != 1 || ySection != 1) { // Remove this if you want the center to pull as well
|
||||
if (xSection == 1)
|
||||
xSection = (directions[i] / 2 ? 2 : 0);
|
||||
if (ySection == 1)
|
||||
ySection = (directions[i] % 2 ? 2 : 0);
|
||||
}
|
||||
if (xSection == 0 && ySection == 0) {
|
||||
diff[0] = bounds.x - i_center[0];
|
||||
diff[1] = bounds.y - i_center[1];
|
||||
}
|
||||
if (xSection == 2 && ySection == 0) {
|
||||
diff[0] = bounds.x + bounds.width - i_center[0];
|
||||
diff[1] = bounds.y - i_center[1];
|
||||
}
|
||||
if (xSection == 2 && ySection == 2) {
|
||||
diff[0] = bounds.x + bounds.width - i_center[0];
|
||||
diff[1] = bounds.y + bounds.height - i_center[1];
|
||||
}
|
||||
if (xSection == 0 && ySection == 2) {
|
||||
diff[0] = bounds.x - i_center[0];
|
||||
diff[1] = bounds.y + bounds.height - i_center[1];
|
||||
}
|
||||
if (diff[0] != 0 || diff[1] != 0) {
|
||||
let length = Math.sqrt(diff[0]*diff[0] + diff[1]*diff[1]);
|
||||
diff[0] *= WINDOW_PLACEMENT_NATURAL_ACCURACY / length / 2; // /2 to make it less influencing than the normal center-move above
|
||||
diff[1] *= WINDOW_PLACEMENT_NATURAL_ACCURACY / length / 2;
|
||||
rects[i].translate(diff[0], diff[1]);
|
||||
}
|
||||
}
|
||||
|
||||
// Update bounding rect
|
||||
bounds = bounds.union(rects[i]);
|
||||
bounds = bounds.union(rects[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (overlap && loop_counter < WINDOW_PLACEMENT_NATURAL_MAX_TRANSLATIONS);
|
||||
|
||||
// Work out scaling by getting the most top-left and most bottom-right window coords.
|
||||
let scale;
|
||||
scale = Math.min(area_rect.width / bounds.width,
|
||||
area_rect.height / bounds.height,
|
||||
1.0);
|
||||
|
||||
// Make bounding rect fill the screen size for later steps
|
||||
bounds.x = bounds.x - (area_rect.width - bounds.width * scale) / 2;
|
||||
bounds.y = bounds.y - (area_rect.height - bounds.height * scale) / 2;
|
||||
bounds.width = area_rect.width / scale;
|
||||
bounds.height = area_rect.height / scale;
|
||||
|
||||
// Move all windows back onto the screen and set their scale
|
||||
for (let i = 0; i < rects.length; i++) {
|
||||
rects[i].translate(-bounds.x, -bounds.y);
|
||||
}
|
||||
|
||||
// TODO: Implement the KDE part "Try to fill the gaps by enlarging windows if they have the space" here. (If this is wanted)
|
||||
|
||||
// rescale to workspace
|
||||
let scales = [];
|
||||
|
||||
let buttonOuterHeight, captionHeight;
|
||||
let buttonOuterWidth = 0;
|
||||
|
||||
let slots = [];
|
||||
for (let i = 0; i < rects.length; i++) {
|
||||
rects[i].x = rects[i].x * scale + area_rect.x;
|
||||
rects[i].y = rects[i].y * scale + area_rect.y;
|
||||
|
||||
slots.push([rects[i].x, rects[i].y, scale, clones[i]]);
|
||||
}
|
||||
|
||||
return slots;
|
||||
}
|
||||
};
|
||||
|
||||
let winInjections, workspaceInjections;
|
||||
|
||||
function resetState() {
|
||||
winInjections = { };
|
||||
workspaceInjections = { };
|
||||
}
|
||||
|
||||
function enable() {
|
||||
resetState();
|
||||
|
||||
let settings = Convenience.getSettings();
|
||||
|
||||
workspaceInjections['_getBestLayout'] = Workspace.Workspace.prototype._getBestLayout;
|
||||
Workspace.Workspace.prototype._getBestLayout = function(windows) {
|
||||
let strategy = new NaturalLayoutStrategy(settings);
|
||||
let layout = { strategy };
|
||||
strategy.computeLayout(windows, layout);
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
||||
/// position window titles on top of windows in overlay ////
|
||||
winInjections['relayout'] = Workspace.WindowOverlay.prototype.relayout;
|
||||
Workspace.WindowOverlay.prototype.relayout = function(animate) {
|
||||
if (settings.get_boolean('window-captions-on-top')) {
|
||||
let [, , , cloneHeight] = this._windowClone.slot;
|
||||
this.title.translation_y = -cloneHeight;
|
||||
}
|
||||
|
||||
winInjections['relayout'].call(this, animate);
|
||||
};
|
||||
}
|
||||
|
||||
function removeInjection(object, injection, name) {
|
||||
if (injection[name] === undefined)
|
||||
delete object[name];
|
||||
else
|
||||
object[name] = injection[name];
|
||||
}
|
||||
|
||||
function disable() {
|
||||
var i;
|
||||
|
||||
for (i in workspaceInjections)
|
||||
removeInjection(Workspace.Workspace.prototype, workspaceInjections, i);
|
||||
for (i in winInjections)
|
||||
removeInjection(Workspace.WindowOverlay.prototype, winInjections, i);
|
||||
|
||||
global.stage.queue_relayout();
|
||||
resetState();
|
||||
}
|
||||
|
||||
function init() {
|
||||
/* do nothing */
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
extension_data += configure_file(
|
||||
input: metadata_name + '.in',
|
||||
output: metadata_name,
|
||||
configuration: metadata_conf
|
||||
)
|
||||
|
||||
extension_schemas += files(metadata_conf.get('gschemaname') + '.gschema.xml')
|
||||
@@ -1,11 +0,0 @@
|
||||
{
|
||||
"uuid": "@uuid@",
|
||||
"extension-id": "@extension_id@",
|
||||
"settings-schema": "@gschemaname@",
|
||||
"gettext-domain": "@gettext_domain@",
|
||||
"name": "Native Window Placement",
|
||||
"description": "Arrange windows in overview in a more compact way.",
|
||||
"shell-version": [ "@shell_current@" ],
|
||||
"url": "@url@",
|
||||
"original-authors": [ "wepmaschda@gmx.de" ]
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
<schemalist gettext-domain="gnome-shell-extensions">
|
||||
<schema id="org.gnome.shell.extensions.native-window-placement" path="/org/gnome/shell/extensions/native-window-placement/">
|
||||
<key name="use-more-screen" type="b">
|
||||
<default>true</default>
|
||||
<summary>Use more screen for windows</summary>
|
||||
<description>Try to use more screen for placing window thumbnails by adapting to screen aspect ratio, and consolidating
|
||||
them further to reduce the bounding box. This setting applies only with the natural placement strategy.</description>
|
||||
</key>
|
||||
<key name="window-captions-on-top" type="b">
|
||||
<default>true</default>
|
||||
<summary>Place window captions on top</summary>
|
||||
<description>If true, place window captions on top the respective thumbnail, overriding shell default of placing it at
|
||||
the bottom. Changing this setting requires restarting the shell to have any effect.</description>
|
||||
</key>
|
||||
</schema>
|
||||
</schemalist>
|
||||
@@ -1,9 +0,0 @@
|
||||
.window-caption {
|
||||
-shell-caption-spacing: 13px; /* current caption height is 26px => set it to half of it. TODO: better solution needed */
|
||||
}
|
||||
|
||||
.window-picker {
|
||||
-horizontal-spacing: 32px;
|
||||
-vertical-spacing: 32px;
|
||||
padding: 64px 32px;
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const PanelMenu = imports.ui.panelMenu;
|
||||
const PopupMenu = imports.ui.popupMenu;
|
||||
const Panel = imports.ui.panel;
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell-extensions');
|
||||
const _ = Gettext.gettext;
|
||||
const N_ = x => x;
|
||||
|
||||
const ExtensionUtils = imports.misc.extensionUtils;
|
||||
const Me = ExtensionUtils.getCurrentExtension();
|
||||
const Convenience = Me.imports.convenience;
|
||||
const PlaceDisplay = Me.imports.placeDisplay;
|
||||
|
||||
const PLACE_ICON_SIZE = 16;
|
||||
|
||||
class PlaceMenuItem extends PopupMenu.PopupBaseMenuItem {
|
||||
constructor(info) {
|
||||
super();
|
||||
this._info = info;
|
||||
|
||||
this._icon = new St.Icon({ gicon: info.icon,
|
||||
icon_size: PLACE_ICON_SIZE });
|
||||
this.actor.add_child(this._icon);
|
||||
|
||||
this._label = new St.Label({ text: info.name, x_expand: true });
|
||||
this.actor.add_child(this._label);
|
||||
|
||||
if (info.isRemovable()) {
|
||||
this._ejectIcon = new St.Icon({ icon_name: 'media-eject-symbolic',
|
||||
style_class: 'popup-menu-icon ' });
|
||||
this._ejectButton = new St.Button({ child: this._ejectIcon });
|
||||
this._ejectButton.connect('clicked', info.eject.bind(info));
|
||||
this.actor.add_child(this._ejectButton);
|
||||
}
|
||||
|
||||
this._changedId = info.connect('changed',
|
||||
this._propertiesChanged.bind(this));
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (this._changedId) {
|
||||
this._info.disconnect(this._changedId);
|
||||
this._changedId = 0;
|
||||
}
|
||||
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
activate(event) {
|
||||
this._info.launch(event.get_time());
|
||||
|
||||
super.activate(event);
|
||||
}
|
||||
|
||||
_propertiesChanged(info) {
|
||||
this._icon.gicon = info.icon;
|
||||
this._label.text = info.name;
|
||||
}
|
||||
};
|
||||
|
||||
const SECTIONS = [
|
||||
'special',
|
||||
'devices',
|
||||
'bookmarks',
|
||||
'network'
|
||||
]
|
||||
|
||||
class PlacesMenu extends PanelMenu.Button {
|
||||
constructor() {
|
||||
super(0.0, _("Places"));
|
||||
|
||||
let hbox = new St.BoxLayout({ style_class: 'panel-status-menu-box' });
|
||||
let label = new St.Label({ text: _("Places"),
|
||||
y_expand: true,
|
||||
y_align: Clutter.ActorAlign.CENTER });
|
||||
hbox.add_child(label);
|
||||
hbox.add_child(PopupMenu.arrowIcon(St.Side.BOTTOM));
|
||||
this.actor.add_actor(hbox);
|
||||
|
||||
this.placesManager = new PlaceDisplay.PlacesManager();
|
||||
|
||||
this._sections = { };
|
||||
|
||||
for (let i=0; i < SECTIONS.length; i++) {
|
||||
let id = SECTIONS[i];
|
||||
this._sections[id] = new PopupMenu.PopupMenuSection();
|
||||
this.placesManager.connect(id + '-updated', () => {
|
||||
this._redisplay(id);
|
||||
});
|
||||
|
||||
this._create(id);
|
||||
this.menu.addMenuItem(this._sections[id]);
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.placesManager.destroy();
|
||||
|
||||
super.destroy();
|
||||
}
|
||||
|
||||
_redisplay(id) {
|
||||
this._sections[id].removeAll();
|
||||
this._create(id);
|
||||
}
|
||||
|
||||
_create(id) {
|
||||
let places = this.placesManager.get(id);
|
||||
|
||||
for (let i = 0; i < places.length; i++)
|
||||
this._sections[id].addMenuItem(new PlaceMenuItem(places[i]));
|
||||
|
||||
this._sections[id].actor.visible = places.length > 0;
|
||||
}
|
||||
};
|
||||
|
||||
function init() {
|
||||
Convenience.initTranslations();
|
||||
}
|
||||
|
||||
let _indicator;
|
||||
|
||||
function enable() {
|
||||
_indicator = new PlacesMenu;
|
||||
|
||||
let pos = 1;
|
||||
if ('apps-menu' in Main.panel.statusArea)
|
||||
pos = 2;
|
||||
Main.panel.addToStatusArea('places-menu', _indicator, pos, 'left');
|
||||
}
|
||||
|
||||
function disable() {
|
||||
_indicator.destroy();
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
extension_data += configure_file(
|
||||
input: metadata_name + '.in',
|
||||
output: metadata_name,
|
||||
configuration: metadata_conf
|
||||
)
|
||||
|
||||
extension_sources += files('placeDisplay.js')
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"extension-id": "@extension_id@",
|
||||
"uuid": "@uuid@",
|
||||
"settings-schema": "@gschemaname@",
|
||||
"gettext-domain": "@gettext_domain@",
|
||||
"name": "Places Status Indicator",
|
||||
"description": "Add a menu for quickly navigating places in the system.\nThis extension is part of Classic Mode and is officially supported by GNOME. Please do not report bugs using the form below, use GNOME's GitLab instance instead.",
|
||||
"shell-version": [ "@shell_current@" ],
|
||||
"url": "@url@"
|
||||
}
|
||||
@@ -1,540 +0,0 @@
|
||||
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
|
||||
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const DND = imports.ui.dnd;
|
||||
const Main = imports.ui.main;
|
||||
const Params = imports.misc.params;
|
||||
const Search = imports.ui.search;
|
||||
const ShellMountOperation = imports.ui.shellMountOperation;
|
||||
const Util = imports.misc.util;
|
||||
|
||||
const Gettext = imports.gettext.domain('gnome-shell-extensions');
|
||||
const _ = Gettext.gettext;
|
||||
const N_ = x => x;
|
||||
|
||||
const BACKGROUND_SCHEMA = 'org.gnome.desktop.background';
|
||||
|
||||
const Hostname1Iface = '<node> \
|
||||
<interface name="org.freedesktop.hostname1"> \
|
||||
<property name="PrettyHostname" type="s" access="read" /> \
|
||||
</interface> \
|
||||
</node>';
|
||||
const Hostname1 = Gio.DBusProxy.makeProxyWrapper(Hostname1Iface);
|
||||
|
||||
class PlaceInfo {
|
||||
constructor() {
|
||||
this._init.apply(this, arguments);
|
||||
}
|
||||
|
||||
_init(kind, file, name, icon) {
|
||||
this.kind = kind;
|
||||
this.file = file;
|
||||
this.name = name || this._getFileName();
|
||||
this.icon = icon ? new Gio.ThemedIcon({ name: icon }) : this.getIcon();
|
||||
}
|
||||
|
||||
destroy() {
|
||||
}
|
||||
|
||||
isRemovable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
_createLaunchCallback(launchContext, tryMount) {
|
||||
return (_ignored, result) => {
|
||||
try {
|
||||
Gio.AppInfo.launch_default_for_uri_finish(result);
|
||||
} catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_MOUNTED)) {
|
||||
let source = {
|
||||
get_icon: () => { return this.icon; }
|
||||
};
|
||||
let op = new ShellMountOperation.ShellMountOperation(source);
|
||||
this.file.mount_enclosing_volume(0, op.mountOp, null, (file, result) => {
|
||||
try {
|
||||
op.close();
|
||||
file.mount_enclosing_volume_finish(result);
|
||||
} catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.FAILED_HANDLED)) {
|
||||
// e.g. user canceled the password dialog
|
||||
return;
|
||||
} catch(e) {
|
||||
Main.notifyError(_("Failed to mount volume for “%s”").format(this.name), e.message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (tryMount) {
|
||||
let callback = this._createLaunchCallback(launchContext, false);
|
||||
Gio.AppInfo.launch_default_for_uri_async(file.get_uri(),
|
||||
launchContext,
|
||||
null,
|
||||
callback);
|
||||
}
|
||||
});
|
||||
} catch(e) {
|
||||
Main.notifyError(_("Failed to launch “%s”").format(this.name), e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
launch(timestamp) {
|
||||
let launchContext = global.create_app_launch_context(timestamp, -1);
|
||||
let callback = this._createLaunchCallback(launchContext, true);
|
||||
Gio.AppInfo.launch_default_for_uri_async(this.file.get_uri(),
|
||||
launchContext,
|
||||
null,
|
||||
callback);
|
||||
}
|
||||
|
||||
getIcon() {
|
||||
this.file.query_info_async('standard::symbolic-icon', 0, 0, null,
|
||||
(file, result) => {
|
||||
try {
|
||||
let info = file.query_info_finish(result);
|
||||
this.icon = info.get_symbolic_icon();
|
||||
this.emit('changed');
|
||||
} catch(e if e instanceof Gio.IOErrorEnum) {
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
// return a generic icon for this kind for now, until we have the
|
||||
// icon from the query info above
|
||||
switch (this.kind) {
|
||||
case 'network':
|
||||
return new Gio.ThemedIcon({ name: 'folder-remote-symbolic' });
|
||||
case 'devices':
|
||||
return new Gio.ThemedIcon({ name: 'drive-harddisk-symbolic' });
|
||||
case 'special':
|
||||
case 'bookmarks':
|
||||
default:
|
||||
if (!this.file.is_native())
|
||||
return new Gio.ThemedIcon({ name: 'folder-remote-symbolic' });
|
||||
else
|
||||
return new Gio.ThemedIcon({ name: 'folder-symbolic' });
|
||||
}
|
||||
}
|
||||
|
||||
_getFileName() {
|
||||
try {
|
||||
let info = this.file.query_info('standard::display-name', 0, null);
|
||||
return info.get_display_name();
|
||||
} catch(e if e instanceof Gio.IOErrorEnum) {
|
||||
return this.file.get_basename();
|
||||
}
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(PlaceInfo.prototype);
|
||||
|
||||
class RootInfo extends PlaceInfo {
|
||||
_init() {
|
||||
super._init('devices', Gio.File.new_for_path('/'), _("Computer"));
|
||||
|
||||
let busName = 'org.freedesktop.hostname1';
|
||||
let objPath = '/org/freedesktop/hostname1';
|
||||
new Hostname1(Gio.DBus.system, busName, objPath, (obj, error) => {
|
||||
if (error)
|
||||
return;
|
||||
|
||||
this._proxy = obj;
|
||||
this._proxy.connect('g-properties-changed',
|
||||
this._propertiesChanged.bind(this));
|
||||
this._propertiesChanged(obj);
|
||||
});
|
||||
}
|
||||
|
||||
getIcon() {
|
||||
return new Gio.ThemedIcon({ name: 'drive-harddisk-symbolic' });
|
||||
}
|
||||
|
||||
_propertiesChanged(proxy) {
|
||||
// GDBusProxy will emit a g-properties-changed when hostname1 goes down
|
||||
// ignore it
|
||||
if (proxy.g_name_owner) {
|
||||
this.name = proxy.PrettyHostname || _("Computer");
|
||||
this.emit('changed');
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (this._proxy) {
|
||||
this._proxy.run_dispose();
|
||||
this._proxy = null;
|
||||
}
|
||||
super.destroy();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class PlaceDeviceInfo extends PlaceInfo {
|
||||
_init(kind, mount) {
|
||||
this._mount = mount;
|
||||
super._init(kind, mount.get_root(), mount.get_name());
|
||||
}
|
||||
|
||||
getIcon() {
|
||||
return this._mount.get_symbolic_icon();
|
||||
}
|
||||
|
||||
isRemovable() {
|
||||
return this._mount.can_eject();
|
||||
}
|
||||
|
||||
eject() {
|
||||
let mountOp = new ShellMountOperation.ShellMountOperation(this._mount);
|
||||
|
||||
if (this._mount.can_eject())
|
||||
this._mount.eject_with_operation(Gio.MountUnmountFlags.NONE,
|
||||
mountOp.mountOp,
|
||||
null, // Gio.Cancellable
|
||||
this._ejectFinish.bind(this));
|
||||
else
|
||||
this._mount.unmount_with_operation(Gio.MountUnmountFlags.NONE,
|
||||
mountOp.mountOp,
|
||||
null, // Gio.Cancellable
|
||||
this._unmountFinish.bind(this));
|
||||
}
|
||||
|
||||
_ejectFinish(mount, result) {
|
||||
try {
|
||||
mount.eject_with_operation_finish(result);
|
||||
} catch(e) {
|
||||
this._reportFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
_unmountFinish(mount, result) {
|
||||
try {
|
||||
mount.unmount_with_operation_finish(result);
|
||||
} catch(e) {
|
||||
this._reportFailure(e);
|
||||
}
|
||||
}
|
||||
|
||||
_reportFailure(exception) {
|
||||
let msg = _("Ejecting drive “%s” failed:").format(this._mount.get_name());
|
||||
Main.notifyError(msg, exception.message);
|
||||
}
|
||||
};
|
||||
|
||||
class PlaceVolumeInfo extends PlaceInfo {
|
||||
_init(kind, volume) {
|
||||
this._volume = volume;
|
||||
super._init(kind, volume.get_activation_root(), volume.get_name());
|
||||
}
|
||||
|
||||
launch(timestamp) {
|
||||
if (this.file) {
|
||||
super.launch(timestamp);
|
||||
return;
|
||||
}
|
||||
|
||||
this._volume.mount(0, null, null, (volume, result) => {
|
||||
volume.mount_finish(result);
|
||||
|
||||
let mount = volume.get_mount();
|
||||
this.file = mount.get_root();
|
||||
super.launch(timestamp);
|
||||
});
|
||||
}
|
||||
|
||||
getIcon() {
|
||||
return this._volume.get_symbolic_icon();
|
||||
}
|
||||
};
|
||||
|
||||
const DEFAULT_DIRECTORIES = [
|
||||
GLib.UserDirectory.DIRECTORY_DOCUMENTS,
|
||||
GLib.UserDirectory.DIRECTORY_PICTURES,
|
||||
GLib.UserDirectory.DIRECTORY_MUSIC,
|
||||
GLib.UserDirectory.DIRECTORY_DOWNLOAD,
|
||||
GLib.UserDirectory.DIRECTORY_VIDEOS,
|
||||
];
|
||||
|
||||
var PlacesManager = class {
|
||||
constructor() {
|
||||
this._places = {
|
||||
special: [],
|
||||
devices: [],
|
||||
bookmarks: [],
|
||||
network: [],
|
||||
};
|
||||
|
||||
this._settings = new Gio.Settings({ schema_id: BACKGROUND_SCHEMA });
|
||||
this._showDesktopIconsChangedId =
|
||||
this._settings.connect('changed::show-desktop-icons',
|
||||
this._updateSpecials.bind(this));
|
||||
this._updateSpecials();
|
||||
|
||||
/*
|
||||
* Show devices, code more or less ported from nautilus-places-sidebar.c
|
||||
*/
|
||||
this._volumeMonitor = Gio.VolumeMonitor.get();
|
||||
this._connectVolumeMonitorSignals();
|
||||
this._updateMounts();
|
||||
|
||||
this._bookmarksFile = this._findBookmarksFile()
|
||||
this._bookmarkTimeoutId = 0;
|
||||
this._monitor = null;
|
||||
|
||||
if (this._bookmarksFile) {
|
||||
this._monitor = this._bookmarksFile.monitor_file(Gio.FileMonitorFlags.NONE, null);
|
||||
this._monitor.connect('changed', () => {
|
||||
if (this._bookmarkTimeoutId > 0)
|
||||
return;
|
||||
/* Defensive event compression */
|
||||
this._bookmarkTimeoutId = Mainloop.timeout_add(100, () => {
|
||||
this._bookmarkTimeoutId = 0;
|
||||
this._reloadBookmarks();
|
||||
return false;
|
||||
});
|
||||
});
|
||||
|
||||
this._reloadBookmarks();
|
||||
}
|
||||
}
|
||||
|
||||
_connectVolumeMonitorSignals() {
|
||||
const signals = ['volume-added', 'volume-removed', 'volume-changed',
|
||||
'mount-added', 'mount-removed', 'mount-changed',
|
||||
'drive-connected', 'drive-disconnected', 'drive-changed'];
|
||||
|
||||
this._volumeMonitorSignals = [];
|
||||
let func = this._updateMounts.bind(this);
|
||||
for (let i = 0; i < signals.length; i++) {
|
||||
let id = this._volumeMonitor.connect(signals[i], func);
|
||||
this._volumeMonitorSignals.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (this._settings)
|
||||
this._settings.disconnect(this._showDesktopIconsChangedId);
|
||||
this._settings = null;
|
||||
|
||||
for (let i = 0; i < this._volumeMonitorSignals.length; i++)
|
||||
this._volumeMonitor.disconnect(this._volumeMonitorSignals[i]);
|
||||
|
||||
if (this._monitor)
|
||||
this._monitor.cancel();
|
||||
if (this._bookmarkTimeoutId)
|
||||
Mainloop.source_remove(this._bookmarkTimeoutId);
|
||||
}
|
||||
|
||||
_updateSpecials() {
|
||||
this._places.special.forEach(p => { p.destroy(); });
|
||||
this._places.special = [];
|
||||
|
||||
let homePath = GLib.get_home_dir();
|
||||
|
||||
this._places.special.push(new PlaceInfo('special',
|
||||
Gio.File.new_for_path(homePath),
|
||||
_("Home")));
|
||||
|
||||
let specials = [];
|
||||
let dirs = DEFAULT_DIRECTORIES.slice();
|
||||
|
||||
if (this._settings.get_boolean('show-desktop-icons'))
|
||||
dirs.push(GLib.UserDirectory.DIRECTORY_DESKTOP);
|
||||
|
||||
for (let i = 0; i < dirs.length; i++) {
|
||||
let specialPath = GLib.get_user_special_dir(dirs[i]);
|
||||
if (specialPath == null || specialPath == homePath)
|
||||
continue;
|
||||
|
||||
let file = Gio.File.new_for_path(specialPath), info;
|
||||
try {
|
||||
info = new PlaceInfo('special', file);
|
||||
} catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
specials.push(info);
|
||||
}
|
||||
|
||||
specials.sort((a, b) => GLib.utf8_collate(a.name, b.name));
|
||||
this._places.special = this._places.special.concat(specials);
|
||||
|
||||
this.emit('special-updated');
|
||||
}
|
||||
|
||||
_updateMounts() {
|
||||
let networkMounts = [];
|
||||
let networkVolumes = [];
|
||||
|
||||
this._places.devices.forEach(p => { p.destroy(); });
|
||||
this._places.devices = [];
|
||||
this._places.network.forEach(p => { p.destroy(); });
|
||||
this._places.network = [];
|
||||
|
||||
/* Add standard places */
|
||||
this._places.devices.push(new RootInfo());
|
||||
this._places.network.push(new PlaceInfo('network',
|
||||
Gio.File.new_for_uri('network:///'),
|
||||
_("Browse Network"),
|
||||
'network-workgroup-symbolic'));
|
||||
|
||||
/* first go through all connected drives */
|
||||
let drives = this._volumeMonitor.get_connected_drives();
|
||||
for (let i = 0; i < drives.length; i++) {
|
||||
let volumes = drives[i].get_volumes();
|
||||
|
||||
for(let j = 0; j < volumes.length; j++) {
|
||||
let identifier = volumes[j].get_identifier('class');
|
||||
if (identifier && identifier.includes('network')) {
|
||||
networkVolumes.push(volumes[j]);
|
||||
} else {
|
||||
let mount = volumes[j].get_mount();
|
||||
if(mount != null)
|
||||
this._addMount('devices', mount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* add all volumes that is not associated with a drive */
|
||||
let volumes = this._volumeMonitor.get_volumes();
|
||||
for(let i = 0; i < volumes.length; i++) {
|
||||
if(volumes[i].get_drive() != null)
|
||||
continue;
|
||||
|
||||
let identifier = volumes[i].get_identifier('class');
|
||||
if (identifier && identifier.includes('network')) {
|
||||
networkVolumes.push(volumes[i]);
|
||||
} else {
|
||||
let mount = volumes[i].get_mount();
|
||||
if(mount != null)
|
||||
this._addMount('devices', mount);
|
||||
}
|
||||
}
|
||||
|
||||
/* add mounts that have no volume (/etc/mtab mounts, ftp, sftp,...) */
|
||||
let mounts = this._volumeMonitor.get_mounts();
|
||||
for(let i = 0; i < mounts.length; i++) {
|
||||
if(mounts[i].is_shadowed())
|
||||
continue;
|
||||
|
||||
if(mounts[i].get_volume())
|
||||
continue;
|
||||
|
||||
let root = mounts[i].get_default_location();
|
||||
if (!root.is_native()) {
|
||||
networkMounts.push(mounts[i]);
|
||||
continue;
|
||||
}
|
||||
this._addMount('devices', mounts[i]);
|
||||
}
|
||||
|
||||
for (let i = 0; i < networkVolumes.length; i++) {
|
||||
let mount = networkVolumes[i].get_mount();
|
||||
if (mount) {
|
||||
networkMounts.push(mount);
|
||||
continue;
|
||||
}
|
||||
this._addVolume('network', networkVolumes[i]);
|
||||
}
|
||||
|
||||
for (let i = 0; i < networkMounts.length; i++) {
|
||||
this._addMount('network', networkMounts[i]);
|
||||
}
|
||||
|
||||
this.emit('devices-updated');
|
||||
this.emit('network-updated');
|
||||
}
|
||||
|
||||
_findBookmarksFile() {
|
||||
let paths = [
|
||||
GLib.build_filenamev([GLib.get_user_config_dir(), 'gtk-3.0', 'bookmarks']),
|
||||
GLib.build_filenamev([GLib.get_home_dir(), '.gtk-bookmarks']),
|
||||
];
|
||||
|
||||
for (let i = 0; i < paths.length; i++) {
|
||||
if (GLib.file_test(paths[i], GLib.FileTest.EXISTS))
|
||||
return Gio.File.new_for_path(paths[i]);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
_reloadBookmarks() {
|
||||
|
||||
this._bookmarks = [];
|
||||
|
||||
let content = Shell.get_file_contents_utf8_sync(this._bookmarksFile.get_path());
|
||||
let lines = content.split('\n');
|
||||
|
||||
let bookmarks = [];
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
let line = lines[i];
|
||||
let components = line.split(' ');
|
||||
let bookmark = components[0];
|
||||
|
||||
if (!bookmark)
|
||||
continue;
|
||||
|
||||
let file = Gio.File.new_for_uri(bookmark);
|
||||
if (file.is_native() && !file.query_exists(null))
|
||||
continue;
|
||||
|
||||
let duplicate = false;
|
||||
for (let i = 0; i < this._places.special.length; i++) {
|
||||
if (file.equal(this._places.special[i].file)) {
|
||||
duplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (duplicate)
|
||||
continue;
|
||||
for (let i = 0; i < bookmarks.length; i++) {
|
||||
if (file.equal(bookmarks[i].file)) {
|
||||
duplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (duplicate)
|
||||
continue;
|
||||
|
||||
let label = null;
|
||||
if (components.length > 1)
|
||||
label = components.slice(1).join(' ');
|
||||
|
||||
bookmarks.push(new PlaceInfo('bookmarks', file, label));
|
||||
}
|
||||
|
||||
this._places.bookmarks = bookmarks;
|
||||
|
||||
this.emit('bookmarks-updated');
|
||||
}
|
||||
|
||||
_addMount(kind, mount) {
|
||||
let devItem;
|
||||
|
||||
try {
|
||||
devItem = new PlaceDeviceInfo(kind, mount);
|
||||
} catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._places[kind].push(devItem);
|
||||
}
|
||||
|
||||
_addVolume(kind, volume) {
|
||||
let volItem;
|
||||
|
||||
try {
|
||||
volItem = new PlaceVolumeInfo(kind, volume);
|
||||
} catch(e if e.matches(Gio.IOErrorEnum, Gio.IOErrorEnum.NOT_FOUND)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._places[kind].push(volItem);
|
||||
}
|
||||
|
||||
get(kind) {
|
||||
return this._places[kind];
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(PlacesManager.prototype);
|
||||
@@ -1 +0,0 @@
|
||||
/* none used*/
|
||||
@@ -1,160 +0,0 @@
|
||||
/* Screenshot Window Sizer for Gnome Shell
|
||||
*
|
||||
* Copyright (c) 2013 Owen Taylor <otaylor@redhat.com>
|
||||
* Copyright (c) 2013 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
const Gio = imports.gi.Gio;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
const ExtensionUtils = imports.misc.extensionUtils;
|
||||
const Me = ExtensionUtils.getCurrentExtension();
|
||||
const Convenience = Me.imports.convenience;
|
||||
|
||||
const MESSAGE_FADE_TIME = 2;
|
||||
|
||||
let text, button;
|
||||
|
||||
function hideMessage() {
|
||||
text.destroy();
|
||||
text = null;
|
||||
}
|
||||
|
||||
function flashMessage(message) {
|
||||
if (!text) {
|
||||
text = new St.Label({ style_class: 'screenshot-sizer-message' });
|
||||
Main.uiGroup.add_actor(text);
|
||||
}
|
||||
|
||||
Tweener.removeTweens(text);
|
||||
text.text = message;
|
||||
|
||||
text.opacity = 255;
|
||||
|
||||
let monitor = Main.layoutManager.primaryMonitor;
|
||||
text.set_position(monitor.x + Math.floor(monitor.width / 2 - text.width / 2),
|
||||
monitor.y + Math.floor(monitor.height / 2 - text.height / 2));
|
||||
|
||||
Tweener.addTween(text,
|
||||
{ opacity: 0,
|
||||
time: MESSAGE_FADE_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: hideMessage });
|
||||
}
|
||||
|
||||
let SIZES = [
|
||||
[624, 351],
|
||||
[800, 450],
|
||||
[1024, 576],
|
||||
[1200, 675],
|
||||
[1600, 900]
|
||||
];
|
||||
|
||||
function cycleScreenshotSizes(display, screen, window, binding) {
|
||||
// Probably this isn't useful with 5 sizes, but you can decrease instead
|
||||
// of increase by holding down shift.
|
||||
let modifiers = binding.get_modifiers();
|
||||
let backwards = (modifiers & Meta.VirtualModifier.SHIFT_MASK) != 0;
|
||||
|
||||
// Unmaximize first
|
||||
if (window.maximized_horizontally || window.maximizedVertically)
|
||||
window.unmaximize(Meta.MaximizeFlags.HORIZONTAL | Meta.MaximizeFlags.VERTICAL);
|
||||
|
||||
let workArea = window.get_work_area_current_monitor();
|
||||
let outerRect = window.get_frame_rect();
|
||||
|
||||
// Double both axes if on a hidpi display
|
||||
let scaleFactor = St.ThemeContext.get_for_stage(global.stage).scale_factor;
|
||||
let scaledSizes = SIZES.map(size => size.map(wh => wh * scaleFactor));
|
||||
|
||||
// Find the nearest 16:9 size for the current window size
|
||||
let nearestIndex;
|
||||
let nearestError;
|
||||
|
||||
for (let i = 0; i < scaledSizes.length; i++) {
|
||||
let [width, height] = scaledSizes[i];
|
||||
|
||||
// ignore sizes bigger than the workArea
|
||||
if (width > workArea.width || height > workArea.height)
|
||||
continue;
|
||||
|
||||
// get the best initial window size
|
||||
let error = Math.abs(width - outerRect.width) + Math.abs(height - outerRect.height);
|
||||
if (nearestIndex == null || error < nearestError) {
|
||||
nearestIndex = i;
|
||||
nearestError = error;
|
||||
}
|
||||
}
|
||||
|
||||
// get the next size up or down from ideal
|
||||
let newIndex = (nearestIndex + (backwards ? -1 : 1)) % scaledSizes.length;
|
||||
let newWidth, newHeight;
|
||||
[newWidth, newHeight] = scaledSizes[newIndex];
|
||||
if (newWidth > workArea.width || newHeight > workArea.height)
|
||||
[newWidth, newHeight] = scaledSizes[0];
|
||||
|
||||
// Push the window onscreen if it would be resized offscreen
|
||||
let newX = outerRect.x;
|
||||
let newY = outerRect.y;
|
||||
if (newX + newWidth > workArea.x + workArea.width)
|
||||
newX = Math.max(workArea.x + workArea.width - newWidth);
|
||||
if (newY + newHeight > workArea.y + workArea.height)
|
||||
newY = Math.max(workArea.y + workArea.height - newHeight);
|
||||
|
||||
window.move_resize_frame(true, newX, newY, newWidth, newHeight);
|
||||
|
||||
let newOuterRect = window.get_frame_rect();
|
||||
let message = '%d×%d'.format(
|
||||
(newOuterRect.width / scaleFactor),
|
||||
(newOuterRect.height / scaleFactor));
|
||||
|
||||
// The new size might have been constrained by geometry hints (e.g. for
|
||||
// a terminal) - in that case, include the actual ratio to the message
|
||||
// we flash
|
||||
let actualNumerator = (newOuterRect.width / newOuterRect.height) * 9;
|
||||
if (Math.abs(actualNumerator - 16) > 0.01)
|
||||
message += ' (%.2f:9)'.format(actualNumerator);
|
||||
|
||||
flashMessage(message);
|
||||
}
|
||||
|
||||
function init() {
|
||||
}
|
||||
|
||||
function enable() {
|
||||
Main.wm.addKeybinding('cycle-screenshot-sizes',
|
||||
Convenience.getSettings(),
|
||||
Meta.KeyBindingFlags.PER_WINDOW,
|
||||
Shell.ActionMode.NORMAL,
|
||||
cycleScreenshotSizes);
|
||||
Main.wm.addKeybinding('cycle-screenshot-sizes-backward',
|
||||
Convenience.getSettings(),
|
||||
Meta.KeyBindingFlags.PER_WINDOW |
|
||||
Meta.KeyBindingFlags.IS_REVERSED,
|
||||
Shell.ActionMode.NORMAL,
|
||||
cycleScreenshotSizes);
|
||||
}
|
||||
|
||||
function disable() {
|
||||
Main.wm.removeKeybinding('cycle-screenshot-sizes');
|
||||
Main.wm.removeKeybinding('cycle-screenshot-sizes-backward');
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
extension_data += configure_file(
|
||||
input: metadata_name + '.in',
|
||||
output: metadata_name,
|
||||
configuration: metadata_conf
|
||||
)
|
||||
|
||||
extension_schemas += files(metadata_conf.get('gschemaname') + '.gschema.xml')
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"extension-id": "@extension_id@",
|
||||
"uuid": "@uuid@",
|
||||
"settings-schema": "@gschemaname@",
|
||||
"gettext-domain": "@gettext_domain@",
|
||||
"name": "Screenshot Window Sizer",
|
||||
"description": "Resize windows for GNOME Software screenshots",
|
||||
"shell-version": [ "@shell_current@" ],
|
||||
"url": "@url@"
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<schemalist gettext-domain="gnome-shell-extensions">
|
||||
<schema id="org.gnome.shell.extensions.screenshot-window-sizer"
|
||||
path="/org/gnome/shell/extensions/screenshot-window-sizer/">
|
||||
<key type="as" name="cycle-screenshot-sizes">
|
||||
<default><![CDATA[['<Alt><Control>s']]]></default>
|
||||
<summary>Cycle Screenshot Sizes</summary>
|
||||
</key>
|
||||
<key type="as" name="cycle-screenshot-sizes-backward">
|
||||
<default><![CDATA[['<Shift><Alt><Control>s']]]></default>
|
||||
<summary>Cycle Screenshot Sizes Backward</summary>
|
||||
</key>
|
||||
</schema>
|
||||
</schemalist>
|
||||
@@ -1,8 +0,0 @@
|
||||
.screenshot-sizer-message {
|
||||
font-size: 36px;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
background-color: rgba(10,10,10,0.7);
|
||||
border-radius: 5px;
|
||||
padding: .5em;
|
||||
}
|
||||
14
extensions/user-theme/Makefile.am
Normal file
14
extensions/user-theme/Makefile.am
Normal file
@@ -0,0 +1,14 @@
|
||||
EXTENSION_ID = user-theme
|
||||
|
||||
include ../../extension.mk
|
||||
|
||||
gschemas_in = org.gnome.shell.extensions.user-theme.gschema.xml.in
|
||||
|
||||
@INTLTOOL_XML_NOMERGE_RULE@
|
||||
|
||||
gsettings_SCHEMAS = $(gschemas_in:.xml.in=.xml)
|
||||
|
||||
@GSETTINGS_RULES@
|
||||
|
||||
CLEANFILES += $(gschemas_in:.xml.in=.valid) $(gsettings_SCHEMAS)
|
||||
EXTRA_DIST += $(gschemas_in)
|
||||
@@ -3,49 +3,37 @@
|
||||
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Lang = imports.lang;
|
||||
const Main = imports.ui.main;
|
||||
|
||||
const SETTINGS_SCHEMA = 'org.gnome.shell.extensions.user-theme';
|
||||
const SETTINGS_KEY = 'name';
|
||||
|
||||
const ExtensionUtils = imports.misc.extensionUtils;
|
||||
const Me = ExtensionUtils.getCurrentExtension();
|
||||
const Convenience = Me.imports.convenience;
|
||||
function ThemeManager() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
class ThemeManager {
|
||||
constructor() {
|
||||
this._settings = Convenience.getSettings();
|
||||
}
|
||||
|
||||
enable() {
|
||||
this._changedId = this._settings.connect('changed::'+SETTINGS_KEY, this._changeTheme.bind(this));
|
||||
ThemeManager.prototype = {
|
||||
_init: function() {
|
||||
this._settings = new Gio.Settings({ schema: SETTINGS_SCHEMA });
|
||||
this._settings.connect('changed::'+SETTINGS_KEY, Lang.bind(this, this._changeTheme));
|
||||
this._changeTheme();
|
||||
}
|
||||
},
|
||||
|
||||
disable() {
|
||||
if (this._changedId) {
|
||||
this._settings.disconnect(this._changedId);
|
||||
this._changedId = 0;
|
||||
}
|
||||
|
||||
Main.setThemeStylesheet(null);
|
||||
Main.loadTheme();
|
||||
}
|
||||
|
||||
_changeTheme() {
|
||||
_changeTheme: function() {
|
||||
let _stylesheet = null;
|
||||
let _themeName = this._settings.get_string(SETTINGS_KEY);
|
||||
|
||||
if (_themeName) {
|
||||
let _userCssStylesheet = GLib.get_home_dir() + '/.themes/' + _themeName + '/gnome-shell/gnome-shell.css';
|
||||
let file = Gio.file_new_for_path(_userCssStylesheet);
|
||||
file = Gio.file_new_for_path(_userCssStylesheet);
|
||||
if (file.query_exists(null))
|
||||
_stylesheet = _userCssStylesheet;
|
||||
else {
|
||||
let sysdirs = GLib.get_system_data_dirs();
|
||||
sysdirs.unshift(GLib.get_user_data_dir());
|
||||
for (let i = 0; i < sysdirs.length; i++) {
|
||||
_userCssStylesheet = sysdirs[i] + '/themes/' + _themeName + '/gnome-shell/gnome-shell.css';
|
||||
let file = Gio.file_new_for_path(_userCssStylesheet);
|
||||
file = Gio.file_new_for_path(_userCssStylesheet);
|
||||
if (file.query_exists(null)) {
|
||||
_stylesheet = _userCssStylesheet;
|
||||
break;
|
||||
@@ -61,8 +49,9 @@ class ThemeManager {
|
||||
Main.setThemeStylesheet(_stylesheet);
|
||||
Main.loadTheme();
|
||||
}
|
||||
};
|
||||
|
||||
function init() {
|
||||
return new ThemeManager();
|
||||
}
|
||||
|
||||
|
||||
function main(metadata) {
|
||||
new ThemeManager();
|
||||
}
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
extension_data += configure_file(
|
||||
input: metadata_name + '.in',
|
||||
output: metadata_name,
|
||||
configuration: metadata_conf
|
||||
)
|
||||
|
||||
extension_schemas += files(metadata_conf.get('gschemaname') + '.gschema.xml')
|
||||
@@ -1,11 +1,9 @@
|
||||
{
|
||||
"uuid": "@uuid@",
|
||||
"extension-id": "@extension_id@",
|
||||
"settings-schema": "@gschemaname@",
|
||||
"gettext-domain": "@gettext_domain@",
|
||||
"name": "User Themes",
|
||||
"description": "Load shell themes from user directory.",
|
||||
"shell-version": [ "@shell_current@" ],
|
||||
"description": "Load shell themes from user directory",
|
||||
"shell-version": [ "3.0" ],
|
||||
"localedir": "@LOCALEDIR@",
|
||||
"original-authors": [ "john.stowers@gmail.com" ],
|
||||
"url": "@url@"
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<schema id="org.gnome.shell.extensions.user-theme" path="/org/gnome/shell/extensions/user-theme/">
|
||||
<key name="name" type="s">
|
||||
<default>""</default>
|
||||
<summary>Theme name</summary>
|
||||
<description>The name of the theme, to be loaded from ~/.themes/name/gnome-shell</description>
|
||||
<_summary>Theme name</_summary>
|
||||
<_description>The name of the theme, to be loaded from ~/.themes/name/gnome-shell</_description>
|
||||
</key>
|
||||
</schema>
|
||||
</schemalist>
|
||||
@@ -1 +0,0 @@
|
||||
/* none used */
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
@import url("stylesheet.css");
|
||||
|
||||
#panel.bottom-panel {
|
||||
border-top-width: 1px;
|
||||
border-bottom-width: 0px;
|
||||
height: 2.25em ;
|
||||
}
|
||||
|
||||
.bottom-panel .window-button > StWidget {
|
||||
background-gradient-drection: vertical;
|
||||
background-color: #fff;
|
||||
background-gradient-start: #fff;
|
||||
background-gradient-end: #eee;
|
||||
color: #000;
|
||||
-st-natural-width: 18.7em;
|
||||
max-width: 18.75em;
|
||||
color: #2e3436;
|
||||
background-color: #eee;
|
||||
border-radius: 2px;
|
||||
padding: 3px 6px 1px;
|
||||
box-shadow: inset -1px -1px 1px rgba(0,0,0,0.5);
|
||||
text-shadow: 0 0 transparent;
|
||||
}
|
||||
|
||||
.bottom-panel .window-button:hover > StWidget {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
.bottom-panel .window-button:active > StWidget,
|
||||
.bottom-panel .window-button:focus > StWidget {
|
||||
box-shadow: inset 1px 1px 2px rgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
.bottom-panel .window-button.focused > StWidget {
|
||||
background-color: #ddd;
|
||||
box-shadow: inset 1px 1px 1px rgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
.bottom-panel .window-button.focused:hover > StWidget {
|
||||
background-color: #e9e9e9;
|
||||
}
|
||||
|
||||
.bottom-panel .window-button.minimized > StWidget {
|
||||
color: #888;
|
||||
box-shadow: inset -1px -1px 1px rgba(0,0,0,0.5);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,12 +0,0 @@
|
||||
extension_data += configure_file(
|
||||
input: metadata_name + '.in',
|
||||
output: metadata_name,
|
||||
configuration: metadata_conf
|
||||
)
|
||||
|
||||
extension_sources += files('prefs.js')
|
||||
extension_schemas += files(metadata_conf.get('gschemaname') + '.gschema.xml')
|
||||
|
||||
if classic_mode_enabled
|
||||
extension_data += files('classic.css')
|
||||
endif
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"extension-id": "@extension_id@",
|
||||
"uuid": "@uuid@",
|
||||
"settings-schema": "@gschemaname@",
|
||||
"gettext-domain": "@gettext_domain@",
|
||||
"name": "Window List",
|
||||
"description": "Display a window list at the bottom of the screen.\nThis extension is part of Classic Mode and is officially supported by GNOME. Please do not report bugs using the form below, use GNOME's GitLab instance instead.",
|
||||
"shell-version": [ "@shell_current@" ],
|
||||
"url": "@url@"
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
<schemalist gettext-domain="gnome-shell-extensions">
|
||||
<enum id="org.gnome.shell.extensions.window-list.GroupingMode">
|
||||
<value value="0" nick="never"/>
|
||||
<value value="1" nick="auto"/>
|
||||
<value value="2" nick="always"/>
|
||||
</enum>
|
||||
<schema id="org.gnome.shell.extensions.window-list"
|
||||
path="/org/gnome/shell/extensions/window-list/">
|
||||
<key name="grouping-mode"
|
||||
enum="org.gnome.shell.extensions.window-list.GroupingMode">
|
||||
<default>'never'</default>
|
||||
<summary>When to group windows</summary>
|
||||
<description>
|
||||
Decides when to group windows from the same application on the
|
||||
window list. Possible values are “never”, “auto” and “always”.
|
||||
</description>
|
||||
</key>
|
||||
<key name="show-on-all-monitors" type="b">
|
||||
<default>false</default>
|
||||
<summary>Show the window list on all monitors</summary>
|
||||
<description>
|
||||
Whether to show the window list on all connected monitors or
|
||||
only on the primary one.
|
||||
</description>
|
||||
</key>
|
||||
</schema>
|
||||
</schemalist>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user