Compare commits
352 Commits
Author | SHA1 | Date | |
---|---|---|---|
a26b0b60d1 | |||
60dbb19c2d | |||
3703a86354 | |||
992b43f914 | |||
ff39edd1ee | |||
a81a16801d | |||
4c6f770dea | |||
c0b01c0210 | |||
400326e549 | |||
d7af6d40e3 | |||
90ebcd32e3 | |||
53d0581377 | |||
439daf828f | |||
d120d03de9 | |||
53fbabe2ca | |||
4bdd40911f | |||
ff4ac0d02e | |||
45dd342cc0 | |||
e5efecd2bd | |||
3bf88b8988 | |||
4ddc1118bb | |||
fd1e7b2a0f | |||
aed1e67add | |||
dc99e8ffcd | |||
6a8b50cb00 | |||
edb50d5dc7 | |||
2f6c951997 | |||
64cd51667d | |||
caa08f27fa | |||
26015ef16d | |||
4798ad5107 | |||
9b05304c2d | |||
795feca393 | |||
31663dcd83 | |||
2f2df61093 | |||
3b8d53060d | |||
c5ce405859 | |||
b3a5fc72fb | |||
8a2cc11cc0 | |||
cbb3a3aec8 | |||
e382da9708 | |||
ab1fbbde92 | |||
5f5266ca60 | |||
68e8b14b8b | |||
abdd8b330c | |||
eb8176deeb | |||
956f89f377 | |||
1c69380923 | |||
d2bc7b200e | |||
afb3b1e718 | |||
061a2cfbfb | |||
243824ab80 | |||
90ddad7ba1 | |||
20b29ff48f | |||
96f4d318c5 | |||
6f7da264ba | |||
640e45c12a | |||
04e28cd7c4 | |||
2cc41c6726 | |||
03a45b665c | |||
5a42179a96 | |||
af3ec56ca1 | |||
289b19aa31 | |||
91eb613d69 | |||
1c7c53d19f | |||
d4304495c6 | |||
b77b205d37 | |||
a15205e6c4 | |||
28dbf7a06e | |||
1ec8e9eb6b | |||
fa09f7a6da | |||
d67e54d3ee | |||
d263c12e2e | |||
4d55ccff39 | |||
2a0adc0fc8 | |||
076e902b2c | |||
8c72623da3 | |||
1fd25573e5 | |||
6527dbc8b7 | |||
3c646ec516 | |||
a9fd350396 | |||
e91e8e993d | |||
276d9a9302 | |||
6b95864076 | |||
d4c577a299 | |||
b90fc1e194 | |||
55497899dd | |||
e37790fdf9 | |||
83402957bb | |||
58325fca76 | |||
8b6962f3bf | |||
c1f91def74 | |||
529f74c0e5 | |||
459a3b18f2 | |||
ac2be7f0d1 | |||
f6b80d5ed4 | |||
d291e568fd | |||
2b78d5bd5d | |||
c9d9846759 | |||
6baafaa530 | |||
c2af05f753 | |||
97df305a6d | |||
fee385ba35 | |||
373fa3c325 | |||
84a6a6faf0 | |||
9432ddb12e | |||
d4a2f9e604 | |||
7f468b36e7 | |||
349e5b39af | |||
cad774aca1 | |||
b25bbf4c0a | |||
72dd458c80 | |||
79d5d3dba0 | |||
c14a4deddf | |||
4bab511fa5 | |||
36b11ee8c7 | |||
3ffc510be7 | |||
ec92bfba14 | |||
f5f22b3935 | |||
159081dcfc | |||
1da4837d98 | |||
0f63ae1869 | |||
32ef951fe0 | |||
3564d78d30 | |||
4bff2675ae | |||
2020d15a1a | |||
64d8d7a91c | |||
eb025901c8 | |||
9fee99bc7a | |||
67bfbc9b4b | |||
11d884d724 | |||
24d42adc04 | |||
110ef17e2d | |||
0143512e00 | |||
4876474be3 | |||
0e4a86f2e6 | |||
18dbc5462f | |||
8f660f563c | |||
fa316ddd3d | |||
7703bee284 | |||
90e6769638 | |||
0b6d09bbe2 | |||
3734479cbd | |||
6cae94edcc | |||
0918bdd612 | |||
a75b1abc93 | |||
e6a08cc9fd | |||
09c9defbf0 | |||
3ba6ff4ca9 | |||
19fa0b5d5b | |||
79db50500d | |||
f26c9ab245 | |||
293adb9bcc | |||
e79b15c645 | |||
08603c1524 | |||
cee7106cb1 | |||
2c0661d377 | |||
471006ba67 | |||
98bd590a5d | |||
9d88a13d3c | |||
159690b2d3 | |||
8a2bfd0e55 | |||
2ddc7cf00f | |||
04f10ceb4e | |||
ceefc5eea4 | |||
9feda69888 | |||
33f9895d71 | |||
2812c21322 | |||
7ac9fb2dd0 | |||
05c99241d6 | |||
9fb8dad80c | |||
004ad86e9d | |||
02c65fab8d | |||
dfe16f4af6 | |||
e52cb3c213 | |||
6e31e59b57 | |||
458778bcfd | |||
d8cabbee0b | |||
3029a4086b | |||
5598de6543 | |||
913aeae166 | |||
dddad9e1b5 | |||
4bfa68d209 | |||
42e3a93c20 | |||
05812ef7f9 | |||
a0df412deb | |||
678a88dbdb | |||
5e944c9a3b | |||
b28b60b47b | |||
16caa74386 | |||
470c65d046 | |||
ef6ea078dd | |||
37ee16b34d | |||
5880b3b0ed | |||
80a5f78eb2 | |||
4b727ef40d | |||
d0d79c5b3e | |||
0882da0a71 | |||
25410a730e | |||
22c445cffc | |||
42bf91fdc4 | |||
7f88e02a26 | |||
d540af847a | |||
2f78907aeb | |||
d471541495 | |||
fa5fb6b8a8 | |||
0a29cf6195 | |||
b7b4c54ab5 | |||
52abf266c0 | |||
11872cfb79 | |||
21309aa28f | |||
38d21c8edf | |||
090908439b | |||
0a17a28608 | |||
926643b025 | |||
1a834f7d8b | |||
3e54087e42 | |||
304b377dae | |||
ac4bcee050 | |||
553503dace | |||
90381ceea2 | |||
687814b6c6 | |||
6153094057 | |||
0245a0cd0e | |||
bcc3dc0711 | |||
3d499219da | |||
94b26888cf | |||
156fdf1fa3 | |||
2a3f9e8f83 | |||
849ce371ff | |||
a76ac5501c | |||
5803aa7e65 | |||
0fd6bc5172 | |||
0e3cea41e0 | |||
45c600cd25 | |||
7fb8e2d0ef | |||
2d5d54f3cd | |||
949359db5d | |||
5bd2695863 | |||
dfbbf9b436 | |||
a230ad9225 | |||
7a87474bcd | |||
479acf2d18 | |||
943c5e2edc | |||
1340413740 | |||
3adec65e20 | |||
d116f707c5 | |||
6f94b8cffe | |||
14a7e310fc | |||
bf680fdc7c | |||
851bf18265 | |||
452e98e3bc | |||
3cb54f6707 | |||
ed7881d6c9 | |||
ea1a45a878 | |||
003807334b | |||
24a5c3c19a | |||
62b2d69c2b | |||
cdbb7f8f5f | |||
ecc1f964c9 | |||
0f4e9189c5 | |||
799f56fe87 | |||
af9ab5dbb6 | |||
3486fcc89a | |||
1e2018d1b7 | |||
fb46bad665 | |||
e2d912c037 | |||
2879d9cdef | |||
300cefd66a | |||
72b4d2a234 | |||
02e438b1f8 | |||
58690c210e | |||
61f19a6c22 | |||
7465338ea1 | |||
9dff05a394 | |||
9f5a5ad635 | |||
2dcd0511c4 | |||
dd1a309cb6 | |||
9563515e97 | |||
ba77c51ee0 | |||
2e83b95484 | |||
756374b2e4 | |||
527ff6fb1d | |||
fb4fc496da | |||
8d9bd87c22 | |||
36acb0a63d | |||
3e0f5aec0c | |||
4f5c3b4b74 | |||
a4bf54e465 | |||
d94606587b | |||
74ea9f9305 | |||
4dc04d8c53 | |||
6e298759a4 | |||
3b320de8d7 | |||
30d3c1fe72 | |||
7469a2626a | |||
d534597589 | |||
ec3c8464d3 | |||
6319f649c2 | |||
44d34aba19 | |||
4245c573df | |||
c27b6493d6 | |||
7200207009 | |||
9ba66fd800 | |||
e4552fca40 | |||
b7d892e4c6 | |||
5b096be68b | |||
e843d11566 | |||
9c7803030e | |||
67ef36ef8e | |||
4c1614f6a5 | |||
3766784799 | |||
56e16ef712 | |||
559c313fc7 | |||
5e10d56d89 | |||
d289ce6aca | |||
c68e69bd6e | |||
a6f312cfd3 | |||
ca51a8c926 | |||
ec95a1c2d3 | |||
a418558b73 | |||
f097304f3b | |||
ea4ea4a9b2 | |||
b94452ee42 | |||
51db34d223 | |||
059c330d95 | |||
557f9ceb97 | |||
4aae57c274 | |||
fb0ca1ba9d | |||
51723bb93b | |||
1e41f869de | |||
28517e4c34 | |||
619066780f | |||
1636e6c187 | |||
d17c94f9b9 | |||
4b47803162 | |||
15a3f39f65 | |||
f7d85e618c | |||
f00500d3d5 | |||
25a5da074c | |||
43d737c663 | |||
789e24b59a | |||
b51bcf3e2b | |||
babb13f603 | |||
21ef33df65 | |||
83b1cedb86 | |||
36ee36283a | |||
74eac21870 | |||
e330c5ea17 | |||
e6644b7feb | |||
47af454115 | |||
1f31e80c47 |
11
.gitignore
vendored
@ -18,7 +18,15 @@ config
|
||||
configure
|
||||
data/gnome-shell.desktop
|
||||
data/gnome-shell.desktop.in
|
||||
intltool-extract.in
|
||||
intltool-merge.in
|
||||
intltool-update.in
|
||||
libtool
|
||||
omf.make
|
||||
po/*.gmo
|
||||
po/Makefile.in.in
|
||||
po/POTFILES
|
||||
po/stamp-it
|
||||
scripts/launcher.pyc
|
||||
src/*.gir
|
||||
src/*.typelib
|
||||
@ -30,4 +38,7 @@ src/gnomeshell-taskpanel
|
||||
src/gnome-shell
|
||||
src/test-recorder
|
||||
src/test-recorder.ogg
|
||||
src/test-theme
|
||||
stamp-h1
|
||||
tests/run-test.sh
|
||||
xmldocs.make
|
||||
|
17
Makefile.am
@ -1,13 +1,22 @@
|
||||
SUBDIRS = data js src
|
||||
SUBDIRS = data js src tests po
|
||||
|
||||
EXTRA_DIST = \
|
||||
.project \
|
||||
.settings
|
||||
.settings \
|
||||
autogen.sh
|
||||
|
||||
# These are files checked into Git that we don't want to distribute
|
||||
DIST_EXCLUDE = \
|
||||
.gitignore \
|
||||
gnome-shell.doap \
|
||||
MAINTAINERS \
|
||||
tools/build/*
|
||||
|
||||
distcheck-hook:
|
||||
@echo "Checking disted javascript against files in git"
|
||||
@echo "Checking disted files against files in git"
|
||||
@failed=false; \
|
||||
for f in `cd $(srcdir) && git ls-files js` ; do \
|
||||
exclude=`(for p in $(DIST_EXCLUDE) ; do echo --exclude=$$p ; done)`; \
|
||||
for f in `cd $(srcdir) && git ls-files $$exclude` ; do \
|
||||
if ! test -e $(distdir)/$$f ; then \
|
||||
echo File missing from distribution: $$f ; \
|
||||
failed=true ; \
|
||||
|
20
README
@ -0,0 +1,20 @@
|
||||
GNOME Shell provides core user interface functions for the GNOME 3 desktop,
|
||||
like switching to windows and launching applications. GNOME Shell takes
|
||||
advantage of the capabilities of modern graphics hardware and introduces
|
||||
innovative user interface concepts to provide a visually attractive and
|
||||
easy to use experience.
|
||||
|
||||
For more information about GNOME Shell, including instructions on how
|
||||
to build GNOME Shell from source and how to get involved with the project,
|
||||
see:
|
||||
|
||||
http://live.gnome.org/GnomeShell
|
||||
|
||||
Bugs should be reported at http://bugzilla.gnome.org against the 'gnome-shell'
|
||||
product.
|
||||
|
||||
License
|
||||
=======
|
||||
GNOME Shell is distributed under the terms of the GNU General Public License,
|
||||
version 2 or later. See the COPYING file for details.
|
||||
|
||||
|
28
autogen.sh
@ -1,8 +1,22 @@
|
||||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
# Run this to generate all the initial makefiles, etc.
|
||||
|
||||
(cd `dirname $0`;
|
||||
touch ChangeLog NEWS &&
|
||||
autoreconf --install --symlink &&
|
||||
autoreconf &&
|
||||
./configure --enable-maintainer-mode $@
|
||||
)
|
||||
srcdir=`dirname $0`
|
||||
test -z "$srcdir" && srcdir=.
|
||||
|
||||
PKG_NAME="gnome-shell"
|
||||
REQUIRED_AUTOMAKE_VERSION=1.10
|
||||
|
||||
(test -f $srcdir/configure.ac \
|
||||
&& test -d $srcdir/src) || {
|
||||
echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
|
||||
echo " top-level gnome-shell directory"
|
||||
exit 1
|
||||
}
|
||||
|
||||
which gnome-autogen.sh || {
|
||||
echo "You need to install gnome-common from GNOME Subversion (or from"
|
||||
echo "your OS vendor's package manager)."
|
||||
exit 1
|
||||
}
|
||||
USE_GNOME2_MACROS=1 USE_COMMON_DOC_BUILD=yes . gnome-autogen.sh
|
||||
|
25
configure.ac
@ -1,8 +1,8 @@
|
||||
AC_INIT(gnome-shell, 2.27.0)
|
||||
AC_INIT(gnome-shell, 2.28.0)
|
||||
|
||||
AC_CONFIG_AUX_DIR(config)
|
||||
|
||||
AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip])
|
||||
AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip foreign])
|
||||
AM_MAINTAINER_MODE
|
||||
|
||||
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])],)
|
||||
@ -22,9 +22,16 @@ AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE, "$GETTEXT_PACKAGE",
|
||||
|
||||
PKG_PROG_PKG_CONFIG(0.16)
|
||||
|
||||
IT_PROG_INTLTOOL(0.26)
|
||||
AM_GLIB_GNU_GETTEXT
|
||||
|
||||
AC_PATH_PROG(GCONFTOOL, gconftool-2, no)
|
||||
AM_GCONF_SOURCE_2
|
||||
|
||||
# Get a value to substitute into gnome-shell.in
|
||||
AM_PATH_PYTHON([2.5])
|
||||
AC_SUBST(PYTHON)
|
||||
|
||||
# We need at least this, since gst_plugin_register_static() was added
|
||||
# in 0.10.16, but nothing older than 0.10.21 has been tested.
|
||||
GSTREAMER_MIN_VERSION=0.10.16
|
||||
@ -43,15 +50,17 @@ fi
|
||||
|
||||
AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
|
||||
|
||||
PKG_CHECK_MODULES(MUTTER_PLUGIN, gio-unix-2.0 gtk+-2.0 dbus-glib-1 mutter-plugins gjs-gi-1.0 libgnome-menu $recorder_modules gconf-2.0 gdk-x11-2.0 clutter-x11-1.0 clutter-glx-1.0)
|
||||
# Collect more than 20 libraries for a prize!
|
||||
PKG_CHECK_MODULES(MUTTER_PLUGIN, gio-unix-2.0 gtk+-2.0 dbus-glib-1 mutter-plugins
|
||||
gjs-gi-1.0 libgnome-menu $recorder_modules gconf-2.0
|
||||
gdk-x11-2.0 clutter-x11-1.0 clutter-glx-1.0
|
||||
gnome-desktop-2.0 >= 2.26 libstartup-notification-1.0
|
||||
gobject-introspection-1.0 >= 0.6.5)
|
||||
PKG_CHECK_MODULES(TIDY, clutter-1.0)
|
||||
PKG_CHECK_MODULES(ST, clutter-1.0 gtk+-2.0 libcroco-0.6)
|
||||
PKG_CHECK_MODULES(BIG, clutter-1.0 gtk+-2.0 librsvg-2.0)
|
||||
PKG_CHECK_MODULES(GDMUSER, dbus-glib-1 gtk+-2.0)
|
||||
PKG_CHECK_MODULES(TRAY, gtk+-2.0)
|
||||
# We require libgnomeui for generating thumbnails for recent files with GnomeThumbnailFactory.
|
||||
# We'll switch to using GnomeDesktopThumbnailFactory once the branch of gnome-desktop that contains
|
||||
# it becomes stable.
|
||||
PKG_CHECK_MODULES(LIBGNOMEUI, libgnomeui-2.0)
|
||||
|
||||
MUTTER_BIN_DIR=`$PKG_CONFIG --variable=exec_prefix mutter-plugins`/bin
|
||||
# FIXME: metacity-plugins.pc should point directly to its .gir file
|
||||
@ -120,4 +129,6 @@ AC_OUTPUT([
|
||||
js/misc/Makefile
|
||||
js/ui/Makefile
|
||||
src/Makefile
|
||||
tests/Makefile
|
||||
po/Makefile.in
|
||||
])
|
||||
|
@ -12,15 +12,25 @@ gnome-shell.desktop.in: gnome-shell.desktop.in.in
|
||||
gnome-shell.desktop: gnome-shell.desktop.in
|
||||
$(AM_V_GEN) sed s/^_// < $< > $@ || rm $@
|
||||
|
||||
imagedir = $(pkgdatadir)/images
|
||||
imagesdir = $(pkgdatadir)/images
|
||||
dist_images_DATA = \
|
||||
add-workspace.svg \
|
||||
app-well-glow.png \
|
||||
back.svg \
|
||||
close.svg \
|
||||
close-black.svg \
|
||||
info.svg \
|
||||
magnifier.svg \
|
||||
remove-workspace.svg
|
||||
|
||||
dist_image_DATA = \
|
||||
add-workspace.svg \
|
||||
close.svg \
|
||||
info.svg \
|
||||
remove-workspace.svg \
|
||||
view-more-activated.svg \
|
||||
view-more.svg
|
||||
themedir = $(pkgdatadir)/theme
|
||||
dist_theme_DATA = \
|
||||
theme/gnome-shell.css \
|
||||
theme/scroll-button-down.png \
|
||||
theme/scroll-button-down-hover.png \
|
||||
theme/scroll-button-up.png \
|
||||
theme/scroll-button-up-hover.png \
|
||||
theme/scroll-vhandle.png
|
||||
|
||||
schemadir = @GCONF_SCHEMA_FILE_DIR@
|
||||
schema_DATA = gnome-shell.schemas
|
||||
|
BIN
data/app-well-glow.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
7
data/back.svg
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
|
||||
<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:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" version="1.0" id="Foreground" x="0px" y="0px" width="12" height="16" viewBox="0 0 12 16" enable-background="new 0 0 29 18" xml:space="preserve" sodipodi:version="0.32" inkscape:version="0.46+devel" sodipodi:docname="back.svg" inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata id="metadata16"><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><defs id="defs14"><inkscape:perspective sodipodi:type="inkscape:persp3d" inkscape:vp_x="0 : 9 : 1" inkscape:vp_y="0 : 1000 : 0" inkscape:vp_z="29 : 9 : 1" inkscape:persp3d-origin="14.5 : 6 : 1" id="perspective18"/></defs><sodipodi:namedview inkscape:window-height="728" inkscape:window-width="1103" inkscape:pageshadow="2" inkscape:pageopacity="1" guidetolerance="10.0" gridtolerance="10.0" objecttolerance="10.0" borderopacity="1.0" bordercolor="#666666" pagecolor="#000000" id="base" showgrid="true" inkscape:zoom="27.260185" inkscape:cx="12.592456" inkscape:cy="8.2696842" inkscape:window-x="145" inkscape:window-y="38" inkscape:current-layer="Foreground" inkscape:snap-global="true" showguides="false"><inkscape:grid type="xygrid" id="grid2391" empspacing="5" visible="true" enabled="true" snapvisiblegridlinesonly="true"/></sodipodi:namedview>
|
||||
|
||||
|
||||
|
||||
<path style="fill: rgb(255, 255, 255); fill-opacity: 1; stroke: none;" d="M 10,2 10,14 2,8 10,2 z" id="path43"/></svg>
|
After Width: | Height: | Size: 1.9 KiB |
66
data/close-black.svg
Normal file
@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
|
||||
|
||||
<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:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Foreground"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="16px"
|
||||
height="16px"
|
||||
viewBox="0 0 16 16"
|
||||
enable-background="new 0 0 16 16"
|
||||
xml:space="preserve"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.46+devel"
|
||||
sodipodi:docname="close-black.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata
|
||||
id="metadata2399"><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><defs
|
||||
id="defs2397"><linearGradient
|
||||
id="linearGradient3173"><stop
|
||||
style="stop-color:#c4c4c4;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3175" /><stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3177" /></linearGradient><inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 8 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="16 : 8 : 1"
|
||||
inkscape:persp3d-origin="8 : 5.3333333 : 1"
|
||||
id="perspective2401" /></defs><sodipodi:namedview
|
||||
inkscape:window-height="811"
|
||||
inkscape:window-width="1272"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
guidetolerance="10.0"
|
||||
gridtolerance="10.0"
|
||||
objecttolerance="10.0"
|
||||
borderopacity="1.0"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff"
|
||||
id="base"
|
||||
showgrid="false"
|
||||
inkscape:zoom="32.125"
|
||||
inkscape:cx="8"
|
||||
inkscape:cy="10.440056"
|
||||
inkscape:window-x="40"
|
||||
inkscape:window-y="40"
|
||||
inkscape:current-layer="Foreground" />
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M10.5,3.5l2,2L10,8l2.5,2.5l-2,2L8,10l-2.5,2.5l-2-2L6,8L3.5,5.5l2-2L8,6L10.5,3.5 z M0,8c0-4.418,3.582-8,8-8s8,3.582,8,8s-3.582,8-8,8S0,12.418,0,8z"
|
||||
id="path2394"
|
||||
style="fill-opacity:1;fill:#000000" />
|
||||
</svg>
|
After Width: | Height: | Size: 2.3 KiB |
@ -1,6 +1,21 @@
|
||||
<gconfschemafile>
|
||||
<schemalist>
|
||||
|
||||
<schema>
|
||||
<key>/schemas/desktop/gnome/shell/development_tools</key>
|
||||
<applyto>/desktop/gnome/shell/development_tools</applyto>
|
||||
<owner>gnome-shell</owner>
|
||||
<type>bool</type>
|
||||
<default>true</default>
|
||||
<locale name="C">
|
||||
<short>Enable internal tools useful for developers and testers from Alt-F2</short>
|
||||
<long>
|
||||
Allows access to internal debugging and monitoring tools using
|
||||
the Alt-F2 dialog.
|
||||
</long>
|
||||
</locale>
|
||||
</schema>
|
||||
|
||||
<schema>
|
||||
<key>/schemas/desktop/gnome/shell/app_monitor/enable_monitoring</key>
|
||||
<applyto>/desktop/gnome/shell/app_monitor/enable_monitoring</applyto>
|
||||
@ -35,7 +50,7 @@
|
||||
<applyto>/desktop/gnome/shell/sidebar/visible</applyto>
|
||||
<owner>gnome-shell</owner>
|
||||
<type>bool</type>
|
||||
<default>true</default>
|
||||
<default>false</default>
|
||||
<locale name="C">
|
||||
<short>Whether or not to display the sidebar</short>
|
||||
<long>
|
||||
|
@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
@ -8,22 +9,22 @@
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
version="1.0"
|
||||
id="Foreground"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="29px"
|
||||
height="18px"
|
||||
viewBox="0 0 29 18"
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 18 18"
|
||||
enable-background="new 0 0 29 18"
|
||||
xml:space="preserve"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.46"
|
||||
sodipodi:docname="search_1.svg"
|
||||
inkscape:version="0.46+devel"
|
||||
sodipodi:docname="magnifier.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata
|
||||
id="metadata16"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs14"><inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 9 : 1"
|
||||
@ -34,46 +35,46 @@
|
||||
inkscape:window-height="728"
|
||||
inkscape:window-width="1103"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageopacity="1"
|
||||
guidetolerance="10.0"
|
||||
gridtolerance="10.0"
|
||||
objecttolerance="10.0"
|
||||
borderopacity="1.0"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff"
|
||||
pagecolor="#000000"
|
||||
id="base"
|
||||
showgrid="false"
|
||||
inkscape:zoom="19.275862"
|
||||
inkscape:cx="14.5"
|
||||
inkscape:cy="9"
|
||||
inkscape:window-x="40"
|
||||
inkscape:window-y="40"
|
||||
inkscape:current-layer="Foreground"><inkscape:grid
|
||||
showgrid="true"
|
||||
inkscape:zoom="27.260185"
|
||||
inkscape:cx="9.5844061"
|
||||
inkscape:cy="9.4435574"
|
||||
inkscape:window-x="142"
|
||||
inkscape:window-y="26"
|
||||
inkscape:current-layer="Foreground"
|
||||
inkscape:snap-global="true"
|
||||
showguides="false"><inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid2391" /></sodipodi:namedview>
|
||||
<path
|
||||
d="M0,3c0-1.657,1.343-3,3-3h17c0.515,0,1.027,0.195,1.42,0.588l6.992,6.992c0.784,0.784,0.784,2.056,0,2.84l-6.992,6.992 C21.028,17.804,20.514,18,20,18H3c-1.657,0-3-1.343-3-3V3z"
|
||||
id="path3"
|
||||
style="fill:#151e2f;fill-opacity:1" />
|
||||
id="grid2391"
|
||||
empspacing="5"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" /></sodipodi:namedview>
|
||||
|
||||
<g
|
||||
id="g5"
|
||||
style="fill:#4669a9;fill-opacity:1">
|
||||
style="fill:#ffffff;fill-opacity:1"
|
||||
transform="translate(-4,-0.023114)">
|
||||
<path
|
||||
fill="#FFFFFF"
|
||||
d="M6.246,13.98c-0.319-0.319-0.319-0.837,0-1.157l3.717-3.717c0.319-0.319,0.837-0.319,1.157,0l0.786,0.787 c0.32,0.319,0.32,0.837,0,1.157l-3.717,3.717c-0.32,0.319-0.838,0.319-1.157,0L6.246,13.98L6.246,13.98z"
|
||||
d="m 6.246,13.98 c -0.319,-0.319 -0.319,-0.837 0,-1.157 L 9.963,9.106 c 0.319,-0.319 0.837,-0.319 1.157,0 l 0.786,0.787 c 0.32,0.319 0.32,0.837 0,1.157 l -3.717,3.717 c -0.32,0.319 -0.838,0.319 -1.157,0 l -0.786,-0.787 0,0 z"
|
||||
id="path7"
|
||||
style="fill:#4669a9;fill-opacity:1" />
|
||||
style="fill:#ffffff;fill-opacity:1" />
|
||||
<path
|
||||
fill="#FFFFFF"
|
||||
d="M9.076,11.937"
|
||||
d="M 9.076,11.937"
|
||||
id="path9"
|
||||
style="fill:#4669a9;fill-opacity:1" />
|
||||
style="fill:#ffffff;fill-opacity:1" />
|
||||
</g>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
fill="#FFFFFF"
|
||||
d="M11.25,7.5c0-1.243,1.007-2.25,2.25-2.25s2.25,1.007,2.25,2.25 s-1.007,2.25-2.25,2.25S11.25,8.743,11.25,7.5z M9,7.5C9,5.015,11.015,3,13.5,3S18,5.015,18,7.5S15.985,12,13.5,12S9,9.985,9,7.5z"
|
||||
d="m 7.25,7.476886 c 0,-1.243 1.007,-2.25 2.2499998,-2.25 1.2430002,0 2.2500002,1.007 2.2500002,2.25 0,1.243 -1.007,2.25 -2.2500002,2.25 C 8.257,9.726886 7.25,8.719886 7.25,7.476886 z m -2.25,0 c 0,-2.485 2.015,-4.5 4.4999998,-4.5 2.4850002,0 4.5000002,2.015 4.5000002,4.5 0,2.4849998 -2.015,4.5 -4.5000002,4.5 C 7.015,11.976886 5,9.9618858 5,7.476886 z"
|
||||
id="path11"
|
||||
style="fill:#4669a9;fill-opacity:1" />
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd" />
|
||||
</svg>
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.9 KiB |
176
data/theme/gnome-shell.css
Normal file
@ -0,0 +1,176 @@
|
||||
/* Copyright 2009, Red Hat, Inc.
|
||||
*
|
||||
* Portions adapted from Mx's data/style/default.css
|
||||
* Copyright 2009 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU Lesser General Public License,
|
||||
* version 2.1, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
StScrollBar
|
||||
{
|
||||
background-color: #354761;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
StScrollView
|
||||
{
|
||||
scrollbar-width: 16px;
|
||||
scrollbar-height: 16px;
|
||||
}
|
||||
|
||||
StButton#up-stepper
|
||||
{
|
||||
border-image: url("scroll-button-up.png") 5;
|
||||
}
|
||||
|
||||
StButton#up-stepper:hover,
|
||||
StButton#up-stepper:active
|
||||
{
|
||||
border-image: url("scroll-button-up-hover.png") 5;
|
||||
}
|
||||
|
||||
StButton#down-stepper
|
||||
{
|
||||
border-image: url("scroll-button-down.png") 5;
|
||||
}
|
||||
|
||||
StButton#down-stepper:hover,
|
||||
StButton#down-stepper:active
|
||||
{
|
||||
border-image: url("scroll-button-down-hover.png") 5;
|
||||
}
|
||||
|
||||
StScrollBar StButton#vhandle
|
||||
{
|
||||
border-image: url("scroll-vhandle.png") 5;
|
||||
}
|
||||
|
||||
StScrollBar StButton#vhandle:hover
|
||||
{
|
||||
border-image: url("scroll-vhandle.png") 5;
|
||||
}
|
||||
|
||||
/* Panel */
|
||||
|
||||
.panel-button {
|
||||
padding: 4px 12px 3px;
|
||||
border-radius: 5px;
|
||||
font: 16px sans-serif;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.panel-button:active, .panel-button:checked {
|
||||
background-color: #314a6c;
|
||||
}
|
||||
|
||||
/* LookingGlass */
|
||||
|
||||
#LookingGlassDialog
|
||||
{
|
||||
background-color: rgba(0,0,0,0.85);
|
||||
spacing: 4px;
|
||||
padding: 4px;
|
||||
border: 1px solid rgba(0,0,172,0.85);
|
||||
border-radius: 4px;
|
||||
|
||||
color: #88ff66;
|
||||
}
|
||||
|
||||
#LookingGlassDialog > #Toolbar
|
||||
{
|
||||
border: 1px solid grey;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
#LookingGlassDialog StLabel
|
||||
{
|
||||
color: #88ff66;
|
||||
}
|
||||
|
||||
#LookingGlassDialog StEntry
|
||||
{
|
||||
color: #88ff66;
|
||||
}
|
||||
|
||||
#LookingGlassDialog StBoxLayout#EvalBox
|
||||
{
|
||||
padding: 4px;
|
||||
spacing: 4px;
|
||||
}
|
||||
|
||||
/* Calendar popup */
|
||||
|
||||
#calendarPopup {
|
||||
border-radius: 5px;
|
||||
background: rgba(0,0,0,0.9);
|
||||
border: 1px solid rgba(128,128,128,0.45);
|
||||
color: white;
|
||||
}
|
||||
|
||||
#calendarPopup .calendar {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.calendar {
|
||||
spacing-rows: 5px;
|
||||
spacing-columns: 3px;
|
||||
}
|
||||
|
||||
.calendar-change-month {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.calendar-change-month:hover {
|
||||
background: #314a6c;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.calendar-change-month:active {
|
||||
background: #213050;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.calendar-day {
|
||||
padding: 1px 2px;
|
||||
}
|
||||
|
||||
.calendar-today {
|
||||
font-weight: bold;
|
||||
background: #ffffff;
|
||||
color: black;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.calendar-other-month-day {
|
||||
color: #cccccc;
|
||||
}
|
||||
|
||||
/* App Switcher */
|
||||
.switcher-list {
|
||||
background: rgba(0,0,0,0.8);
|
||||
border: 1px solid rgba(128,128,128,0.40);
|
||||
border-radius: 8px;
|
||||
padding: 18px;
|
||||
}
|
||||
|
||||
.switcher-list .item-box {
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.switcher-list .selected-item-box {
|
||||
padding: 8px;
|
||||
border-radius: 4px;
|
||||
background: rgba(255,255,255,0.33);
|
||||
}
|
BIN
data/theme/scroll-button-down-hover.png
Normal file
After Width: | Height: | Size: 225 B |
BIN
data/theme/scroll-button-down.png
Normal file
After Width: | Height: | Size: 225 B |
BIN
data/theme/scroll-button-up-hover.png
Normal file
After Width: | Height: | Size: 211 B |
BIN
data/theme/scroll-button-up.png
Normal file
After Width: | Height: | Size: 211 B |
BIN
data/theme/scroll-vhandle.png
Normal file
After Width: | Height: | Size: 323 B |
@ -1,66 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
|
||||
<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:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Foreground"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="29px"
|
||||
height="18px"
|
||||
viewBox="0 0 29 18"
|
||||
enable-background="new 0 0 29 18"
|
||||
xml:space="preserve"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.46"
|
||||
sodipodi:docname="search_2.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata
|
||||
id="metadata16"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs14"><inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 9 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="29 : 9 : 1"
|
||||
inkscape:persp3d-origin="14.5 : 6 : 1"
|
||||
id="perspective18" />
|
||||
|
||||
|
||||
</defs><sodipodi:namedview
|
||||
inkscape:window-height="728"
|
||||
inkscape:window-width="1103"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
guidetolerance="10.0"
|
||||
gridtolerance="10.0"
|
||||
objecttolerance="10.0"
|
||||
borderopacity="1.0"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff"
|
||||
id="base"
|
||||
showgrid="false"
|
||||
inkscape:zoom="19.275862"
|
||||
inkscape:cx="14.5"
|
||||
inkscape:cy="9"
|
||||
inkscape:window-x="40"
|
||||
inkscape:window-y="40"
|
||||
inkscape:current-layer="Foreground"><inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid2391" /></sodipodi:namedview>
|
||||
|
||||
<path
|
||||
style="fill:#4669a9;fill-opacity:1"
|
||||
id="path9"
|
||||
d="" />
|
||||
<path
|
||||
id="path3"
|
||||
style="fill:#3d5a93;fill-opacity:1"
|
||||
d="M 0,3 C 0,1.343 1.343,0 3,0 L 20,0 C 20.515,0 21.027,0.195 21.42,0.588 L 28.412,7.58 C 29.196,8.364 29.196,9.636 28.412,10.42 L 21.42,17.412 C 21.028,17.804 20.514,18 20,18 L 3,18 C 1.343,18 0,16.657 0,15 L 0,3 zM 13.5,3 C 11.015,3 9,5.015 9,7.5 C 9,8.2423219 9.1815696,8.9452421 9.5,9.5625 L 6.25,12.8125 C 5.931,13.1325 5.9310002,13.64975 6.25,13.96875 L 7.03125,14.78125 C 7.35025,15.10025 7.8674999,15.10025 8.1875,14.78125 L 11.46875,11.5 C 12.080227,11.810879 12.767137,12 13.5,12 C 15.985,12 18,9.985 18,7.5 C 18,5.015 15.985,3 13.5,3 z M 11.25,7.5 C 11.25,6.257 12.257,5.25 13.5,5.25 C 14.743,5.25 15.75,6.257 15.75,7.5 C 15.75,8.743 14.743,9.75 13.5,9.75 C 12.257,9.75 11.25,8.743 11.25,7.5 z" />
|
||||
</svg>
|
Before Width: | Height: | Size: 2.7 KiB |
53
gnome-shell.doap
Normal file
@ -0,0 +1,53 @@
|
||||
<Project xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
|
||||
xmlns:foaf="http://xmlns.com/foaf/0.1/"
|
||||
xmlns:gnome="http://api.gnome.org/doap-extensions#"
|
||||
xmlns="http://usefulinc.com/ns/doap#">
|
||||
|
||||
<name xml:lang="en">GNOME Shell</name>
|
||||
<shortdesc xml:lang="en">Next generation GNOME desktop shell</shortdesc>
|
||||
<!--
|
||||
<homepage rdf:resource="http://live.gnome.org/GnomeShell" />
|
||||
-->
|
||||
<mailing-list rdf:resource="http://mail.gnome.org/mailman/listinfo/gnome-shell-list" />
|
||||
<download-page rdf:resource="http://download.gnome.org/sources/gnome-shell/" />
|
||||
<bug-database rdf:resource="http://bugzilla.gnome.org/browse.cgi?product=gnome-shell" />
|
||||
|
||||
<category rdf:resource="http://api.gnome.org/doap-extensions#desktop" />
|
||||
|
||||
<maintainer>
|
||||
<foaf:Person>
|
||||
<foaf:name>William Jon McCann</foaf:name>
|
||||
<foaf:mbox rdf:resource="mailto:jmccann@redhat.com" />
|
||||
<gnome:userid>mccann</gnome:userid>
|
||||
</foaf:Person>
|
||||
</maintainer>
|
||||
<maintainer>
|
||||
<foaf:Person>
|
||||
<foaf:name>Owen Taylor</foaf:name>
|
||||
<foaf:mbox rdf:resource="mailto:otaylor@redhat.com" />
|
||||
<gnome:userid>otaylor</gnome:userid>
|
||||
</foaf:Person>
|
||||
</maintainer>
|
||||
<maintainer>
|
||||
<foaf:Person>
|
||||
<foaf:name>Colin Walters</foaf:name>
|
||||
<foaf:mbox rdf:resource="mailto:walters@verbum.org" />
|
||||
<gnome:userid>cwalters</gnome:userid>
|
||||
</foaf:Person>
|
||||
</maintainer>
|
||||
<maintainer>
|
||||
<foaf:Person>
|
||||
<foaf:name>Dan Winship</foaf:name>
|
||||
<foaf:mbox rdf:resource="mailto:danw@gnome.org" />
|
||||
<gnome:userid>danw</gnome:userid>
|
||||
</foaf:Person>
|
||||
</maintainer>
|
||||
<maintainer>
|
||||
<foaf:Person>
|
||||
<foaf:name>Marina Zhurakhinskaya</foaf:name>
|
||||
<foaf:mbox rdf:resource="mailto:marinaz@redhat.com" />
|
||||
<gnome:userid>marinaz</gnome:userid>
|
||||
</foaf:Person>
|
||||
</maintainer>
|
||||
</Project>
|
@ -1,4 +1,5 @@
|
||||
jsmiscdir = $(pkgdatadir)/js/misc
|
||||
|
||||
dist_jsmisc_DATA = \
|
||||
docInfo.js
|
||||
docInfo.js \
|
||||
format.js
|
||||
|
@ -85,19 +85,18 @@ DocInfo.prototype = {
|
||||
|
||||
var docManagerInstance = null;
|
||||
|
||||
function getDocManager(size) {
|
||||
function getDocManager() {
|
||||
if (docManagerInstance == null)
|
||||
docManagerInstance = new DocManager(size);
|
||||
docManagerInstance = new DocManager();
|
||||
return docManagerInstance;
|
||||
}
|
||||
|
||||
function DocManager(size) {
|
||||
this._init(size);
|
||||
function DocManager() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
DocManager.prototype = {
|
||||
_init: function(iconSize) {
|
||||
this._iconSize = iconSize;
|
||||
_init: function() {
|
||||
this._recentManager = Gtk.RecentManager.get_default();
|
||||
this._items = {};
|
||||
this._recentManager.connect('changed', Lang.bind(this, function(recentManager) {
|
||||
@ -112,6 +111,9 @@ DocManager.prototype = {
|
||||
let newItems = {};
|
||||
for (let i = 0; i < docs.length; i++) {
|
||||
let recentInfo = docs[i];
|
||||
if (!recentInfo.exists())
|
||||
continue;
|
||||
|
||||
let docInfo = new DocInfo(recentInfo);
|
||||
|
||||
// we use GtkRecentInfo URI as an item Id
|
||||
@ -126,7 +128,7 @@ DocManager.prototype = {
|
||||
dump them here */
|
||||
let texCache = Shell.TextureCache.get_default();
|
||||
for (var uri in deleted) {
|
||||
texCache.evict_recent_thumbnail(this._iconSize, this._items[uri]);
|
||||
texCache.evict_recent_thumbnail(this._items[uri]);
|
||||
}
|
||||
this._items = newItems;
|
||||
},
|
||||
|
44
js/misc/format.js
Normal file
@ -0,0 +1,44 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
/*
|
||||
* This function is intended to extend the String object and provide
|
||||
* an String.format API for string formatting.
|
||||
* It has to be set up using String.prototype.format = Format.format;
|
||||
* Usage:
|
||||
* "somestring %s %d".format('hello', 5);
|
||||
* It supports %s, %d and %f, for %f it also support precisions like
|
||||
* "%.2f".format(1.526)
|
||||
*/
|
||||
|
||||
function format() {
|
||||
let str = this;
|
||||
let i = 0;
|
||||
let args = arguments;
|
||||
|
||||
return str.replace(/%(?:\.([0-9]+))?(.)/g, function (str, precisionGroup, genericGroup) {
|
||||
|
||||
if (precisionGroup != '' && genericGroup != 'f')
|
||||
throw new Error("Precision can only be specified for 'f'");
|
||||
|
||||
switch (genericGroup) {
|
||||
case '%':
|
||||
return '%';
|
||||
break;
|
||||
case 's':
|
||||
return args[i++].toString();
|
||||
break;
|
||||
case 'd':
|
||||
return parseInt(args[i++]);
|
||||
break;
|
||||
case 'f':
|
||||
if (precisionGroup == '')
|
||||
return parseFloat(args[i++]);
|
||||
else
|
||||
return parseFloat(args[i++]).toFixed(parseInt(precisionGroup));
|
||||
break;
|
||||
default:
|
||||
throw new Error('Unsupported conversion character %' + genericGroup);
|
||||
}
|
||||
return ""; // Suppress warning
|
||||
});
|
||||
}
|
@ -3,19 +3,24 @@ jsuidir = $(pkgdatadir)/js/ui
|
||||
dist_jsui_DATA = \
|
||||
altTab.js \
|
||||
appDisplay.js \
|
||||
appIcon.js \
|
||||
button.js \
|
||||
calendar.js \
|
||||
chrome.js \
|
||||
dash.js \
|
||||
dnd.js \
|
||||
docDisplay.js \
|
||||
environment.js \
|
||||
genericDisplay.js \
|
||||
lightbox.js \
|
||||
link.js \
|
||||
lookingGlass.js \
|
||||
main.js \
|
||||
overlay.js \
|
||||
overview.js \
|
||||
panel.js \
|
||||
places.js \
|
||||
runDialog.js \
|
||||
shellDBus.js \
|
||||
sidebar.js \
|
||||
tweener.js \
|
||||
widget.js \
|
||||
|
848
js/ui/altTab.js
@ -2,33 +2,38 @@
|
||||
|
||||
const Big = imports.gi.Big;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gdk = imports.gi.Gdk;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Pango = imports.gi.Pango;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const AppIcon = imports.ui.appIcon;
|
||||
const Main = imports.ui.main;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
const POPUP_BG_COLOR = new Clutter.Color();
|
||||
POPUP_BG_COLOR.from_pixel(0x00000080);
|
||||
const POPUP_INDICATOR_COLOR = new Clutter.Color();
|
||||
POPUP_INDICATOR_COLOR.from_pixel(0xf0f0f0ff);
|
||||
const POPUP_TRANSPARENT = new Clutter.Color();
|
||||
POPUP_TRANSPARENT.from_pixel(0x00000000);
|
||||
const POPUP_ARROW_COLOR = new Clutter.Color();
|
||||
POPUP_ARROW_COLOR.from_pixel(0xffffffff);
|
||||
const TRANSPARENT_COLOR = new Clutter.Color();
|
||||
TRANSPARENT_COLOR.from_pixel(0x00000000);
|
||||
const POPUP_SEPARATOR_COLOR = new Clutter.Color();
|
||||
POPUP_SEPARATOR_COLOR.from_pixel(0x80808066);
|
||||
|
||||
const POPUP_INDICATOR_WIDTH = 4;
|
||||
const POPUP_GRID_SPACING = 8;
|
||||
const POPUP_ICON_SIZE = 48;
|
||||
const POPUP_NUM_COLUMNS = 5;
|
||||
const POPUP_APPICON_SIZE = 96;
|
||||
const POPUP_LIST_SPACING = 8;
|
||||
|
||||
const POPUP_LABEL_MAX_WIDTH = POPUP_NUM_COLUMNS * (POPUP_ICON_SIZE + POPUP_GRID_SPACING);
|
||||
const POPUP_POINTER_SELECTION_THRESHOLD = 3;
|
||||
|
||||
const OVERLAY_COLOR = new Clutter.Color();
|
||||
OVERLAY_COLOR.from_pixel(0x00000044);
|
||||
const THUMBNAIL_SIZE = 256;
|
||||
const THUMBNAIL_POPUP_TIME = 1000; // milliseconds
|
||||
|
||||
const SHOW_TIME = 0.05;
|
||||
const SWITCH_TIME = 0.1;
|
||||
const HOVER_TIME = 500; // milliseconds
|
||||
|
||||
function mod(a, b) {
|
||||
return (a + b) % b;
|
||||
}
|
||||
|
||||
function AltTabPopup() {
|
||||
this._init();
|
||||
@ -36,256 +41,639 @@ function AltTabPopup() {
|
||||
|
||||
AltTabPopup.prototype = {
|
||||
_init : function() {
|
||||
let global = Shell.Global.get();
|
||||
this.actor = new Clutter.Group({ reactive: true,
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: global.screen_width,
|
||||
height: global.screen_height });
|
||||
|
||||
this.actor = new Big.Box({ background_color : POPUP_BG_COLOR,
|
||||
corner_radius: POPUP_GRID_SPACING,
|
||||
padding: POPUP_GRID_SPACING,
|
||||
spacing: POPUP_GRID_SPACING,
|
||||
orientation: Big.BoxOrientation.VERTICAL });
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
|
||||
// Icon grid. It would be nice to use Tidy.Grid for the this,
|
||||
// but Tidy.Grid is lame in various ways. (Eg, it seems to
|
||||
// have a minimum size of 200x200.) So we create a vertical
|
||||
// Big.Box containing multiple horizontal Big.Boxes.
|
||||
this._grid = new Big.Box({ spacing: POPUP_GRID_SPACING,
|
||||
orientation: Big.BoxOrientation.VERTICAL });
|
||||
let gcenterbox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
x_align: Big.BoxAlignment.CENTER });
|
||||
gcenterbox.append(this._grid, Big.BoxPackFlags.NONE);
|
||||
this.actor.append(gcenterbox, Big.BoxPackFlags.NONE);
|
||||
this._haveModal = false;
|
||||
|
||||
// Selected-window label
|
||||
this._label = new Clutter.Text({ font_name: "Sans 16px",
|
||||
ellipsize: Pango.EllipsizeMode.END });
|
||||
|
||||
let labelbox = new Big.Box({ background_color: POPUP_INDICATOR_COLOR,
|
||||
corner_radius: POPUP_GRID_SPACING / 2,
|
||||
padding: POPUP_GRID_SPACING / 2 });
|
||||
labelbox.append(this._label, Big.BoxPackFlags.NONE);
|
||||
let lcenterbox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
x_align: Big.BoxAlignment.CENTER,
|
||||
width: POPUP_LABEL_MAX_WIDTH + POPUP_GRID_SPACING });
|
||||
lcenterbox.append(labelbox, Big.BoxPackFlags.NONE);
|
||||
this.actor.append(lcenterbox, Big.BoxPackFlags.NONE);
|
||||
|
||||
// Indicator around selected icon
|
||||
this._indicator = new Big.Rectangle({ border_width: POPUP_INDICATOR_WIDTH,
|
||||
corner_radius: POPUP_INDICATOR_WIDTH / 2,
|
||||
border_color: POPUP_INDICATOR_COLOR,
|
||||
color: POPUP_TRANSPARENT });
|
||||
this.actor.append(this._indicator, Big.BoxPackFlags.FIXED);
|
||||
|
||||
this._items = [];
|
||||
this._toplevels = global.window_group.get_children();
|
||||
this._currentApp = 0;
|
||||
this._currentWindows = [];
|
||||
this._thumbnailTimeoutId = 0;
|
||||
|
||||
global.stage.add_actor(this.actor);
|
||||
|
||||
// Dark translucent window used to cover all but the
|
||||
// currently-selected window while Alt-Tabbing. Actually
|
||||
// contains four actors which can we rearrange to create
|
||||
// a hole in the overlay.
|
||||
this._overlay = new Clutter.Group({ reactive: true });
|
||||
this._overlay_top = new Clutter.Rectangle({ color: OVERLAY_COLOR,
|
||||
border_width: 0 });
|
||||
this._overlay_bottom = new Clutter.Rectangle({ color: OVERLAY_COLOR,
|
||||
border_width: 0 });
|
||||
this._overlay_left = new Clutter.Rectangle({ color: OVERLAY_COLOR,
|
||||
border_width: 0 });
|
||||
this._overlay_right = new Clutter.Rectangle({ color: OVERLAY_COLOR,
|
||||
border_width: 0 });
|
||||
this._overlay.add_actor(this._overlay_top);
|
||||
this._overlay.add_actor(this._overlay_bottom);
|
||||
this._overlay.add_actor(this._overlay_left);
|
||||
this._overlay.add_actor(this._overlay_right);
|
||||
},
|
||||
|
||||
addWindow : function(win) {
|
||||
let item = { window: win,
|
||||
metaWindow: win.get_meta_window() };
|
||||
show : function(backward) {
|
||||
let appMonitor = Shell.AppMonitor.get_default();
|
||||
let apps = appMonitor.get_running_apps ("");
|
||||
|
||||
let pixbuf = item.metaWindow.icon;
|
||||
item.icon = new Clutter.Texture({ width: POPUP_ICON_SIZE,
|
||||
height: POPUP_ICON_SIZE,
|
||||
keep_aspect_ratio: true });
|
||||
Shell.clutter_texture_set_from_pixbuf(item.icon, pixbuf);
|
||||
if (!apps.length)
|
||||
return false;
|
||||
|
||||
item.box = new Big.Box({ padding: POPUP_INDICATOR_WIDTH * 2 });
|
||||
item.box.append(item.icon, Big.BoxPackFlags.NONE);
|
||||
if (!Main.pushModal(this.actor))
|
||||
return false;
|
||||
this._haveModal = true;
|
||||
|
||||
item.above = null;
|
||||
for (let i = 1; i < this._toplevels.length; i++) {
|
||||
if (this._toplevels[i] == win) {
|
||||
item.above = this._toplevels[i - 1];
|
||||
break;
|
||||
}
|
||||
this._keyPressEventId = global.stage.connect('key-press-event', Lang.bind(this, this._keyPressEvent));
|
||||
this._keyReleaseEventId = global.stage.connect('key-release-event', Lang.bind(this, this._keyReleaseEvent));
|
||||
|
||||
this._motionEventId = this.actor.connect('motion-event', Lang.bind(this, this._mouseMoved));
|
||||
this._mouseActive = false;
|
||||
this._mouseMovement = 0;
|
||||
|
||||
this._appSwitcher = new AppSwitcher(apps);
|
||||
this.actor.add_actor(this._appSwitcher.actor);
|
||||
this._appSwitcher.connect('item-activated', Lang.bind(this, this._appActivated));
|
||||
this._appSwitcher.connect('item-hovered', Lang.bind(this, this._appHovered));
|
||||
|
||||
let primary = global.get_primary_monitor();
|
||||
this._appSwitcher.actor.x = primary.x + Math.floor((primary.width - this._appSwitcher.actor.width) / 2);
|
||||
this._appSwitcher.actor.y = primary.y + Math.floor((primary.height - this._appSwitcher.actor.height) / 2);
|
||||
|
||||
this._appIcons = this._appSwitcher.icons;
|
||||
|
||||
// _currentWindows give the index of the selected window for
|
||||
// each app; they all start at 0.
|
||||
this._currentWindows = this._appIcons.map(function (app) { return 0; });
|
||||
|
||||
// Make the initial selection
|
||||
if (this._appIcons.length == 1) {
|
||||
if (!backward && this._appIcons[0].windows.length > 1) {
|
||||
// For compatibility with the multi-app case below
|
||||
this._select(0, 1);
|
||||
} else
|
||||
this._select(0);
|
||||
} else if (backward) {
|
||||
this._select(this._appIcons.length - 1);
|
||||
} else {
|
||||
if (this._appIcons[0].windows.length > 1) {
|
||||
let curAppNextWindow = this._appIcons[0].windows[1];
|
||||
let nextAppWindow = this._appIcons[1].windows[0];
|
||||
|
||||
// If the next window of the current app is more-recently-used
|
||||
// than the first window of the next app, then select it.
|
||||
if (curAppNextWindow.get_workspace() == global.screen.get_active_workspace() &&
|
||||
curAppNextWindow.get_user_time() > nextAppWindow.get_user_time())
|
||||
this._select(0, 1);
|
||||
else
|
||||
this._select(1);
|
||||
} else
|
||||
this._select(1);
|
||||
}
|
||||
|
||||
item.visible = item.metaWindow.showing_on_its_workspace();
|
||||
|
||||
if (!item.visible) {
|
||||
let rect = new Meta.Rectangle();
|
||||
if (item.metaWindow.get_icon_geometry(rect))
|
||||
item.icon_rect = rect;
|
||||
// There's a race condition; if the user released Alt before
|
||||
// we got the grab, then we won't be notified. (See
|
||||
// https://bugzilla.gnome.org/show_bug.cgi?id=596695 for
|
||||
// details.) So we check now. (Have to do this after updating
|
||||
// selection.)
|
||||
let mods = global.get_modifier_keys();
|
||||
if (!(mods & Gdk.ModifierType.MOD1_MASK)) {
|
||||
this._finish();
|
||||
return false;
|
||||
}
|
||||
|
||||
item.n = this._items.length;
|
||||
this._items.push(item);
|
||||
|
||||
// Add it to the grid
|
||||
if (!this._gridRow || this._gridRow.get_children().length == POPUP_NUM_COLUMNS) {
|
||||
this._gridRow = new Big.Box({ spacing: POPUP_GRID_SPACING,
|
||||
orientation: Big.BoxOrientation.HORIZONTAL });
|
||||
this._grid.append(this._gridRow, Big.BoxPackFlags.NONE);
|
||||
}
|
||||
this._gridRow.append(item.box, Big.BoxPackFlags.NONE);
|
||||
return true;
|
||||
},
|
||||
|
||||
show : function(initialSelection) {
|
||||
let global = Shell.Global.get();
|
||||
_nextApp : function() {
|
||||
return mod(this._currentApp + 1, this._appIcons.length);
|
||||
},
|
||||
_previousApp : function() {
|
||||
return mod(this._currentApp - 1, this._appIcons.length);
|
||||
},
|
||||
|
||||
Main.startModal();
|
||||
_nextWindow : function() {
|
||||
return mod(this._currentWindows[this._currentApp] + 1,
|
||||
this._appIcons[this._currentApp].windows.length);
|
||||
},
|
||||
_previousWindow : function() {
|
||||
return mod(this._currentWindows[this._currentApp] - 1,
|
||||
this._appIcons[this._currentApp].windows.length);
|
||||
},
|
||||
|
||||
global.window_group.add_actor(this._overlay);
|
||||
this._overlay.raise_top();
|
||||
this._overlay.show();
|
||||
this.actor.opacity = 0;
|
||||
Tweener.addTween(this.actor, { opacity: 255,
|
||||
time: SHOW_TIME,
|
||||
transition: "easeOutQuad" });
|
||||
_keyPressEvent : function(actor, event) {
|
||||
let keysym = event.get_key_symbol();
|
||||
let shift = (Shell.get_event_state(event) & Clutter.ModifierType.SHIFT_MASK);
|
||||
|
||||
this.actor.show_all();
|
||||
this.actor.x = Math.floor((global.screen_width - this.actor.width) / 2);
|
||||
this.actor.y = Math.floor((global.screen_height - this.actor.height) / 2);
|
||||
// The WASD stuff is for debugging in Xephyr, where the arrow
|
||||
// keys aren't mapped correctly
|
||||
|
||||
this.select(initialSelection);
|
||||
if (keysym == Clutter.Tab)
|
||||
this._select(shift ? this._previousApp() : this._nextApp());
|
||||
else if (keysym == Clutter.grave)
|
||||
this._select(this._currentApp, shift ? this._previousWindow() : this._nextWindow());
|
||||
else if (keysym == Clutter.Escape)
|
||||
this.destroy();
|
||||
else if (this._thumbnails) {
|
||||
if (keysym == Clutter.Left || keysym == Clutter.a)
|
||||
this._select(this._currentApp, this._previousWindow());
|
||||
else if (keysym == Clutter.Right || keysym == Clutter.d)
|
||||
this._select(this._currentApp, this._nextWindow());
|
||||
else if (keysym == Clutter.Up || keysym == Clutter.w)
|
||||
this._select(this._currentApp, null, true);
|
||||
} else {
|
||||
if (keysym == Clutter.Left || keysym == Clutter.a)
|
||||
this._select(this._previousApp());
|
||||
else if (keysym == Clutter.Right || keysym == Clutter.d)
|
||||
this._select(this._nextApp());
|
||||
else if (keysym == Clutter.Down || keysym == Clutter.s)
|
||||
this._select(this._currentApp, this._currentWindows[this._currentApp]);
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
_keyReleaseEvent : function(actor, event) {
|
||||
let keysym = event.get_key_symbol();
|
||||
|
||||
if (keysym == Clutter.Alt_L || keysym == Clutter.Alt_R)
|
||||
this._finish();
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
_appActivated : function(appSwitcher, n) {
|
||||
Main.activateWindow(this._appIcons[n].windows[this._currentWindows[n]]);
|
||||
this.destroy();
|
||||
},
|
||||
|
||||
_appHovered : function(appSwitcher, n) {
|
||||
if (!this._mouseActive)
|
||||
return;
|
||||
|
||||
this._select(n, this._currentWindows[n]);
|
||||
},
|
||||
|
||||
_windowActivated : function(thumbnailList, n) {
|
||||
Main.activateWindow(this._appIcons[this._currentApp].windows[n]);
|
||||
this.destroy();
|
||||
},
|
||||
|
||||
_windowHovered : function(thumbnailList, n) {
|
||||
if (!this._mouseActive)
|
||||
return;
|
||||
|
||||
this._select(this._currentApp, n);
|
||||
},
|
||||
|
||||
_mouseMoved : function(actor, event) {
|
||||
if (++this._mouseMovement < POPUP_POINTER_SELECTION_THRESHOLD)
|
||||
return;
|
||||
|
||||
this.actor.disconnect(this._motionEventId);
|
||||
this._mouseActive = true;
|
||||
|
||||
this._appSwitcher.checkHover();
|
||||
if (this._thumbnails)
|
||||
this._thumbnails.checkHover();
|
||||
},
|
||||
|
||||
_finish : function() {
|
||||
let app = this._appIcons[this._currentApp];
|
||||
let window = app.windows[this._currentWindows[this._currentApp]];
|
||||
Main.activateWindow(window);
|
||||
this.destroy();
|
||||
},
|
||||
|
||||
destroy : function() {
|
||||
this.actor.destroy();
|
||||
this._overlay.destroy();
|
||||
|
||||
Main.endModal();
|
||||
},
|
||||
|
||||
select : function(n) {
|
||||
if (this._selected) {
|
||||
// Unselect previous
|
||||
_onDestroy : function() {
|
||||
if (this._haveModal)
|
||||
Main.popModal(this.actor);
|
||||
|
||||
if (this._allocationChangedId) {
|
||||
this._selected.box.disconnect(this._allocationChangedId);
|
||||
delete this._allocationChangedId;
|
||||
}
|
||||
if (this._keyPressEventId)
|
||||
global.stage.disconnect(this._keyPressEventId);
|
||||
if (this._keyReleaseEventId)
|
||||
global.stage.disconnect(this._keyReleaseEventId);
|
||||
|
||||
if (this._selected.above)
|
||||
this._selected.window.raise(this._selected.above);
|
||||
else
|
||||
this._selected.window.lower_bottom();
|
||||
if (this._thumbnailTimeoutId != 0)
|
||||
Mainloop.source_remove(this._thumbnailTimeoutId);
|
||||
},
|
||||
|
||||
_select : function(app, window, noTimeout) {
|
||||
if ((app != this._currentApp || !window) && this._thumbnails) {
|
||||
this._thumbnails.actor.destroy();
|
||||
this._thumbnails = null;
|
||||
this._appSwitcher.showArrow(-1);
|
||||
}
|
||||
|
||||
let item = this._items[n];
|
||||
let changed = this._selected && item != this._selected;
|
||||
this._selected = item;
|
||||
if (this._thumbnailTimeoutId != 0) {
|
||||
Mainloop.source_remove(this._thumbnailTimeoutId);
|
||||
this._thumbnailTimeoutId = 0;
|
||||
}
|
||||
|
||||
if (this._selected) {
|
||||
this._label.set_size(-1, -1);
|
||||
this._label.text = this._selected.metaWindow.title;
|
||||
if (this._label.width > POPUP_LABEL_MAX_WIDTH)
|
||||
this._label.width = POPUP_LABEL_MAX_WIDTH;
|
||||
this._currentApp = app;
|
||||
if (window != null) {
|
||||
this._appSwitcher.highlight(-1);
|
||||
this._appSwitcher.showArrow(app);
|
||||
} else {
|
||||
this._appSwitcher.highlight(app);
|
||||
if (this._appIcons[this._currentApp].windows.length > 1)
|
||||
this._appSwitcher.showArrow(app);
|
||||
}
|
||||
|
||||
// Figure out this._selected.box's coordinates in terms of
|
||||
// this.actor
|
||||
let bx = this._selected.box.x, by = this._selected.box.y;
|
||||
let actor = this._selected.box.get_parent();
|
||||
while (actor != this.actor) {
|
||||
bx += actor.x;
|
||||
by += actor.y;
|
||||
actor = actor.get_parent();
|
||||
if (window != null) {
|
||||
if (!this._thumbnails)
|
||||
this._createThumbnails();
|
||||
this._currentWindows[this._currentApp] = window;
|
||||
this._thumbnails.highlight(window);
|
||||
} else if (this._appIcons[this._currentApp].windows.length > 1 &&
|
||||
!noTimeout) {
|
||||
this._thumbnailTimeoutId = Mainloop.timeout_add (
|
||||
THUMBNAIL_POPUP_TIME,
|
||||
Lang.bind(this, function () {
|
||||
this._select(this._currentApp,
|
||||
this._currentWindows[this._currentApp]);
|
||||
return false;
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
_createThumbnails : function() {
|
||||
this._thumbnails = new ThumbnailList (this._appIcons[this._currentApp].windows);
|
||||
this._thumbnails.connect('item-activated', Lang.bind(this, this._windowActivated));
|
||||
this._thumbnails.connect('item-hovered', Lang.bind(this, this._windowHovered));
|
||||
|
||||
this.actor.add_actor(this._thumbnails.actor);
|
||||
|
||||
let thumbnailCenter;
|
||||
if (this._thumbnails.actor.width < this._appSwitcher.actor.width) {
|
||||
// Center the thumbnails under the corresponding AppIcon.
|
||||
// If this is being called when the switcher is first
|
||||
// being brought up, then nothing will have been assigned
|
||||
// an allocation yet, and the get_transformed_position()
|
||||
// call will return 0,0.
|
||||
// (http://bugzilla.openedhand.com/show_bug.cgi?id=1115).
|
||||
// Calling clutter_actor_get_allocation_box() would force
|
||||
// it to properly allocate itself, but we can't call that
|
||||
// because it has an out-caller-allocates arg. So we use
|
||||
// clutter_stage_get_actor_at_pos(), which will force a
|
||||
// reallocation as a side effect.
|
||||
global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, 0, 0);
|
||||
|
||||
let icon = this._appIcons[this._currentApp].actor;
|
||||
let [stageX, stageY] = icon.get_transformed_position();
|
||||
thumbnailCenter = stageX + icon.width / 2;
|
||||
} else {
|
||||
// Center the thumbnails on the monitor
|
||||
let primary = global.get_primary_monitor();
|
||||
thumbnailCenter = primary.x + primary.width / 2;
|
||||
}
|
||||
|
||||
this._thumbnails.actor.x = Math.floor(thumbnailCenter - this._thumbnails.actor.width / 2);
|
||||
this._thumbnails.actor.y = this._appSwitcher.actor.y + this._appSwitcher.actor.height + POPUP_LIST_SPACING;
|
||||
}
|
||||
};
|
||||
|
||||
function SwitcherList(squareItems) {
|
||||
this._init(squareItems);
|
||||
}
|
||||
|
||||
SwitcherList.prototype = {
|
||||
_init : function(squareItems) {
|
||||
this.actor = new St.Bin({ style_class: 'switcher-list' });
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
|
||||
// Here we use a GenericContainer so that we can force all the
|
||||
// children except the separator to have the same width.
|
||||
this._list = new Shell.GenericContainer();
|
||||
this._list.spacing = POPUP_LIST_SPACING;
|
||||
|
||||
this._list.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
||||
this._list.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||
this._list.connect('allocate', Lang.bind(this, this._allocate));
|
||||
|
||||
this.actor.add_actor(this._list);
|
||||
|
||||
this._items = [];
|
||||
this._highlighted = -1;
|
||||
this._separator = null;
|
||||
this._squareItems = squareItems;
|
||||
|
||||
this._hoverTimeout = 0;
|
||||
},
|
||||
|
||||
_onDestroy: function() {
|
||||
if (this._hoverTimeout != 0) {
|
||||
Mainloop.source_remove(this._hoverTimeout);
|
||||
this._hoverTimeout = 0;
|
||||
}
|
||||
},
|
||||
|
||||
addItem : function(item) {
|
||||
let box = new St.Bin({ style_class: 'item-box' });
|
||||
let bbox;
|
||||
|
||||
if (item instanceof Shell.ButtonBox)
|
||||
bbox = item;
|
||||
else {
|
||||
bbox = new Shell.ButtonBox({ reactive: true });
|
||||
bbox.append(item, Big.BoxPackFlags.NONE);
|
||||
}
|
||||
box.add_actor(bbox);
|
||||
this._list.add_actor(box);
|
||||
|
||||
let n = this._items.length;
|
||||
bbox.connect('activate', Lang.bind(this, function () {
|
||||
this._itemActivated(n);
|
||||
}));
|
||||
bbox.connect('notify::hover', Lang.bind(this, function () {
|
||||
this._hoverChanged(bbox, n);
|
||||
}));
|
||||
|
||||
this._items.push(box);
|
||||
},
|
||||
|
||||
addSeparator: function () {
|
||||
// FIXME: make this work with StWidgets and CSS
|
||||
let box = new Big.Box({ padding_top: 2, padding_bottom: 2 });
|
||||
box.append(new Clutter.Rectangle({ width: 1,
|
||||
color: POPUP_SEPARATOR_COLOR }),
|
||||
Big.BoxPackFlags.EXPAND);
|
||||
this._separator = box;
|
||||
this._list.add_actor(box);
|
||||
},
|
||||
|
||||
highlight: function(index) {
|
||||
if (this._highlighted != -1)
|
||||
this._items[this._highlighted].style_class = 'item-box';
|
||||
|
||||
this._highlighted = index;
|
||||
|
||||
if (this._highlighted != -1)
|
||||
this._items[this._highlighted].style_class = 'selected-item-box';
|
||||
},
|
||||
|
||||
// Used after the mouse movement exceeds the threshold, to check
|
||||
// if it's already hovering over an icon
|
||||
checkHover: function() {
|
||||
for (let i = 0; i < this._items.length; i++) {
|
||||
if (this._items[i].get_child().hover) {
|
||||
this._hoverChanged(this._items[i].get_child(), i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
if (changed) {
|
||||
Tweener.addTween(this._indicator,
|
||||
{ x: bx,
|
||||
y: by,
|
||||
width: this._selected.box.width,
|
||||
height: this._selected.box.height,
|
||||
time: SWITCH_TIME,
|
||||
transition: "easeOutQuad" });
|
||||
_itemActivated: function(n) {
|
||||
this.emit('item-activated', n);
|
||||
},
|
||||
|
||||
_hoverChanged: function(box, n) {
|
||||
if (this._hoverTimeout != 0) {
|
||||
Mainloop.source_remove(this._hoverTimeout);
|
||||
this._hoverTimeout = 0;
|
||||
}
|
||||
|
||||
if (box.hover) {
|
||||
this._hoverTimeout = Mainloop.timeout_add(
|
||||
HOVER_TIME,
|
||||
Lang.bind (this, function () {
|
||||
this._itemHovered(n);
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
_itemHovered: function(n) {
|
||||
this.emit('item-hovered', n);
|
||||
},
|
||||
|
||||
_maxChildWidth: function (forHeight) {
|
||||
let maxChildMin = 0;
|
||||
let maxChildNat = 0;
|
||||
|
||||
for (let i = 0; i < this._items.length; i++) {
|
||||
let [childMin, childNat] = this._items[i].get_preferred_width(forHeight);
|
||||
maxChildMin = Math.max(childMin, maxChildMin);
|
||||
maxChildNat = Math.max(childNat, maxChildNat);
|
||||
|
||||
if (this._squareItems) {
|
||||
let [childMin, childNat] = this._items[i].get_preferred_height(-1);
|
||||
maxChildMin = Math.max(childMin, maxChildMin);
|
||||
maxChildNat = Math.max(childNat, maxChildNat);
|
||||
}
|
||||
}
|
||||
|
||||
return [maxChildMin, maxChildNat];
|
||||
},
|
||||
|
||||
_getPreferredWidth: function (actor, forHeight, alloc) {
|
||||
let [maxChildMin, maxChildNat] = this._maxChildWidth(forHeight);
|
||||
|
||||
let separatorWidth = 0;
|
||||
if (this._separator) {
|
||||
let [sepMin, sepNat] = this._separator.get_preferred_width(forHeight);
|
||||
separatorWidth = sepNat + this._list.spacing;
|
||||
}
|
||||
|
||||
let totalSpacing = this._list.spacing * (this._items.length - 1);
|
||||
alloc.min_size = this._items.length * maxChildMin + separatorWidth + totalSpacing;
|
||||
alloc.nat_size = this._items.length * maxChildNat + separatorWidth + totalSpacing;
|
||||
},
|
||||
|
||||
_getPreferredHeight: function (actor, forWidth, alloc) {
|
||||
let maxChildMin = 0;
|
||||
let maxChildNat = 0;
|
||||
|
||||
for (let i = 0; i < this._items.length; i++) {
|
||||
let [childMin, childNat] = this._items[i].get_preferred_height(-1);
|
||||
maxChildMin = Math.max(childMin, maxChildMin);
|
||||
maxChildNat = Math.max(childNat, maxChildNat);
|
||||
}
|
||||
|
||||
if (this._squareItems) {
|
||||
let [childMin, childNat] = this._maxChildWidth(-1);
|
||||
maxChildMin = Math.max(childMin, maxChildMin);
|
||||
maxChildNat = Math.max(childNat, maxChildNat);
|
||||
}
|
||||
|
||||
alloc.min_size = maxChildMin;
|
||||
alloc.nat_size = maxChildNat;
|
||||
},
|
||||
|
||||
_allocate: function (actor, box, flags) {
|
||||
let childHeight = box.y2 - box.y1;
|
||||
|
||||
let [maxChildMin, maxChildNat] = this._maxChildWidth(childHeight);
|
||||
let totalSpacing = this._list.spacing * (this._items.length - 1);
|
||||
|
||||
let separatorWidth = 0;
|
||||
if (this._separator) {
|
||||
let [sepMin, sepNat] = this._separator.get_preferred_width(childHeight);
|
||||
separatorWidth = sepNat;
|
||||
totalSpacing += this._list.spacing;
|
||||
}
|
||||
|
||||
let childWidth = Math.floor(Math.max(0, box.x2 - box.x1 - totalSpacing - separatorWidth) / this._items.length);
|
||||
|
||||
let x = 0;
|
||||
let children = this._list.get_children();
|
||||
let childBox = new Clutter.ActorBox();
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
if (this._items.indexOf(children[i]) != -1) {
|
||||
let [childMin, childNat] = children[i].get_preferred_height(childWidth);
|
||||
let vSpacing = (childHeight - childNat) / 2;
|
||||
childBox.x1 = x;
|
||||
childBox.y1 = vSpacing;
|
||||
childBox.x2 = x + childWidth;
|
||||
childBox.y2 = childBox.y1 + childNat;
|
||||
children[i].allocate(childBox, flags);
|
||||
|
||||
x += this._list.spacing + childWidth;
|
||||
} else if (children[i] == this._separator) {
|
||||
// We want the separator to be more compact than the rest.
|
||||
childBox.x1 = x;
|
||||
childBox.y1 = 0;
|
||||
childBox.x2 = x + separatorWidth;
|
||||
childBox.y2 = childHeight;
|
||||
children[i].allocate(childBox, flags);
|
||||
x += this._list.spacing + separatorWidth;
|
||||
} else {
|
||||
Tweener.removeTweens(this.indicator);
|
||||
this._indicator.set_position(bx, by);
|
||||
this._indicator.set_size(this._selected.box.width,
|
||||
this._selected.box.height);
|
||||
// Something else, eg, AppSwitcher's arrows;
|
||||
// we don't allocate it.
|
||||
}
|
||||
this._indicator.show();
|
||||
|
||||
if (this._overlay.visible) {
|
||||
if (this._selected.visible)
|
||||
this._selected.window.raise(this._overlay);
|
||||
this._adjust_overlay();
|
||||
}
|
||||
|
||||
this._allocationChangedId =
|
||||
this._selected.box.connect('notify::allocation',
|
||||
Lang.bind(this, this._allocationChanged));
|
||||
} else {
|
||||
this._label.text = "";
|
||||
this._indicator.hide();
|
||||
}
|
||||
},
|
||||
|
||||
_allocationChanged : function() {
|
||||
if (this._selected)
|
||||
this.select(this._selected.n);
|
||||
},
|
||||
|
||||
_adjust_overlay : function() {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
if (this._selected && this._selected.icon_rect) {
|
||||
// We want to highlight a specific rectangle within the
|
||||
// task bar, so rearrange the pieces of the overlay to
|
||||
// cover the whole screen except that rectangle
|
||||
|
||||
let rect = this._selected.icon_rect;
|
||||
|
||||
this._overlay_top.x = 0;
|
||||
this._overlay_top.y = 0;
|
||||
this._overlay_top.width = global.screen_width;
|
||||
this._overlay_top.height = rect.y;
|
||||
|
||||
this._overlay_left.x = 0;
|
||||
this._overlay_left.y = rect.y;
|
||||
this._overlay_left.width = rect.x;
|
||||
this._overlay_left.height = rect.height;
|
||||
this._overlay_left.show();
|
||||
|
||||
this._overlay_right.x = rect.x + rect.width;
|
||||
this._overlay_right.y = rect.y;
|
||||
this._overlay_right.width = global.screen_width - rect.x - rect.width;
|
||||
this._overlay_right.height = rect.height;
|
||||
this._overlay_right.show();
|
||||
|
||||
this._overlay_bottom.x = 0;
|
||||
this._overlay_bottom.y = rect.y + rect.height;
|
||||
this._overlay_bottom.width = global.screen_width;
|
||||
this._overlay_bottom.height = global.screen_height - rect.y - rect.height;
|
||||
this._overlay_bottom.show();
|
||||
} else {
|
||||
// Either there's no current selection, or the selection
|
||||
// is a visible window. Make the overlay cover the whole
|
||||
// screen. select() will raise the selected window over
|
||||
// the overlay.
|
||||
|
||||
this._overlay_top.x = 0;
|
||||
this._overlay_top.y = 0;
|
||||
this._overlay_top.width = global.screen_width;
|
||||
this._overlay_top.height = global.screen_height;
|
||||
this._overlay_top.show();
|
||||
|
||||
this._overlay_left.hide();
|
||||
this._overlay_right.hide();
|
||||
this._overlay_bottom.hide();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Signals.addSignalMethods(SwitcherList.prototype);
|
||||
|
||||
function AppSwitcher(apps) {
|
||||
this._init(apps);
|
||||
}
|
||||
|
||||
AppSwitcher.prototype = {
|
||||
__proto__ : SwitcherList.prototype,
|
||||
|
||||
_init : function(apps) {
|
||||
SwitcherList.prototype._init.call(this, true);
|
||||
|
||||
// Construct the AppIcons, sort by time, add to the popup
|
||||
let activeWorkspace = global.screen.get_active_workspace();
|
||||
let workspaceIcons = [];
|
||||
let otherIcons = [];
|
||||
for (let i = 0; i < apps.length; i++) {
|
||||
let appIcon = new AppIcon.AppIcon({ appInfo: apps[i],
|
||||
size: POPUP_APPICON_SIZE });
|
||||
if (this._hasWindowsOnWorkspace(appIcon, activeWorkspace))
|
||||
workspaceIcons.push(appIcon);
|
||||
else
|
||||
otherIcons.push(appIcon);
|
||||
}
|
||||
|
||||
workspaceIcons.sort(Lang.bind(this, this._sortAppIcon));
|
||||
otherIcons.sort(Lang.bind(this, this._sortAppIcon));
|
||||
|
||||
this.icons = [];
|
||||
this._arrows = [];
|
||||
for (let i = 0; i < workspaceIcons.length; i++)
|
||||
this._addIcon(workspaceIcons[i]);
|
||||
if (workspaceIcons.length > 0 && otherIcons.length > 0)
|
||||
this.addSeparator();
|
||||
for (let i = 0; i < otherIcons.length; i++)
|
||||
this._addIcon(otherIcons[i]);
|
||||
|
||||
this._shownArrow = -1;
|
||||
},
|
||||
|
||||
_allocate: function (actor, box, flags) {
|
||||
// Allocate the main list items
|
||||
SwitcherList.prototype._allocate.call(this, actor, box, flags);
|
||||
|
||||
let arrowHeight = Math.floor(this.actor.get_theme_node().get_padding(St.Side.BOTTOM) / 3);
|
||||
let arrowWidth = arrowHeight * 2;
|
||||
|
||||
// Now allocate each arrow underneath its item
|
||||
let childBox = new Clutter.ActorBox();
|
||||
for (let i = 0; i < this._items.length; i++) {
|
||||
let itemBox = this._items[i].allocation;
|
||||
childBox.x1 = Math.floor(itemBox.x1 + (itemBox.x2 - itemBox.x1 - arrowWidth) / 2);
|
||||
childBox.x2 = childBox.x1 + arrowWidth;
|
||||
childBox.y1 = itemBox.y2 + arrowHeight;
|
||||
childBox.y2 = childBox.y1 + arrowHeight;
|
||||
this._arrows[i].allocate(childBox, flags);
|
||||
}
|
||||
},
|
||||
|
||||
showArrow : function(n) {
|
||||
if (this._shownArrow != -1)
|
||||
this._arrows[this._shownArrow].hide();
|
||||
|
||||
this._shownArrow = n;
|
||||
|
||||
if (this._shownArrow != -1)
|
||||
this._arrows[this._shownArrow].show();
|
||||
},
|
||||
|
||||
_addIcon : function(appIcon) {
|
||||
this.icons.push(appIcon);
|
||||
this.addItem(appIcon.actor);
|
||||
|
||||
let arrow = new Shell.DrawingArea();
|
||||
arrow.connect('redraw', Lang.bind(this,
|
||||
function (area, texture) {
|
||||
Shell.draw_box_pointer(texture, Shell.PointerDirection.DOWN,
|
||||
TRANSPARENT_COLOR,
|
||||
POPUP_ARROW_COLOR);
|
||||
}));
|
||||
this._list.add_actor(arrow);
|
||||
this._arrows.push(arrow);
|
||||
arrow.hide();
|
||||
},
|
||||
|
||||
_hasWindowsOnWorkspace: function(appIcon, workspace) {
|
||||
for (let i = 0; i < appIcon.windows.length; i++) {
|
||||
if (appIcon.windows[i].get_workspace() == workspace)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_hasVisibleWindows : function(appIcon) {
|
||||
for (let i = 0; i < appIcon.windows.length; i++) {
|
||||
if (appIcon.windows[i].showing_on_its_workspace())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_sortAppIcon : function(appIcon1, appIcon2) {
|
||||
let vis1 = this._hasVisibleWindows(appIcon1);
|
||||
let vis2 = this._hasVisibleWindows(appIcon2);
|
||||
|
||||
if (vis1 && !vis2) {
|
||||
return -1;
|
||||
} else if (vis2 && !vis1) {
|
||||
return 1;
|
||||
} else {
|
||||
// The app's most-recently-used window is first
|
||||
// in its list
|
||||
return (appIcon2.windows[0].get_user_time() -
|
||||
appIcon1.windows[0].get_user_time());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function ThumbnailList(windows) {
|
||||
this._init(windows);
|
||||
}
|
||||
|
||||
ThumbnailList.prototype = {
|
||||
__proto__ : SwitcherList.prototype,
|
||||
|
||||
_init : function(windows) {
|
||||
SwitcherList.prototype._init.call(this);
|
||||
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
let mutterWindow = windows[i].get_compositor_private();
|
||||
let windowTexture = mutterWindow.get_texture ();
|
||||
let [width, height] = windowTexture.get_size();
|
||||
let scale = Math.min(1.0, THUMBNAIL_SIZE / width, THUMBNAIL_SIZE / height);
|
||||
|
||||
let clone = new Clutter.Clone ({ source: windowTexture,
|
||||
reactive: true,
|
||||
width: width * scale,
|
||||
height: height * scale });
|
||||
let box = new Big.Box({ padding: AppIcon.APPICON_BORDER_WIDTH + AppIcon.APPICON_PADDING });
|
||||
box.append(clone, Big.BoxPackFlags.NONE);
|
||||
this.addItem(box);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -6,12 +6,14 @@ const Pango = imports.gi.Pango;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Tidy = imports.gi.Tidy;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const AppIcon = imports.ui.appIcon;
|
||||
const DND = imports.ui.dnd;
|
||||
const GenericDisplay = imports.ui.genericDisplay;
|
||||
const Main = imports.ui.main;
|
||||
@ -20,18 +22,12 @@ const Workspaces = imports.ui.workspaces;
|
||||
const ENTERED_MENU_COLOR = new Clutter.Color();
|
||||
ENTERED_MENU_COLOR.from_pixel(0x00ff0022);
|
||||
|
||||
const GLOW_COLOR = new Clutter.Color();
|
||||
GLOW_COLOR.from_pixel(0x4f6ba4ff);
|
||||
const GLOW_PADDING = 5;
|
||||
|
||||
|
||||
const APP_ICON_SIZE = 48;
|
||||
const WELL_DEFAULT_COLUMNS = 4;
|
||||
const WELL_ITEM_HSPACING = 0;
|
||||
const WELL_ITEM_MIN_HSPACING = 4;
|
||||
const WELL_ITEM_VSPACING = 4;
|
||||
|
||||
const MENU_ICON_SIZE = 24;
|
||||
const MENU_SPACING = 15;
|
||||
const MENU_ARROW_SIZE = 12;
|
||||
const MENU_SPACING = 7;
|
||||
|
||||
const MAX_ITEMS = 30;
|
||||
|
||||
@ -61,7 +57,13 @@ AppDisplayItem.prototype = {
|
||||
|
||||
// Opens an application represented by this display item.
|
||||
launch : function() {
|
||||
this._appInfo.launch();
|
||||
let windows = Shell.AppMonitor.get_default().get_windows_for_app(this._appInfo.get_id());
|
||||
if (windows.length > 0) {
|
||||
let mostRecentWindow = windows[0];
|
||||
Main.overview.activateWindow(mostRecentWindow, Main.currentTime());
|
||||
} else {
|
||||
this._appInfo.launch();
|
||||
}
|
||||
},
|
||||
|
||||
//// Protected method overrides ////
|
||||
@ -74,6 +76,10 @@ AppDisplayItem.prototype = {
|
||||
// Returns a preview icon for the item.
|
||||
_createPreviewIcon : function() {
|
||||
return this._appInfo.create_icon_texture(GenericDisplay.PREVIEW_ICON_SIZE);
|
||||
},
|
||||
|
||||
shellWorkspaceLaunch: function() {
|
||||
this.launch();
|
||||
}
|
||||
};
|
||||
|
||||
@ -81,8 +87,8 @@ const MENU_UNSELECTED = 0;
|
||||
const MENU_SELECTED = 1;
|
||||
const MENU_ENTERED = 2;
|
||||
|
||||
function MenuItem(name, id, iconName) {
|
||||
this._init(name, id, iconName);
|
||||
function MenuItem(name, id) {
|
||||
this._init(name, id);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -90,31 +96,19 @@ function MenuItem(name, id, iconName) {
|
||||
* Shows the list of menus in the sidebar.
|
||||
*/
|
||||
MenuItem.prototype = {
|
||||
_init: function(name, id, iconName) {
|
||||
_init: function(name, id) {
|
||||
this.id = id;
|
||||
|
||||
this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
spacing: 4,
|
||||
corner_radius: 4,
|
||||
padding_right: 4,
|
||||
padding_left: 4,
|
||||
reactive: true });
|
||||
this.actor.connect('button-press-event', Lang.bind(this, function (a, e) {
|
||||
this.setState(MENU_SELECTED);
|
||||
}));
|
||||
|
||||
let iconTheme = Gtk.IconTheme.get_default();
|
||||
let pixbuf = null;
|
||||
this._icon = new Clutter.Texture({ width: MENU_ICON_SIZE,
|
||||
height: MENU_ICON_SIZE });
|
||||
// Wine manages not to have an icon
|
||||
try {
|
||||
pixbuf = iconTheme.load_icon(iconName, MENU_ICON_SIZE, 0 /* flags */);
|
||||
} catch (e) {
|
||||
pixbuf = iconTheme.load_icon('gtk-file', MENU_ICON_SIZE, 0);
|
||||
}
|
||||
if (pixbuf != null)
|
||||
Shell.clutter_texture_set_from_pixbuf(this._icon, pixbuf);
|
||||
this.actor.append(this._icon, Big.BoxPackFlags.NONE);
|
||||
this._text = new Clutter.Text({ color: GenericDisplay.ITEM_DISPLAY_NAME_COLOR,
|
||||
font_name: "Sans 14px",
|
||||
text: name });
|
||||
@ -122,7 +116,8 @@ MenuItem.prototype = {
|
||||
// We use individual boxes for the label and the arrow to ensure that they
|
||||
// are aligned vertically. Just setting y_align: Big.BoxAlignment.CENTER
|
||||
// on this.actor does not seem to achieve that.
|
||||
let labelBox = new Big.Box({ y_align: Big.BoxAlignment.CENTER });
|
||||
let labelBox = new Big.Box({ y_align: Big.BoxAlignment.CENTER,
|
||||
padding: 4 });
|
||||
|
||||
labelBox.append(this._text, Big.BoxPackFlags.NONE);
|
||||
|
||||
@ -130,8 +125,8 @@ MenuItem.prototype = {
|
||||
|
||||
let arrowBox = new Big.Box({ y_align: Big.BoxAlignment.CENTER });
|
||||
|
||||
this._arrow = new Shell.Arrow({ surface_width: MENU_ICON_SIZE / 2,
|
||||
surface_height: MENU_ICON_SIZE / 2,
|
||||
this._arrow = new Shell.Arrow({ surface_width: MENU_ARROW_SIZE,
|
||||
surface_height: MENU_ARROW_SIZE,
|
||||
direction: Gtk.ArrowType.RIGHT,
|
||||
opacity: 0 });
|
||||
arrowBox.append(this._arrow, Big.BoxPackFlags.NONE);
|
||||
@ -161,45 +156,42 @@ MenuItem.prototype = {
|
||||
}
|
||||
Signals.addSignalMethods(MenuItem.prototype);
|
||||
|
||||
|
||||
/* This class represents a display containing a collection of application items.
|
||||
* The applications are sorted based on their popularity by default, and based on
|
||||
* their name if some search filter is applied.
|
||||
*
|
||||
* showPrefs - a boolean indicating if this AppDisplay should contain preference
|
||||
* applets, rather than applications
|
||||
*/
|
||||
function AppDisplay() {
|
||||
this._init();
|
||||
function AppDisplay(showPrefs) {
|
||||
this._init(showPrefs);
|
||||
}
|
||||
|
||||
AppDisplay.prototype = {
|
||||
__proto__: GenericDisplay.GenericDisplay.prototype,
|
||||
|
||||
_init : function() {
|
||||
_init : function(showPrefs) {
|
||||
GenericDisplay.GenericDisplay.prototype._init.call(this);
|
||||
|
||||
this._showPrefs = showPrefs;
|
||||
|
||||
this._menus = [];
|
||||
this._menuDisplays = [];
|
||||
|
||||
// map<itemId, array of category names>
|
||||
this._appCategories = {};
|
||||
// map<search term, map<appId, true>>
|
||||
// We use a map of appIds instead of an array to ensure that we don't have duplicates and for easier lookup.
|
||||
this._menuSearchAppMatches = {};
|
||||
|
||||
this._appMonitor = Shell.AppMonitor.get_default();
|
||||
this._appSystem = Shell.AppSystem.get_default();
|
||||
this._appsStale = true;
|
||||
this._appSystem.connect('installed-changed', Lang.bind(this, function(appSys) {
|
||||
this._appsStale = true;
|
||||
this._redisplay(false);
|
||||
this._redisplayMenus();
|
||||
this._redisplay(GenericDisplay.RedisplayFlags.NONE);
|
||||
}));
|
||||
this._appSystem.connect('favorites-changed', Lang.bind(this, function(appSys) {
|
||||
this._redisplay(false);
|
||||
this._appsStale = true;
|
||||
this._redisplay(GenericDisplay.RedisplayFlags.NONE);
|
||||
}));
|
||||
this._appMonitor.connect('changed', Lang.bind(this, function(monitor) {
|
||||
this._redisplay(false);
|
||||
}));
|
||||
|
||||
// Load the apps now so it doesn't slow down the first
|
||||
// transition into the overlay
|
||||
this._refreshCache();
|
||||
|
||||
this._focusInMenus = true;
|
||||
this._activeMenuIndex = -1;
|
||||
@ -208,7 +200,6 @@ AppDisplay.prototype = {
|
||||
this._menuDisplay = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
spacing: MENU_SPACING
|
||||
});
|
||||
this._redisplayMenus();
|
||||
|
||||
this.connect('expanded', Lang.bind(this, function (self) {
|
||||
this._filterReset();
|
||||
@ -251,6 +242,39 @@ AppDisplay.prototype = {
|
||||
return true;
|
||||
},
|
||||
|
||||
setSearch: function(text) {
|
||||
let lowertext = text.toLowerCase();
|
||||
if (lowertext == this._search)
|
||||
return;
|
||||
|
||||
// We prepare menu matches up-front, so that we don't
|
||||
// need to go over all menu items for each application
|
||||
// and then get all applications for a matching menu
|
||||
// to see if a particular application passed to
|
||||
// _isInfoMatching() is a match.
|
||||
let terms = lowertext.split(/\s+/);
|
||||
this._menuSearchAppMatches = {};
|
||||
for (let i = 0; i < terms.length; i++) {
|
||||
let term = terms[i];
|
||||
this._menuSearchAppMatches[term] = {};
|
||||
for (let j = 0; j < this._menus.length; j++) {
|
||||
let menuItem = this._menus[j];
|
||||
// Match only on the beginning of the words in category names,
|
||||
// because otherwise it introduces unnecessary noise in the results.
|
||||
if (menuItem.name.toLowerCase().indexOf(term) == 0 ||
|
||||
menuItem.name.toLowerCase().indexOf(" " + term) > 0) {
|
||||
let menuApps = this._appSystem.get_applications_for_menu(menuItem.id);
|
||||
for (let k = 0; k < menuApps.length; k++) {
|
||||
let menuApp = menuApps[k];
|
||||
this._menuSearchAppMatches[term][menuApp.get_id()] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GenericDisplay.GenericDisplay.prototype.setSearch.call(this, text);
|
||||
},
|
||||
|
||||
// Protected overrides
|
||||
|
||||
_filterActive: function() {
|
||||
@ -282,8 +306,8 @@ AppDisplay.prototype = {
|
||||
})).filter(function (e) { return e != null });
|
||||
},
|
||||
|
||||
_addMenuItem: function(name, id, icon, index) {
|
||||
let display = new MenuItem(name, id, icon);
|
||||
_addMenuItem: function(name, id, index) {
|
||||
let display = new MenuItem(name, id);
|
||||
this._menuDisplays.push(display);
|
||||
display.connect('state-changed', Lang.bind(this, function (display) {
|
||||
let activated = display.getState() != MENU_UNSELECTED;
|
||||
@ -301,17 +325,21 @@ AppDisplay.prototype = {
|
||||
this._activeMenuApps = this._appSystem.get_applications_for_menu(id);
|
||||
}
|
||||
}
|
||||
this._redisplay(true);
|
||||
this._redisplay(GenericDisplay.RedisplayFlags.FULL);
|
||||
}));
|
||||
this._menuDisplay.append(display.actor, 0);
|
||||
},
|
||||
|
||||
_redisplayMenus: function() {
|
||||
this._menuDisplay.remove_all();
|
||||
this._addMenuItem('Frequent', null, 'gtk-select-all');
|
||||
this._addMenuItem(_("Frequent"), null, 'gtk-select-all');
|
||||
// Adding an empty box here results in double spacing between
|
||||
// "Frequent" and the other items.
|
||||
let separator_actor = new Big.Box();
|
||||
this._menuDisplay.append(separator_actor, 0);
|
||||
for (let i = 0; i < this._menus.length; i++) {
|
||||
let menu = this._menus[i];
|
||||
this._addMenuItem(menu.name, menu.id, menu.icon, i+1);
|
||||
this._addMenuItem(menu.name, menu.id, i+1);
|
||||
}
|
||||
},
|
||||
|
||||
@ -324,38 +352,47 @@ AppDisplay.prototype = {
|
||||
|
||||
// Gets information about all applications by calling Gio.app_info_get_all().
|
||||
_refreshCache : function() {
|
||||
let me = this;
|
||||
if (!this._appsStale)
|
||||
return;
|
||||
return true;
|
||||
this._allItems = {};
|
||||
this._appCategories = {};
|
||||
|
||||
this._menus = this._appSystem.get_menus();
|
||||
// Loop over the toplevel menu items, load the set of desktop file ids
|
||||
// associated with each one
|
||||
for (let i = 0; i < this._menus.length; i++) {
|
||||
let menu = this._menus[i];
|
||||
let menuApps = this._appSystem.get_applications_for_menu(menu.id);
|
||||
for (let j = 0; j < menuApps.length; j++) {
|
||||
let app = menuApps[j];
|
||||
if (this._showPrefs) {
|
||||
// Get the desktop file ids for settings/preferences.
|
||||
// These are used for search results, but not in the app menus.
|
||||
let settings = this._appSystem.get_all_settings();
|
||||
for (let i = 0; i < settings.length; i++) {
|
||||
let app = settings[i];
|
||||
this._addApp(app);
|
||||
}
|
||||
}
|
||||
|
||||
// Now grab the desktop file ids for settings/preferences.
|
||||
// These show up in search, but not with the rest of apps.
|
||||
let settings = this._appSystem.get_all_settings();
|
||||
for (let i = 0; i < settings.length; i++) {
|
||||
let app = settings[i];
|
||||
this._addApp(app);
|
||||
} else {
|
||||
// Loop over the toplevel menu items, load the set of desktop file ids
|
||||
// associated with each one, skipping empty menus
|
||||
let allMenus = this._appSystem.get_menus();
|
||||
this._menus = [];
|
||||
for (let i = 0; i < allMenus.length; i++) {
|
||||
let menu = allMenus[i];
|
||||
let menuApps = this._appSystem.get_applications_for_menu(menu.id);
|
||||
let hasVisibleApps = menuApps.some(function (app) { return !app.get_is_nodisplay(); });
|
||||
if (!hasVisibleApps) {
|
||||
continue;
|
||||
}
|
||||
this._menus.push(menu);
|
||||
for (let j = 0; j < menuApps.length; j++) {
|
||||
let app = menuApps[j];
|
||||
this._addApp(app);
|
||||
}
|
||||
}
|
||||
this._redisplayMenus();
|
||||
}
|
||||
|
||||
this._appsStale = false;
|
||||
return false;
|
||||
},
|
||||
|
||||
// Stub this out; the app display always has a category selected
|
||||
_setDefaultList : function() {
|
||||
this._matchedItems = [];
|
||||
this._matchedItems = {};
|
||||
this._matchedItemKeys = [];
|
||||
},
|
||||
|
||||
// Compares items associated with the item ids based on the alphabetical order
|
||||
@ -368,7 +405,7 @@ AppDisplay.prototype = {
|
||||
},
|
||||
|
||||
// Checks if the item info can be a match for the search string by checking
|
||||
// the name, description, execution command, and categories for the application.
|
||||
// the name, description, execution command, and category for the application.
|
||||
// Item info is expected to be Shell.AppInfo.
|
||||
// Returns a boolean flag indicating if itemInfo is a match.
|
||||
_isInfoMatching : function(itemInfo, search) {
|
||||
@ -380,10 +417,10 @@ AppDisplay.prototype = {
|
||||
if (this._activeMenu == null || search != "")
|
||||
return this._isInfoMatchingSearch(itemInfo, search);
|
||||
else
|
||||
return this._isInfoMatchingMenu(itemInfo, search);
|
||||
return this._isInfoMatchingMenu(itemInfo);
|
||||
},
|
||||
|
||||
_isInfoMatchingMenu : function(itemInfo, search) {
|
||||
_isInfoMatchingMenu: function(itemInfo) {
|
||||
let id = itemInfo.get_id();
|
||||
for (let i = 0; i < this._activeMenuApps.length; i++) {
|
||||
let activeApp = this._activeMenuApps[i];
|
||||
@ -421,11 +458,11 @@ AppDisplay.prototype = {
|
||||
return true;
|
||||
}
|
||||
|
||||
let categories = itemInfo.get_categories();
|
||||
for (let i = 0; i < categories.length; i++) {
|
||||
let category = fold(categories[i]);
|
||||
if (category.indexOf(search) >= 0)
|
||||
if (this._menuSearchAppMatches[search]) {
|
||||
if (this._menuSearchAppMatches[search].hasOwnProperty(itemInfo.get_id()))
|
||||
return true;
|
||||
} else {
|
||||
log("Missing an entry for search term " + search + " in this._menuSearchAppMatches");
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -439,123 +476,156 @@ AppDisplay.prototype = {
|
||||
|
||||
Signals.addSignalMethods(AppDisplay.prototype);
|
||||
|
||||
function WellDisplayItem(appInfo, isFavorite) {
|
||||
this._init(appInfo, isFavorite);
|
||||
function BaseWellItem(appInfo, isFavorite, hasMenu) {
|
||||
this._init(appInfo, isFavorite, hasMenu);
|
||||
}
|
||||
|
||||
WellDisplayItem.prototype = {
|
||||
_init : function(appInfo, isFavorite) {
|
||||
this.appInfo = appInfo;
|
||||
BaseWellItem.prototype = {
|
||||
__proto__: AppIcon.AppIcon.prototype,
|
||||
|
||||
_init: function(appInfo, isFavorite) {
|
||||
AppIcon.AppIcon.prototype._init.call(this, { appInfo: appInfo,
|
||||
menuType: AppIcon.MenuType.ON_RIGHT,
|
||||
glow: true });
|
||||
|
||||
this.isFavorite = isFavorite;
|
||||
|
||||
this.actor = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
corner_radius: 2,
|
||||
border: 0,
|
||||
padding: 1,
|
||||
border_color: GenericDisplay.ITEM_DISPLAY_SELECTED_BACKGROUND_COLOR,
|
||||
reactive: true });
|
||||
this.actor._delegate = this;
|
||||
this.actor.connect('button-release-event', Lang.bind(this, function (b, e) {
|
||||
this._handleActivate();
|
||||
this._draggable = DND.makeDraggable(this.actor, true);
|
||||
|
||||
// Do these as anonymous functions to avoid conflict with handlers in subclasses
|
||||
this.actor.connect('button-press-event', Lang.bind(this, function(actor, event) {
|
||||
let [stageX, stageY] = event.get_coords();
|
||||
this._dragStartX = stageX;
|
||||
this._dragStartY = stageY;
|
||||
return false;
|
||||
}));
|
||||
|
||||
let draggable = DND.makeDraggable(this.actor);
|
||||
|
||||
let iconBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
x_align: Big.BoxAlignment.CENTER });
|
||||
this._icon = appInfo.create_icon_texture(APP_ICON_SIZE);
|
||||
iconBox.append(this._icon, Big.BoxPackFlags.NONE);
|
||||
|
||||
this.actor.append(iconBox, Big.BoxPackFlags.NONE);
|
||||
|
||||
this._windows = Shell.AppMonitor.get_default().get_windows_for_app(appInfo.get_id());
|
||||
|
||||
let nameBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
x_align: Big.BoxAlignment.CENTER });
|
||||
this._nameBox = nameBox;
|
||||
|
||||
this._name = new Clutter.Text({ color: GenericDisplay.ITEM_DISPLAY_NAME_COLOR,
|
||||
font_name: "Sans 12px",
|
||||
line_alignment: Pango.Alignment.CENTER,
|
||||
ellipsize: Pango.EllipsizeMode.END,
|
||||
text: appInfo.get_name() });
|
||||
nameBox.append(this._name, Big.BoxPackFlags.NONE);
|
||||
if (this._windows.length > 0) {
|
||||
let glow = new Shell.DrawingArea({});
|
||||
glow.connect('redraw', Lang.bind(this, function (e, tex) {
|
||||
Shell.draw_glow(tex,
|
||||
GLOW_COLOR.red / 255,
|
||||
GLOW_COLOR.green / 255,
|
||||
GLOW_COLOR.blue / 255,
|
||||
GLOW_COLOR.alpha / 255);
|
||||
}));
|
||||
this._name.connect('notify::allocation', Lang.bind(this, function () {
|
||||
let x = this._name.x;
|
||||
let y = this._name.y;
|
||||
let width = this._name.width;
|
||||
let height = this._name.height;
|
||||
// If we're smaller than the allocated box width, pad out the glow a bit
|
||||
// to make it more visible
|
||||
if ((width + GLOW_PADDING * 2) < this._nameBox.width) {
|
||||
width += GLOW_PADDING * 2;
|
||||
x -= GLOW_PADDING;
|
||||
this.actor.connect('notify::hover', Lang.bind(this, function () {
|
||||
let hover = this.actor.hover;
|
||||
if (!hover) {
|
||||
if (this.actor.pressed && this._dragStartX != null) {
|
||||
this.actor.fake_release();
|
||||
this._draggable.startDrag(this._dragStartX, this._dragStartY,
|
||||
Main.currentTime());
|
||||
} else {
|
||||
this._dragStartX = null;
|
||||
this._dragStartY = null;
|
||||
}
|
||||
glow.set_size(width, height);
|
||||
glow.set_position(x, y);
|
||||
}));
|
||||
nameBox.add_actor(glow);
|
||||
glow.lower(this._name);
|
||||
}
|
||||
this.actor.append(nameBox, Big.BoxPackFlags.NONE);
|
||||
}
|
||||
}));
|
||||
},
|
||||
|
||||
_handleActivate: function () {
|
||||
if (this._windows.length == 0)
|
||||
this.launch();
|
||||
else {
|
||||
/* Pick the first window and activate it;
|
||||
* In the future, we want to have a menu dropdown here. */
|
||||
let first = this._windows[0];
|
||||
Main.overlay.activateWindow (first, Clutter.get_current_event_time());
|
||||
}
|
||||
this.emit('activated');
|
||||
},
|
||||
|
||||
// Opens an application represented by this display item.
|
||||
launch : function() {
|
||||
shellWorkspaceLaunch : function() {
|
||||
// Here we just always launch the application again, even if we know
|
||||
// it was already running. For most applications this
|
||||
// should have the effect of creating a new window, whether that's
|
||||
// a second process (in the case of Calculator) or IPC to existing
|
||||
// instance (Firefox). There are a few less-sensical cases such
|
||||
// as say Pidgin, but ideally what we do there is have the app
|
||||
// express to us that it doesn't do relaunch=new-window in the
|
||||
// .desktop file.
|
||||
this.appInfo.launch();
|
||||
},
|
||||
|
||||
// Draggable interface - FIXME deduplicate with GenericDisplay
|
||||
getDragActor: function(stageX, stageY) {
|
||||
this.dragActor = this.appInfo.create_icon_texture(APP_ICON_SIZE);
|
||||
|
||||
// If the user dragged from the icon itself, then position
|
||||
// the dragActor over the original icon. Otherwise center it
|
||||
// around the pointer
|
||||
let [iconX, iconY] = this._icon.get_transformed_position();
|
||||
let [iconWidth, iconHeight] = this._icon.get_transformed_size();
|
||||
if (stageX > iconX && stageX <= iconX + iconWidth &&
|
||||
stageY > iconY && stageY <= iconY + iconHeight)
|
||||
this.dragActor.set_position(iconX, iconY);
|
||||
else
|
||||
this.dragActor.set_position(stageX - this.dragActor.width / 2, stageY - this.dragActor.height / 2);
|
||||
return this.dragActor;
|
||||
getDragActor: function() {
|
||||
return this.createDragActor();
|
||||
},
|
||||
|
||||
// Returns the original icon that is being used as a source for the cloned texture
|
||||
// that represents the item as it is being dragged.
|
||||
getDragActorSource: function() {
|
||||
return this._icon;
|
||||
return this.actor;
|
||||
}
|
||||
}
|
||||
|
||||
function RunningWellItem(appInfo, isFavorite) {
|
||||
this._init(appInfo, isFavorite);
|
||||
}
|
||||
|
||||
RunningWellItem.prototype = {
|
||||
__proto__: BaseWellItem.prototype,
|
||||
|
||||
_init: function(appInfo, isFavorite) {
|
||||
BaseWellItem.prototype._init.call(this, appInfo, isFavorite);
|
||||
|
||||
this._dragStartX = 0;
|
||||
this._dragStartY = 0;
|
||||
|
||||
this.actor.connect('activate', Lang.bind(this, this._onActivate));
|
||||
},
|
||||
|
||||
setWidth: function(width) {
|
||||
this._nameBox.width = width + GLOW_PADDING * 2;
|
||||
_onActivate: function (actor, event) {
|
||||
let modifiers = Shell.get_event_state(event);
|
||||
|
||||
if (modifiers & Clutter.ModifierType.CONTROL_MASK) {
|
||||
this.appInfo.launch();
|
||||
} else {
|
||||
this.activateMostRecentWindow();
|
||||
}
|
||||
},
|
||||
|
||||
activateMostRecentWindow: function () {
|
||||
// The _get_windows_for_app sorts them for us
|
||||
let mostRecentWindow = this.windows[0];
|
||||
Main.overview.activateWindow(mostRecentWindow, Main.currentTime());
|
||||
},
|
||||
|
||||
highlightWindow: function(metaWindow) {
|
||||
Main.overview.getWorkspacesForWindow(metaWindow).setHighlightWindow(metaWindow);
|
||||
},
|
||||
|
||||
activateWindow: function(metaWindow) {
|
||||
if (metaWindow) {
|
||||
this._didActivateWindow = true;
|
||||
Main.overview.activateWindow(metaWindow, Main.currentTime());
|
||||
} else
|
||||
Main.overview.hide();
|
||||
},
|
||||
|
||||
menuPoppedUp: function() {
|
||||
Main.overview.getWorkspacesForWindow(null).setApplicationWindowSelection(this.appInfo.get_id());
|
||||
},
|
||||
|
||||
menuPoppedDown: function() {
|
||||
if (this._didActivateWindow)
|
||||
return;
|
||||
|
||||
Main.overview.getWorkspacesForWindow(null).setApplicationWindowSelection(null);
|
||||
}
|
||||
};
|
||||
|
||||
Signals.addSignalMethods(WellDisplayItem.prototype);
|
||||
function InactiveWellItem(appInfo, isFavorite) {
|
||||
this._init(appInfo, isFavorite);
|
||||
}
|
||||
|
||||
InactiveWellItem.prototype = {
|
||||
__proto__: BaseWellItem.prototype,
|
||||
|
||||
_init : function(appInfo, isFavorite) {
|
||||
BaseWellItem.prototype._init.call(this, appInfo, isFavorite);
|
||||
|
||||
this.actor.connect('notify::pressed', Lang.bind(this, this._onPressedChanged));
|
||||
this.actor.connect('activate', Lang.bind(this, this._onActivate));
|
||||
},
|
||||
|
||||
_onPressedChanged: function() {
|
||||
this.setHighlight(this.actor.pressed);
|
||||
},
|
||||
|
||||
_onActivate: function() {
|
||||
if (this.windows.length == 0) {
|
||||
this.appInfo.launch();
|
||||
Main.overview.hide();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
menuPoppedUp: function() {
|
||||
},
|
||||
|
||||
menuPoppedDown: function() {
|
||||
}
|
||||
};
|
||||
|
||||
function WellGrid() {
|
||||
this._init();
|
||||
@ -565,9 +635,7 @@ WellGrid.prototype = {
|
||||
_init: function() {
|
||||
this.actor = new Shell.GenericContainer();
|
||||
|
||||
this._separator = new Big.Box({ border_color: GenericDisplay.ITEM_DISPLAY_NAME_COLOR,
|
||||
border_top: 1,
|
||||
height: 1 });
|
||||
this._separator = new Big.Box({ height: 1 });
|
||||
this.actor.add_actor(this._separator);
|
||||
this._separatorIndex = 0;
|
||||
this._cachedSeparatorY = 0;
|
||||
@ -585,9 +653,8 @@ WellGrid.prototype = {
|
||||
nColumns = children.length;
|
||||
else
|
||||
nColumns = WELL_DEFAULT_COLUMNS;
|
||||
let spacing = Math.max(nColumns - 1, 0) * WELL_ITEM_HSPACING;
|
||||
alloc.min_size = itemMin * nColumns + spacing;
|
||||
alloc.natural_size = itemNatural * nColumns + spacing;
|
||||
alloc.min_size = itemMin;
|
||||
alloc.natural_size = itemNatural * nColumns;
|
||||
},
|
||||
|
||||
_getPreferredHeight: function (grid, forWidth, alloc) {
|
||||
@ -611,26 +678,21 @@ WellGrid.prototype = {
|
||||
let y = box.y1;
|
||||
let columnIndex = 0;
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
let [childMinWidth, childMinHeight,
|
||||
childNaturalWidth, childNaturalHeight] = children[i].get_preferred_size();
|
||||
let [childMinWidth, childNaturalWidth] = children[i].get_preferred_width(-1);
|
||||
|
||||
/* Center the item in its allocation */
|
||||
/* Center the item in its allocation horizontally */
|
||||
let width = Math.min(itemWidth, childNaturalWidth);
|
||||
let height = Math.min(itemHeight, childNaturalHeight);
|
||||
let horizSpacing = (itemWidth - width) / 2;
|
||||
let vertSpacing = (itemHeight - height) / 2;
|
||||
|
||||
let childBox = new Clutter.ActorBox();
|
||||
childBox.x1 = Math.floor(x + horizSpacing);
|
||||
childBox.y1 = Math.floor(y + vertSpacing);
|
||||
childBox.y1 = y;
|
||||
childBox.x2 = childBox.x1 + width;
|
||||
childBox.y2 = childBox.y1 + height;
|
||||
childBox.y2 = childBox.y1 + itemHeight;
|
||||
children[i].allocate(childBox, flags);
|
||||
|
||||
let atSeparator = (i == this._separatorIndex - 1);
|
||||
|
||||
columnIndex++;
|
||||
if (columnIndex == columns || atSeparator) {
|
||||
if (columnIndex == columns) {
|
||||
columnIndex = 0;
|
||||
}
|
||||
|
||||
@ -638,29 +700,9 @@ WellGrid.prototype = {
|
||||
y += itemHeight + WELL_ITEM_VSPACING;
|
||||
x = box.x1;
|
||||
} else {
|
||||
x += itemWidth + WELL_ITEM_HSPACING;
|
||||
}
|
||||
|
||||
if (atSeparator) {
|
||||
y += separatorNatural + WELL_ITEM_VSPACING;
|
||||
x += itemWidth;
|
||||
}
|
||||
}
|
||||
|
||||
let separatorRowIndex = Math.ceil(this._separatorIndex / columns);
|
||||
|
||||
/* Allocate the separator */
|
||||
let childBox = new Clutter.ActorBox();
|
||||
childBox.x1 = box.x1;
|
||||
childBox.y1 = (itemHeight + WELL_ITEM_VSPACING) * separatorRowIndex;
|
||||
this._cachedSeparatorY = childBox.y1;
|
||||
childBox.x2 = box.x2;
|
||||
childBox.y2 = childBox.y1+separatorNatural;
|
||||
this._separator.allocate(childBox, flags);
|
||||
},
|
||||
|
||||
setSeparatorIndex: function (index) {
|
||||
this._separatorIndex = index;
|
||||
this.actor.queue_relayout();
|
||||
},
|
||||
|
||||
removeAll: function () {
|
||||
@ -668,11 +710,6 @@ WellGrid.prototype = {
|
||||
for (let i = 0; i < itemChildren.length; i++) {
|
||||
itemChildren[i].destroy();
|
||||
}
|
||||
this._separatorIndex = 0;
|
||||
},
|
||||
|
||||
isBeforeSeparator: function(x, y) {
|
||||
return y < this._cachedSeparatorY;
|
||||
},
|
||||
|
||||
_getItemChildren: function () {
|
||||
@ -688,29 +725,40 @@ WellGrid.prototype = {
|
||||
let children = this._getItemChildren();
|
||||
if (children.length == 0)
|
||||
return [0, WELL_DEFAULT_COLUMNS, 0, 0];
|
||||
let nColumns;
|
||||
if (children.length < WELL_DEFAULT_COLUMNS)
|
||||
nColumns = children.length;
|
||||
else
|
||||
let nColumns = 0;
|
||||
let usedWidth = 0;
|
||||
// Big.Box will allocate us at 0x0 if we are not visible; this is probably a
|
||||
// Big.Box bug but it can't be fixed because if children are skipped in allocate()
|
||||
// Clutter gets confused (see http://bugzilla.openedhand.com/show_bug.cgi?id=1831)
|
||||
if (forWidth <= 0) {
|
||||
nColumns = WELL_DEFAULT_COLUMNS;
|
||||
|
||||
if (forWidth >= 0 && forWidth < minWidth) {
|
||||
log("WellGrid: trying to allocate for width " + forWidth + " but min is " + minWidth);
|
||||
/* FIXME - we should fall back to fewer than WELL_DEFAULT_COLUMNS here */
|
||||
} else {
|
||||
while (nColumns < WELL_DEFAULT_COLUMNS &&
|
||||
nColumns < children.length &&
|
||||
usedWidth + itemMinWidth <= forWidth) {
|
||||
// By including WELL_ITEM_MIN_HSPACING in usedWidth, we are ensuring
|
||||
// that the number of columns we end up with will allow the spacing
|
||||
// between the columns to be at least that value.
|
||||
usedWidth += itemMinWidth + WELL_ITEM_MIN_HSPACING;
|
||||
nColumns++;
|
||||
}
|
||||
}
|
||||
|
||||
let horizSpacingTotal = Math.max(nColumns - 1, 0) * WELL_ITEM_HSPACING;
|
||||
let minWidth = itemMinWidth * nColumns + horizSpacingTotal;
|
||||
if (nColumns == 0) {
|
||||
log("WellGrid: couldn't fit a column in width " + forWidth);
|
||||
/* FIXME - fall back to smaller icon size */
|
||||
}
|
||||
|
||||
let minWidth = itemMinWidth * nColumns;
|
||||
|
||||
let lastColumnIndex = nColumns - 1;
|
||||
let separatorColumns = lastColumnIndex - ((lastColumnIndex + this._separatorIndex) % nColumns);
|
||||
let rows = Math.ceil((children.length + separatorColumns) / nColumns);
|
||||
let rows = Math.ceil(children.length / nColumns);
|
||||
|
||||
let itemWidth;
|
||||
if (forWidth < 0) {
|
||||
if (forWidth <= 0) {
|
||||
itemWidth = itemNaturalWidth;
|
||||
} else {
|
||||
itemWidth = Math.max(forWidth - horizSpacingTotal, 0) / nColumns;
|
||||
itemWidth = Math.floor(forWidth / nColumns);
|
||||
}
|
||||
|
||||
let itemNaturalHeight = 0;
|
||||
@ -720,7 +768,7 @@ WellGrid.prototype = {
|
||||
itemNaturalHeight = childNatural;
|
||||
}
|
||||
|
||||
return [rows, WELL_DEFAULT_COLUMNS, itemWidth, itemNaturalHeight];
|
||||
return [rows, nColumns, itemWidth, itemNaturalHeight];
|
||||
},
|
||||
|
||||
_getItemPreferredWidth: function () {
|
||||
@ -751,6 +799,9 @@ AppWell.prototype = {
|
||||
x_align: Big.BoxAlignment.CENTER });
|
||||
this.actor._delegate = this;
|
||||
|
||||
this._pendingRedisplay = false;
|
||||
this.actor.connect('notify::mapped', Lang.bind(this, this._onMappedNotify));
|
||||
|
||||
this._grid = new WellGrid();
|
||||
this.actor.append(this._grid.actor, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
@ -763,7 +814,10 @@ AppWell.prototype = {
|
||||
this._appSystem.connect('favorites-changed', Lang.bind(this, function(appSys) {
|
||||
this._redisplay();
|
||||
}));
|
||||
this._appMonitor.connect('changed', Lang.bind(this, function(monitor) {
|
||||
this._appMonitor.connect('window-added', Lang.bind(this, function(monitor) {
|
||||
this._redisplay();
|
||||
}));
|
||||
this._appMonitor.connect('window-removed', Lang.bind(this, function(monitor) {
|
||||
this._redisplay();
|
||||
}));
|
||||
|
||||
@ -787,7 +841,20 @@ AppWell.prototype = {
|
||||
values[id] = index; return values; }, {});
|
||||
},
|
||||
|
||||
_onMappedNotify: function() {
|
||||
let mapped = this.actor.mapped;
|
||||
if (mapped && this._pendingRedisplay)
|
||||
this._redisplay();
|
||||
},
|
||||
|
||||
_redisplay: function () {
|
||||
let mapped = this.actor.mapped;
|
||||
if (!mapped) {
|
||||
this._pendingRedisplay = true;
|
||||
return;
|
||||
}
|
||||
this._pendingRedisplay = false;
|
||||
|
||||
this._grid.removeAll();
|
||||
|
||||
let favoriteIds = this._appSystem.get_favorites();
|
||||
@ -796,69 +863,61 @@ AppWell.prototype = {
|
||||
/* hardcode here pending some design about how exactly desktop contexts behave */
|
||||
let contextId = "";
|
||||
|
||||
let runningIds = this._appMonitor.get_running_app_ids(contextId).filter(function (e) {
|
||||
return !(e in favoriteIdsHash);
|
||||
let running = this._appMonitor.get_running_apps(contextId).filter(function (e) {
|
||||
return !(e.get_id() in favoriteIdsHash);
|
||||
});
|
||||
let favorites = this._lookupApps(favoriteIds);
|
||||
let running = this._lookupApps(runningIds);
|
||||
|
||||
let displays = []
|
||||
this._addApps(favorites, true);
|
||||
this._grid.setSeparatorIndex(favorites.length);
|
||||
this._addApps(running, false);
|
||||
this._displays = displays;
|
||||
},
|
||||
|
||||
_addApps: function(apps) {
|
||||
_addApps: function(apps, isFavorite) {
|
||||
for (let i = 0; i < apps.length; i++) {
|
||||
let app = apps[i];
|
||||
let display = new WellDisplayItem(app, this.isFavorite);
|
||||
display.connect('activated', Lang.bind(this, function (display) {
|
||||
Main.overlay.hide();
|
||||
}));
|
||||
let windows = this._appMonitor.get_windows_for_app(app.get_id());
|
||||
let display;
|
||||
if (windows.length > 0)
|
||||
display = new RunningWellItem(app, isFavorite);
|
||||
else
|
||||
display = new InactiveWellItem(app, isFavorite);
|
||||
this._grid.actor.add_actor(display.actor);
|
||||
}
|
||||
},
|
||||
|
||||
// Draggable target interface
|
||||
acceptDrop : function(source, actor, x, y, time) {
|
||||
let global = Shell.Global.get();
|
||||
let appSystem = Shell.AppSystem.get_default();
|
||||
|
||||
let id = null;
|
||||
if (source instanceof WellDisplayItem) {
|
||||
id = source.appInfo.get_id();
|
||||
} else if (source instanceof AppDisplayItem) {
|
||||
id = source.getId();
|
||||
let app = null;
|
||||
if (source instanceof AppDisplayItem) {
|
||||
app = appSystem.lookup_cached_app(source.getId());
|
||||
} else if (source instanceof Workspaces.WindowClone) {
|
||||
let appMonitor = Shell.AppMonitor.get_default();
|
||||
let app = appMonitor.get_window_app(source.metaWindow);
|
||||
id = app.get_id();
|
||||
app = appMonitor.get_window_app(source.metaWindow);
|
||||
}
|
||||
|
||||
if (id == null) {
|
||||
// Don't allow favoriting of transient apps
|
||||
if (app == null || app.is_transient()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let appSystem = Shell.AppSystem.get_default();
|
||||
let id = app.get_id();
|
||||
|
||||
let favoriteIds = this._appSystem.get_favorites();
|
||||
let favoriteIdsObject = this._arrayValues(favoriteIds);
|
||||
|
||||
let dropIsFavorite = this._grid.isBeforeSeparator(x - this._grid.actor.x,
|
||||
y - this._grid.actor.y);
|
||||
let srcIsFavorite = (id in favoriteIdsObject);
|
||||
|
||||
if (srcIsFavorite && (!dropIsFavorite)) {
|
||||
Mainloop.idle_add(function () {
|
||||
appSystem.remove_favorite(id);
|
||||
return false;
|
||||
});
|
||||
} else if ((!srcIsFavorite) && dropIsFavorite) {
|
||||
if (srcIsFavorite) {
|
||||
return false;
|
||||
} else {
|
||||
Mainloop.idle_add(function () {
|
||||
appSystem.add_favorite(id);
|
||||
return false;
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
636
js/ui/appIcon.js
Normal file
@ -0,0 +1,636 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Big = imports.gi.Big;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Pango = imports.gi.Pango;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const GenericDisplay = imports.ui.genericDisplay;
|
||||
const Main = imports.ui.main;
|
||||
const Workspaces = imports.ui.workspaces;
|
||||
|
||||
const GLOW_COLOR = new Clutter.Color();
|
||||
GLOW_COLOR.from_pixel(0x4f6ba4ff);
|
||||
const GLOW_PADDING_HORIZONTAL = 3;
|
||||
const GLOW_PADDING_VERTICAL = 3;
|
||||
|
||||
const APPICON_DEFAULT_ICON_SIZE = 48;
|
||||
|
||||
const APPICON_PADDING = 1;
|
||||
const APPICON_BORDER_WIDTH = 1;
|
||||
const APPICON_CORNER_RADIUS = 4;
|
||||
|
||||
const APPICON_MENU_POPUP_TIMEOUT_MS = 600;
|
||||
|
||||
const APPICON_DEFAULT_BORDER_COLOR = new Clutter.Color();
|
||||
APPICON_DEFAULT_BORDER_COLOR.from_pixel(0x787878ff);
|
||||
const APPICON_MENU_BACKGROUND_COLOR = new Clutter.Color();
|
||||
APPICON_MENU_BACKGROUND_COLOR.from_pixel(0x292929ff);
|
||||
const APPICON_MENU_FONT = 'Sans 14px';
|
||||
const APPICON_MENU_COLOR = new Clutter.Color();
|
||||
APPICON_MENU_COLOR.from_pixel(0xffffffff);
|
||||
const APPICON_MENU_SELECTED_COLOR = new Clutter.Color();
|
||||
APPICON_MENU_SELECTED_COLOR.from_pixel(0x005b97ff);
|
||||
const APPICON_MENU_SEPARATOR_COLOR = new Clutter.Color();
|
||||
APPICON_MENU_SEPARATOR_COLOR.from_pixel(0x787878ff);
|
||||
const APPICON_MENU_BORDER_WIDTH = 1;
|
||||
const APPICON_MENU_ARROW_SIZE = 12;
|
||||
const APPICON_MENU_CORNER_RADIUS = 4;
|
||||
const APPICON_MENU_PADDING = 4;
|
||||
|
||||
const TRANSPARENT_COLOR = new Clutter.Color();
|
||||
TRANSPARENT_COLOR.from_pixel(0x00000000);
|
||||
|
||||
const MenuType = { NONE: 0, ON_RIGHT: 1, BELOW: 2 };
|
||||
|
||||
function AppIcon(params) {
|
||||
this._init(params);
|
||||
}
|
||||
|
||||
AppIcon.prototype = {
|
||||
_init : function(params) {
|
||||
this.appInfo = params.appInfo;
|
||||
if (!this.appInfo)
|
||||
throw new Error('AppIcon constructor requires "appInfo" param');
|
||||
|
||||
this._menuType = ('menuType' in params) ? params.menuType : MenuType.NONE;
|
||||
this._iconSize = ('size' in params) ? params.size : APPICON_DEFAULT_ICON_SIZE;
|
||||
let showGlow = ('glow' in params) ? params.glow : false;
|
||||
|
||||
this.actor = new Shell.ButtonBox({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
border: APPICON_BORDER_WIDTH,
|
||||
corner_radius: APPICON_CORNER_RADIUS,
|
||||
padding: APPICON_PADDING,
|
||||
reactive: true });
|
||||
this.actor._delegate = this;
|
||||
this.highlight_border_color = APPICON_DEFAULT_BORDER_COLOR;
|
||||
this._signalIds = [];
|
||||
|
||||
// Note, we don't presently update the window list dynamically here; this actor
|
||||
// gets destroyed and recreated by AppWell, and in alt-tab the whole thing is
|
||||
// created each time
|
||||
this.windows = Shell.AppMonitor.get_default().get_windows_for_app(this.appInfo.get_id());
|
||||
for (let i = 0; i < this.windows.length; i++) {
|
||||
let sigId = this.windows[i].connect('notify::user-time', Lang.bind(this, this._resortWindows));
|
||||
this._signalIds.push([this.windows[i], sigId]);
|
||||
}
|
||||
this._resortWindows();
|
||||
|
||||
this.actor.connect('destroy', Lang.bind(this, this._destroy));
|
||||
this.actor.connect('notify::mapped', Lang.bind(this, this._onMappedChanged));
|
||||
|
||||
if (this._menuType != MenuType.NONE) {
|
||||
this.actor.connect('button-press-event', Lang.bind(this, this._updateMenuOnButtonPress));
|
||||
this.actor.connect('notify::hover', Lang.bind(this, this._updateMenuOnHoverChanged));
|
||||
this.actor.connect('activate', Lang.bind(this, this._updateMenuOnActivate));
|
||||
|
||||
this._menuTimeoutId = 0;
|
||||
this._menu = null;
|
||||
}
|
||||
|
||||
let iconBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
x_align: Big.BoxAlignment.CENTER,
|
||||
y_align: Big.BoxAlignment.CENTER,
|
||||
width: this._iconSize,
|
||||
height: this._iconSize });
|
||||
this.icon = this.appInfo.create_icon_texture(this._iconSize);
|
||||
iconBox.append(this.icon, Big.BoxPackFlags.NONE);
|
||||
|
||||
this.actor.append(iconBox, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
let nameBox = new Shell.GenericContainer();
|
||||
nameBox.connect('get-preferred-width', Lang.bind(this, this._nameBoxGetPreferredWidth));
|
||||
nameBox.connect('get-preferred-height', Lang.bind(this, this._nameBoxGetPreferredHeight));
|
||||
nameBox.connect('allocate', Lang.bind(this, this._nameBoxAllocate));
|
||||
this._nameBox = nameBox;
|
||||
|
||||
this._name = new Clutter.Text({ color: GenericDisplay.ITEM_DISPLAY_NAME_COLOR,
|
||||
font_name: "Sans 12px",
|
||||
line_alignment: Pango.Alignment.CENTER,
|
||||
ellipsize: Pango.EllipsizeMode.END,
|
||||
text: this.appInfo.get_name() });
|
||||
nameBox.add_actor(this._name);
|
||||
if (showGlow) {
|
||||
this._glowBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL });
|
||||
let glowPath = GLib.filename_to_uri(global.imagedir + 'app-well-glow.png', '');
|
||||
for (let i = 0; i < this.windows.length && i < 3; i++) {
|
||||
let glow = Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.FOREVER,
|
||||
glowPath, -1, -1);
|
||||
glow.keep_aspect_ratio = false;
|
||||
this._glowBox.append(glow, Big.BoxPackFlags.EXPAND);
|
||||
}
|
||||
this._nameBox.add_actor(this._glowBox);
|
||||
this._glowBox.lower(this._name);
|
||||
}
|
||||
else
|
||||
this._glowBox = null;
|
||||
|
||||
this.actor.append(nameBox, Big.BoxPackFlags.NONE);
|
||||
},
|
||||
|
||||
_nameBoxGetPreferredWidth: function (nameBox, forHeight, alloc) {
|
||||
let [min, natural] = this._name.get_preferred_width(forHeight);
|
||||
alloc.min_size = min + GLOW_PADDING_HORIZONTAL * 2;
|
||||
alloc.natural_size = natural + GLOW_PADDING_HORIZONTAL * 2;
|
||||
},
|
||||
|
||||
_nameBoxGetPreferredHeight: function (nameBox, forWidth, alloc) {
|
||||
let [min, natural] = this._name.get_preferred_height(forWidth);
|
||||
alloc.min_size = min + GLOW_PADDING_VERTICAL * 2;
|
||||
alloc.natural_size = natural + GLOW_PADDING_VERTICAL * 2;
|
||||
},
|
||||
|
||||
_nameBoxAllocate: function (nameBox, box, flags) {
|
||||
let childBox = new Clutter.ActorBox();
|
||||
let [minWidth, naturalWidth] = this._name.get_preferred_width(-1);
|
||||
let [minHeight, naturalHeight] = this._name.get_preferred_height(-1);
|
||||
let availWidth = box.x2 - box.x1;
|
||||
let availHeight = box.y2 - box.y1;
|
||||
let targetWidth = availWidth;
|
||||
let xPadding = 0;
|
||||
if (naturalWidth < availWidth) {
|
||||
xPadding = Math.floor((availWidth - naturalWidth) / 2);
|
||||
}
|
||||
childBox.x1 = xPadding;
|
||||
childBox.x2 = availWidth - xPadding;
|
||||
childBox.y1 = GLOW_PADDING_VERTICAL;
|
||||
childBox.y2 = availHeight - GLOW_PADDING_VERTICAL;
|
||||
this._name.allocate(childBox, flags);
|
||||
|
||||
// Now the glow
|
||||
if (this._glowBox != null) {
|
||||
let glowPaddingHoriz = Math.max(0, xPadding - GLOW_PADDING_HORIZONTAL);
|
||||
glowPaddingHoriz = Math.max(GLOW_PADDING_HORIZONTAL, glowPaddingHoriz);
|
||||
childBox.x1 = glowPaddingHoriz;
|
||||
childBox.x2 = availWidth - glowPaddingHoriz;
|
||||
childBox.y1 = 0;
|
||||
childBox.y2 = availHeight;
|
||||
this._glowBox.allocate(childBox, flags);
|
||||
}
|
||||
},
|
||||
|
||||
_destroy: function() {
|
||||
for (let i = 0; i < this._signalIds.length; i++) {
|
||||
let [obj, sigId] = this._signalIds[i];
|
||||
obj.disconnect(sigId);
|
||||
}
|
||||
},
|
||||
|
||||
_onMappedChanged: function() {
|
||||
let mapped = this.actor.mapped;
|
||||
if (mapped && this._windowSortStale)
|
||||
this._resortWindows();
|
||||
},
|
||||
|
||||
_resortWindows: function() {
|
||||
let mapped = this.actor.mapped;
|
||||
if (!mapped) {
|
||||
this._windowSortStale = true;
|
||||
return;
|
||||
}
|
||||
this._windowSortStale = false;
|
||||
this.windows.sort(function (a, b) {
|
||||
let activeWorkspace = global.screen.get_active_workspace();
|
||||
let wsA = a.get_workspace() == activeWorkspace;
|
||||
let wsB = b.get_workspace() == activeWorkspace;
|
||||
|
||||
if (wsA && !wsB)
|
||||
return -1;
|
||||
else if (wsB && !wsA)
|
||||
return 1;
|
||||
|
||||
let visA = a.showing_on_its_workspace();
|
||||
let visB = b.showing_on_its_workspace();
|
||||
|
||||
if (visA && !visB)
|
||||
return -1;
|
||||
else if (visB && !visA)
|
||||
return 1;
|
||||
else
|
||||
return b.get_user_time() - a.get_user_time();
|
||||
});
|
||||
},
|
||||
|
||||
// AppIcon itself is not a draggable, but if you want to make
|
||||
// a subclass of it draggable, you can use this method to create
|
||||
// a drag actor
|
||||
createDragActor: function() {
|
||||
return this.appInfo.create_icon_texture(this._iconSize);
|
||||
},
|
||||
|
||||
setHighlight: function(highlight) {
|
||||
if (highlight) {
|
||||
this.actor.border_color = this.highlight_border_color;
|
||||
} else {
|
||||
this.actor.border_color = TRANSPARENT_COLOR;
|
||||
}
|
||||
},
|
||||
|
||||
_updateMenuOnActivate: function(actor, event) {
|
||||
if (this._menuTimeoutId != 0) {
|
||||
Mainloop.source_remove(this._menuTimeoutId);
|
||||
this._menuTimeoutId = 0;
|
||||
}
|
||||
this.emit('activate');
|
||||
return false;
|
||||
},
|
||||
|
||||
_updateMenuOnHoverChanged: function() {
|
||||
if (!this.actor.hover && this._menuTimeoutId != 0) {
|
||||
Mainloop.source_remove(this._menuTimeoutId);
|
||||
this._menuTimeoutId = 0;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_updateMenuOnButtonPress: function(actor, event) {
|
||||
let button = event.get_button();
|
||||
if (button == 1) {
|
||||
if (this._menuTimeoutId != 0)
|
||||
Mainloop.source_remove(this._menuTimeoutId);
|
||||
this._menuTimeoutId = Mainloop.timeout_add(APPICON_MENU_POPUP_TIMEOUT_MS,
|
||||
Lang.bind(this, function () { this.popupMenu(button); }));
|
||||
} else if (button == 3) {
|
||||
this.popupMenu(button);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
popupMenu: function(activatingButton) {
|
||||
if (this._menuTimeoutId != 0) {
|
||||
Mainloop.source_remove(this._menuTimeoutId);
|
||||
this._menuTimeoutId = 0;
|
||||
}
|
||||
|
||||
this.actor.fake_release();
|
||||
|
||||
if (!this._menu) {
|
||||
this._menu = new AppIconMenu(this, this._menuType);
|
||||
this._menu.connect('highlight-window', Lang.bind(this, function (menu, window) {
|
||||
this.highlightWindow(window);
|
||||
}));
|
||||
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.menuPoppedUp();
|
||||
else
|
||||
this.menuPoppedDown();
|
||||
}));
|
||||
}
|
||||
|
||||
this._menu.popup(activatingButton);
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
// Default implementations; AppDisplay.RunningWellItem overrides these
|
||||
highlightWindow: function(window) {
|
||||
this.emit('highlight-window', window);
|
||||
},
|
||||
|
||||
activateWindow: function(window) {
|
||||
this.emit('activate-window', window);
|
||||
},
|
||||
|
||||
menuPoppedUp: function() {
|
||||
this.emit('menu-popped-up', this._menu);
|
||||
},
|
||||
|
||||
menuPoppedDown: function() {
|
||||
this.emit('menu-popped-down', this._menu);
|
||||
}
|
||||
};
|
||||
|
||||
Signals.addSignalMethods(AppIcon.prototype);
|
||||
|
||||
function AppIconMenu(source, type) {
|
||||
this._init(source, type);
|
||||
}
|
||||
|
||||
AppIconMenu.prototype = {
|
||||
_init: function(source, type) {
|
||||
this._source = source;
|
||||
this._type = type;
|
||||
|
||||
this.actor = new Shell.GenericContainer({ 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._windowContainer = new Shell.Menu({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
border_color: source.highlight_border_color,
|
||||
border: APPICON_MENU_BORDER_WIDTH,
|
||||
background_color: APPICON_MENU_BACKGROUND_COLOR,
|
||||
padding: 4,
|
||||
corner_radius: APPICON_MENU_CORNER_RADIUS,
|
||||
width: Main.overview._dash.actor.width * 0.75 });
|
||||
this._windowContainer.connect('unselected', Lang.bind(this, this._onItemUnselected));
|
||||
this._windowContainer.connect('selected', Lang.bind(this, this._onItemSelected));
|
||||
this._windowContainer.connect('cancelled', Lang.bind(this, this._onWindowSelectionCancelled));
|
||||
this._windowContainer.connect('activate', Lang.bind(this, this._onItemActivate));
|
||||
this.actor.add_actor(this._windowContainer);
|
||||
|
||||
// Stay popped up on release over application icon
|
||||
this._windowContainer.set_persistent_source(this._source.actor);
|
||||
|
||||
// Intercept events while the menu has the pointer grab to do window-related effects
|
||||
this._windowContainer.connect('enter-event', Lang.bind(this, this._onMenuEnter));
|
||||
this._windowContainer.connect('leave-event', Lang.bind(this, this._onMenuLeave));
|
||||
this._windowContainer.connect('button-release-event', Lang.bind(this, this._onMenuButtonRelease));
|
||||
|
||||
this._arrow = new Shell.DrawingArea();
|
||||
this._arrow.connect('redraw', Lang.bind(this, function (area, texture) {
|
||||
Shell.draw_box_pointer(texture,
|
||||
this._type == MenuType.ON_RIGHT ? Shell.PointerDirection.LEFT : Shell.PointerDirection.UP,
|
||||
source.highlight_border_color,
|
||||
APPICON_MENU_BACKGROUND_COLOR);
|
||||
}));
|
||||
this.actor.add_actor(this._arrow);
|
||||
|
||||
// Chain our visibility and lifecycle to that of the source
|
||||
source.actor.connect('notify::mapped', Lang.bind(this, function () {
|
||||
if (!source.actor.mapped)
|
||||
this._windowContainer.popdown();
|
||||
}));
|
||||
source.actor.connect('destroy', Lang.bind(this, function () { this.actor.destroy(); }));
|
||||
|
||||
global.stage.add_actor(this.actor);
|
||||
},
|
||||
|
||||
_getPreferredWidth: function(actor, forHeight, alloc) {
|
||||
let [min, natural] = this._windowContainer.get_preferred_width(forHeight);
|
||||
if (this._type == MenuType.ON_RIGHT) {
|
||||
min += APPICON_MENU_ARROW_SIZE;
|
||||
natural += APPICON_MENU_ARROW_SIZE;
|
||||
}
|
||||
alloc.min_size = min;
|
||||
alloc.natural_size = natural;
|
||||
},
|
||||
|
||||
_getPreferredHeight: function(actor, forWidth, alloc) {
|
||||
let [min, natural] = this._windowContainer.get_preferred_height(forWidth);
|
||||
if (this._type == MenuType.BELOW) {
|
||||
min += APPICON_MENU_ARROW_SIZE;
|
||||
natural += APPICON_MENU_ARROW_SIZE;
|
||||
}
|
||||
alloc.min_size = min;
|
||||
alloc.natural_size = natural;
|
||||
},
|
||||
|
||||
_allocate: function(actor, box, flags) {
|
||||
let childBox = new Clutter.ActorBox();
|
||||
|
||||
let width = box.x2 - box.x1;
|
||||
let height = box.y2 - box.y1;
|
||||
|
||||
if (this._type == MenuType.ON_RIGHT) {
|
||||
childBox.x1 = 0;
|
||||
childBox.x2 = APPICON_MENU_ARROW_SIZE;
|
||||
childBox.y1 = Math.floor((height / 2) - (APPICON_MENU_ARROW_SIZE / 2));
|
||||
childBox.y2 = childBox.y1 + APPICON_MENU_ARROW_SIZE;
|
||||
this._arrow.allocate(childBox, flags);
|
||||
|
||||
childBox.x1 = APPICON_MENU_ARROW_SIZE - APPICON_MENU_BORDER_WIDTH;
|
||||
childBox.x2 = width;
|
||||
childBox.y1 = 0;
|
||||
childBox.y2 = height;
|
||||
this._windowContainer.allocate(childBox, flags);
|
||||
} else /* MenuType.BELOW */ {
|
||||
childBox.x1 = Math.floor((width / 2) - (APPICON_MENU_ARROW_SIZE / 2));
|
||||
childBox.x2 = childBox.x1 + APPICON_MENU_ARROW_SIZE;
|
||||
childBox.y1 = 0;
|
||||
childBox.y2 = APPICON_MENU_ARROW_SIZE;
|
||||
this._arrow.allocate(childBox, flags);
|
||||
|
||||
childBox.x1 = 0;
|
||||
childBox.x2 = width;
|
||||
childBox.y1 = APPICON_MENU_ARROW_SIZE - APPICON_MENU_BORDER_WIDTH;
|
||||
childBox.y2 = height;
|
||||
this._windowContainer.allocate(childBox, flags);
|
||||
}
|
||||
},
|
||||
|
||||
_redisplay: function() {
|
||||
this._windowContainer.remove_all();
|
||||
|
||||
let windows = this._source.windows;
|
||||
|
||||
this._windowContainer.show();
|
||||
|
||||
let iconsDiffer = false;
|
||||
let texCache = Shell.TextureCache.get_default();
|
||||
if (windows.length > 0) {
|
||||
let firstIcon = windows[0].mini_icon;
|
||||
for (let i = 1; i < windows.length; i++) {
|
||||
if (!texCache.pixbuf_equal(windows[i].mini_icon, firstIcon)) {
|
||||
iconsDiffer = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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 icon = null;
|
||||
if (iconsDiffer)
|
||||
icon = Shell.TextureCache.get_default().bind_pixbuf_property(windows[i], "mini-icon");
|
||||
|
||||
let box = this._appendMenuItem(icon, windows[i].title);
|
||||
box._window = windows[i];
|
||||
}
|
||||
|
||||
if (windows.length > 0)
|
||||
this._appendSeparator();
|
||||
|
||||
this._newWindowMenuItem = windows.length > 0 ? this._appendMenuItem(null, _("New Window")) : null;
|
||||
|
||||
let favorites = Shell.AppSystem.get_default().get_favorites();
|
||||
let id = this._source.appInfo.get_id();
|
||||
this._isFavorite = false;
|
||||
for (let i = 0; i < favorites.length; i++) {
|
||||
if (id == favorites[i]) {
|
||||
this._isFavorite = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (windows.length > 0)
|
||||
this._appendSeparator();
|
||||
this._toggleFavoriteMenuItem = this._appendMenuItem(null, this._isFavorite ? _("Remove from favorites")
|
||||
: _("Add to favorites"));
|
||||
|
||||
this._highlightedItem = null;
|
||||
},
|
||||
|
||||
_appendSeparator: function () {
|
||||
let box = new Big.Box({ padding_top: 2, padding_bottom: 2 });
|
||||
box.append(new Clutter.Rectangle({ height: 1,
|
||||
color: APPICON_MENU_SEPARATOR_COLOR }),
|
||||
Big.BoxPackFlags.EXPAND);
|
||||
this._windowContainer.append_separator(box, Big.BoxPackFlags.NONE);
|
||||
},
|
||||
|
||||
_appendMenuItem: function(iconTexture, labelText) {
|
||||
/* Use padding here rather than spacing in the box above so that
|
||||
* we have a larger reactive area.
|
||||
*/
|
||||
let box = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
padding_top: 4,
|
||||
padding_bottom: 4,
|
||||
spacing: 4,
|
||||
reactive: true });
|
||||
let vCenter;
|
||||
if (iconTexture != null) {
|
||||
vCenter = new Big.Box({ y_align: Big.BoxAlignment.CENTER });
|
||||
vCenter.append(iconTexture, Big.BoxPackFlags.NONE);
|
||||
box.append(vCenter, Big.BoxPackFlags.NONE);
|
||||
}
|
||||
vCenter = new Big.Box({ y_align: Big.BoxAlignment.CENTER });
|
||||
let label = new Clutter.Text({ text: labelText,
|
||||
font_name: APPICON_MENU_FONT,
|
||||
ellipsize: Pango.EllipsizeMode.END,
|
||||
color: APPICON_MENU_COLOR });
|
||||
vCenter.append(label, Big.BoxPackFlags.NONE);
|
||||
box.append(vCenter, Big.BoxPackFlags.NONE);
|
||||
this._windowContainer.append(box, Big.BoxPackFlags.NONE);
|
||||
return box;
|
||||
},
|
||||
|
||||
popup: function(activatingButton) {
|
||||
let [stageX, stageY] = this._source.actor.get_transformed_position();
|
||||
let [stageWidth, stageHeight] = this._source.actor.get_transformed_size();
|
||||
|
||||
this._redisplay();
|
||||
|
||||
this._windowContainer.popup(activatingButton, Main.currentTime());
|
||||
|
||||
this.emit('popup', true);
|
||||
|
||||
let x, y;
|
||||
if (this._type == MenuType.ON_RIGHT) {
|
||||
x = Math.floor(stageX + stageWidth);
|
||||
y = Math.floor(stageY + (stageHeight / 2) - (this.actor.height / 2));
|
||||
} else {
|
||||
x = Math.floor(stageX + (stageWidth / 2) - (this.actor.width / 2));
|
||||
y = Math.floor(stageY + stageHeight);
|
||||
}
|
||||
|
||||
this.actor.set_position(x, y);
|
||||
this.actor.show();
|
||||
},
|
||||
|
||||
popdown: function() {
|
||||
this._windowContainer.popdown();
|
||||
this.emit('popup', false);
|
||||
this.actor.hide();
|
||||
},
|
||||
|
||||
selectWindow: function(metaWindow) {
|
||||
this._selectMenuItemForWindow(metaWindow);
|
||||
},
|
||||
|
||||
_findMetaWindowForActor: function (actor) {
|
||||
if (actor._delegate instanceof Workspaces.WindowClone)
|
||||
return actor._delegate.metaWindow;
|
||||
else if (actor.get_meta_window)
|
||||
return actor.get_meta_window();
|
||||
return null;
|
||||
},
|
||||
|
||||
// This function is called while the menu has a pointer grab; what we want
|
||||
// to do is see if the mouse was released over a window representation
|
||||
_onMenuButtonRelease: function (actor, event) {
|
||||
let metaWindow = this._findMetaWindowForActor(event.get_source());
|
||||
if (metaWindow) {
|
||||
this.emit('activate-window', metaWindow);
|
||||
}
|
||||
},
|
||||
|
||||
_updateHighlight: function (item) {
|
||||
if (this._highlightedItem) {
|
||||
this._highlightedItem.background_color = TRANSPARENT_COLOR;
|
||||
this.emit('highlight-window', null);
|
||||
}
|
||||
this._highlightedItem = item;
|
||||
if (this._highlightedItem) {
|
||||
this._highlightedItem.background_color = APPICON_MENU_SELECTED_COLOR;
|
||||
let window = this._highlightedItem._window;
|
||||
if (window)
|
||||
this.emit('highlight-window', window);
|
||||
}
|
||||
},
|
||||
|
||||
_selectMenuItemForWindow: function (metaWindow) {
|
||||
let children = this._windowContainer.get_children();
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
let child = children[i];
|
||||
let menuMetaWindow = child._window;
|
||||
if (menuMetaWindow == metaWindow)
|
||||
this._updateHighlight(child);
|
||||
}
|
||||
},
|
||||
|
||||
// Called while menu has a pointer grab
|
||||
_onMenuEnter: function (actor, event) {
|
||||
let metaWindow = this._findMetaWindowForActor(event.get_source());
|
||||
if (metaWindow) {
|
||||
this._selectMenuItemForWindow(metaWindow);
|
||||
}
|
||||
},
|
||||
|
||||
// Called while menu has a pointer grab
|
||||
_onMenuLeave: function (actor, event) {
|
||||
let metaWindow = this._findMetaWindowForActor(event.get_source());
|
||||
if (metaWindow) {
|
||||
this._updateHighlight(null);
|
||||
}
|
||||
},
|
||||
|
||||
_onItemUnselected: function (actor, child) {
|
||||
this._updateHighlight(null);
|
||||
},
|
||||
|
||||
_onItemSelected: function (actor, child) {
|
||||
this._updateHighlight(child);
|
||||
},
|
||||
|
||||
_onItemActivate: function (actor, child) {
|
||||
if (child._window) {
|
||||
let metaWindow = child._window;
|
||||
this.emit('activate-window', metaWindow);
|
||||
} else if (child == this._newWindowMenuItem) {
|
||||
this._source.appInfo.launch();
|
||||
this.emit('activate-window', null);
|
||||
} else if (child == this._toggleFavoriteMenuItem) {
|
||||
let appSys = Shell.AppSystem.get_default();
|
||||
if (this._isFavorite)
|
||||
appSys.remove_favorite(this._source.appInfo.get_id());
|
||||
else
|
||||
appSys.add_favorite(this._source.appInfo.get_id());
|
||||
}
|
||||
this.popdown();
|
||||
},
|
||||
|
||||
_onWindowSelectionCancelled: function () {
|
||||
this.emit('highlight-window', null);
|
||||
this.popdown();
|
||||
}
|
||||
};
|
||||
|
||||
Signals.addSignalMethods(AppIconMenu.prototype);
|
112
js/ui/button.js
@ -4,8 +4,8 @@ const Big = imports.gi.Big;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
const DEFAULT_BUTTON_COLOR = new Clutter.Color();
|
||||
@ -22,14 +22,12 @@ const DEFAULT_FONT = 'Sans Bold 16px';
|
||||
// Padding on the left and right side of the button.
|
||||
const SIDE_PADDING = 14;
|
||||
|
||||
function Button(widget, buttonColor, pressedButtonColor, textColor, staysPressed, minWidth, minHeight, font) {
|
||||
this._init(widget, buttonColor, pressedButtonColor, textColor, staysPressed, minWidth, minHeight, font);
|
||||
function Button(widget, buttonColor, pressedButtonColor, textColor, font) {
|
||||
this._init(widget, buttonColor, pressedButtonColor, textColor, font);
|
||||
}
|
||||
|
||||
Button.prototype = {
|
||||
_init : function(widgetOrText, buttonColor, pressedButtonColor, textColor, staysPressed, minWidth, minHeight, font) {
|
||||
let me = this;
|
||||
|
||||
_init : function(widgetOrText, buttonColor, pressedButtonColor, textColor, font) {
|
||||
this._buttonColor = buttonColor
|
||||
if (buttonColor == null)
|
||||
this._buttonColor = DEFAULT_BUTTON_COLOR;
|
||||
@ -42,32 +40,20 @@ Button.prototype = {
|
||||
if (textColor == null)
|
||||
this._textColor = DEFAULT_TEXT_COLOR;
|
||||
|
||||
this._staysPressed = staysPressed
|
||||
if (staysPressed == null)
|
||||
this._staysPressed = false;
|
||||
|
||||
this._font = font;
|
||||
if (font == null)
|
||||
this._font = DEFAULT_FONT;
|
||||
|
||||
if (minWidth == null)
|
||||
minWidth = 0;
|
||||
if (minHeight == null)
|
||||
minHeight = 0;
|
||||
|
||||
// if this._staysPressed is true, this._active will be true past the first release of a button, until a subsequent one (the button
|
||||
// is unpressed) or until release() is called explicitly
|
||||
this._active = false;
|
||||
this._isBetweenPressAndRelease = false;
|
||||
this._mouseIsOverButton = false;
|
||||
|
||||
this.button = new Big.Box({ reactive: true,
|
||||
corner_radius: 5,
|
||||
padding_left: SIDE_PADDING,
|
||||
padding_right: SIDE_PADDING,
|
||||
orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
y_align: Big.BoxAlignment.CENTER
|
||||
});
|
||||
this.actor = new Shell.ButtonBox({ reactive: true,
|
||||
corner_radius: 5,
|
||||
padding_left: SIDE_PADDING,
|
||||
padding_right: SIDE_PADDING,
|
||||
orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
y_align: Big.BoxAlignment.CENTER
|
||||
});
|
||||
if (typeof widgetOrText == 'string') {
|
||||
this._widget = new Clutter.Text({ font_name: this._font,
|
||||
color: this._textColor,
|
||||
@ -76,65 +62,25 @@ Button.prototype = {
|
||||
this._widget = widgetOrText;
|
||||
}
|
||||
|
||||
this.button.append(this._widget, Big.BoxPackFlags.EXPAND);
|
||||
this.actor.append(this._widget, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
this._minWidth = minWidth;
|
||||
this._minHeight = minHeight;
|
||||
|
||||
this.button.connect('button-press-event',
|
||||
function(o, event) {
|
||||
me._isBetweenPressAndRelease = true;
|
||||
me.button.backgroundColor = me._pressedButtonColor;
|
||||
return false;
|
||||
});
|
||||
this.button.connect('button-release-event',
|
||||
function(o, event) {
|
||||
me._isBetweenPressAndRelease = false;
|
||||
if (!me._staysPressed || me._active) {
|
||||
me.release();
|
||||
} else {
|
||||
me._active = true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
this.button.connect('enter-event',
|
||||
function(o, event) {
|
||||
me._mouseIsOverButton = true;
|
||||
if (!me._active) {
|
||||
me.button.backgroundColor = me._buttonColor;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
this.button.connect('leave-event',
|
||||
function(o, event) {
|
||||
me._isBetweenPressAndRelease = false;
|
||||
me._mouseIsOverButton = false;
|
||||
if (!me._active) {
|
||||
me.button.backgroundColor = null;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
this.actor.connect('notify::hover', Lang.bind(this, this._updateColors));
|
||||
this.actor.connect('notify::pressed', Lang.bind(this, this._updateColors));
|
||||
this.actor.connect('notify::active', Lang.bind(this, this._updateColors));
|
||||
},
|
||||
|
||||
pressIn : function() {
|
||||
if (!this._isBetweenPressAndRelease && this._staysPressed) {
|
||||
this._active = true;
|
||||
this.button.backgroundColor = this._pressedButtonColor;
|
||||
}
|
||||
},
|
||||
|
||||
release : function() {
|
||||
if (!this._isBetweenPressAndRelease && this._staysPressed) {
|
||||
this._active = false;
|
||||
if (this._mouseIsOverButton) {
|
||||
this.button.backgroundColor = this._buttonColor;
|
||||
} else {
|
||||
this.button.backgroundColor = null;
|
||||
}
|
||||
}
|
||||
_updateColors : function() {
|
||||
if (this.actor.active || this.actor.pressed)
|
||||
this.actor.backgroundColor = this._pressedButtonColor;
|
||||
else if (this.actor.hover)
|
||||
this.actor.backgroundColor = this._buttonColor;
|
||||
else
|
||||
this.actor.backgroundColor = null;
|
||||
}
|
||||
};
|
||||
|
||||
Signals.addSignalMethods(Button.prototype);
|
||||
|
||||
/* Delay before the icon should appear, in seconds after the pointer has entered the parent */
|
||||
const ANIMATION_TIME = 0.25;
|
||||
|
||||
@ -145,11 +91,11 @@ const ANIMATION_TIME = 0.25;
|
||||
* size -- size in pixels of both the button and the icon it contains
|
||||
* texture -- optional, must be used if the texture for the icon is already created (else, use setIconFromName)
|
||||
*/
|
||||
function iconButton(parent, size, texture) {
|
||||
function IconButton(parent, size, texture) {
|
||||
this._init(parent, size, texture);
|
||||
}
|
||||
|
||||
iconButton.prototype = {
|
||||
IconButton.prototype = {
|
||||
_init : function(parent, size, texture) {
|
||||
this._size = size;
|
||||
if (texture)
|
||||
@ -160,16 +106,15 @@ iconButton.prototype = {
|
||||
this.actor.set_opacity(0);
|
||||
parent.connect("enter-event", Lang.bind(this, function(actor, event) {
|
||||
this._shouldHide = false;
|
||||
|
||||
// Nothing to do if the cursor has come back from a child of the parent actor
|
||||
if (actor.get_children().indexOf(Shell.get_event_related(event)) != -1)
|
||||
if (actor.get_children().indexOf(event.get_related()) != -1)
|
||||
return;
|
||||
|
||||
this._fadeIn();
|
||||
}));
|
||||
parent.connect("leave-event", Lang.bind(this, function(actor, event) {
|
||||
// Nothing to do if the cursor has merely entered a child of the parent actor
|
||||
if (actor.get_children().indexOf(Shell.get_event_related(event)) != -1)
|
||||
if (actor.get_children().indexOf(event.get_related()) != -1)
|
||||
return;
|
||||
|
||||
// Remember that we should not be visible to hide the button if forceShow is unset
|
||||
@ -225,4 +170,3 @@ iconButton.prototype = {
|
||||
transition :"easeOutQuad" });
|
||||
}
|
||||
};
|
||||
|
||||
|
177
js/ui/calendar.js
Normal file
@ -0,0 +1,177 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Lang = imports.lang;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const Gettext_gtk20 = imports.gettext.domain('gtk20');
|
||||
|
||||
const MSECS_IN_DAY = 24 * 60 * 60 * 1000;
|
||||
|
||||
function _sameDay(dateA, dateB) {
|
||||
return (dateA.getDate() == dateB.getDate() &&
|
||||
dateA.getMonth() == dateB.getMonth() &&
|
||||
dateA.getYear() == dateB.getYear());
|
||||
}
|
||||
|
||||
function Calendar() {
|
||||
this._init();
|
||||
};
|
||||
|
||||
Calendar.prototype = {
|
||||
_init: function() {
|
||||
// FIXME: This is actually the fallback method for GTK+ for the week start;
|
||||
// GTK+ by preference uses nl_langinfo (NL_TIME_FIRST_WEEKDAY). We probably
|
||||
// should add a C function so we can do the full handling.
|
||||
this._weekStart = NaN;
|
||||
let weekStartString = Gettext_gtk20.gettext("calendar:week_start:0");
|
||||
if (weekStartString.indexOf("calendar:week_start:") == 0) {
|
||||
this._weekStart = parseInt(weekStartString.substring(20));
|
||||
}
|
||||
|
||||
if (isNaN(this._weekStart) || this._weekStart < 0 || this._weekStart > 6) {
|
||||
log("Translation of 'calendar:week_start:0' in GTK+ is not correct");
|
||||
this.weekStart = 0;
|
||||
}
|
||||
|
||||
// Find the ordering for month/year in the calendar heading
|
||||
switch (Gettext_gtk20.gettext("calendar:MY")) {
|
||||
case "calendar:MY":
|
||||
this._headerFormat = "%B %Y";
|
||||
break;
|
||||
case "calendar:YM":
|
||||
this._headerFormat = "%Y %B";
|
||||
break;
|
||||
default:
|
||||
log("Translation of 'calendar:MY' in GTK+ is not correct");
|
||||
this._headerFormat = "%B %Y";
|
||||
break;
|
||||
}
|
||||
|
||||
// Start off with the current date
|
||||
this.date = new Date();
|
||||
|
||||
this.actor = new St.Table({ homogeneous: false,
|
||||
style_class: "calendar",
|
||||
reactive: true });
|
||||
|
||||
this.actor.connect('scroll-event',
|
||||
Lang.bind(this, this._onScroll));
|
||||
|
||||
// Top line of the calendar '<| September 2009 |>'
|
||||
this._topBox = new St.BoxLayout();
|
||||
this.actor.add(this._topBox,
|
||||
{ row: 0, col: 0, col_span: 7 });
|
||||
|
||||
let back = new St.Button({ label: "<", style_class: 'calendar-change-month' });
|
||||
this._topBox.add(back);
|
||||
back.connect("clicked", Lang.bind(this, this._prevMonth));
|
||||
|
||||
this._dateLabel = new St.Label();
|
||||
this._topBox.add(this._dateLabel, { expand: true, x_fill: false, x_align: St.Align.MIDDLE });
|
||||
|
||||
let forward = new St.Button({ label: ">", style_class: 'calendar-change-month' });
|
||||
this._topBox.add(forward);
|
||||
forward.connect("clicked", Lang.bind(this, this._nextMonth));
|
||||
|
||||
// We need to figure out the abbreviated localized names for the days of the week;
|
||||
// we do this by just getting the next 7 days starting from right now and then putting
|
||||
// them in the right cell in the table. It doesn't matter if we add them in order
|
||||
let iter = new Date(this.date);
|
||||
iter.setSeconds(0); // Leap second protection. Hah!
|
||||
iter.setHours(12);
|
||||
for (let i = 0; i < 7; i++) {
|
||||
this.actor.add(new St.Label({ text: iter.toLocaleFormat("%a") }),
|
||||
{ row: 1,
|
||||
col: (7 + iter.getDay() - this._weekStart) % 7,
|
||||
x_fill: false, x_align: 1.0 });
|
||||
iter.setTime(iter.getTime() + MSECS_IN_DAY);
|
||||
}
|
||||
|
||||
// All the children after this are days, and get removed when we update the calendar
|
||||
this._firstDayIndex = this.actor.get_children().length;
|
||||
|
||||
this._update();
|
||||
},
|
||||
|
||||
// Sets the calendar to show a specific date
|
||||
setDate: function(date) {
|
||||
if (!_sameDay(date, this.date)) {
|
||||
this.date = date;
|
||||
this._update();
|
||||
}
|
||||
},
|
||||
|
||||
_onScroll : function(actor, event) {
|
||||
switch (event.get_scroll_direction()) {
|
||||
case Clutter.ScrollDirection.UP:
|
||||
case Clutter.ScrollDirection.LEFT:
|
||||
this._prevMonth();
|
||||
break;
|
||||
case Clutter.ScrollDirection.DOWN:
|
||||
case Clutter.ScrollDirection.RIGHT:
|
||||
this._nextMonth();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_prevMonth: function() {
|
||||
if (this.date.getMonth() == 0) {
|
||||
this.date.setMonth(11);
|
||||
this.date.setFullYear(this.date.getFullYear() - 1);
|
||||
} else {
|
||||
this.date.setMonth(this.date.getMonth() - 1);
|
||||
}
|
||||
this._update();
|
||||
},
|
||||
|
||||
_nextMonth: function() {
|
||||
if (this.date.getMonth() == 11) {
|
||||
this.date.setMonth(0);
|
||||
this.date.setFullYear(this.date.getFullYear() + 1);
|
||||
} else {
|
||||
this.date.setMonth(this.date.getMonth() + 1);
|
||||
}
|
||||
this._update();
|
||||
},
|
||||
|
||||
_update: function() {
|
||||
this._dateLabel.text = this.date.toLocaleFormat(this._headerFormat);
|
||||
|
||||
// Remove everything but the topBox and the weekday labels
|
||||
let children = this.actor.get_children();
|
||||
for (let i = this._firstDayIndex; i < children.length; i++)
|
||||
children[i].destroy();
|
||||
|
||||
// Start at the beginning of the week before the start of the month
|
||||
let iter = new Date(this.date);
|
||||
iter.setDate(1);
|
||||
iter.setSeconds(0);
|
||||
iter.setHours(12);
|
||||
iter.setTime(iter.getTime() - (iter.getDay() - this._weekStart) * MSECS_IN_DAY);
|
||||
|
||||
let now = new Date();
|
||||
|
||||
let row = 2;
|
||||
while (true) {
|
||||
let label = new St.Label({ text: iter.getDate().toString() });
|
||||
if (_sameDay(now, iter))
|
||||
label.style_class = "calendar-day calendar-today";
|
||||
else if (iter.getMonth() != this.date.getMonth())
|
||||
label.style_class = "calendar-day calendar-other-month-day";
|
||||
else
|
||||
label.style_class = "calendar-day";
|
||||
this.actor.add(label,
|
||||
{ row: row, col: (7 + iter.getDay() - this._weekStart) % 7,
|
||||
x_fill: false, x_align: 1.0 });
|
||||
|
||||
iter.setTime(iter.getTime() + MSECS_IN_DAY);
|
||||
if (iter.getDay() == this._weekStart) {
|
||||
// We stop on the first "first day of the week" after the month we are displaying
|
||||
if (iter.getMonth() > this.date.getMonth() || iter.getYear() > this.date.getYear())
|
||||
break;
|
||||
row++;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
@ -9,7 +9,7 @@ const Shell = imports.gi.Shell;
|
||||
const Main = imports.ui.main;
|
||||
|
||||
// This manages the shell "chrome"; the UI that's visible in the
|
||||
// normal mode (ie, outside the overlay), that surrounds the main
|
||||
// normal mode (ie, outside the Overview), that surrounds the main
|
||||
// workspace content.
|
||||
|
||||
function Chrome() {
|
||||
@ -18,13 +18,11 @@ function Chrome() {
|
||||
|
||||
Chrome.prototype = {
|
||||
_init: function() {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
// The group itself has zero size so it doesn't interfere with DND
|
||||
this.actor = new Clutter.Group({ width: 0, height: 0 });
|
||||
global.stage.add_actor(this.actor);
|
||||
this.nonOverlayActor = new Clutter.Group();
|
||||
this.actor.add_actor(this.nonOverlayActor);
|
||||
this.nonOverviewActor = new Clutter.Group();
|
||||
this.actor.add_actor(this.nonOverviewActor);
|
||||
|
||||
this._obscuredByFullscreen = false;
|
||||
|
||||
@ -37,10 +35,10 @@ Chrome.prototype = {
|
||||
global.screen.connect('notify::n-workspaces',
|
||||
Lang.bind(this, this._queueUpdateRegions));
|
||||
|
||||
Main.overlay.connect('showing',
|
||||
Lang.bind(this, this._overlayShowing));
|
||||
Main.overlay.connect('hidden',
|
||||
Lang.bind(this, this._overlayHidden));
|
||||
Main.overview.connect('showing',
|
||||
Lang.bind(this, this._overviewShowing));
|
||||
Main.overview.connect('hidden',
|
||||
Lang.bind(this, this._overviewHidden));
|
||||
|
||||
this._queueUpdateRegions();
|
||||
},
|
||||
@ -78,27 +76,27 @@ Chrome.prototype = {
|
||||
else if (shapeActor && !this._verifyAncestry(shapeActor, actor))
|
||||
throw new Error('shapeActor is not a descendent of actor');
|
||||
|
||||
this.nonOverlayActor.add_actor(actor);
|
||||
this.nonOverviewActor.add_actor(actor);
|
||||
|
||||
if (shapeActor)
|
||||
this._trackActor(shapeActor, true, true);
|
||||
},
|
||||
|
||||
// setVisibleInOverlay:
|
||||
// setVisibleInOverview:
|
||||
// @actor: an actor in the chrome layer
|
||||
// @visible: overlay visibility
|
||||
// @visible: Overview visibility
|
||||
//
|
||||
// By default, actors in the chrome layer are automatically hidden
|
||||
// when the overlay is shown. This can be used to override that
|
||||
// when the Overview is shown. This can be used to override that
|
||||
// behavior
|
||||
setVisibleInOverlay: function(actor, visible) {
|
||||
setVisibleInOverview: function(actor, visible) {
|
||||
if (!this._verifyAncestry(actor, this.actor))
|
||||
throw new Error('actor is not a descendent of the chrome layer');
|
||||
|
||||
if (visible)
|
||||
actor.reparent(this.actor);
|
||||
else
|
||||
actor.reparent(this.nonOverlayActor);
|
||||
actor.reparent(this.nonOverviewActor);
|
||||
},
|
||||
|
||||
// addInputRegionActor:
|
||||
@ -126,8 +124,8 @@ Chrome.prototype = {
|
||||
//
|
||||
// Removes @actor from the chrome layer
|
||||
removeActor: function(actor) {
|
||||
if (actor.get_parent() == this.nonOverlayActor)
|
||||
this.nonOverlayActor.remove_actor(actor);
|
||||
if (actor.get_parent() == this.nonOverviewActor)
|
||||
this.nonOverviewActor.remove_actor(actor);
|
||||
else
|
||||
this.actor.remove_actor(actor);
|
||||
this._untrackActor(actor, true, true);
|
||||
@ -172,7 +170,7 @@ Chrome.prototype = {
|
||||
this._trackedActors.push(actorData);
|
||||
|
||||
actor = actor.get_parent();
|
||||
if (actor != this.actor && actor != this.nonOverlayActor)
|
||||
if (actor != this.actor && actor != this.nonOverviewActor)
|
||||
this._trackActor(actor, false, false);
|
||||
|
||||
if (inputRegion || strut)
|
||||
@ -200,7 +198,7 @@ Chrome.prototype = {
|
||||
actor.disconnect(actorData.parentSetId);
|
||||
|
||||
actor = actor.get_parent();
|
||||
if (actor && actor != this.actor && actor != this.nonOverlayActor)
|
||||
if (actor && actor != this.actor && actor != this.nonOverviewActor)
|
||||
this._untrackActor(actor, false, false);
|
||||
}
|
||||
|
||||
@ -211,23 +209,23 @@ Chrome.prototype = {
|
||||
_actorReparented: function(actor, oldParent) {
|
||||
if (this._verifyAncestry(actor, this.actor)) {
|
||||
let newParent = actor.get_parent();
|
||||
if (newParent != this.actor && newParent != this.nonOverlayActor)
|
||||
if (newParent != this.actor && newParent != this.nonOverviewActor)
|
||||
this._trackActor(newParent, false, false);
|
||||
}
|
||||
if (oldParent != this.actor && oldParent != this.nonOverlayActor)
|
||||
if (oldParent != this.actor && oldParent != this.nonOverviewActor)
|
||||
this._untrackActor(oldParent, false, false);
|
||||
},
|
||||
|
||||
_overlayShowing: function() {
|
||||
_overviewShowing: function() {
|
||||
this.actor.show();
|
||||
this.nonOverlayActor.hide();
|
||||
this.nonOverviewActor.hide();
|
||||
this._queueUpdateRegions();
|
||||
},
|
||||
|
||||
_overlayHidden: function() {
|
||||
_overviewHidden: function() {
|
||||
if (this._obscuredByFullscreen)
|
||||
this.actor.hide();
|
||||
this.nonOverlayActor.show();
|
||||
this.nonOverviewActor.show();
|
||||
this._queueUpdateRegions();
|
||||
},
|
||||
|
||||
@ -238,7 +236,6 @@ Chrome.prototype = {
|
||||
},
|
||||
|
||||
_windowsRestacked: function() {
|
||||
let global = Shell.Global.get();
|
||||
let windows = global.get_windows();
|
||||
|
||||
// The chrome layer should be visible unless there is a window
|
||||
@ -272,7 +269,7 @@ Chrome.prototype = {
|
||||
break;
|
||||
}
|
||||
|
||||
let shouldBeVisible = !this._obscuredByFullscreen || Main.overlay.visible;
|
||||
let shouldBeVisible = !this._obscuredByFullscreen || Main.overview.visible;
|
||||
if (this.actor.visible != shouldBeVisible) {
|
||||
this.actor.visible = shouldBeVisible;
|
||||
this._queueUpdateRegions();
|
||||
@ -280,7 +277,6 @@ Chrome.prototype = {
|
||||
},
|
||||
|
||||
_updateRegions: function() {
|
||||
let global = Shell.Global.get();
|
||||
let rects = [], struts = [], i;
|
||||
|
||||
delete this._updateRegionIdle;
|
||||
|
835
js/ui/dash.js
316
js/ui/dnd.js
@ -8,15 +8,40 @@ const Tweener = imports.ui.tweener;
|
||||
|
||||
const SNAP_BACK_ANIMATION_TIME = 0.25;
|
||||
|
||||
function _Draggable(actor) {
|
||||
this._init(actor);
|
||||
let eventHandlerActor = null;
|
||||
let currentDraggable = null;
|
||||
|
||||
function _getEventHandlerActor() {
|
||||
if (!eventHandlerActor) {
|
||||
eventHandlerActor = new Clutter.Rectangle();
|
||||
eventHandlerActor.width = 0;
|
||||
eventHandlerActor.height = 0;
|
||||
global.stage.add_actor(eventHandlerActor);
|
||||
// We connect to 'event' rather than 'captured-event' because the capturing phase doesn't happen
|
||||
// when you've grabbed the pointer.
|
||||
eventHandlerActor.connect('event',
|
||||
function(actor, event) {
|
||||
return currentDraggable._onEvent(actor, event);
|
||||
});
|
||||
}
|
||||
return eventHandlerActor;
|
||||
}
|
||||
|
||||
function _Draggable(actor, manualMode) {
|
||||
this._init(actor, manualMode);
|
||||
}
|
||||
|
||||
_Draggable.prototype = {
|
||||
_init : function(actor) {
|
||||
_init : function(actor, manualMode) {
|
||||
this.actor = actor;
|
||||
this.actor.connect('button-press-event',
|
||||
Lang.bind(this, this._onButtonPress));
|
||||
if (!manualMode)
|
||||
this.actor.connect('button-press-event',
|
||||
Lang.bind(this, this._onButtonPress));
|
||||
this._onEventId = null;
|
||||
|
||||
this._buttonDown = false; // The mouse button has been pressed and has not yet been released.
|
||||
this._dragInProgress = false; // The drag has been started, and has not been dropped or cancelled yet.
|
||||
this._snapBackInProgress = false; // The drag has been cancelled and the item is in the process of snapping back.
|
||||
},
|
||||
|
||||
_onButtonPress : function (actor, event) {
|
||||
@ -25,7 +50,8 @@ _Draggable.prototype = {
|
||||
if (Tweener.getTweenCount(actor))
|
||||
return false;
|
||||
|
||||
this._grabActor(actor);
|
||||
this._buttonDown = true;
|
||||
this._grabActor();
|
||||
|
||||
let [stageX, stageY] = event.get_coords();
|
||||
this._dragStartX = stageX;
|
||||
@ -34,97 +60,168 @@ _Draggable.prototype = {
|
||||
return false;
|
||||
},
|
||||
|
||||
_grabActor : function (actor) {
|
||||
Clutter.grab_pointer(actor);
|
||||
|
||||
// We intercept motion and button-release events so that when
|
||||
// you release after dragging, the app doesn't see that and
|
||||
// think you just clicked. We connect to 'event' rather than
|
||||
// 'captured-event' because the capturing phase doesn't happen
|
||||
// when you've grabbed the pointer.
|
||||
this._onEventId = actor.connect('event',
|
||||
Lang.bind(this, this._onEvent));
|
||||
_grabActor: function() {
|
||||
Clutter.grab_pointer(this.actor);
|
||||
this._onEventId = this.actor.connect('event',
|
||||
Lang.bind(this, this._onEvent));
|
||||
},
|
||||
|
||||
_ungrabActor : function (actor) {
|
||||
_ungrabActor: function() {
|
||||
Clutter.ungrab_pointer();
|
||||
actor.disconnect(this._onEventId);
|
||||
this.actor.disconnect(this._onEventId);
|
||||
this._onEventId = null;
|
||||
},
|
||||
|
||||
_onEvent : function (actor, event) {
|
||||
if (this._dragActor) {
|
||||
if (actor != this._dragActor )
|
||||
_grabEvents: function() {
|
||||
Clutter.grab_pointer(_getEventHandlerActor());
|
||||
Clutter.grab_keyboard(_getEventHandlerActor());
|
||||
},
|
||||
|
||||
_ungrabEvents: function() {
|
||||
Clutter.ungrab_pointer();
|
||||
Clutter.ungrab_keyboard();
|
||||
},
|
||||
|
||||
_onEvent: function(actor, event) {
|
||||
// We intercept BUTTON_RELEASE event to know that the button was released in case we
|
||||
// didn't start the drag, to drop the draggable in case the drag was in progress, and
|
||||
// to complete the drag and ensure that whatever happens to be under the pointer does
|
||||
// not get triggered if the drag was cancelled with Esc.
|
||||
if (event.type() == Clutter.EventType.BUTTON_RELEASE) {
|
||||
this._buttonDown = false;
|
||||
if (this._dragInProgress) {
|
||||
return this._dragActorDropped(event);
|
||||
} else if (this._dragActor != null && !this._snapBackInProgress) {
|
||||
// Drag must have been cancelled with Esc.
|
||||
this._dragComplete();
|
||||
return true;
|
||||
} else {
|
||||
// Drag has never started.
|
||||
this._ungrabActor();
|
||||
return false;
|
||||
} else if (actor != this.actor)
|
||||
return false;
|
||||
}
|
||||
// We intercept MOTION event to figure out if the drag has started and to draw
|
||||
// this._dragActor under the pointer when dragging is in progress
|
||||
} else if (event.type() == Clutter.EventType.MOTION) {
|
||||
if (this._dragInProgress) {
|
||||
return this._updateDragPosition(event);
|
||||
} else if (this._dragActor == null) {
|
||||
return this._maybeStartDrag(event);
|
||||
}
|
||||
// We intercept KEY_PRESS event so that we can process Esc key press to cancel
|
||||
// dragging and ignore all other key presses.
|
||||
} else if (event.type() == Clutter.EventType.KEY_PRESS && this._dragInProgress) {
|
||||
let symbol = event.get_key_symbol();
|
||||
if (symbol == Clutter.Escape) {
|
||||
this._cancelDrag(event.get_time());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (event.type() == Clutter.EventType.BUTTON_RELEASE)
|
||||
return this._onButtonRelease(actor, event);
|
||||
else if (event.type() == Clutter.EventType.MOTION)
|
||||
return this._onMotion(actor, event);
|
||||
else
|
||||
return false;
|
||||
return false;
|
||||
},
|
||||
|
||||
_onMotion : function (actor, event) {
|
||||
/**
|
||||
* startDrag:
|
||||
* @stageX: X coordinate of event
|
||||
* @stageY: Y coordinate of event
|
||||
* @time: Event timestamp
|
||||
*
|
||||
* Directly initiate a drag and drop operation from the given actor.
|
||||
* This function is useful to call if you've specified manualMode
|
||||
* for the draggable.
|
||||
*/
|
||||
startDrag: function (stageX, stageY, time) {
|
||||
currentDraggable = this;
|
||||
this._dragInProgress = true;
|
||||
|
||||
this.emit('drag-begin', time);
|
||||
if (this._onEventId)
|
||||
this._ungrabActor();
|
||||
this._grabEvents();
|
||||
|
||||
this._dragStartX = stageX;
|
||||
this._dragStartY = stageY;
|
||||
|
||||
if (this.actor._delegate && this.actor._delegate.getDragActor) {
|
||||
this._dragActor = this.actor._delegate.getDragActor(this._dragStartX, this._dragStartY);
|
||||
// Drag actor does not always have to be the same as actor. For example drag actor
|
||||
// can be an image that's part of the actor. So to perform "snap back" correctly we need
|
||||
// to know what was the drag actor source.
|
||||
if (this.actor._delegate.getDragActorSource) {
|
||||
this._dragActorSource = this.actor._delegate.getDragActorSource();
|
||||
// If the user dragged from the source, then position
|
||||
// the dragActor over it. Otherwise, center it
|
||||
// around the pointer
|
||||
let [sourceX, sourceY] = this._dragActorSource.get_transformed_position();
|
||||
let [sourceWidth, sourceHeight] = this._dragActorSource.get_transformed_size();
|
||||
let x, y;
|
||||
if (stageX > sourceX && stageX <= sourceX + sourceWidth &&
|
||||
stageY > sourceY && stageY <= sourceY + sourceHeight) {
|
||||
x = sourceX;
|
||||
y = sourceY;
|
||||
} else {
|
||||
x = stageX - this._dragActor.width / 2;
|
||||
y = stageY - this._dragActor.height / 2;
|
||||
}
|
||||
this._dragActor.set_position(x, y);
|
||||
} else {
|
||||
this._dragActorSource = this.actor;
|
||||
}
|
||||
this._dragOrigParent = undefined;
|
||||
|
||||
this._dragOffsetX = this._dragActor.x - this._dragStartX;
|
||||
this._dragOffsetY = this._dragActor.y - this._dragStartY;
|
||||
} else {
|
||||
this._dragActor = this.actor;
|
||||
this._dragActorSource = undefined;
|
||||
this._dragOrigParent = this.actor.get_parent();
|
||||
this._dragOrigX = this._dragActor.x;
|
||||
this._dragOrigY = this._dragActor.y;
|
||||
this._dragOrigScale = this._dragActor.scale_x;
|
||||
|
||||
let [actorStageX, actorStageY] = this.actor.get_transformed_position();
|
||||
this._dragOffsetX = actorStageX - this._dragStartX;
|
||||
this._dragOffsetY = actorStageY - this._dragStartY;
|
||||
|
||||
// Set the actor's scale such that it will keep the same
|
||||
// transformed size when it's reparented to the stage
|
||||
let [scaledWidth, scaledHeight] = this.actor.get_transformed_size();
|
||||
this.actor.set_scale(scaledWidth / this.actor.width,
|
||||
scaledHeight / this.actor.height);
|
||||
}
|
||||
|
||||
this._dragActor.reparent(this.actor.get_stage());
|
||||
this._dragActor.raise_top();
|
||||
},
|
||||
|
||||
_maybeStartDrag: function(event) {
|
||||
let [stageX, stageY] = event.get_coords();
|
||||
|
||||
// If we haven't begun a drag, see if the user has moved the
|
||||
// mouse enough to trigger a drag
|
||||
// See if the user has moved the mouse enough to trigger a drag
|
||||
let threshold = Gtk.Settings.get_default().gtk_dnd_drag_threshold;
|
||||
if (!this._dragActor &&
|
||||
(Math.abs(stageX - this._dragStartX) > threshold ||
|
||||
if ((Math.abs(stageX - this._dragStartX) > threshold ||
|
||||
Math.abs(stageY - this._dragStartY) > threshold)) {
|
||||
this.emit('drag-begin', event.get_time());
|
||||
|
||||
if (this.actor._delegate && this.actor._delegate.getDragActor) {
|
||||
this._dragActor = this.actor._delegate.getDragActor(this._dragStartX, this._dragStartY);
|
||||
// Drag actor does not always have to be the same as actor. For example drag actor
|
||||
// can be an image that's part of the actor. So to perform "snap back" correctly we need
|
||||
// to know what was the drag actor source.
|
||||
if (this.actor._delegate.getDragActorSource)
|
||||
this._dragActorSource = this.actor._delegate.getDragActorSource();
|
||||
else
|
||||
this._dragActorSource = this.actor;
|
||||
this._dragOrigParent = undefined;
|
||||
this._ungrabActor(actor);
|
||||
this._grabActor(this._dragActor);
|
||||
|
||||
this._dragOffsetX = this._dragActor.x - this._dragStartX;
|
||||
this._dragOffsetY = this._dragActor.y - this._dragStartY;
|
||||
} else {
|
||||
this._dragActor = actor;
|
||||
this._dragActorSource = undefined;
|
||||
this._dragOrigParent = actor.get_parent();
|
||||
this._dragOrigX = this._dragActor.x;
|
||||
this._dragOrigY = this._dragActor.y;
|
||||
this._dragOrigScale = this._dragActor.scale_x;
|
||||
|
||||
let [actorStageX, actorStageY] = actor.get_transformed_position();
|
||||
this._dragOffsetX = actorStageX - this._dragStartX;
|
||||
this._dragOffsetY = actorStageY - this._dragStartY;
|
||||
|
||||
// Set the actor's scale such that it will keep the same
|
||||
// transformed size when it's reparented to the stage
|
||||
let [scaledWidth, scaledHeight] = actor.get_transformed_size();
|
||||
actor.set_scale(scaledWidth / actor.width,
|
||||
scaledHeight / actor.height);
|
||||
}
|
||||
|
||||
this._dragActor.reparent(actor.get_stage());
|
||||
this._dragActor.raise_top();
|
||||
this.startDrag(stageX, stageY, event.get_time());
|
||||
this._updateDragPosition(event);
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
_updateDragPosition : function (event) {
|
||||
let [stageX, stageY] = event.get_coords();
|
||||
|
||||
// If we are dragging, update the position
|
||||
if (this._dragActor) {
|
||||
this._dragActor.set_position(stageX + this._dragOffsetX,
|
||||
stageY + this._dragOffsetY);
|
||||
// Because we want to find out what other actor is located at the current position of this._dragActor,
|
||||
// we have to temporarily hide this._dragActor.
|
||||
this._dragActor.hide();
|
||||
let target = actor.get_stage().get_actor_at_pos(Clutter.PickMode.ALL,
|
||||
stageX + this._dragOffsetX,
|
||||
stageY + this._dragOffsetY);
|
||||
this._dragActor.hide();
|
||||
let target = this._dragActor.get_stage().get_actor_at_pos(Clutter.PickMode.ALL,
|
||||
stageX + this._dragOffsetX,
|
||||
stageY + this._dragOffsetY);
|
||||
this._dragActor.show();
|
||||
while (target) {
|
||||
if (target._delegate && target._delegate.handleDragOver) {
|
||||
@ -132,52 +229,54 @@ _Draggable.prototype = {
|
||||
// We currently loop through all parents on drag-over even if one of the children has handled it.
|
||||
// We can check the return value of the function and break the loop if it's true if we don't want
|
||||
// to continue checking the parents.
|
||||
target._delegate.handleDragOver(this.actor._delegate, actor,
|
||||
target._delegate.handleDragOver(this.actor._delegate, this._dragActor,
|
||||
(stageX + this._dragOffsetX - targX) / target.scale_x,
|
||||
(stageY + this._dragOffsetY - targY) / target.scale_y,
|
||||
event.get_time());
|
||||
}
|
||||
target = target.get_parent();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
_onButtonRelease : function (actor, event) {
|
||||
this._ungrabActor(actor);
|
||||
|
||||
let dragging = (actor == this._dragActor);
|
||||
this._dragActor = undefined;
|
||||
|
||||
if (!dragging)
|
||||
return false;
|
||||
|
||||
// Find a drop target
|
||||
actor.hide();
|
||||
_dragActorDropped: function(event) {
|
||||
// Find a drop target. Because we want to find out what other actor is located at
|
||||
// the current position of this._dragActor, we have to temporarily hide this._dragActor.
|
||||
this._dragActor.hide();
|
||||
let [dropX, dropY] = event.get_coords();
|
||||
let target = actor.get_stage().get_actor_at_pos(Clutter.PickMode.ALL,
|
||||
dropX, dropY);
|
||||
actor.show();
|
||||
let target = this._dragActor.get_stage().get_actor_at_pos(Clutter.PickMode.ALL,
|
||||
dropX, dropY);
|
||||
this._dragActor.show();
|
||||
while (target) {
|
||||
if (target._delegate && target._delegate.acceptDrop) {
|
||||
let [targX, targY] = target.get_transformed_position();
|
||||
if (target._delegate.acceptDrop(this.actor._delegate, actor,
|
||||
if (target._delegate.acceptDrop(this.actor._delegate, this._dragActor,
|
||||
(dropX - targX) / target.scale_x,
|
||||
(dropY - targY) / target.scale_y,
|
||||
event.get_time())) {
|
||||
// If it accepted the drop without taking the actor,
|
||||
// destroy it.
|
||||
if (actor.get_parent() == actor.get_stage())
|
||||
actor.destroy();
|
||||
if (this._dragActor.get_parent() == this._dragActor.get_stage())
|
||||
this._dragActor.destroy();
|
||||
|
||||
this._dragInProgress = false;
|
||||
this.emit('drag-end', event.get_time(), true);
|
||||
this._dragComplete();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
target = target.get_parent();
|
||||
}
|
||||
|
||||
this._cancelDrag(event.get_time());
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
_cancelDrag: function(eventTime) {
|
||||
this._dragInProgress = false;
|
||||
// Snap back to the actor source if the source is still around, snap back
|
||||
// to the original location if the actor itself was being dragged or the
|
||||
// source is no longer around.
|
||||
@ -187,17 +286,17 @@ _Draggable.prototype = {
|
||||
[snapBackX, snapBackY] = this._dragActorSource.get_transformed_position();
|
||||
}
|
||||
|
||||
this._snapBackInProgress = true;
|
||||
// No target, so snap back
|
||||
Tweener.addTween(actor,
|
||||
Tweener.addTween(this._dragActor,
|
||||
{ x: snapBackX,
|
||||
y: snapBackY,
|
||||
time: SNAP_BACK_ANIMATION_TIME,
|
||||
transition: "easeOutQuad",
|
||||
onComplete: this._onSnapBackComplete,
|
||||
onCompleteScope: this,
|
||||
onCompleteParams: [actor, event.get_time()]
|
||||
onCompleteParams: [this._dragActor, eventTime]
|
||||
});
|
||||
return true;
|
||||
},
|
||||
|
||||
_onSnapBackComplete : function (dragActor, eventTime) {
|
||||
@ -209,11 +308,28 @@ _Draggable.prototype = {
|
||||
dragActor.destroy();
|
||||
}
|
||||
this.emit('drag-end', eventTime, false);
|
||||
|
||||
this._snapBackInProgress = false;
|
||||
if (!this._buttonDown)
|
||||
this._dragComplete();
|
||||
},
|
||||
|
||||
_dragComplete: function() {
|
||||
this._dragActor = undefined;
|
||||
currentDraggable = null;
|
||||
this._ungrabEvents();
|
||||
}
|
||||
};
|
||||
|
||||
Signals.addSignalMethods(_Draggable.prototype);
|
||||
|
||||
function makeDraggable(actor) {
|
||||
return new _Draggable(actor);
|
||||
/**
|
||||
* makeDraggable:
|
||||
* @actor: Source actor
|
||||
* @manualMode: If given, do not automatically start drag and drop on click
|
||||
*
|
||||
* Create an object which controls drag and drop for the given actor.
|
||||
*/
|
||||
function makeDraggable(actor, manualMode) {
|
||||
return new _Draggable(actor, manualMode);
|
||||
}
|
||||
|
@ -1,17 +1,24 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Big = imports.gi.Big;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Lang = imports.lang;
|
||||
const Pango = imports.gi.Pango;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const Mainloop = imports.mainloop;
|
||||
|
||||
const DocInfo = imports.misc.docInfo;
|
||||
const DND = imports.ui.dnd;
|
||||
const GenericDisplay = imports.ui.genericDisplay;
|
||||
const Main = imports.ui.main;
|
||||
|
||||
const DASH_DOCS_ICON_SIZE = 16;
|
||||
|
||||
const DEFAULT_SPACING = 4;
|
||||
|
||||
/* This class represents a single display item containing information about a document.
|
||||
* We take the current number of seconds in the constructor to avoid looking up the current
|
||||
* time for every item when they are created in a batch.
|
||||
@ -68,21 +75,34 @@ DocDisplayItem.prototype = {
|
||||
|
||||
// Creates and returns a large preview icon, but only if this._docInfo is an image file
|
||||
// and we were able to generate a pixbuf from it successfully.
|
||||
_createLargePreviewIcon : function(availableWidth, availableHeight) {
|
||||
_createLargePreviewIcon : function() {
|
||||
if (this._docInfo.mimeType == null || this._docInfo.mimeType.indexOf("image/") != 0)
|
||||
return null;
|
||||
|
||||
return Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.NONE,
|
||||
this._docInfo.uri, availableWidth, availableHeight);
|
||||
try {
|
||||
return Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.NONE,
|
||||
this._docInfo.uri, -1, -1);
|
||||
} catch (e) {
|
||||
// An exception will be raised when the image format isn't know
|
||||
/* FIXME: http://bugzilla.gnome.org/show_bug.cgi?id=591480: should
|
||||
* only ignore GDK_PIXBUF_ERROR_UNKNOWN_TYPE. */
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
//// Drag and Drop ////
|
||||
|
||||
shellWorkspaceLaunch: function() {
|
||||
this.launch();
|
||||
},
|
||||
|
||||
//// Private Methods ////
|
||||
|
||||
// Updates the last visited time displayed in the description text for the item.
|
||||
// Updates the last visited time displayed in the description text for the item.
|
||||
_resetTimeDisplay: function(currentSecs) {
|
||||
let lastSecs = this._docInfo.timestamp;
|
||||
let timeDelta = currentSecs - lastSecs;
|
||||
let [text, nextUpdate] = Shell.Global.get().format_time_relative_pretty(timeDelta);
|
||||
let [text, nextUpdate] = global.format_time_relative_pretty(timeDelta);
|
||||
this._timeoutTime = currentSecs + nextUpdate;
|
||||
this._setDescriptionText(text);
|
||||
}
|
||||
@ -100,8 +120,6 @@ DocDisplay.prototype = {
|
||||
|
||||
_init : function() {
|
||||
GenericDisplay.GenericDisplay.prototype._init.call(this);
|
||||
let me = this;
|
||||
|
||||
// We keep a single timeout callback for updating last visited times
|
||||
// for all the items in the display. This avoids creating individual
|
||||
// callbacks for each item in the display. So proper time updates
|
||||
@ -110,16 +128,16 @@ DocDisplay.prototype = {
|
||||
this._updateTimeoutTargetTime = -1;
|
||||
this._updateTimeoutId = 0;
|
||||
|
||||
this._docManager = DocInfo.getDocManager(GenericDisplay.ITEM_DISPLAY_ICON_SIZE);
|
||||
this._docManager = DocInfo.getDocManager();
|
||||
this._docsStale = true;
|
||||
this._docManager.connect('changed', function(mgr, userData) {
|
||||
me._docsStale = true;
|
||||
// Changes in local recent files should not happen when we are in the overlay mode,
|
||||
this._docManager.connect('changed', Lang.bind(this, function(mgr, userData) {
|
||||
this._docsStale = true;
|
||||
// Changes in local recent files should not happen when we are in the Overview mode,
|
||||
// but redisplaying right away is cool when we use Zephyr.
|
||||
// Also, we might be displaying remote documents, like Google Docs, in the future
|
||||
// which might be edited by someone else.
|
||||
me._redisplay(false);
|
||||
});
|
||||
this._redisplay(GenericDisplay.RedisplayFlags.NONE);
|
||||
}));
|
||||
|
||||
this.connect('destroy', Lang.bind(this, function (o) {
|
||||
if (this._updateTimeoutId > 0)
|
||||
@ -132,9 +150,10 @@ DocDisplay.prototype = {
|
||||
// Gets the list of recent items from the recent items manager.
|
||||
_refreshCache : function() {
|
||||
if (!this._docsStale)
|
||||
return;
|
||||
return true;
|
||||
this._allItems = this._docManager.getItems();
|
||||
this._docsStale = false;
|
||||
return false;
|
||||
},
|
||||
|
||||
// Sets the list of the displayed items based on how recently they were last visited.
|
||||
@ -148,26 +167,29 @@ DocDisplay.prototype = {
|
||||
// we should do the sorting manually because we want the order to be based on last visited.
|
||||
//
|
||||
// This function is called each time the search string is set back to '' or we display
|
||||
// the overlay, so we are doing the sorting over the same items multiple times if the list
|
||||
// the Overview, so we are doing the sorting over the same items multiple times if the list
|
||||
// of recent items didn't change. We could store an additional array of doc ids and sort
|
||||
// them once when they are returned by this._recentManager.get_items() to avoid having to do
|
||||
// this sorting each time, but the sorting seems to be very fast anyway, so there is no need
|
||||
// to introduce an additional class variable.
|
||||
this._matchedItems = [];
|
||||
this._matchedItems = {};
|
||||
this._matchedItemKeys = [];
|
||||
let docIdsToRemove = [];
|
||||
for (docId in this._allItems) {
|
||||
// this._allItems[docId].exists() checks if the resource still exists
|
||||
if (this._allItems[docId].exists())
|
||||
this._matchedItems.push(docId);
|
||||
else
|
||||
if (this._allItems[docId].exists()) {
|
||||
this._matchedItems[docId] = 1;
|
||||
this._matchedItemKeys.push(docId);
|
||||
} else {
|
||||
docIdsToRemove.push(docId);
|
||||
}
|
||||
}
|
||||
|
||||
for (docId in docIdsToRemove) {
|
||||
delete this._allItems[docId];
|
||||
}
|
||||
|
||||
this._matchedItems.sort(Lang.bind(this, function (a,b) { return this._compareItems(a,b); }));
|
||||
this._matchedItemKeys.sort(Lang.bind(this, this._compareItems));
|
||||
},
|
||||
|
||||
// Compares items associated with the item ids based on how recently the items
|
||||
@ -236,3 +258,187 @@ DocDisplay.prototype = {
|
||||
};
|
||||
|
||||
Signals.addSignalMethods(DocDisplay.prototype);
|
||||
|
||||
function DashDocDisplayItem(docInfo) {
|
||||
this._init(docInfo);
|
||||
}
|
||||
|
||||
DashDocDisplayItem.prototype = {
|
||||
_init: function(docInfo) {
|
||||
this._info = docInfo;
|
||||
this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
spacing: DEFAULT_SPACING,
|
||||
reactive: true });
|
||||
this.actor.connect('button-release-event', Lang.bind(this, function () {
|
||||
docInfo.launch();
|
||||
Main.overview.hide();
|
||||
}));
|
||||
|
||||
this._icon = docInfo.createIcon(DASH_DOCS_ICON_SIZE);
|
||||
let iconBox = new Big.Box({ y_align: Big.BoxAlignment.CENTER });
|
||||
iconBox.append(this._icon, Big.BoxPackFlags.NONE);
|
||||
this.actor.append(iconBox, Big.BoxPackFlags.NONE);
|
||||
let name = new Clutter.Text({ font_name: "Sans 14px",
|
||||
color: GenericDisplay.ITEM_DISPLAY_NAME_COLOR,
|
||||
ellipsize: Pango.EllipsizeMode.END,
|
||||
text: docInfo.name });
|
||||
this.actor.append(name, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
let draggable = DND.makeDraggable(this.actor);
|
||||
this.actor._delegate = this;
|
||||
},
|
||||
|
||||
getDragActorSource: function() {
|
||||
return this._icon;
|
||||
},
|
||||
|
||||
getDragActor: function(stageX, stageY) {
|
||||
this.dragActor = this._info.createIcon(DASH_DOCS_ICON_SIZE);
|
||||
return this.dragActor;
|
||||
},
|
||||
|
||||
//// Drag and drop functions ////
|
||||
|
||||
shellWorkspaceLaunch: function () {
|
||||
this._info.launch();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Class used to display two column recent documents in the dash
|
||||
*/
|
||||
function DashDocDisplay() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
DashDocDisplay.prototype = {
|
||||
_init: function() {
|
||||
this.actor = new Shell.GenericContainer();
|
||||
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._docManager = DocInfo.getDocManager();
|
||||
this._docManager.connect('changed', Lang.bind(this, function(mgr) {
|
||||
this._redisplay();
|
||||
}));
|
||||
this._redisplay();
|
||||
},
|
||||
|
||||
_getPreferredWidth: function(actor, forHeight, alloc) {
|
||||
let children = actor.get_children();
|
||||
|
||||
// We use two columns maximum. Just take the min and natural size of the
|
||||
// first two items, even though strictly speaking it's not correct; we'd
|
||||
// need to calculate how many items we could fit for the height, then
|
||||
// take the biggest preferred width for each column.
|
||||
// In practice the dash gets a fixed width anyways.
|
||||
|
||||
// If we have one child, add its minimum and natural size
|
||||
if (children.length > 0) {
|
||||
let [minSize, naturalSize] = children[0].get_preferred_width(forHeight);
|
||||
alloc.min_size += minSize;
|
||||
alloc.natural_size += naturalSize;
|
||||
}
|
||||
// If we have two, add its size, plus DEFAULT_SPACING
|
||||
if (children.length > 1) {
|
||||
let [minSize, naturalSize] = children[1].get_preferred_width(forHeight);
|
||||
alloc.min_size += DEFAULT_SPACING + minSize;
|
||||
alloc.natural_size += DEFAULT_SPACING + naturalSize;
|
||||
}
|
||||
},
|
||||
|
||||
_getPreferredHeight: function(actor, forWidth, alloc) {
|
||||
let children = actor.get_children();
|
||||
|
||||
// Two columns, where we go vertically down first. So just take
|
||||
// the height of half of the children as our preferred height.
|
||||
|
||||
let firstColumnChildren = children.length / 2;
|
||||
|
||||
alloc.min_size = 0;
|
||||
for (let i = 0; i < firstColumnChildren; i++) {
|
||||
let child = children[i];
|
||||
let [minSize, naturalSize] = child.get_preferred_height(forWidth);
|
||||
alloc.natural_size += naturalSize;
|
||||
|
||||
if (i > 0 && i < children.length - 1) {
|
||||
alloc.min_size += DEFAULT_SPACING;
|
||||
alloc.natural_size += DEFAULT_SPACING;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_allocate: function(actor, box, flags) {
|
||||
let width = box.x2 - box.x1;
|
||||
let height = box.y2 - box.y1;
|
||||
|
||||
let children = actor.get_children();
|
||||
|
||||
// The width of an item is our allocated width, minus spacing, divided in half.
|
||||
let itemWidth = Math.floor((width - DEFAULT_SPACING) / 2);
|
||||
let x = box.x1;
|
||||
let y = box.y1;
|
||||
let columnIndex = 0;
|
||||
let i = 0;
|
||||
// Loop over the children, going vertically down first. When we run
|
||||
// out of vertical space (our y variable is bigger than box.y2), switch
|
||||
// to the second column.
|
||||
for (; i < children.length; i++) {
|
||||
let child = children[i];
|
||||
|
||||
let [minSize, naturalSize] = child.get_preferred_height(-1);
|
||||
|
||||
if (y + naturalSize > box.y2) {
|
||||
// Is this the second column? Ok, break.
|
||||
if (columnIndex == 1) {
|
||||
break;
|
||||
}
|
||||
// Set x to the halfway point.
|
||||
columnIndex += 1;
|
||||
x = x + itemWidth + DEFAULT_SPACING;
|
||||
// And y is back to the top.
|
||||
y = box.y1;
|
||||
}
|
||||
|
||||
let childBox = new Clutter.ActorBox();
|
||||
childBox.x1 = x;
|
||||
childBox.y1 = y;
|
||||
childBox.x2 = childBox.x1 + itemWidth;
|
||||
childBox.y2 = y + naturalSize;
|
||||
|
||||
y = childBox.y2 + DEFAULT_SPACING;
|
||||
|
||||
child.show();
|
||||
child.allocate(childBox, flags);
|
||||
}
|
||||
|
||||
// Everything else didn't fit, just hide it.
|
||||
for (; i < children.length; i++) {
|
||||
children[i].hide();
|
||||
}
|
||||
},
|
||||
|
||||
_redisplay: function() {
|
||||
this.actor.remove_all();
|
||||
|
||||
let docs = this._docManager.getItems();
|
||||
let docUrls = [];
|
||||
for (let url in docs) {
|
||||
docUrls.push(url);
|
||||
}
|
||||
docUrls.sort(function (urlA, urlB) { return docs[urlB].timestamp - docs[urlA].timestamp; });
|
||||
let textureCache = Shell.TextureCache.get_default();
|
||||
|
||||
for (let i = 0; i < docUrls.length; i++) {
|
||||
let url = docUrls[i];
|
||||
let docInfo = docs[url];
|
||||
let display = new DashDocDisplayItem(docInfo);
|
||||
this.actor.add_actor(display.actor);
|
||||
}
|
||||
this.emit('changed');
|
||||
}
|
||||
};
|
||||
|
||||
Signals.addSignalMethods(DashDocDisplay.prototype);
|
||||
|
||||
|
36
js/ui/environment.js
Normal file
@ -0,0 +1,36 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const St = imports.gi.St;
|
||||
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
const Format = imports.misc.format;
|
||||
|
||||
// "monkey patch" in some varargs ClutterContainer methods; we need
|
||||
// to do this per-container class since there is no representation
|
||||
// of interfaces in Javascript
|
||||
function _patchContainerClass(containerClass) {
|
||||
// This one is a straightforward mapping of the C method
|
||||
containerClass.prototype.child_set = function(actor, props) {
|
||||
let meta = this.get_child_meta(actor);
|
||||
for (prop in props)
|
||||
meta[prop] = props[prop];
|
||||
};
|
||||
|
||||
// clutter_container_add() actually is a an add-many-actors
|
||||
// method. We conveniently, but somewhat dubiously, take the
|
||||
// this opportunity to make it do something more useful.
|
||||
containerClass.prototype.add = function(actor, props) {
|
||||
this.add_actor(actor);
|
||||
if (props)
|
||||
this.child_set(actor, props);
|
||||
};
|
||||
}
|
||||
|
||||
_patchContainerClass(St.BoxLayout);
|
||||
_patchContainerClass(St.Table);
|
||||
|
||||
function init() {
|
||||
Tweener.init();
|
||||
String.prototype.format = Format.format;
|
||||
}
|
@ -7,16 +7,21 @@ const Gdk = imports.gi.Gdk;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Pango = imports.gi.Pango;
|
||||
const Signals = imports.signals;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Tidy = imports.gi.Tidy;
|
||||
|
||||
const Button = imports.ui.button;
|
||||
const DND = imports.ui.dnd;
|
||||
const Link = imports.ui.link;
|
||||
const Main = imports.ui.main;
|
||||
|
||||
const RedisplayFlags = { NONE: 0,
|
||||
RESET_CONTROLS: 1 << 0,
|
||||
FULL: 1 << 1,
|
||||
SUBSEARCH: 1 << 2 };
|
||||
|
||||
const ITEM_DISPLAY_NAME_COLOR = new Clutter.Color();
|
||||
ITEM_DISPLAY_NAME_COLOR.from_pixel(0xffffffff);
|
||||
const ITEM_DISPLAY_DESCRIPTION_COLOR = new Clutter.Color();
|
||||
@ -88,13 +93,12 @@ GenericDisplayItem.prototype = {
|
||||
spacing: DEFAULT_PADDING });
|
||||
this._infoContent.append(this._infoText, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
let global = Shell.Global.get();
|
||||
let infoIconUri = "file://" + global.imagedir + "info.svg";
|
||||
let infoIcon = Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.FOREVER,
|
||||
infoIconUri,
|
||||
INFORMATION_BUTTON_SIZE,
|
||||
INFORMATION_BUTTON_SIZE);
|
||||
this._informationButton = new Button.iconButton(this.actor, INFORMATION_BUTTON_SIZE, infoIcon);
|
||||
this._informationButton = new Button.IconButton(this.actor, INFORMATION_BUTTON_SIZE, infoIcon);
|
||||
let buttonBox = new Big.Box({ width: INFORMATION_BUTTON_SIZE + 2 * DEFAULT_PADDING,
|
||||
height: INFORMATION_BUTTON_SIZE,
|
||||
padding_left: DEFAULT_PADDING, padding_right: DEFAULT_PADDING,
|
||||
@ -122,12 +126,12 @@ GenericDisplayItem.prototype = {
|
||||
this._description = null;
|
||||
this._icon = null;
|
||||
|
||||
this._initialLoadComplete = false;
|
||||
|
||||
// An array of details description actors that we create over time for the item.
|
||||
// It is used for updating the description text inside the details actor when
|
||||
// the description text for the item is updated.
|
||||
this._detailsDescriptions = [];
|
||||
|
||||
this.dragActor = null;
|
||||
},
|
||||
|
||||
//// Draggable object interface ////
|
||||
@ -135,21 +139,9 @@ GenericDisplayItem.prototype = {
|
||||
// Returns a cloned texture of the item's icon to represent the item as it
|
||||
// is being dragged.
|
||||
getDragActor: function(stageX, stageY) {
|
||||
this.dragActor = this._createIcon();
|
||||
|
||||
// If the user dragged from the icon itself, then position
|
||||
// the dragActor over the original icon. Otherwise center it
|
||||
// around the pointer
|
||||
let [iconX, iconY] = this._icon.get_transformed_position();
|
||||
let [iconWidth, iconHeight] = this._icon.get_transformed_size();
|
||||
if (stageX > iconX && stageX <= iconX + iconWidth &&
|
||||
stageY > iconY && stageY <= iconY + iconHeight)
|
||||
this.dragActor.set_position(iconX, iconY);
|
||||
else
|
||||
this.dragActor.set_position(stageX - this.dragActor.width / 2, stageY - this.dragActor.height / 2);
|
||||
return this.dragActor;
|
||||
return this._createIcon();
|
||||
},
|
||||
|
||||
|
||||
// Returns the item icon, a separate copy of which is used to
|
||||
// represent the item as it is being dragged. This is used to
|
||||
// determine a snap-back location for the drag icon if it does
|
||||
@ -183,18 +175,14 @@ GenericDisplayItem.prototype = {
|
||||
/*
|
||||
* Returns an actor containing item details. In the future details can have more information than what
|
||||
* the preview pop-up has and be item-type specific.
|
||||
*
|
||||
* availableWidth - width available for displaying details
|
||||
*/
|
||||
createDetailsActor: function(availableWidth) {
|
||||
createDetailsActor: function() {
|
||||
|
||||
let details = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
spacing: PREVIEW_BOX_SPACING,
|
||||
width: availableWidth });
|
||||
spacing: PREVIEW_BOX_SPACING });
|
||||
|
||||
let mainDetails = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
spacing: PREVIEW_BOX_SPACING,
|
||||
width: availableWidth });
|
||||
spacing: PREVIEW_BOX_SPACING });
|
||||
|
||||
// Inner box with name and description
|
||||
let textDetails = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
@ -216,7 +204,7 @@ GenericDisplayItem.prototype = {
|
||||
mainDetails.append(textDetails, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
let previewIcon = this._createPreviewIcon();
|
||||
let largePreviewIcon = this._createLargePreviewIcon(availableWidth, -1);
|
||||
let largePreviewIcon = this._createLargePreviewIcon();
|
||||
|
||||
if (previewIcon != null && largePreviewIcon == null) {
|
||||
mainDetails.prepend(previewIcon, Big.BoxPackFlags.NONE);
|
||||
@ -303,7 +291,7 @@ GenericDisplayItem.prototype = {
|
||||
//// Virtual protected methods ////
|
||||
|
||||
// Creates and returns a large preview icon, but only if we have a detailed image.
|
||||
_createLargePreviewIcon : function(availableWidth, availableHeight) {
|
||||
_createLargePreviewIcon : function() {
|
||||
return null;
|
||||
},
|
||||
|
||||
@ -356,9 +344,10 @@ GenericDisplay.prototype = {
|
||||
|
||||
// map<itemId, Object> where Object represents the item info
|
||||
this._allItems = {};
|
||||
// an array of itemIds of items that match the current request
|
||||
// in the order in which the items should be displayed
|
||||
this._matchedItems = [];
|
||||
// set<itemId>
|
||||
this._matchedItems = {};
|
||||
// sorted array of items matched by search
|
||||
this._matchedItemKeys = [];
|
||||
// map<itemId, GenericDisplayItem>
|
||||
this._displayedItems = {};
|
||||
this._openDetailIndex = -1;
|
||||
@ -376,17 +365,29 @@ GenericDisplay.prototype = {
|
||||
|
||||
// Sets the search string and displays the matching items.
|
||||
setSearch: function(text) {
|
||||
this._search = text.toLowerCase();
|
||||
this._redisplay(true);
|
||||
let lowertext = text.toLowerCase();
|
||||
if (lowertext == this._search)
|
||||
return;
|
||||
let flags = RedisplayFlags.RESET_CONTROLS;
|
||||
if (this._search != '') {
|
||||
// Because we combine search terms with OR, we have to be sure that no new term
|
||||
// was introduced before deciding that the new search results will be a subset of
|
||||
// the existing search results.
|
||||
if (lowertext.indexOf(this._search) == 0 &&
|
||||
lowertext.split(/\s+/).length == this._search.split(/\s+/).length)
|
||||
flags |= RedisplayFlags.SUBSEARCH;
|
||||
}
|
||||
this._search = lowertext;
|
||||
this._redisplay(flags);
|
||||
},
|
||||
|
||||
// Launches the item that is currently selected, closing the overlay
|
||||
// Launches the item that is currently selected, closing the Overview
|
||||
activateSelected: function() {
|
||||
if (this._selectedIndex != -1) {
|
||||
let selected = this._findDisplayedByIndex(this._selectedIndex);
|
||||
selected.launch();
|
||||
this.unsetSelected();
|
||||
Main.overlay.hide();
|
||||
Main.overview.hide();
|
||||
}
|
||||
},
|
||||
|
||||
@ -445,12 +446,20 @@ GenericDisplay.prototype = {
|
||||
|
||||
// Returns true if the display has any displayed items.
|
||||
hasItems: function() {
|
||||
return this._list.displayedCount > 0;
|
||||
// TODO: figure out why this._list.displayedCount is returning a
|
||||
// positive number when this._mathedItems.length is 0
|
||||
// This can be triggered if a search string is entered for which there are no matches.
|
||||
// log("this._mathedItems.length: " + this._matchedItems.length + " this._list.displayedCount " + this._list.displayedCount);
|
||||
return this._matchedItemKeys.length > 0;
|
||||
},
|
||||
|
||||
getMatchedItemsCount: function() {
|
||||
return this._matchedItemKeys.length;
|
||||
},
|
||||
|
||||
// Load the initial state
|
||||
load: function() {
|
||||
this._redisplay(true);
|
||||
this._redisplay(RedisplayFlags.FULL);
|
||||
},
|
||||
|
||||
// Should be called when the display is closed
|
||||
@ -465,60 +474,32 @@ GenericDisplay.prototype = {
|
||||
return null;
|
||||
},
|
||||
|
||||
createDetailsForIndex: function(index, width, height) {
|
||||
createDetailsForIndex: function(index) {
|
||||
let item = this._findDisplayedByIndex(index);
|
||||
return item.createDetailsActor(width, height);
|
||||
return item.createDetailsActor();
|
||||
},
|
||||
|
||||
// Displays the page specified by the pageNumber argument.
|
||||
displayPage: function(pageNumber) {
|
||||
// Cleanup from the previous selection, but don't unset this._selectedIndex
|
||||
if (this.hasSelected()) {
|
||||
this._findDisplayedByIndex(this._selectedIndex).markSelected(false);
|
||||
}
|
||||
this._list.page = pageNumber;
|
||||
},
|
||||
|
||||
//// Protected methods ////
|
||||
|
||||
/*
|
||||
* Displays items that match the current request and should show up on the current page.
|
||||
* Updates the display control to reflect the matched items set and the page selected.
|
||||
*
|
||||
* resetDisplayControl - indicates if the display control should be re-created because
|
||||
* the results or the space allocated for them changed. If it's false,
|
||||
* the existing display control is used and only the page links are
|
||||
* updated to reflect the current page selection.
|
||||
*/
|
||||
_displayMatchedItems: function(resetDisplayControl) {
|
||||
// When generating a new list to display, we first remove all the old
|
||||
// displayed items which will unset the selection. So we need
|
||||
// to keep a flag which indicates if this display had the selection.
|
||||
let hadSelected = this.hasSelected();
|
||||
|
||||
_recreateDisplayItems: function() {
|
||||
this._removeAllDisplayItems();
|
||||
for (let i = 0; i < this._matchedItems.length; i++) {
|
||||
this._addDisplayItem(this._matchedItems[i]);
|
||||
this._setDefaultList();
|
||||
for (let itemId in this._allItems) {
|
||||
this._addDisplayItem(itemId);
|
||||
}
|
||||
|
||||
if (hadSelected) {
|
||||
this._selectedIndex = -1;
|
||||
this.selectFirstItem();
|
||||
}
|
||||
|
||||
// We currently redisplay matching items and raise the sideshow as part of two different callbacks.
|
||||
// Checking what is under the pointer after a timeout allows us to not merge these callbacks into one, at least for now.
|
||||
Mainloop.timeout_add(5,
|
||||
Lang.bind(this,
|
||||
function() {
|
||||
// Check if the pointer is over one of the items and display the information button if it is.
|
||||
let [child, x, y, mask] = Gdk.Screen.get_default().get_root_window().get_pointer();
|
||||
let global = Shell.Global.get();
|
||||
let actor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE,
|
||||
x, y);
|
||||
if (actor != null) {
|
||||
let item = this._findDisplayedByActor(actor);
|
||||
if (item != null) {
|
||||
item.onDrawnUnderPointer();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
},
|
||||
|
||||
// Creates a display item based on the information associated with itemId
|
||||
// and adds it to the displayed items.
|
||||
// Creates a display item based on the information associated with itemId
|
||||
// and adds it to the list of displayed items, but does not yet display it.
|
||||
_addDisplayItem : function(itemId) {
|
||||
if (this._displayedItems.hasOwnProperty(itemId)) {
|
||||
log("Tried adding a display item for " + itemId + ", but an item with this item id is already among displayed items.");
|
||||
@ -549,7 +530,6 @@ GenericDisplay.prototype = {
|
||||
this.emit('show-details', index);
|
||||
}
|
||||
}));
|
||||
this._list.add_actor(displayItem.actor);
|
||||
this._displayedItems[itemId] = displayItem;
|
||||
},
|
||||
|
||||
@ -588,33 +568,139 @@ GenericDisplay.prototype = {
|
||||
this.unsetSelected();
|
||||
},
|
||||
|
||||
_compareSearchMatch: function(a, b) {
|
||||
let countA = this._matchedItems[a];
|
||||
let countB = this._matchedItems[b];
|
||||
if (countA > countB)
|
||||
return -1;
|
||||
else if (countA < countB)
|
||||
return 1;
|
||||
else
|
||||
return this._compareItems(a, b);
|
||||
},
|
||||
|
||||
_setMatches: function(matches) {
|
||||
this._matchedItems = matches;
|
||||
this._matchedItemKeys = [];
|
||||
for (let itemId in this._matchedItems) {
|
||||
this._matchedItemKeys.push(itemId);
|
||||
}
|
||||
this._matchedItemKeys.sort(Lang.bind(this, this._compareSearchMatch));
|
||||
},
|
||||
|
||||
/**
|
||||
* _redisplaySubSearch:
|
||||
* A somewhat more optimized function called when we know
|
||||
* that we're going to be displaying a subset of the items
|
||||
* we already had, in the same order. In that case, we can
|
||||
* just hide the actors that shouldn't be shown.
|
||||
*/
|
||||
_redisplaySubSearch: function() {
|
||||
let matches = this._getSearchMatchedItems(true);
|
||||
|
||||
// Just hide all from the old set,
|
||||
// we'll show the ones we want below
|
||||
for (let itemId in this._displayedItems) {
|
||||
let item = this._displayedItems[itemId];
|
||||
item.actor.hide();
|
||||
}
|
||||
|
||||
this._setMatches(matches);
|
||||
|
||||
for (let itemId in matches) {
|
||||
let item = this._displayedItems[itemId];
|
||||
item.actor.show();
|
||||
}
|
||||
this._list.queue_relayout();
|
||||
},
|
||||
|
||||
_redisplayReordering: function() {
|
||||
if (!this._filterActive()) {
|
||||
this._setDefaultList();
|
||||
} else {
|
||||
this._setMatches(this._getSearchMatchedItems(false));
|
||||
}
|
||||
this._list.remove_all();
|
||||
for (let i = 0; i < this._matchedItemKeys.length; i++) {
|
||||
let itemId = this._matchedItemKeys[i];
|
||||
let item = this._displayedItems[itemId];
|
||||
item.actor.show();
|
||||
this._list.add_actor(item.actor);
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Updates the displayed items, applying the search string if one exists.
|
||||
*
|
||||
* resetPage - indicates if the page selection should be reset when displaying the matching results.
|
||||
* We reset the page selection when the change in results was initiated by the user by
|
||||
* entering a different search criteria or by viewing the results list in a different
|
||||
* size mode, but we keep the page selection the same if the results got updated on
|
||||
* their own while the user was browsing through the result pages.
|
||||
* @flags: Flags controlling redisplay behavior as follows:
|
||||
* RESET_CONTROLS - indicates if the page selection should be reset when displaying the matching results.
|
||||
* We reset the page selection when the change in results was initiated by the user by
|
||||
* entering a different search criteria or by viewing the results list in a different
|
||||
* size mode, but we keep the page selection the same if the results got updated on
|
||||
* their own while the user was browsing through the result pages.
|
||||
* SUBSEARCH - Indicates that the current _search is a superstring of the previous
|
||||
* one, which implies we only need to re-search through previous results.
|
||||
* FULL - Indicates that we need refresh all displayed items.
|
||||
*/
|
||||
_redisplay: function(resetPage) {
|
||||
this._refreshCache();
|
||||
if (!this._filterActive())
|
||||
this._setDefaultList();
|
||||
else
|
||||
this._doSearchFilter();
|
||||
_redisplay: function(flags) {
|
||||
let resetPage = (flags & RedisplayFlags.RESET_CONTROLS) > 0;
|
||||
let isSubSearch = (flags & RedisplayFlags.SUBSEARCH) > 0;
|
||||
let fullReload = (flags & RedisplayFlags.FULL) > 0;
|
||||
|
||||
let hadSelected = this.hasSelected();
|
||||
this.unsetSelected();
|
||||
|
||||
if (!this._initialLoadComplete)
|
||||
fullReload = true;
|
||||
|
||||
if (!this._refreshCache())
|
||||
fullReload = true;
|
||||
|
||||
if (fullReload) {
|
||||
this._recreateDisplayItems();
|
||||
this._initialLoadComplete = true;
|
||||
}
|
||||
|
||||
if (isSubSearch) {
|
||||
this._redisplaySubSearch();
|
||||
} else {
|
||||
this._redisplayReordering();
|
||||
}
|
||||
|
||||
if (resetPage)
|
||||
this._list.page = 0;
|
||||
|
||||
this._displayMatchedItems(true);
|
||||
if (hadSelected) {
|
||||
this._selectedIndex = -1;
|
||||
this.selectFirstItem();
|
||||
}
|
||||
|
||||
Mainloop.idle_add(Lang.bind(this, this._checkInformationIcon),
|
||||
Meta.PRIORITY_BEFORE_REDRAW);
|
||||
|
||||
this.emit('redisplayed');
|
||||
},
|
||||
|
||||
// Check if the pointer is over one of the items and display the information button if it is.
|
||||
// We want to do this between finishing our changes to the display and the point where
|
||||
// the display is redrawn.
|
||||
_checkInformationIcon: function() {
|
||||
let [child, x, y, mask] = Gdk.Screen.get_default().get_root_window().get_pointer();
|
||||
let actor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE,
|
||||
x, y);
|
||||
if (actor != null) {
|
||||
let item = this._findDisplayedByActor(actor);
|
||||
if (item != null) {
|
||||
item.onDrawnUnderPointer();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
//// Pure virtual protected methods ////
|
||||
|
||||
|
||||
// Performs the steps needed to have the latest information about the items.
|
||||
// Implementation should return %true if we are up to date, and %false
|
||||
// if a full reload occurred.
|
||||
_refreshCache: function() {
|
||||
throw new Error("Not implemented");
|
||||
},
|
||||
@ -646,76 +732,57 @@ GenericDisplay.prototype = {
|
||||
|
||||
//// Private methods ////
|
||||
|
||||
_getSearchMatchedItems: function() {
|
||||
let matchedItemsForSearch = {};
|
||||
_getItemSearchScore: function(itemId, terms) {
|
||||
let item = this._allItems[itemId];
|
||||
let score = 0;
|
||||
for (let i = 0; i < terms.length; i++) {
|
||||
let term = terms[i];
|
||||
if (this._isInfoMatching(item, term)) {
|
||||
score++;
|
||||
}
|
||||
}
|
||||
return score;
|
||||
},
|
||||
|
||||
_getSearchMatchedItems: function(isSubSearch) {
|
||||
// Break the search up into terms, and search for each
|
||||
// individual term. Keep track of the number of terms
|
||||
// each item matched.
|
||||
let terms = this._search.split(/\s+/);
|
||||
for (let i = 0; i < terms.length; i++) {
|
||||
let term = terms[i];
|
||||
for (itemId in this._allItems) {
|
||||
let item = this._allItems[itemId];
|
||||
if (this._isInfoMatching(item, term)) {
|
||||
let count = matchedItemsForSearch[itemId];
|
||||
if (!count)
|
||||
count = 0;
|
||||
count += 1;
|
||||
matchedItemsForSearch[itemId] = count;
|
||||
}
|
||||
let matchScores = {};
|
||||
|
||||
if (isSubSearch) {
|
||||
for (let i = 0; i < this._matchedItemKeys.length; i++) {
|
||||
let itemId = this._matchedItemKeys[i];
|
||||
let score = this._getItemSearchScore(itemId, terms);
|
||||
if (score > 0)
|
||||
matchScores[itemId] = score;
|
||||
}
|
||||
}
|
||||
return matchedItemsForSearch;
|
||||
},
|
||||
|
||||
// Applies the search string to the list of items to find matches,
|
||||
// and displays the matching items.
|
||||
_doSearchFilter: function() {
|
||||
let matchedItemsForSearch;
|
||||
|
||||
if (this._filterActive()) {
|
||||
matchedItemsForSearch = this._getSearchMatchedItems();
|
||||
} else {
|
||||
matchedItemsForSearch = {};
|
||||
for (let itemId in this._allItems) {
|
||||
matchedItemsForSearch[itemId] = 1;
|
||||
for (let itemId in this._displayedItems) {
|
||||
let score = this._getItemSearchScore(itemId, terms);
|
||||
if (score > 0)
|
||||
matchScores[itemId] = score;
|
||||
}
|
||||
}
|
||||
|
||||
this._matchedItems = [];
|
||||
for (itemId in matchedItemsForSearch) {
|
||||
this._matchedItems.push(itemId);
|
||||
}
|
||||
this._matchedItems.sort(Lang.bind(this, function (a, b) {
|
||||
let countA = matchedItemsForSearch[a];
|
||||
let countB = matchedItemsForSearch[b];
|
||||
if (countA > countB)
|
||||
return -1;
|
||||
else if (countA < countB)
|
||||
return 1;
|
||||
else
|
||||
return this._compareItems(a, b);
|
||||
}));
|
||||
},
|
||||
|
||||
// Displays the page specified by the pageNumber argument.
|
||||
_displayPage: function(pageNumber) {
|
||||
this._list.page = pageNumber;
|
||||
return matchScores;
|
||||
},
|
||||
|
||||
/*
|
||||
* Updates the display control to reflect the matched items set and the page selected.
|
||||
*
|
||||
* resetDisplayControl - indicates if the display control should be re-created because
|
||||
* resetDisplayControl - indicates if the display control should be re-created because
|
||||
* the results or the space allocated for them changed. If it's false,
|
||||
* the existing display control is used and only the page links are
|
||||
* updated to reflect the current page selection.
|
||||
*/
|
||||
_updateDisplayControl: function(resetDisplayControl) {
|
||||
if (resetDisplayControl) {
|
||||
this._selectedIndex = -1;
|
||||
this.displayControl.remove_all();
|
||||
let nPages = this._list.n_pages;
|
||||
// Don't show the page indicator if there is only one page.
|
||||
if (nPages == 1)
|
||||
return;
|
||||
let pageNumber = this._list.page;
|
||||
for (let i = 0; i < nPages; i++) {
|
||||
let pageControl = new Link.Link({ color: (i == pageNumber) ? DISPLAY_CONTROL_SELECTED_COLOR : ITEM_DISPLAY_DESCRIPTION_COLOR,
|
||||
@ -729,7 +796,7 @@ GenericDisplay.prototype = {
|
||||
pageControl.connect('clicked',
|
||||
Lang.bind(this,
|
||||
function(o, event) {
|
||||
this._displayPage(pageNumberLocalScope);
|
||||
this.displayPage(pageNumberLocalScope);
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
@ -745,6 +812,9 @@ GenericDisplay.prototype = {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.hasSelected()) {
|
||||
this.selectFirstItem();
|
||||
}
|
||||
},
|
||||
|
||||
// Returns a display item based on its index in the ordering of the
|
||||
@ -769,17 +839,8 @@ GenericDisplay.prototype = {
|
||||
// Selects (e.g. highlights) a display item at the provided index,
|
||||
// updates this.selectedItemDetails actor, and emits 'selected' signal.
|
||||
_selectIndex: function(index) {
|
||||
if (index >= this._list.displayedCount)
|
||||
return
|
||||
|
||||
// If the item is already selected, all we do is toggling the details pane.
|
||||
if (this._selectedIndex == index && index >= 0) {
|
||||
this.emit('details', index);
|
||||
return;
|
||||
}
|
||||
|
||||
// Cleanup from the previous item
|
||||
if (this._selectedIndex >= 0) {
|
||||
if (this.hasSelected()) {
|
||||
this._findDisplayedByIndex(this._selectedIndex).markSelected(false);
|
||||
}
|
||||
|
||||
|
151
js/ui/lightbox.js
Normal file
@ -0,0 +1,151 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Lang = imports.lang;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
const SHADE_COLOR = new Clutter.Color();
|
||||
SHADE_COLOR.from_pixel(0x00000044);
|
||||
|
||||
/**
|
||||
* Lightbox:
|
||||
* @container: parent Clutter.Container
|
||||
* @width: (optional) shade actor width
|
||||
* @height: (optional) shade actor height
|
||||
*
|
||||
* Lightbox creates a dark translucent "shade" actor to hide the
|
||||
* contents of @container, and allows you to specify particular actors
|
||||
* in @container to highlight by bringing them above the shade. It
|
||||
* tracks added and removed actors in @container while the lightboxing
|
||||
* is active, and ensures that all actors are returned to their
|
||||
* original stacking order when the lightboxing is removed. (However,
|
||||
* if actors are restacked by outside code while the lightboxing is
|
||||
* active, the lightbox may later revert them back to their original
|
||||
* order.)
|
||||
*
|
||||
* By default, the shade window will have the height and width of
|
||||
* @container and will track any changes in its size. You can override
|
||||
* this by passing an explicit width and height
|
||||
*/
|
||||
function Lightbox(container, width, height) {
|
||||
this._init(container, width, height);
|
||||
}
|
||||
|
||||
Lightbox.prototype = {
|
||||
_init : function(container, width, height) {
|
||||
this._container = container;
|
||||
this._children = container.get_children();
|
||||
this.actor = new Clutter.Rectangle({ color: SHADE_COLOR,
|
||||
x: 0,
|
||||
y: 0,
|
||||
border_width: 0,
|
||||
reactive: true });
|
||||
|
||||
container.add_actor(this.actor);
|
||||
this.actor.raise_top();
|
||||
|
||||
this._destroySignalId = this.actor.connect('destroy', Lang.bind(this, this.destroy));
|
||||
|
||||
if (width && height) {
|
||||
this.actor.width = width;
|
||||
this.actor.height = height;
|
||||
this._allocationChangedSignalId = 0;
|
||||
} else {
|
||||
this.actor.width = container.width;
|
||||
this.actor.height = container.height;
|
||||
this._allocationChangedSignalId = container.connect('allocation-changed', Lang.bind(this, this._allocationChanged));
|
||||
}
|
||||
|
||||
this._actorAddedSignalId = container.connect('actor-added', Lang.bind(this, this._actorAdded));
|
||||
this._actorRemovedSignalId = container.connect('actor-removed', Lang.bind(this, this._actorRemoved));
|
||||
|
||||
this._highlighted = null;
|
||||
},
|
||||
|
||||
_allocationChanged : function(container, box, flags) {
|
||||
this.actor.width = this._container.width;
|
||||
this.actor.height = this._container.height;
|
||||
},
|
||||
|
||||
_actorAdded : function(container, newChild) {
|
||||
let children = this._container.get_children();
|
||||
let myIndex = children.indexOf(this.actor);
|
||||
let newChildIndex = children.indexOf(newChild);
|
||||
|
||||
if (newChildIndex > myIndex) {
|
||||
// The child was added above the shade (presumably it was
|
||||
// made the new top-most child). Move it below the shade,
|
||||
// and add it to this._children as the new topmost actor.
|
||||
newChild.lower(this.actor);
|
||||
this._children.push(newChild);
|
||||
} else if (newChildIndex == 0) {
|
||||
// Bottom of stack
|
||||
this._children.unshift(newChild);
|
||||
} else {
|
||||
// Somewhere else; insert it into the correct spot
|
||||
let prevChild = this._children.indexOf(children[newChildIndex - 1]);
|
||||
if (prevChild != -1) // paranoia
|
||||
this._children.splice(prevChild + 1, 0, newChild);
|
||||
}
|
||||
},
|
||||
|
||||
_actorRemoved : function(container, child) {
|
||||
let index = this._children.indexOf(child);
|
||||
if (index != -1) // paranoia
|
||||
this._children.splice(index, 1);
|
||||
|
||||
if (child == this._highlighted)
|
||||
this._highlighted = null;
|
||||
},
|
||||
|
||||
/**
|
||||
* highlight:
|
||||
* @window: actor to highlight
|
||||
*
|
||||
* Highlights the indicated actor and unhighlights any other
|
||||
* currently-highlighted actor. With no arguments or a false/null
|
||||
* argument, all actors will be unhighlighted.
|
||||
*/
|
||||
highlight : function(window) {
|
||||
if (this._highlighted == window)
|
||||
return;
|
||||
|
||||
// Walk this._children raising and lowering actors as needed.
|
||||
// Things get a little tricky if the to-be-raised and
|
||||
// to-be-lowered actors were originally adjacent, in which
|
||||
// case we may need to indicate some *other* actor as the new
|
||||
// sibling of the to-be-lowered one.
|
||||
|
||||
let below = this.actor;
|
||||
for (let i = this._children.length - 1; i >= 0; i--) {
|
||||
if (this._children[i] == window)
|
||||
this._children[i].raise_top();
|
||||
else if (this._children[i] == this._highlighted)
|
||||
this._children[i].lower(below);
|
||||
else
|
||||
below = this._children[i];
|
||||
}
|
||||
|
||||
this._highlighted = window;
|
||||
},
|
||||
|
||||
/**
|
||||
* destroy:
|
||||
*
|
||||
* Destroys the lightbox. This is called automatically if the
|
||||
* lightbox's container is destroyed.
|
||||
*/
|
||||
destroy : function() {
|
||||
if (this._allocationChangedSignalId != 0)
|
||||
this._container.disconnect(this._allocationChangedSignalId);
|
||||
this._container.disconnect(this._actorAddedSignalId);
|
||||
this._container.disconnect(this._actorRemovedSignalId);
|
||||
|
||||
this.actor.disconnect(this._destroySignalId);
|
||||
|
||||
this.highlight(null);
|
||||
this.actor.destroy();
|
||||
}
|
||||
};
|
@ -4,6 +4,7 @@ const Big = imports.gi.Big;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Pango = imports.gi.Pango;
|
||||
const St = imports.gi.St;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const Lang = imports.lang;
|
||||
@ -12,18 +13,7 @@ const Mainloop = imports.mainloop;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const Main = imports.ui.main;
|
||||
|
||||
const LG_BORDER_COLOR = new Clutter.Color();
|
||||
LG_BORDER_COLOR.from_pixel(0x0000aca0);
|
||||
const LG_BACKGROUND_COLOR = new Clutter.Color();
|
||||
LG_BACKGROUND_COLOR.from_pixel(0x000000d5);
|
||||
const GREY = new Clutter.Color();
|
||||
GREY.from_pixel(0xAFAFAFFF);
|
||||
const MATRIX_GREEN = new Clutter.Color();
|
||||
MATRIX_GREEN.from_pixel(0x88ff66ff);
|
||||
// FIXME pull from GConf
|
||||
const MATRIX_FONT = 'Monospace 10';
|
||||
|
||||
/* Imports...feel free to add here as needed */
|
||||
/* Imports...feel free to add here as needed */
|
||||
var commandHeader = "const Clutter = imports.gi.Clutter; " +
|
||||
"const GLib = imports.gi.GLib; " +
|
||||
"const Gtk = imports.gi.Gtk; " +
|
||||
@ -35,7 +25,6 @@ var commandHeader = "const Clutter = imports.gi.Clutter; " +
|
||||
"const Tweener = imports.ui.tweener; " +
|
||||
/* Utility functions...we should probably be able to use these
|
||||
* in the shell core code too. */
|
||||
"const global = Shell.Global.get(); " +
|
||||
"const stage = global.stage; " +
|
||||
"const color = function(pixel) { let c= new Clutter.Color(); c.from_pixel(pixel); return c; }; " +
|
||||
/* Special lookingGlass functions */
|
||||
@ -48,7 +37,7 @@ function Notebook() {
|
||||
|
||||
Notebook.prototype = {
|
||||
_init: function() {
|
||||
this.actor = new Big.Box();
|
||||
this.actor = new St.BoxLayout({ vertical: true });
|
||||
|
||||
this.tabControls = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
spacing: 4, padding: 2 });
|
||||
@ -59,21 +48,24 @@ Notebook.prototype = {
|
||||
|
||||
appendPage: function(name, child) {
|
||||
let labelOuterBox = new Big.Box({ padding: 2 });
|
||||
let labelBox = new Big.Box({ padding: 2, border_color: MATRIX_GREEN,
|
||||
reactive: true });
|
||||
let labelBox = new St.BoxLayout({ reactive: true });
|
||||
labelOuterBox.append(labelBox, Big.BoxPackFlags.NONE);
|
||||
let label = new Clutter.Text({ color: MATRIX_GREEN,
|
||||
font_name: MATRIX_FONT,
|
||||
text: name });
|
||||
let label = new St.Label({ text: name });
|
||||
labelBox.connect('button-press-event', Lang.bind(this, function () {
|
||||
this.selectChild(child);
|
||||
return true;
|
||||
}));
|
||||
labelBox.append(label, Big.BoxPackFlags.EXPAND);
|
||||
this._tabs.push([child, labelBox]);
|
||||
child.hide();
|
||||
this.actor.append(child, Big.BoxPackFlags.EXPAND);
|
||||
labelBox.add(label, { expand: true });
|
||||
this.tabControls.append(labelOuterBox, Big.BoxPackFlags.NONE);
|
||||
|
||||
let scrollview = new St.ScrollView({ x_fill: true, y_fill: true });
|
||||
scrollview.get_hscroll_bar().hide();
|
||||
scrollview.add_actor(child);
|
||||
|
||||
this._tabs.push([child, labelBox, scrollview]);
|
||||
scrollview.hide();
|
||||
this.actor.add(scrollview, { expand: true });
|
||||
|
||||
if (this._selectedIndex == -1)
|
||||
this.selectIndex(0);
|
||||
},
|
||||
@ -81,10 +73,10 @@ Notebook.prototype = {
|
||||
_unselect: function() {
|
||||
if (this._selectedIndex < 0)
|
||||
return;
|
||||
let [child, labelBox] = this._tabs[this._selectedIndex];
|
||||
let [child, labelBox, scrollview] = this._tabs[this._selectedIndex];
|
||||
labelBox.padding = 2;
|
||||
labelBox.border = 0;
|
||||
child.hide();
|
||||
scrollview.hide();
|
||||
this._selectedIndex = -1;
|
||||
},
|
||||
|
||||
@ -96,10 +88,10 @@ Notebook.prototype = {
|
||||
this.emit('selection', null);
|
||||
return;
|
||||
}
|
||||
let [child, labelBox] = this._tabs[index];
|
||||
let [child, labelBox, scrollview] = this._tabs[index];
|
||||
labelBox.padding = 1;
|
||||
labelBox.border = 1;
|
||||
child.show();
|
||||
scrollview.show();
|
||||
this._selectedIndex = index;
|
||||
this.emit('selection', child);
|
||||
},
|
||||
@ -109,7 +101,7 @@ Notebook.prototype = {
|
||||
this.selectIndex(-1);
|
||||
else {
|
||||
for (let i = 0; i < this._tabs.length; i++) {
|
||||
let [tabChild, labelBox] = this._tabs[i];
|
||||
let [tabChild, labelBox, scrollview] = this._tabs[i];
|
||||
if (tabChild == child) {
|
||||
this.selectIndex(i);
|
||||
return;
|
||||
@ -131,20 +123,19 @@ Result.prototype = {
|
||||
|
||||
this.actor = new Big.Box();
|
||||
|
||||
let cmdTxt = new Clutter.Text({ color: MATRIX_GREEN,
|
||||
font_name: MATRIX_FONT,
|
||||
ellipsize: Pango.EllipsizeMode.END,
|
||||
text: command });
|
||||
let cmdTxt = new St.Label({ text: command });
|
||||
cmdTxt.ellipsize = Pango.EllipsizeMode.END;
|
||||
|
||||
this.actor.append(cmdTxt, Big.BoxPackFlags.NONE);
|
||||
let resultTxt = new Clutter.Text({ color: MATRIX_GREEN,
|
||||
font_name: MATRIX_FONT,
|
||||
ellipsize: Pango.EllipsizeMode.END,
|
||||
text: "r(" + index + ") = " + o });
|
||||
let resultTxt = new St.Label({ text: "r(" + index + ") = " + o });
|
||||
resultTxt.ellipsize = Pango.EllipsizeMode.END;
|
||||
|
||||
this.actor.append(resultTxt, Big.BoxPackFlags.NONE);
|
||||
let line = new Big.Box({ border_color: GREY,
|
||||
border_bottom: 1,
|
||||
height: 8 });
|
||||
this.actor.append(line, Big.BoxPackFlags.NONE);
|
||||
let line = new Clutter.Rectangle({ name: "Separator",
|
||||
height: 1 });
|
||||
let padBin = new St.Bin({ name: "Separator", x_fill: true, y_fill: true });
|
||||
padBin.add_actor(line);
|
||||
this.actor.append(padBin, Big.BoxPackFlags.NONE);
|
||||
}
|
||||
}
|
||||
|
||||
@ -159,17 +150,14 @@ ActorHierarchy.prototype = {
|
||||
|
||||
this._parentList = [];
|
||||
|
||||
this.actor = new Big.Box({ spacing: 4,
|
||||
border: 1,
|
||||
padding: 4,
|
||||
border_color: GREY });
|
||||
this.actor = new St.BoxLayout({ name: "ActorHierarchy", vertical: true });
|
||||
},
|
||||
|
||||
setTarget: function(actor) {
|
||||
this._previousTarget = this._target;
|
||||
this.target = actor;
|
||||
|
||||
this.actor.remove_all();
|
||||
this.actor.get_children().forEach(function (child) { child.destroy(); });
|
||||
|
||||
if (!(actor instanceof Clutter.Actor))
|
||||
return;
|
||||
@ -182,11 +170,9 @@ ActorHierarchy.prototype = {
|
||||
while ((parent = parent.get_parent()) != null) {
|
||||
this._parentList.push(parent);
|
||||
|
||||
let link = new Clutter.Text({ color: MATRIX_GREEN,
|
||||
font_name: MATRIX_FONT,
|
||||
reactive: true,
|
||||
text: "" + parent });
|
||||
this.actor.append(link, Big.BoxPackFlags.IF_FITS);
|
||||
let link = new St.Label({ reactive: true,
|
||||
text: "" + parent });
|
||||
this.actor.add_actor(link);
|
||||
let parentTarget = parent;
|
||||
link.connect('button-press-event', Lang.bind(this, function () {
|
||||
this._selectByActor(parentTarget);
|
||||
@ -215,16 +201,13 @@ PropertyInspector.prototype = {
|
||||
|
||||
this._parentList = [];
|
||||
|
||||
this.actor = new Big.Box({ spacing: 4,
|
||||
border: 1,
|
||||
padding: 4,
|
||||
border_color: GREY });
|
||||
this.actor = new St.BoxLayout({ name: "PropertyInspector", vertical: true });
|
||||
},
|
||||
|
||||
setTarget: function(actor) {
|
||||
this.target = actor;
|
||||
|
||||
this.actor.remove_all();
|
||||
this.actor.get_children().forEach(function (child) { child.destroy(); });
|
||||
|
||||
for (let propName in actor) {
|
||||
let valueStr;
|
||||
@ -234,11 +217,9 @@ PropertyInspector.prototype = {
|
||||
valueStr = '<error>';
|
||||
}
|
||||
let propText = propName + ": " + valueStr;
|
||||
let propDisplay = new Clutter.Text({ color: MATRIX_GREEN,
|
||||
font_name: MATRIX_FONT,
|
||||
reactive: true,
|
||||
text: propText });
|
||||
this.actor.append(propDisplay, Big.BoxPackFlags.IF_FITS);
|
||||
let propDisplay = new St.Label({ reactive: true,
|
||||
text: propText });
|
||||
this.actor.add_actor(propDisplay);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -249,22 +230,18 @@ function Inspector() {
|
||||
|
||||
Inspector.prototype = {
|
||||
_init: function() {
|
||||
let global = Shell.Global.get();
|
||||
let width = 150;
|
||||
let eventHandler = new Big.Box({ background_color: LG_BACKGROUND_COLOR,
|
||||
border: 1,
|
||||
border_color: LG_BORDER_COLOR,
|
||||
corner_radius: 4,
|
||||
y: global.stage.height/2,
|
||||
reactive: true
|
||||
});
|
||||
let primary = global.get_primary_monitor();
|
||||
let eventHandler = new St.BoxLayout({ name: "LookingGlassDialog",
|
||||
vertical: false,
|
||||
y: primary.y + Math.floor(primary.height / 2),
|
||||
reactive: true });
|
||||
eventHandler.connect('notify::allocation', Lang.bind(this, function () {
|
||||
eventHandler.x = Math.floor((global.stage.width)/2 - (eventHandler.width)/2);
|
||||
eventHandler.x = primary.x + Math.floor((primary.width - eventHandler.width) / 2);
|
||||
}));
|
||||
global.stage.add_actor(eventHandler);
|
||||
let displayText = new Clutter.Text({ color: MATRIX_GREEN,
|
||||
font_name: MATRIX_FONT, text: '' });
|
||||
eventHandler.append(displayText, Big.BoxPackFlags.EXPAND);
|
||||
let displayText = new St.Label();
|
||||
eventHandler.add(displayText, { expand: true });
|
||||
|
||||
let borderPaintTarget = null;
|
||||
let borderPaintId = null;
|
||||
@ -274,7 +251,6 @@ Inspector.prototype = {
|
||||
}));
|
||||
|
||||
eventHandler.connect('button-press-event', Lang.bind(this, function (actor, event) {
|
||||
let global = Shell.Global.get();
|
||||
Clutter.ungrab_pointer(eventHandler);
|
||||
|
||||
let [stageX, stageY] = event.get_coords();
|
||||
@ -288,7 +264,6 @@ Inspector.prototype = {
|
||||
}));
|
||||
|
||||
eventHandler.connect('motion-event', Lang.bind(this, function (actor, event) {
|
||||
let global = Shell.Global.get();
|
||||
let [stageX, stageY] = event.get_coords();
|
||||
let target = global.stage.get_actor_at_pos(Clutter.PickMode.ALL,
|
||||
stageX,
|
||||
@ -312,8 +287,6 @@ function LookingGlass() {
|
||||
|
||||
LookingGlass.prototype = {
|
||||
_init : function() {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
this._idleHistorySaveId = 0;
|
||||
let historyPath = global.configdir + "/lookingglass-history.txt";
|
||||
this._historyFile = Gio.file_new_for_path(historyPath);
|
||||
@ -327,29 +300,26 @@ LookingGlass.prototype = {
|
||||
this._offset = 0;
|
||||
this._results = [];
|
||||
|
||||
// TODO replace with scrolling or something better
|
||||
this._maxItems = 10;
|
||||
// Sort of magic, but...eh.
|
||||
this._maxItems = 150;
|
||||
|
||||
this.actor = new St.BoxLayout({ name: "LookingGlassDialog",
|
||||
vertical: true,
|
||||
visible: false });
|
||||
|
||||
let gconf = Shell.GConf.get_default();
|
||||
gconf.watch_directory("/desktop/gnome/interface");
|
||||
gconf.connect("changed::/desktop/gnome/interface/monospace_font_name",
|
||||
Lang.bind(this, this._updateFont));
|
||||
this._updateFont();
|
||||
|
||||
this.actor = new Big.Box({ background_color: LG_BACKGROUND_COLOR,
|
||||
border: 1,
|
||||
border_color: LG_BORDER_COLOR,
|
||||
corner_radius: 4,
|
||||
padding_top: 8,
|
||||
padding_left: 4,
|
||||
padding_right: 4,
|
||||
padding_bottom: 4,
|
||||
spacing: 4,
|
||||
visible: false
|
||||
});
|
||||
global.stage.add_actor(this.actor);
|
||||
|
||||
let toolbar = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
border: 1, border_color: GREY,
|
||||
corner_radius: 4 });
|
||||
this.actor.append(toolbar, Big.BoxPackFlags.NONE);
|
||||
let toolbar = new St.BoxLayout({ name: "Toolbar" });
|
||||
this.actor.add_actor(toolbar);
|
||||
let inspectIcon = Shell.TextureCache.get_default().load_gicon(new Gio.ThemedIcon({ name: 'gtk-color-picker' }),
|
||||
24);
|
||||
toolbar.append(inspectIcon, Big.BoxPackFlags.NONE);
|
||||
toolbar.add_actor(inspectIcon);
|
||||
inspectIcon.reactive = true;
|
||||
inspectIcon.connect('button-press-event', Lang.bind(this, function () {
|
||||
let inspector = new Inspector();
|
||||
@ -367,32 +337,27 @@ LookingGlass.prototype = {
|
||||
}));
|
||||
|
||||
let notebook = new Notebook();
|
||||
this.actor.append(notebook.actor, Big.BoxPackFlags.EXPAND);
|
||||
toolbar.append(notebook.tabControls, Big.BoxPackFlags.END);
|
||||
this.actor.add(notebook.actor, { expand: true });
|
||||
|
||||
this._evalBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
spacing: 4 });
|
||||
let emptyBox = new St.Bin();
|
||||
toolbar.add(emptyBox, { expand: true });
|
||||
toolbar.add_actor(notebook.tabControls);
|
||||
|
||||
this._evalBox = new St.BoxLayout({ name: "EvalBox", vertical: true });
|
||||
notebook.appendPage('Evaluator', this._evalBox);
|
||||
|
||||
this._resultsArea = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
spacing: 4 });
|
||||
this._evalBox.append(this._resultsArea, Big.BoxPackFlags.EXPAND);
|
||||
this._evalBox.add(this._resultsArea, { expand: true });
|
||||
|
||||
let entryArea = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL });
|
||||
this._evalBox.append(entryArea, Big.BoxPackFlags.NONE);
|
||||
this._evalBox.add_actor(entryArea);
|
||||
|
||||
let label = new Clutter.Text({ color: MATRIX_GREEN,
|
||||
font_name: MATRIX_FONT,
|
||||
text: 'js>>> ' });
|
||||
let label = new St.Label({ text: 'js>>> ' });
|
||||
entryArea.append(label, Big.BoxPackFlags.NONE);
|
||||
|
||||
this._entry = new Clutter.Text({ color: MATRIX_GREEN,
|
||||
font_name: MATRIX_FONT,
|
||||
editable: true,
|
||||
activatable: true,
|
||||
singleLineMode: true,
|
||||
text: ''});
|
||||
/* kind of a hack */
|
||||
this._entry = new St.Entry();
|
||||
/* unmapping the edit box will un-focus it, undo that */
|
||||
notebook.connect('selection', Lang.bind(this, function (nb, child) {
|
||||
if (child == this._evalBox)
|
||||
global.stage.set_key_focus(this._entry);
|
||||
@ -409,7 +374,7 @@ LookingGlass.prototype = {
|
||||
notebook.selectIndex(0);
|
||||
}));
|
||||
|
||||
this._entry.connect('activate', Lang.bind(this, function (o, e) {
|
||||
this._entry.clutter_text.connect('activate', Lang.bind(this, function (o, e) {
|
||||
let text = o.get_text();
|
||||
// Ensure we don't get newlines in the command; the history file is
|
||||
// newline-separated.
|
||||
@ -422,8 +387,8 @@ LookingGlass.prototype = {
|
||||
this._historyNavIndex = -1;
|
||||
return true;
|
||||
}));
|
||||
this._entry.connect('key-press-event', Lang.bind(this, function(o, e) {
|
||||
let symbol = Shell.get_event_key_symbol(e);
|
||||
this._entry.clutter_text.connect('key-press-event', Lang.bind(this, function(o, e) {
|
||||
let symbol = e.get_key_symbol();
|
||||
if (symbol == Clutter.Escape) {
|
||||
this.close();
|
||||
return true;
|
||||
@ -452,6 +417,19 @@ LookingGlass.prototype = {
|
||||
}));
|
||||
},
|
||||
|
||||
_updateFont: function() {
|
||||
let gconf = Shell.GConf.get_default();
|
||||
let fontName = gconf.get_string("/desktop/gnome/interface/monospace_font_name");
|
||||
// This is mishandled by the scanner - should by Pango.FontDescription_from_string(fontName);
|
||||
// https://bugzilla.gnome.org/show_bug.cgi?id=595889
|
||||
let fontDesc = Pango.Font.description_from_string(fontName);
|
||||
// We ignore everything but size and style; you'd be crazy to set your system-wide
|
||||
// monospace font to be bold/oblique/etc. Could easily be added here.
|
||||
this.actor.style =
|
||||
'font-size: ' + fontDesc.get_size() / 1024. + (fontDesc.get_size_is_absolute() ? 'px' : 'pt') + ';'
|
||||
+ 'font-family: "' + fontDesc.get_family() + '";';
|
||||
},
|
||||
|
||||
_readHistory: function () {
|
||||
if (!this._historyFile.query_exists(null))
|
||||
return;
|
||||
@ -524,12 +502,11 @@ LookingGlass.prototype = {
|
||||
},
|
||||
|
||||
_resizeTo: function(actor) {
|
||||
let stage = Shell.Global.get().stage;
|
||||
let stageWidth = stage.width;
|
||||
let myWidth = stage.width * 0.7;
|
||||
let myHeight = stage.height * 0.7;
|
||||
let primary = global.get_primary_monitor();
|
||||
let myWidth = primary.width * 0.7;
|
||||
let myHeight = primary.height * 0.7;
|
||||
let [srcX, srcY] = actor.get_transformed_position();
|
||||
this.actor.x = srcX + (stage.width-myWidth)/2;
|
||||
this.actor.x = srcX + (primary.width - myWidth) / 2;
|
||||
this._hiddenY = srcY + actor.height - myHeight - 4; // -4 to hide the top corners
|
||||
this._targetY = this._hiddenY + myHeight;
|
||||
this.actor.y = this._hiddenY;
|
||||
@ -549,16 +526,15 @@ LookingGlass.prototype = {
|
||||
if (this._open)
|
||||
return;
|
||||
|
||||
if (!Main.pushModal(this.actor))
|
||||
return;
|
||||
|
||||
this.actor.show();
|
||||
this.actor.lower(Main.chrome.actor);
|
||||
this._open = true;
|
||||
|
||||
Tweener.removeTweens(this.actor);
|
||||
|
||||
if (!Main.startModal())
|
||||
return;
|
||||
|
||||
let global = Shell.Global.get();
|
||||
global.stage.set_key_focus(this._entry);
|
||||
|
||||
Tweener.addTween(this.actor, { time: 0.5,
|
||||
@ -575,7 +551,7 @@ LookingGlass.prototype = {
|
||||
this._open = false;
|
||||
Tweener.removeTweens(this.actor);
|
||||
|
||||
Main.endModal();
|
||||
Main.popModal(this.actor);
|
||||
|
||||
Tweener.addTween(this.actor, { time: 0.5,
|
||||
transition: "easeOutQuad",
|
||||
|
279
js/ui/main.js
@ -1,21 +1,25 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const DBus = imports.dbus;
|
||||
const Gdk = imports.gi.Gdk;
|
||||
const Gio = imports.gi.Gio;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const Chrome = imports.ui.chrome;
|
||||
const Overlay = imports.ui.overlay;
|
||||
const Environment = imports.ui.environment;
|
||||
const Overview = imports.ui.overview;
|
||||
const Panel = imports.ui.panel;
|
||||
const RunDialog = imports.ui.runDialog;
|
||||
const LookingGlass = imports.ui.lookingGlass;
|
||||
const ShellDBus = imports.ui.shellDBus;
|
||||
const Sidebar = imports.ui.sidebar;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const WindowManager = imports.ui.windowManager;
|
||||
|
||||
const DEFAULT_BACKGROUND_COLOR = new Clutter.Color();
|
||||
@ -24,21 +28,42 @@ DEFAULT_BACKGROUND_COLOR.from_pixel(0x2266bbff);
|
||||
let chrome = null;
|
||||
let panel = null;
|
||||
let sidebar = null;
|
||||
let overlay = null;
|
||||
let overview = null;
|
||||
let runDialog = null;
|
||||
let lookingGlass = null;
|
||||
let wm = null;
|
||||
let recorder = null;
|
||||
let inModal = false;
|
||||
let shellDBusService = null;
|
||||
let modalCount = 0;
|
||||
let modalActorFocusStack = [];
|
||||
|
||||
function start() {
|
||||
let global = Shell.Global.get();
|
||||
// Add a binding for "global" in the global JS namespace; (gjs
|
||||
// keeps the web browser convention of having that namespace be
|
||||
// called "window".)
|
||||
window.global = Shell.Global.get();
|
||||
|
||||
Gio.DesktopAppInfo.set_desktop_env("GNOME");
|
||||
|
||||
global.grab_dbus_service();
|
||||
shellDBusService = new ShellDBus.GnomeShell();
|
||||
// Force a connection now; dbus.js will do this internally
|
||||
// if we use its name acquisition stuff but we aren't right
|
||||
// now; to do so we'd need to convert from its async calls
|
||||
// back into sync ones.
|
||||
DBus.session.flush();
|
||||
|
||||
Tweener.init();
|
||||
Environment.init();
|
||||
|
||||
// Ensure ShellAppMonitor is initialized; this will
|
||||
// also initialize ShellAppSystem first. ShellAppSystem
|
||||
// needs to load all the .desktop files, and ShellAppMonitor
|
||||
// will use those to associate with windows. Right now
|
||||
// the Monitor doesn't listen for installed app changes
|
||||
// and recalculate application associations, so to avoid
|
||||
// races for now we initialize it here. It's better to
|
||||
// be predictable anyways.
|
||||
Shell.AppMonitor.get_default();
|
||||
|
||||
// The background color really only matters if there is no desktop
|
||||
// window (say, nautilus) running. We set it mostly so things look good
|
||||
@ -46,25 +71,36 @@ function start() {
|
||||
global.stage.color = DEFAULT_BACKGROUND_COLOR;
|
||||
|
||||
// Mutter currently hardcodes putting "Yessir. The compositor is running""
|
||||
// in the overlay. Clear that out.
|
||||
// in the Overview. Clear that out.
|
||||
let children = global.overlay_group.get_children();
|
||||
for (let i = 0; i < children.length; i++)
|
||||
children[i].destroy();
|
||||
|
||||
let themeContext = St.ThemeContext.get_for_stage (global.stage);
|
||||
let stylesheetPath = global.datadir + "/theme/gnome-shell.css";
|
||||
let theme = new St.Theme ({ application_stylesheet: stylesheetPath });
|
||||
themeContext.set_theme (theme);
|
||||
|
||||
global.connect('panel-run-dialog', function(panel) {
|
||||
// Make sure not more than one run dialog is shown.
|
||||
if (runDialog == null) {
|
||||
runDialog = new RunDialog.RunDialog();
|
||||
}
|
||||
runDialog.open();
|
||||
getRunDialog().open();
|
||||
});
|
||||
let shellwm = global.window_manager;
|
||||
shellwm.takeover_keybinding("panel_main_menu");
|
||||
shellwm.connect("keybinding::panel_main_menu", function () {
|
||||
overview.toggle();
|
||||
});
|
||||
shellwm.takeover_keybinding("panel_run_dialog");
|
||||
shellwm.connect("keybinding::panel_run_dialog", function () {
|
||||
getRunDialog().open();
|
||||
});
|
||||
|
||||
overlay = new Overlay.Overlay();
|
||||
overview = new Overview.Overview();
|
||||
chrome = new Chrome.Chrome();
|
||||
panel = new Panel.Panel();
|
||||
sidebar = new Sidebar.Sidebar();
|
||||
wm = new WindowManager.WindowManager();
|
||||
|
||||
|
||||
global.screen.connect('toggle-recording', function() {
|
||||
if (recorder == null) {
|
||||
recorder = new Shell.Recorder({ stage: global.stage });
|
||||
@ -77,15 +113,26 @@ function start() {
|
||||
}
|
||||
});
|
||||
|
||||
_relayout();
|
||||
|
||||
panel.startupAnimation();
|
||||
|
||||
let display = global.screen.get_display();
|
||||
display.connect('overlay-key', Lang.bind(overlay, overlay.toggle));
|
||||
global.connect('panel-main-menu', Lang.bind(overlay, overlay.toggle));
|
||||
|
||||
display.connect('overlay-key', Lang.bind(overview, overview.toggle));
|
||||
global.connect('panel-main-menu', Lang.bind(overview, overview.toggle));
|
||||
|
||||
global.stage.connect('captured-event', _globalKeyPressHandler);
|
||||
|
||||
Mainloop.idle_add(_removeUnusedWorkspaces);
|
||||
}
|
||||
|
||||
function _relayout() {
|
||||
let primary = global.get_primary_monitor();
|
||||
panel.actor.set_position(primary.x, primary.y);
|
||||
panel.actor.set_size(primary.width, Panel.PANEL_HEIGHT);
|
||||
overview.relayout();
|
||||
}
|
||||
|
||||
// metacity-clutter currently uses the same prefs as plain metacity,
|
||||
// which probably means we'll be starting out with multiple workspaces;
|
||||
// remove any unused ones. (We do this from an idle handler, because
|
||||
@ -93,8 +140,6 @@ function start() {
|
||||
// is called.)
|
||||
function _removeUnusedWorkspaces() {
|
||||
|
||||
let global = Shell.Global.get();
|
||||
|
||||
let windows = global.get_windows();
|
||||
let maxWorkspace = 0;
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
@ -116,27 +161,136 @@ function _removeUnusedWorkspaces() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Used to go into a mode where all keyboard and mouse input goes to
|
||||
// the stage. Returns true if we successfully grabbed the keyboard and
|
||||
// went modal, false otherwise
|
||||
function startModal() {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
if (!global.grab_keyboard())
|
||||
// This function encapsulates hacks to make certain global keybindings
|
||||
// work even when we are in one of our modes where global keybindings
|
||||
// are disabled with a global grab. (When there is a global grab, then
|
||||
// all key events will be delivered to the stage, so ::captured-event
|
||||
// on the stage can be used for global keybindings.)
|
||||
//
|
||||
// We expect to need to conditionally enable just a few keybindings
|
||||
// depending on circumstance; the main hackiness here is that we are
|
||||
// assuming that keybindings have their default values; really we
|
||||
// should be asking Mutter to resolve the key into an action and then
|
||||
// base our handling based on the action.
|
||||
function _globalKeyPressHandler(actor, event) {
|
||||
if (modalCount == 0)
|
||||
return false;
|
||||
|
||||
let type = event.type();
|
||||
|
||||
if (type == Clutter.EventType.KEY_PRESS) {
|
||||
let symbol = event.get_key_symbol();
|
||||
if (symbol == Clutter.Print) {
|
||||
// We want to be able to take screenshots of the shell at all times
|
||||
let gconf = Shell.GConf.get_default();
|
||||
let command = gconf.get_string("/apps/metacity/keybinding_commands/command_screenshot");
|
||||
if (command != null && command != "") {
|
||||
let [ok, len, args] = GLib.shell_parse_argv(command);
|
||||
let p = new Shell.Process({'args' : args});
|
||||
p.run();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} else if (type == Clutter.EventType.KEY_RELEASE) {
|
||||
let symbol = event.get_key_symbol();
|
||||
if (symbol == Clutter.Super_L || symbol == Clutter.Super_R) {
|
||||
// The super key is the default for triggering the overview, and should
|
||||
// get us out of the overview when we are already in it.
|
||||
if (overview.visible)
|
||||
overview.hide();
|
||||
|
||||
return true;
|
||||
} else if (symbol == Clutter.F2 && (Shell.get_event_state(event) & Clutter.ModifierType.MOD1_MASK)) {
|
||||
getRunDialog().open();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function _findModal(actor) {
|
||||
for (let i = 0; i < modalActorFocusStack.length; i++) {
|
||||
let [stackActor, stackFocus] = modalActorFocusStack[i];
|
||||
if (stackActor == actor) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* pushModal:
|
||||
* @actor: #ClutterActor which will be given keyboard focus
|
||||
*
|
||||
* Ensure we are in a mode where all keyboard and mouse input goes to
|
||||
* the stage. Multiple calls to this function act in a stacking fashion;
|
||||
* the effect will be undone when an equal number of popModal() invocations
|
||||
* have been made.
|
||||
*
|
||||
* Next, record the current Clutter keyboard focus on a stack. If the modal stack
|
||||
* returns to this actor, reset the focus to the actor which was focused
|
||||
* at the time pushModal() was invoked.
|
||||
*
|
||||
* Returns: true iff we successfully acquired a grab or already had one
|
||||
*/
|
||||
function pushModal(actor) {
|
||||
if (modalCount == 0) {
|
||||
if (!global.begin_modal(currentTime())) {
|
||||
log("pushModal: invocation of begin_modal failed");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
global.set_stage_input_mode(Shell.StageInputMode.FULLSCREEN);
|
||||
|
||||
inModal = true;
|
||||
modalCount += 1;
|
||||
actor.connect('destroy', function() {
|
||||
let index = _findModal(actor);
|
||||
if (index >= 0)
|
||||
modalActorFocusStack.splice(index, 1);
|
||||
});
|
||||
let curFocus = global.stage.get_key_focus();
|
||||
if (curFocus != null) {
|
||||
curFocus.connect('destroy', function() {
|
||||
let index = _findModal(actor);
|
||||
if (index >= 0)
|
||||
modalActorFocusStack[index][1] = null;
|
||||
});
|
||||
}
|
||||
modalActorFocusStack.push([actor, curFocus]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function endModal() {
|
||||
let global = Shell.Global.get();
|
||||
/**
|
||||
* popModal:
|
||||
* @actor: #ClutterActor passed to original invocation of pushModal().
|
||||
*
|
||||
* Reverse the effect of pushModal(). If this invocation is undoing
|
||||
* the topmost invocation, then the focus will be restored to the
|
||||
* previous focus at the time when pushModal() was invoked.
|
||||
*/
|
||||
function popModal(actor) {
|
||||
modalCount -= 1;
|
||||
let focusIndex = _findModal(actor);
|
||||
if (focusIndex >= 0) {
|
||||
if (focusIndex == modalActorFocusStack.length - 1) {
|
||||
let [stackActor, stackFocus] = modalActorFocusStack[focusIndex];
|
||||
global.stage.set_key_focus(stackFocus);
|
||||
} else {
|
||||
// Remove from the middle, shift the focus chain up
|
||||
for (let i = focusIndex; i < modalActorFocusStack.length - 1; i++) {
|
||||
modalActorFocusStack[i + 1][1] = modalActorFocusStack[i][1];
|
||||
}
|
||||
}
|
||||
modalActorFocusStack.splice(focusIndex, 1);
|
||||
}
|
||||
if (modalCount > 0)
|
||||
return;
|
||||
|
||||
global.ungrab_keyboard();
|
||||
global.end_modal(currentTime());
|
||||
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
|
||||
inModal = false;
|
||||
}
|
||||
|
||||
function createLookingGlass() {
|
||||
@ -147,17 +301,70 @@ function createLookingGlass() {
|
||||
return lookingGlass;
|
||||
}
|
||||
|
||||
function createAppLaunchContext() {
|
||||
let global = Shell.Global.get();
|
||||
let screen = global.screen;
|
||||
let display = screen.get_display();
|
||||
function getRunDialog() {
|
||||
if (runDialog == null) {
|
||||
runDialog = new RunDialog.RunDialog();
|
||||
}
|
||||
return runDialog;
|
||||
}
|
||||
|
||||
function createAppLaunchContext() {
|
||||
let context = new Gdk.AppLaunchContext();
|
||||
context.set_timestamp(display.get_current_time());
|
||||
context.set_timestamp(currentTime());
|
||||
|
||||
// Make sure that the app is opened on the current workspace even if
|
||||
// the user switches before it starts
|
||||
context.set_desktop(screen.get_active_workspace_index());
|
||||
context.set_desktop(global.screen.get_active_workspace_index());
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* currentTime:
|
||||
*
|
||||
* Gets the current X server time from the current Clutter, Gdk, or X
|
||||
* event. If called from outside an event handler, this may return
|
||||
* %Clutter.CURRENT_TIME (aka 0), or it may return a slightly
|
||||
* out-of-date timestamp.
|
||||
*/
|
||||
function currentTime() {
|
||||
// meta_display_get_current_time() will return the correct time
|
||||
// when handling an X or Gdk event, but will return CurrentTime
|
||||
// from some Clutter event callbacks.
|
||||
//
|
||||
// clutter_get_current_event_time() will return the correct time
|
||||
// from a Clutter event callback, but may return an out-of-date
|
||||
// timestamp if called at other times.
|
||||
//
|
||||
// So we try meta_display_get_current_time() first, since we
|
||||
// can recognize a "wrong" answer from that, and then fall back
|
||||
// to clutter_get_current_event_time().
|
||||
|
||||
let time = global.screen.get_display().get_current_time();
|
||||
if (time != Clutter.CURRENT_TIME)
|
||||
return time;
|
||||
|
||||
return Clutter.get_current_event_time();
|
||||
}
|
||||
|
||||
/**
|
||||
* activateWindow:
|
||||
* @window: the Meta.Window to activate
|
||||
* @time: (optional) current event time
|
||||
*
|
||||
* Activates @window, switching to its workspace first if necessary
|
||||
*/
|
||||
function activateWindow(window, time) {
|
||||
let activeWorkspaceNum = global.screen.get_active_workspace_index();
|
||||
let windowWorkspaceNum = window.get_workspace().index();
|
||||
|
||||
if (!time)
|
||||
time = currentTime();
|
||||
|
||||
if (windowWorkspaceNum != activeWorkspaceNum) {
|
||||
let workspace = global.screen.get_workspace_by_index(windowWorkspaceNum);
|
||||
workspace.activate_with_focus(window, time);
|
||||
} else {
|
||||
window.activate(time);
|
||||
}
|
||||
}
|
||||
|
423
js/ui/overlay.js
@ -1,423 +0,0 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Big = imports.gi.Big;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const Lang = imports.lang;
|
||||
|
||||
const AppDisplay = imports.ui.appDisplay;
|
||||
const DocDisplay = imports.ui.docDisplay;
|
||||
const GenericDisplay = imports.ui.genericDisplay;
|
||||
const Link = imports.ui.link;
|
||||
const Main = imports.ui.main;
|
||||
const Panel = imports.ui.panel;
|
||||
const Dash = imports.ui.dash;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const Workspaces = imports.ui.workspaces;
|
||||
|
||||
const ROOT_OVERLAY_COLOR = new Clutter.Color();
|
||||
ROOT_OVERLAY_COLOR.from_pixel(0x000000ff);
|
||||
|
||||
// Time for initial animation going into overlay mode
|
||||
const ANIMATION_TIME = 0.25;
|
||||
|
||||
// We divide the screen into a grid of rows and columns, which we use
|
||||
// to help us position the overlay components, such as the side panel
|
||||
// that lists applications and documents, the workspaces display, and
|
||||
// the button for adding additional workspaces.
|
||||
// In the regular mode, the side panel takes up one column on the left,
|
||||
// and the workspaces display takes up the remaining columns.
|
||||
// In the expanded side panel display mode, the side panel takes up two
|
||||
// columns, and the workspaces display slides all the way to the right,
|
||||
// being visible only in the last quarter of the right-most column.
|
||||
// In the future, this mode will have more components, such as a display
|
||||
// of documents which were recently opened with a given application, which
|
||||
// will take up the remaining sections of the display.
|
||||
|
||||
const WIDE_SCREEN_CUT_OFF_RATIO = 1.4;
|
||||
|
||||
const COLUMNS_REGULAR_SCREEN = 4;
|
||||
const ROWS_REGULAR_SCREEN = 8;
|
||||
const COLUMNS_WIDE_SCREEN = 5;
|
||||
const ROWS_WIDE_SCREEN = 10;
|
||||
|
||||
const DEFAULT_PADDING = 4;
|
||||
|
||||
// Padding around workspace grid / Spacing between Dash and Workspaces
|
||||
const WORKSPACE_GRID_PADDING = 12;
|
||||
|
||||
const COLUMNS_FOR_WORKSPACES_REGULAR_SCREEN = 3;
|
||||
const ROWS_FOR_WORKSPACES_REGULAR_SCREEN = 6;
|
||||
|
||||
const COLUMNS_FOR_WORKSPACES_WIDE_SCREEN = 4;
|
||||
const ROWS_FOR_WORKSPACES_WIDE_SCREEN = 8;
|
||||
|
||||
// A multi-state; PENDING is used during animations
|
||||
const STATE_ACTIVE = true;
|
||||
const STATE_PENDING_INACTIVE = false;
|
||||
const STATE_INACTIVE = false;
|
||||
|
||||
const SHADOW_COLOR = new Clutter.Color();
|
||||
SHADOW_COLOR.from_pixel(0x00000033);
|
||||
const TRANSPARENT_COLOR = new Clutter.Color();
|
||||
TRANSPARENT_COLOR.from_pixel(0x00000000);
|
||||
|
||||
const SHADOW_WIDTH = 6;
|
||||
|
||||
const NUMBER_OF_SECTIONS_IN_SEARCH = 2;
|
||||
|
||||
let wideScreen = false;
|
||||
let displayGridColumnWidth = null;
|
||||
let displayGridRowHeight = null;
|
||||
|
||||
function Overlay() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
Overlay.prototype = {
|
||||
_init : function() {
|
||||
let me = this;
|
||||
|
||||
let global = Shell.Global.get();
|
||||
|
||||
this._group = new Clutter.Group();
|
||||
this._group._delegate = this;
|
||||
|
||||
this.visible = false;
|
||||
this.animationInProgress = false;
|
||||
this._hideInProgress = false;
|
||||
|
||||
this._recalculateGridSizes();
|
||||
|
||||
this._activeDisplayPane = null;
|
||||
|
||||
// Used to catch any clicks when we have an active pane; see the comments
|
||||
// in addPane below.
|
||||
this._transparentBackground = new Clutter.Rectangle({ opacity: 0,
|
||||
reactive: true });
|
||||
this._group.add_actor(this._transparentBackground);
|
||||
|
||||
// Background color for the overlay
|
||||
this._backOver = new Clutter.Rectangle({ color: ROOT_OVERLAY_COLOR });
|
||||
this._group.add_actor(this._backOver);
|
||||
|
||||
this._group.hide();
|
||||
global.overlay_group.add_actor(this._group);
|
||||
|
||||
// TODO - recalculate everything when desktop size changes
|
||||
this._dash = new Dash.Dash(displayGridColumnWidth);
|
||||
this._group.add_actor(this._dash.actor);
|
||||
|
||||
// Container to hold popup pane chrome.
|
||||
this._paneContainer = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
spacing: 6
|
||||
});
|
||||
// Note here we explicitly don't set the paneContainer to be reactive yet; that's done
|
||||
// inside the notify::visible handler on panes.
|
||||
this._paneContainer.connect('button-release-event', Lang.bind(this, function(background) {
|
||||
this._activeDisplayPane.close();
|
||||
return true;
|
||||
}));
|
||||
this._group.add_actor(this._paneContainer);
|
||||
|
||||
this._transparentBackground.lower_bottom();
|
||||
this._paneContainer.lower_bottom();
|
||||
|
||||
this._repositionChildren();
|
||||
|
||||
this._workspaces = null;
|
||||
},
|
||||
|
||||
_recalculateGridSizes: function () {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
wideScreen = (global.screen_width/global.screen_height > WIDE_SCREEN_CUT_OFF_RATIO);
|
||||
|
||||
// We divide the screen into an imaginary grid which helps us determine the layout of
|
||||
// different visual components.
|
||||
if (wideScreen) {
|
||||
displayGridColumnWidth = global.screen_width / COLUMNS_WIDE_SCREEN;
|
||||
displayGridRowHeight = global.screen_height / ROWS_WIDE_SCREEN;
|
||||
} else {
|
||||
displayGridColumnWidth = global.screen_width / COLUMNS_REGULAR_SCREEN;
|
||||
displayGridRowHeight = global.screen_height / ROWS_REGULAR_SCREEN;
|
||||
}
|
||||
},
|
||||
|
||||
_repositionChildren: function () {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
let contentHeight = global.screen_height - Panel.PANEL_HEIGHT;
|
||||
|
||||
this._dash.actor.set_position(0, Panel.PANEL_HEIGHT);
|
||||
this._dash.actor.set_size(displayGridColumnWidth, contentHeight);
|
||||
|
||||
this._backOver.set_position(0, Panel.PANEL_HEIGHT);
|
||||
this._backOver.set_size(global.screen_width, contentHeight);
|
||||
|
||||
this._paneContainer.set_position(this._dash.actor.x + this._dash.actor.width + DEFAULT_PADDING,
|
||||
Panel.PANEL_HEIGHT);
|
||||
// Dynamic width
|
||||
this._paneContainer.height = contentHeight;
|
||||
|
||||
this._transparentBackground.set_position(this._paneContainer.x, this._paneContainer.y);
|
||||
this._transparentBackground.set_size(global.screen_width - this._paneContainer.x,
|
||||
this._paneContainer.height);
|
||||
},
|
||||
|
||||
addPane: function (pane) {
|
||||
pane.actor.width = displayGridColumnWidth * 2;
|
||||
this._paneContainer.append(pane.actor, Big.BoxPackFlags.NONE);
|
||||
// When a pane is displayed, we raise the transparent background to the top
|
||||
// and connect to button-release-event on it, then raise the pane above that.
|
||||
// The idea here is that clicking anywhere outside the pane should close it.
|
||||
// When the active pane is closed, undo the effect.
|
||||
let backgroundEventId = null;
|
||||
pane.connect('open-state-changed', Lang.bind(this, function (pane, isOpen) {
|
||||
if (isOpen) {
|
||||
this._activeDisplayPane = pane;
|
||||
this._transparentBackground.raise_top();
|
||||
this._paneContainer.raise_top();
|
||||
if (backgroundEventId != null)
|
||||
this._transparentBackground.disconnect(backgroundEventId);
|
||||
backgroundEventId = this._transparentBackground.connect('button-release-event', Lang.bind(this, function () {
|
||||
this._activeDisplayPane.close();
|
||||
return true;
|
||||
}));
|
||||
} else if (pane == this._activeDisplayPane) {
|
||||
this._activeDisplayPane = null;
|
||||
if (backgroundEventId != null) {
|
||||
this._transparentBackground.disconnect(backgroundEventId);
|
||||
backgroundEventId = null;
|
||||
}
|
||||
this._transparentBackground.lower_bottom();
|
||||
this._paneContainer.lower_bottom();
|
||||
}
|
||||
}));
|
||||
},
|
||||
|
||||
//// Draggable target interface ////
|
||||
|
||||
// Closes any active panes if a GenericDisplayItem is being
|
||||
// dragged over the overlay, i.e. as soon as it starts being dragged.
|
||||
// This allows the user to place the item on any workspace.
|
||||
handleDragOver : function(source, actor, x, y, time) {
|
||||
if (source instanceof GenericDisplay.GenericDisplayItem
|
||||
|| source instanceof AppDisplay.WellDisplayItem) {
|
||||
if (this._activeDisplayPane != null)
|
||||
this._activeDisplayPane.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
//// Public methods ////
|
||||
|
||||
show : function() {
|
||||
if (this.visible)
|
||||
return;
|
||||
if (!Main.startModal())
|
||||
return;
|
||||
|
||||
this.visible = true;
|
||||
this.animationInProgress = true;
|
||||
|
||||
let global = Shell.Global.get();
|
||||
let screenWidth = global.screen_width;
|
||||
let screenHeight = global.screen_height;
|
||||
|
||||
this._dash.show();
|
||||
|
||||
let columnsUsed = wideScreen ? COLUMNS_FOR_WORKSPACES_WIDE_SCREEN : COLUMNS_FOR_WORKSPACES_REGULAR_SCREEN;
|
||||
let rowsUsed = wideScreen ? ROWS_FOR_WORKSPACES_WIDE_SCREEN : ROWS_FOR_WORKSPACES_REGULAR_SCREEN;
|
||||
|
||||
let workspacesWidth = displayGridColumnWidth * columnsUsed - WORKSPACE_GRID_PADDING * 2;
|
||||
// We scale the vertical padding by (screenHeight / screenWidth) so that the workspace preserves its aspect ratio.
|
||||
let workspacesHeight = displayGridRowHeight * rowsUsed - WORKSPACE_GRID_PADDING * (screenHeight / screenWidth) * 2;
|
||||
|
||||
let workspacesX = displayGridColumnWidth + WORKSPACE_GRID_PADDING;
|
||||
let workspacesY = displayGridRowHeight + WORKSPACE_GRID_PADDING * (screenHeight / screenWidth);
|
||||
|
||||
// place the 'Add Workspace' button in the bottom row of the grid
|
||||
let addButtonSize = Math.floor(displayGridRowHeight * 3/5);
|
||||
let addButtonX = workspacesX + workspacesWidth - addButtonSize;
|
||||
let addButtonY = screenHeight - Math.floor(displayGridRowHeight * 4/5);
|
||||
|
||||
this._workspaces = new Workspaces.Workspaces(workspacesWidth, workspacesHeight, workspacesX, workspacesY,
|
||||
addButtonSize, addButtonX, addButtonY);
|
||||
this._group.add_actor(this._workspaces.actor);
|
||||
|
||||
// All the the actors in the window group are completely obscured,
|
||||
// hiding the group holding them while the overlay is displayed greatly
|
||||
// increases performance of the overlay especially when there are many
|
||||
// windows visible.
|
||||
//
|
||||
// If we switched to displaying the actors in the overlay rather than
|
||||
// clones of them, this would obviously no longer be necessary.
|
||||
global.window_group.hide();
|
||||
this._group.show();
|
||||
|
||||
// Try to make the menu not too visible behind the empty space between
|
||||
// the workspace previews by sliding in its clipping rectangle.
|
||||
// We want to finish drawing the Dash just before the top workspace fully
|
||||
// slides in on the top. Which means that we have more time to wait before
|
||||
// drawing the dash if the active workspace is displayed on the bottom of
|
||||
// the workspaces grid, and almost no time to wait if it is displayed in the top
|
||||
// row of the workspaces grid. The calculations used below try to roughly
|
||||
// capture the animation ratio for when workspaces are covering the top of the overlay
|
||||
// vs. when workspaces are already below the top of the overlay, and apply it
|
||||
// to clipping the dash. The clipping is removed in this._showDone().
|
||||
this._dash.actor.set_clip(0, 0,
|
||||
this._workspaces.getFullSizeX(),
|
||||
this._dash.actor.height);
|
||||
Tweener.addTween(this._dash.actor,
|
||||
{ clipWidthRight: this._dash._width + WORKSPACE_GRID_PADDING + this._workspaces.getWidthToTopActiveWorkspace(),
|
||||
time: ANIMATION_TIME,
|
||||
transition: "easeOutQuad",
|
||||
onComplete: this._showDone,
|
||||
onCompleteScope: this
|
||||
|
||||
});
|
||||
|
||||
this.emit('showing');
|
||||
},
|
||||
|
||||
hide : function() {
|
||||
if (!this.visible || this._hideInProgress)
|
||||
return;
|
||||
|
||||
let global = Shell.Global.get();
|
||||
|
||||
this.animationInProgress = true;
|
||||
this._hideInProgress = true;
|
||||
if (this._activeDisplayPane != null)
|
||||
this._activeDisplayPane.close();
|
||||
// lower the panes, so that workspaces display is on top while sliding out
|
||||
this._dash.actor.lower(this._workspaces.actor);
|
||||
this._workspaces.hide();
|
||||
|
||||
// Try to make the menu not too visible behind the empty space between
|
||||
// the workspace previews by sliding in its clipping rectangle.
|
||||
// The logic used is the same as described in this.show(). If the active workspace
|
||||
// is displayed in the top row, than almost full animation time is needed for it
|
||||
// to reach the top of the overlay and cover the Dash fully, while if the
|
||||
// active workspace is in the lower row, than the top left workspace reaches the
|
||||
// top of the overlay sooner as it is moving out of the way.
|
||||
// The clipping is removed in this._hideDone().
|
||||
this._dash.actor.set_clip(0, 0,
|
||||
this._dash.actor.width + WORKSPACE_GRID_PADDING + this._workspaces.getWidthToTopActiveWorkspace(),
|
||||
this._dash.actor.height);
|
||||
Tweener.addTween(this._dash.actor,
|
||||
{ clipWidthRight: this._workspaces.getFullSizeX() + this._workspaces.getWidthToTopActiveWorkspace() - global.screen_width,
|
||||
time: ANIMATION_TIME,
|
||||
transition: "easeOutQuad",
|
||||
onComplete: this._hideDone,
|
||||
onCompleteScope: this
|
||||
});
|
||||
|
||||
this.emit('hiding');
|
||||
},
|
||||
|
||||
toggle: function() {
|
||||
if (this.visible)
|
||||
this.hide();
|
||||
else
|
||||
this.show();
|
||||
},
|
||||
|
||||
/**
|
||||
* activateWindow:
|
||||
* @metaWindow: A #MetaWindow
|
||||
* @time: Event timestamp integer
|
||||
*
|
||||
* Make the given MetaWindow be the focus window, switching
|
||||
* to the workspace it's on if necessary. This function
|
||||
* should only be used when the overlay is currently active;
|
||||
* outside of that, use the relevant methods on MetaDisplay.
|
||||
*/
|
||||
activateWindow: function (metaWindow, time) {
|
||||
this._workspaces.activateWindowFromOverlay(metaWindow, time);
|
||||
this.hide();
|
||||
},
|
||||
|
||||
//// Private methods ////
|
||||
|
||||
// Raises the Dash to the top, so that we can tell if the pointer is above one of its items.
|
||||
// We need to do this once the workspaces are shown because the workspaces actor currently covers
|
||||
// the whole screen, regardless of where the workspaces are actually displayed.
|
||||
//
|
||||
// Once we rework the workspaces actor to only cover the area it actually needs, we can
|
||||
// remove this workaround. Also http://bugzilla.openedhand.com/show_bug.cgi?id=1513 requests being
|
||||
// able to pick only a reactive actor at a certain position, rather than any actor. Being able
|
||||
// to do that would allow us to not have to raise the Dash.
|
||||
_showDone: function() {
|
||||
if (this._hideInProgress)
|
||||
return;
|
||||
|
||||
this._dash.actor.raise_top();
|
||||
this._dash.actor.remove_clip();
|
||||
|
||||
this.animationInProgress = false;
|
||||
|
||||
this.emit('shown');
|
||||
},
|
||||
|
||||
_hideDone: function() {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
global.window_group.show();
|
||||
|
||||
this._workspaces.destroy();
|
||||
this._workspaces = null;
|
||||
|
||||
this._dash.actor.remove_clip();
|
||||
this._dash.hide();
|
||||
this._group.hide();
|
||||
|
||||
this.visible = false;
|
||||
this.animationInProgress = false;
|
||||
this._hideInProgress = false;
|
||||
|
||||
Main.endModal();
|
||||
this.emit('hidden');
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(Overlay.prototype);
|
||||
|
||||
Tweener.registerSpecialProperty("clipHeightBottom", _clipHeightBottomGet, _clipHeightBottomSet);
|
||||
|
||||
function _clipHeightBottomGet(actor) {
|
||||
let [xOffset, yOffset, clipWidth, clipHeight] = actor.get_clip();
|
||||
return clipHeight;
|
||||
}
|
||||
|
||||
function _clipHeightBottomSet(actor, clipHeight) {
|
||||
actor.set_clip(0, 0, actor.width, clipHeight);
|
||||
}
|
||||
|
||||
Tweener.registerSpecialProperty("clipHeightTop", _clipHeightTopGet, _clipHeightTopSet);
|
||||
|
||||
function _clipHeightTopGet(actor) {
|
||||
let [xOffset, yOffset, clipWidth, clipHeight] = actor.get_clip();
|
||||
return clipHeight;
|
||||
}
|
||||
|
||||
function _clipHeightTopSet(actor, clipHeight) {
|
||||
actor.set_clip(0, actor.height - clipHeight, actor.width, clipHeight);
|
||||
}
|
||||
|
||||
Tweener.registerSpecialProperty("clipWidthRight", _clipWidthRightGet, _clipWidthRightSet);
|
||||
|
||||
function _clipWidthRightGet(actor) {
|
||||
let [xOffset, yOffset, clipWidth, clipHeight] = actor.get_clip();
|
||||
return clipWidth;
|
||||
}
|
||||
|
||||
function _clipWidthRightSet(actor, clipWidth) {
|
||||
actor.set_clip(0, 0, clipWidth, actor.height);
|
||||
}
|
495
js/ui/overview.js
Normal file
@ -0,0 +1,495 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Big = imports.gi.Big;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const Lang = imports.lang;
|
||||
|
||||
const AppDisplay = imports.ui.appDisplay;
|
||||
const DocDisplay = imports.ui.docDisplay;
|
||||
const GenericDisplay = imports.ui.genericDisplay;
|
||||
const Link = imports.ui.link;
|
||||
const Main = imports.ui.main;
|
||||
const Panel = imports.ui.panel;
|
||||
const Dash = imports.ui.dash;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const Workspaces = imports.ui.workspaces;
|
||||
|
||||
const ROOT_OVERVIEW_COLOR = new Clutter.Color();
|
||||
ROOT_OVERVIEW_COLOR.from_pixel(0x000000ff);
|
||||
|
||||
// Time for initial animation going into Overview mode
|
||||
const ANIMATION_TIME = 0.25;
|
||||
|
||||
// We divide the screen into a grid of rows and columns, which we use
|
||||
// to help us position the Overview components, such as the side panel
|
||||
// that lists applications and documents, the workspaces display, and
|
||||
// the button for adding additional workspaces.
|
||||
// In the regular mode, the side panel takes up one column on the left,
|
||||
// and the workspaces display takes up the remaining columns.
|
||||
// In the expanded side panel display mode, the side panel takes up two
|
||||
// columns, and the workspaces display slides all the way to the right,
|
||||
// being visible only in the last quarter of the right-most column.
|
||||
// In the future, this mode will have more components, such as a display
|
||||
// of documents which were recently opened with a given application, which
|
||||
// will take up the remaining sections of the display.
|
||||
|
||||
const WIDE_SCREEN_CUT_OFF_RATIO = 1.4;
|
||||
// A common netbook resolution is 1024x600, which trips the widescreen
|
||||
// ratio. However that leaves way too few pixels for the dash. So
|
||||
// just treat this as a regular screen.
|
||||
const WIDE_SCREEN_MINIMUM_HEIGHT = 768;
|
||||
|
||||
const COLUMNS_REGULAR_SCREEN = 4;
|
||||
const ROWS_REGULAR_SCREEN = 8;
|
||||
const COLUMNS_WIDE_SCREEN = 5;
|
||||
const ROWS_WIDE_SCREEN = 10;
|
||||
|
||||
const DEFAULT_PADDING = 4;
|
||||
|
||||
// Padding around workspace grid / Spacing between Dash and Workspaces
|
||||
const WORKSPACE_GRID_PADDING = 12;
|
||||
|
||||
const COLUMNS_FOR_WORKSPACES_REGULAR_SCREEN = 3;
|
||||
const ROWS_FOR_WORKSPACES_REGULAR_SCREEN = 6;
|
||||
|
||||
const COLUMNS_FOR_WORKSPACES_WIDE_SCREEN = 4;
|
||||
const ROWS_FOR_WORKSPACES_WIDE_SCREEN = 8;
|
||||
|
||||
// A multi-state; PENDING is used during animations
|
||||
const STATE_ACTIVE = true;
|
||||
const STATE_PENDING_INACTIVE = false;
|
||||
const STATE_INACTIVE = false;
|
||||
|
||||
const SHADOW_COLOR = new Clutter.Color();
|
||||
SHADOW_COLOR.from_pixel(0x00000033);
|
||||
const TRANSPARENT_COLOR = new Clutter.Color();
|
||||
TRANSPARENT_COLOR.from_pixel(0x00000000);
|
||||
|
||||
const SHADOW_WIDTH = 6;
|
||||
|
||||
const NUMBER_OF_SECTIONS_IN_SEARCH = 2;
|
||||
|
||||
let wideScreen = false;
|
||||
let displayGridColumnWidth = null;
|
||||
let displayGridRowHeight = null;
|
||||
let addRemoveButtonSize = null;
|
||||
|
||||
function Overview() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
Overview.prototype = {
|
||||
_init : function() {
|
||||
this._group = new Clutter.Group();
|
||||
this._group._delegate = this;
|
||||
|
||||
this.visible = false;
|
||||
this.animationInProgress = false;
|
||||
this._hideInProgress = false;
|
||||
|
||||
this._recalculateGridSizes();
|
||||
|
||||
this._activeDisplayPane = null;
|
||||
|
||||
// During transitions, we raise this to the top to avoid having the overview
|
||||
// area be reactive; it causes too many issues such as double clicks on
|
||||
// Dash elements, or mouseover handlers in the workspaces.
|
||||
this._coverPane = new Clutter.Rectangle({ opacity: 0,
|
||||
reactive: true });
|
||||
this._group.add_actor(this._coverPane);
|
||||
this._coverPane.connect('event', Lang.bind(this, function (actor, event) { return true; }));
|
||||
|
||||
// Similar to the cover pane but used for dialogs ("panes"); see the comments
|
||||
// in addPane below.
|
||||
this._transparentBackground = new Clutter.Rectangle({ opacity: 0,
|
||||
reactive: true });
|
||||
this._group.add_actor(this._transparentBackground);
|
||||
|
||||
// Background color for the Overview
|
||||
this._backOver = new Clutter.Rectangle({ color: ROOT_OVERVIEW_COLOR });
|
||||
this._group.add_actor(this._backOver);
|
||||
|
||||
this._group.hide();
|
||||
global.overlay_group.add_actor(this._group);
|
||||
|
||||
// TODO - recalculate everything when desktop size changes
|
||||
this._dash = new Dash.Dash();
|
||||
this._group.add_actor(this._dash.actor);
|
||||
|
||||
// Container to hold popup pane chrome.
|
||||
this._paneContainer = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
spacing: 6
|
||||
});
|
||||
// Note here we explicitly don't set the paneContainer to be reactive yet; that's done
|
||||
// inside the notify::visible handler on panes.
|
||||
this._paneContainer.connect('button-release-event', Lang.bind(this, function(background) {
|
||||
this._activeDisplayPane.close();
|
||||
return true;
|
||||
}));
|
||||
this._group.add_actor(this._paneContainer);
|
||||
|
||||
this._transparentBackground.lower_bottom();
|
||||
this._paneContainer.lower_bottom();
|
||||
|
||||
this._coverPane.lower_bottom();
|
||||
|
||||
this._workspaces = null;
|
||||
},
|
||||
|
||||
_recalculateGridSizes: function () {
|
||||
let primary = global.get_primary_monitor();
|
||||
wideScreen = (primary.width/primary.height > WIDE_SCREEN_CUT_OFF_RATIO) &&
|
||||
(primary.height >= WIDE_SCREEN_MINIMUM_HEIGHT);
|
||||
|
||||
// We divide the screen into an imaginary grid which helps us determine the layout of
|
||||
// different visual components.
|
||||
if (wideScreen) {
|
||||
displayGridColumnWidth = primary.width / COLUMNS_WIDE_SCREEN;
|
||||
displayGridRowHeight = primary.height / ROWS_WIDE_SCREEN;
|
||||
} else {
|
||||
displayGridColumnWidth = primary.width / COLUMNS_REGULAR_SCREEN;
|
||||
displayGridRowHeight = primary.height / ROWS_REGULAR_SCREEN;
|
||||
}
|
||||
},
|
||||
|
||||
relayout: function () {
|
||||
let primary = global.get_primary_monitor();
|
||||
|
||||
this._group.set_position(primary.x, primary.y);
|
||||
|
||||
let contentY = Panel.PANEL_HEIGHT;
|
||||
let contentHeight = primary.height - contentY;
|
||||
|
||||
this._coverPane.set_position(0, contentY);
|
||||
this._coverPane.set_size(primary.width, contentHeight);
|
||||
|
||||
let workspaceColumnsUsed = wideScreen ? COLUMNS_FOR_WORKSPACES_WIDE_SCREEN : COLUMNS_FOR_WORKSPACES_REGULAR_SCREEN;
|
||||
let workspaceRowsUsed = wideScreen ? ROWS_FOR_WORKSPACES_WIDE_SCREEN : ROWS_FOR_WORKSPACES_REGULAR_SCREEN;
|
||||
|
||||
this._workspacesWidth = displayGridColumnWidth * workspaceColumnsUsed
|
||||
- WORKSPACE_GRID_PADDING * 2;
|
||||
// We scale the vertical padding by (primary.height / primary.width)
|
||||
// so that the workspace preserves its aspect ratio.
|
||||
this._workspacesHeight = displayGridRowHeight * workspaceRowsUsed
|
||||
- WORKSPACE_GRID_PADDING * (primary.height / primary.width) * 2;
|
||||
|
||||
this._workspacesX = displayGridColumnWidth + WORKSPACE_GRID_PADDING;
|
||||
this._workspacesY = displayGridRowHeight + WORKSPACE_GRID_PADDING * (primary.height / primary.width);
|
||||
|
||||
this._dash.actor.set_position(0, contentY);
|
||||
this._dash.actor.set_size(displayGridColumnWidth, contentHeight);
|
||||
this._dash.searchArea.height = this._workspacesY - contentY;
|
||||
this._dash.sectionArea.height = this._workspacesHeight;
|
||||
|
||||
// place the 'Add Workspace' button in the bottom row of the grid
|
||||
addRemoveButtonSize = Math.floor(displayGridRowHeight * 3/5);
|
||||
this._addButtonX = this._workspacesX + this._workspacesWidth - addRemoveButtonSize;
|
||||
this._addButtonY = primary.height - Math.floor(displayGridRowHeight * 4/5);
|
||||
|
||||
// The parent (this._group) is positioned at the top left of the primary monitor
|
||||
// while this._backOver occupies the entire screen.
|
||||
this._backOver.set_position(- primary.x, - primary.y);
|
||||
this._backOver.set_size(global.screen_width, global.screen_height);
|
||||
|
||||
this._paneContainer.set_position(this._dash.actor.x + this._dash.actor.width + DEFAULT_PADDING,
|
||||
contentY);
|
||||
// Dynamic width
|
||||
this._paneContainer.height = contentHeight;
|
||||
|
||||
this._transparentBackground.set_position(this._paneContainer.x, this._paneContainer.y);
|
||||
this._transparentBackground.set_size(primary.width - this._paneContainer.x,
|
||||
this._paneContainer.height);
|
||||
|
||||
if (this._activeDisplayPane != null)
|
||||
this._activeDisplayPane.actor.width = displayGridColumnWidth * 2;
|
||||
},
|
||||
|
||||
addPane: function (pane) {
|
||||
this._paneContainer.append(pane.actor, Big.BoxPackFlags.NONE);
|
||||
// When a pane is displayed, we raise the transparent background to the top
|
||||
// and connect to button-release-event on it, then raise the pane above that.
|
||||
// The idea here is that clicking anywhere outside the pane should close it.
|
||||
// When the active pane is closed, undo the effect.
|
||||
let backgroundEventId = null;
|
||||
pane.connect('open-state-changed', Lang.bind(this, function (pane, isOpen) {
|
||||
if (isOpen) {
|
||||
pane.actor.width = displayGridColumnWidth * 2;
|
||||
this._activeDisplayPane = pane;
|
||||
this._transparentBackground.raise_top();
|
||||
this._paneContainer.raise_top();
|
||||
if (backgroundEventId != null)
|
||||
this._transparentBackground.disconnect(backgroundEventId);
|
||||
backgroundEventId = this._transparentBackground.connect('button-release-event', Lang.bind(this, function () {
|
||||
this._activeDisplayPane.close();
|
||||
return true;
|
||||
}));
|
||||
} else if (pane == this._activeDisplayPane) {
|
||||
this._activeDisplayPane = null;
|
||||
if (backgroundEventId != null) {
|
||||
this._transparentBackground.disconnect(backgroundEventId);
|
||||
backgroundEventId = null;
|
||||
}
|
||||
this._transparentBackground.lower_bottom();
|
||||
this._paneContainer.lower_bottom();
|
||||
}
|
||||
}));
|
||||
},
|
||||
|
||||
//// Draggable target interface ////
|
||||
|
||||
// Closes any active panes if a GenericDisplayItem is being
|
||||
// dragged over the Overview, i.e. as soon as it starts being dragged.
|
||||
// This allows the user to place the item on any workspace.
|
||||
handleDragOver : function(source, actor, x, y, time) {
|
||||
if (source instanceof GenericDisplay.GenericDisplayItem
|
||||
|| source instanceof AppDisplay.BaseWellItem) {
|
||||
if (this._activeDisplayPane != null)
|
||||
this._activeDisplayPane.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
//// Public methods ////
|
||||
|
||||
// Returns the scale the Overview has when we just start zooming out
|
||||
// to overview mode. That is, when just the active workspace is showing.
|
||||
getZoomedInScale : function() {
|
||||
return 1 / this._workspaces.getScale();
|
||||
},
|
||||
|
||||
// Returns the position the Overview has when we just start zooming out
|
||||
// to overview mode. That is, when just the active workspace is showing.
|
||||
getZoomedInPosition : function() {
|
||||
let [posX, posY] = this._workspaces.getActiveWorkspacePosition();
|
||||
let scale = this.getZoomedInScale();
|
||||
|
||||
return [- posX * scale, - posY * scale];
|
||||
},
|
||||
|
||||
// Returns the current scale of the Overview.
|
||||
getScale : function() {
|
||||
return this._group.scaleX;
|
||||
},
|
||||
|
||||
// Returns the current position of the Overview.
|
||||
getPosition : function() {
|
||||
return [this._group.x, this._group.y];
|
||||
},
|
||||
|
||||
show : function() {
|
||||
if (this.visible)
|
||||
return;
|
||||
if (!Main.pushModal(this._dash.actor))
|
||||
return;
|
||||
|
||||
this.visible = true;
|
||||
this.animationInProgress = true;
|
||||
|
||||
this._dash.show();
|
||||
|
||||
/* TODO: make this stuff dynamic */
|
||||
this._workspaces = new Workspaces.Workspaces(this._workspacesWidth, this._workspacesHeight,
|
||||
this._workspacesX, this._workspacesY);
|
||||
this._group.add_actor(this._workspaces.actor);
|
||||
|
||||
// The workspaces actor is as big as the screen, so we have to raise the dash above it
|
||||
// for drag and drop to work. In the future we should fix the workspaces to not
|
||||
// be as big as the screen.
|
||||
this._dash.actor.raise(this._workspaces.actor);
|
||||
|
||||
// Create (+) button
|
||||
this._addButton = new AddWorkspaceButton(addRemoveButtonSize, this._addButtonX, this._addButtonY, Lang.bind(this, this._acceptNewWorkspaceDrop));
|
||||
this._addButton.actor.connect('button-release-event', Lang.bind(this, this._addNewWorkspace));
|
||||
this._group.add_actor(this._addButton.actor);
|
||||
this._addButton.actor.raise(this._workspaces.actor);
|
||||
|
||||
// All the the actors in the window group are completely obscured,
|
||||
// hiding the group holding them while the Overview is displayed greatly
|
||||
// increases performance of the Overview especially when there are many
|
||||
// windows visible.
|
||||
//
|
||||
// If we switched to displaying the actors in the Overview rather than
|
||||
// clones of them, this would obviously no longer be necessary.
|
||||
global.window_group.hide();
|
||||
this._group.show();
|
||||
|
||||
// Create a zoom out effect. First scale the Overview group up and
|
||||
// position it so that the active workspace fills up the whole screen,
|
||||
// then transform the group to its normal dimensions and position.
|
||||
// The opposite transition is used in hide().
|
||||
this._group.scaleX = this._group.scaleY = this.getZoomedInScale();
|
||||
[this._group.x, this._group.y] = this.getZoomedInPosition();
|
||||
let primary = global.get_primary_monitor();
|
||||
Tweener.addTween(this._group,
|
||||
{ x: primary.x,
|
||||
y: primary.y,
|
||||
scaleX: 1,
|
||||
scaleY: 1,
|
||||
transition: 'easeOutQuad',
|
||||
time: ANIMATION_TIME,
|
||||
onComplete: this._showDone,
|
||||
onCompleteScope: this
|
||||
});
|
||||
|
||||
// Make Dash fade in so that it doesn't appear to big.
|
||||
this._dash.actor.opacity = 0;
|
||||
Tweener.addTween(this._dash.actor,
|
||||
{ opacity: 255,
|
||||
transition: 'easeOutQuad',
|
||||
time: ANIMATION_TIME
|
||||
});
|
||||
|
||||
this._coverPane.raise_top();
|
||||
this.emit('showing');
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
if (!this.visible || this._hideInProgress)
|
||||
return;
|
||||
|
||||
this.animationInProgress = true;
|
||||
this._hideInProgress = true;
|
||||
if (this._activeDisplayPane != null)
|
||||
this._activeDisplayPane.close();
|
||||
this._workspaces.hide();
|
||||
|
||||
this._addButton.actor.destroy();
|
||||
this._addButton.actor = null;
|
||||
this._addButton = null;
|
||||
|
||||
// Create a zoom in effect by transforming the Overview group so that
|
||||
// the active workspace fills up the whole screen. The opposite
|
||||
// transition is used in show().
|
||||
let scale = this.getZoomedInScale();
|
||||
let [posX, posY] = this.getZoomedInPosition();
|
||||
Tweener.addTween(this._group,
|
||||
{ x: posX,
|
||||
y: posY,
|
||||
scaleX: scale,
|
||||
scaleY: scale,
|
||||
transition: 'easeOutQuad',
|
||||
time: ANIMATION_TIME,
|
||||
onComplete: this._hideDone,
|
||||
onCompleteScope: this
|
||||
});
|
||||
|
||||
// Make Dash fade out so that it doesn't appear to big.
|
||||
Tweener.addTween(this._dash.actor,
|
||||
{ opacity: 0,
|
||||
transition: 'easeOutQuad',
|
||||
time: ANIMATION_TIME
|
||||
});
|
||||
|
||||
this._coverPane.raise_top();
|
||||
this.emit('hiding');
|
||||
},
|
||||
|
||||
toggle: function() {
|
||||
if (this.visible)
|
||||
this.hide();
|
||||
else
|
||||
this.show();
|
||||
},
|
||||
|
||||
/**
|
||||
* getWorkspacesForWindow:
|
||||
* @metaWindow: A #MetaWindow
|
||||
*
|
||||
* Returns the Workspaces object associated with the given window.
|
||||
* This method is not be accessible if the overview is not open
|
||||
* and will return %null.
|
||||
*/
|
||||
getWorkspacesForWindow: function(metaWindow) {
|
||||
return this._workspaces;
|
||||
},
|
||||
|
||||
/**
|
||||
* activateWindow:
|
||||
* @metaWindow: A #MetaWindow
|
||||
* @time: Event timestamp integer
|
||||
*
|
||||
* Make the given MetaWindow be the focus window, switching
|
||||
* to the workspace it's on if necessary. This function
|
||||
* should only be used when the Overview is currently active;
|
||||
* outside of that, use the relevant methods on MetaDisplay.
|
||||
*/
|
||||
activateWindow: function (metaWindow, time) {
|
||||
this._workspaces.activateWindowFromOverview(metaWindow, time);
|
||||
},
|
||||
|
||||
//// Private methods ////
|
||||
|
||||
_showDone: function() {
|
||||
if (this._hideInProgress)
|
||||
return;
|
||||
|
||||
this.animationInProgress = false;
|
||||
this._coverPane.lower_bottom();
|
||||
|
||||
this.emit('shown');
|
||||
},
|
||||
|
||||
_hideDone: function() {
|
||||
global.window_group.show();
|
||||
|
||||
this._workspaces.destroy();
|
||||
this._workspaces = null;
|
||||
|
||||
this._dash.hide();
|
||||
this._group.hide();
|
||||
|
||||
this.visible = false;
|
||||
this.animationInProgress = false;
|
||||
this._hideInProgress = false;
|
||||
|
||||
this._coverPane.lower_bottom();
|
||||
|
||||
Main.popModal(this._dash.actor);
|
||||
this.emit('hidden');
|
||||
},
|
||||
|
||||
_addNewWorkspace: function() {
|
||||
global.screen.append_new_workspace(false, Main.currentTime());
|
||||
},
|
||||
|
||||
_acceptNewWorkspaceDrop: function(source, dropActor, x, y, time) {
|
||||
this._addNewWorkspace();
|
||||
return this._workspaces.acceptNewWorkspaceDrop(source, dropActor, x, y, time);
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(Overview.prototype);
|
||||
|
||||
function AddWorkspaceButton(buttonSize, buttonX, buttonY, acceptDropCallback) {
|
||||
this._init(buttonSize, buttonX, buttonY, acceptDropCallback);
|
||||
}
|
||||
|
||||
AddWorkspaceButton.prototype = {
|
||||
_init: function(buttonSize, buttonX, buttonY, acceptDropCallback) {
|
||||
this.actor = new Clutter.Group({ x: buttonX,
|
||||
y: buttonY,
|
||||
width: global.screen_width - buttonX,
|
||||
height: global.screen_height - buttonY,
|
||||
reactive: true });
|
||||
this.actor._delegate = this;
|
||||
this._acceptDropCallback = acceptDropCallback;
|
||||
|
||||
let plus = new Clutter.Texture({ x: 0,
|
||||
y: 0,
|
||||
width: buttonSize,
|
||||
height: buttonSize });
|
||||
plus.set_from_file(global.imagedir + 'add-workspace.svg');
|
||||
this.actor.add_actor(plus);
|
||||
},
|
||||
|
||||
// Draggable target interface
|
||||
acceptDrop: function(source, actor, x, y, time) {
|
||||
return this._acceptDropCallback(source, actor, x, y, time);
|
||||
}
|
||||
};
|
489
js/ui/panel.js
@ -7,18 +7,32 @@ const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const Signals = imports.signals;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const Button = imports.ui.button;
|
||||
const Calendar = imports.ui.calendar;
|
||||
const Main = imports.ui.main;
|
||||
|
||||
const PANEL_HEIGHT = 26;
|
||||
const TRAY_HEIGHT = PANEL_HEIGHT - 1;
|
||||
|
||||
const PANEL_BACKGROUND_COLOR = new Clutter.Color();
|
||||
PANEL_BACKGROUND_COLOR.from_pixel(0x000000ff);
|
||||
const DEFAULT_PADDING = 4;
|
||||
|
||||
const PANEL_ICON_SIZE = 24;
|
||||
|
||||
const BACKGROUND_TOP = new Clutter.Color();
|
||||
BACKGROUND_TOP.from_pixel(0x161616ff);
|
||||
const BACKGROUND_BOTTOM = new Clutter.Color();
|
||||
BACKGROUND_BOTTOM.from_pixel(0x000000ff);
|
||||
|
||||
const PANEL_FOREGROUND_COLOR = new Clutter.Color();
|
||||
PANEL_FOREGROUND_COLOR.from_pixel(0xffffffff);
|
||||
const SN_BACKGROUND_COLOR = new Clutter.Color();
|
||||
SN_BACKGROUND_COLOR.from_pixel(0xffff00a0);
|
||||
|
||||
const TRANSPARENT_COLOR = new Clutter.Color();
|
||||
TRANSPARENT_COLOR.from_pixel(0x00000000);
|
||||
@ -41,91 +55,288 @@ const TRAY_SPACING_MIN = 8;
|
||||
// Used for the tray icon container with gtk pre-2.16, which doesn't
|
||||
// fully support tray icon transparency
|
||||
const TRAY_BACKGROUND_COLOR = new Clutter.Color();
|
||||
TRAY_BACKGROUND_COLOR.from_pixel(0xefefefff);
|
||||
TRAY_BACKGROUND_COLOR.from_pixel(0x0b0b0bff);
|
||||
const TRAY_BORDER_COLOR = new Clutter.Color();
|
||||
TRAY_BORDER_COLOR.from_pixel(0x00000033);
|
||||
const TRAY_CORNER_RADIUS = 5;
|
||||
const TRAY_BORDER_WIDTH = 0;
|
||||
|
||||
const HOT_CORNER_ACTIVATION_TIMEOUT = 0.5;
|
||||
|
||||
function AppPanelMenu() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
AppPanelMenu.prototype = {
|
||||
_init: function() {
|
||||
this._metaDisplay = global.screen.get_display();
|
||||
|
||||
this._focusedApp = null;
|
||||
this._activeSequence = null;
|
||||
this._startupSequences = {};
|
||||
|
||||
this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
spacing: DEFAULT_PADDING,
|
||||
y_align: Big.BoxAlignment.CENTER });
|
||||
this._iconBox = new Big.Box({ width: PANEL_ICON_SIZE, height: PANEL_ICON_SIZE,
|
||||
x_align: Big.BoxAlignment.CENTER,
|
||||
y_align: Big.BoxAlignment.CENTER });
|
||||
this.actor.append(this._iconBox, Big.BoxPackFlags.NONE);
|
||||
let labelBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
y_align: Big.BoxAlignment.CENTER });
|
||||
this._label = new Clutter.Text({ font_name: DEFAULT_FONT,
|
||||
color: PANEL_FOREGROUND_COLOR,
|
||||
text: "" });
|
||||
labelBox.append(this._label, Big.BoxPackFlags.EXPAND);
|
||||
this.actor.append(labelBox, Big.BoxPackFlags.NONE);
|
||||
|
||||
this._startupBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
y_align: Big.BoxAlignment.CENTER });
|
||||
this.actor.append(this._startupBox, Big.BoxPackFlags.NONE);
|
||||
|
||||
Main.overview.connect('hiding', Lang.bind(this, function () {
|
||||
this.actor.opacity = 255;
|
||||
}));
|
||||
Main.overview.connect('showing', Lang.bind(this, function () {
|
||||
this.actor.opacity = 192;
|
||||
}));
|
||||
|
||||
this._metaDisplay.connect('notify::focus-window', Lang.bind(this, this._sync));
|
||||
|
||||
let appMonitor = Shell.AppMonitor.get_default();
|
||||
appMonitor.connect('startup-sequence-changed', Lang.bind(this, this._sync));
|
||||
// For now just resync on application add/remove; this is mainly to handle
|
||||
// cases where the focused window's application changes without the focus
|
||||
// changing. An example case is how we map Firefox based on the window
|
||||
// title which is a dynamic property.
|
||||
appMonitor.connect('app-added', Lang.bind(this, this._sync));
|
||||
appMonitor.connect('app-removed', Lang.bind(this, this._sync));
|
||||
|
||||
this._sync();
|
||||
},
|
||||
|
||||
_sync: function() {
|
||||
let appMonitor = Shell.AppMonitor.get_default();
|
||||
|
||||
let focusWindow = this._metaDisplay.get_focus_window();
|
||||
let focusedApp;
|
||||
if (focusWindow == null) {
|
||||
focusedApp = null;
|
||||
} else {
|
||||
focusedApp = appMonitor.get_window_app(focusWindow);
|
||||
}
|
||||
|
||||
let lastSequence = null;
|
||||
if (focusedApp == null) {
|
||||
let sequences = appMonitor.get_startup_sequences();
|
||||
if (sequences.length > 0)
|
||||
lastSequence = sequences[sequences.length - 1];
|
||||
}
|
||||
|
||||
// If the currently focused app hasn't changed and the current
|
||||
// startup sequence hasn't changed, we have nothing to do
|
||||
if (focusedApp == this._focusedApp
|
||||
&& ((lastSequence == null && this._activeSequence == null)
|
||||
|| (lastSequence != null && this._activeSequence != null
|
||||
&& lastSequence.get_id() == this._activeSequence.get_id())))
|
||||
return;
|
||||
|
||||
this._focusedApp = focusedApp;
|
||||
this._activeSequence = lastSequence;
|
||||
|
||||
this._iconBox.remove_all();
|
||||
this._iconBox.hide();
|
||||
this._label.text = '';
|
||||
if (this._focusedApp != null) {
|
||||
let icon = focusedApp.create_icon_texture(PANEL_ICON_SIZE);
|
||||
this._iconBox.append(icon, Big.BoxPackFlags.NONE);
|
||||
this._iconBox.show();
|
||||
this._label.text = focusedApp.get_name();
|
||||
} else if (this._activeSequence != null) {
|
||||
let icon = this._activeSequence.create_icon(PANEL_ICON_SIZE);
|
||||
this._iconBox.append(icon, Big.BoxPackFlags.NONE);
|
||||
this._iconBox.show();
|
||||
this._label.text = this._activeSequence.get_name();
|
||||
}
|
||||
|
||||
this.emit('changed');
|
||||
}
|
||||
}
|
||||
|
||||
Signals.addSignalMethods(AppPanelMenu.prototype);
|
||||
|
||||
function Panel() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
Panel.prototype = {
|
||||
_init : function() {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
// Put the background under the panel within a group.
|
||||
this.actor = new Clutter.Group();
|
||||
this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL
|
||||
});
|
||||
let backgroundGradient = Shell.create_vertical_gradient(BACKGROUND_TOP,
|
||||
BACKGROUND_BOTTOM);
|
||||
this.actor.connect('notify::allocation', Lang.bind(this, function () {
|
||||
let [width, height] = this.actor.get_size();
|
||||
backgroundGradient.set_size(width, height);
|
||||
}));
|
||||
this.actor.add_actor(backgroundGradient);
|
||||
|
||||
// backBox contains the panel background and the clock.
|
||||
let backBox = new Big.Box({ width: global.screen_width,
|
||||
height: PANEL_HEIGHT,
|
||||
backgroundColor: PANEL_BACKGROUND_COLOR,
|
||||
x_align: Big.BoxAlignment.CENTER });
|
||||
this.actor.add_actor(backBox);
|
||||
this._leftBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
y_align: Big.BoxAlignment.CENTER,
|
||||
spacing: DEFAULT_PADDING,
|
||||
padding_right: DEFAULT_PADDING });
|
||||
this._centerBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
y_align: Big.BoxAlignment.CENTER });
|
||||
this._rightBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
y_align: Big.BoxAlignment.CENTER,
|
||||
padding_left: DEFAULT_PADDING });
|
||||
|
||||
let box = new Big.Box({ x: 0,
|
||||
y: 0,
|
||||
height: PANEL_HEIGHT,
|
||||
width: global.screen_width,
|
||||
orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
spacing: 4 });
|
||||
/* This box container ensures that the centerBox is positioned in the *absolute*
|
||||
* center, but can be pushed aside if necessary. */
|
||||
this._boxContainer = new Shell.GenericContainer();
|
||||
this.actor.append(this._boxContainer, Big.BoxPackFlags.EXPAND);
|
||||
this._boxContainer.add_actor(this._leftBox);
|
||||
this._boxContainer.add_actor(this._centerBox);
|
||||
this._boxContainer.add_actor(this._rightBox);
|
||||
this._boxContainer.connect('get-preferred-width', Lang.bind(this, function(box, forHeight, alloc) {
|
||||
let children = box.get_children();
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
let [childMin, childNatural] = children[i].get_preferred_width(forHeight);
|
||||
alloc.min_size += childMin;
|
||||
alloc.natural_size += childNatural;
|
||||
}
|
||||
}));
|
||||
this._boxContainer.connect('get-preferred-height', Lang.bind(this, function(box, forWidth, alloc) {
|
||||
let children = box.get_children();
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
let [childMin, childNatural] = children[i].get_preferred_height(forWidth);
|
||||
if (childMin > alloc.min_size)
|
||||
alloc.min_size = childMin;
|
||||
if (childNatural > alloc.natural_size)
|
||||
alloc.natural_size = childNatural;
|
||||
}
|
||||
}));
|
||||
this._boxContainer.connect('allocate', Lang.bind(this, function(container, box, flags) {
|
||||
let allocWidth = box.x2 - box.x1;
|
||||
let allocHeight = box.y2 - box.y1;
|
||||
let [leftMinWidth, leftNaturalWidth] = this._leftBox.get_preferred_width(-1);
|
||||
let [centerMinWidth, centerNaturalWidth] = this._centerBox.get_preferred_width(-1);
|
||||
let [rightMinWidth, rightNaturalWidth] = this._rightBox.get_preferred_width(-1);
|
||||
let leftWidth, centerWidth, rightWidth;
|
||||
if (allocWidth < (leftNaturalWidth + centerNaturalWidth + rightNaturalWidth)) {
|
||||
leftWidth = leftMinWidth;
|
||||
centerWidth = centerMinWidth;
|
||||
rightWidth = rightMinWidth;
|
||||
} else {
|
||||
leftWidth = leftNaturalWidth;
|
||||
centerWidth = centerNaturalWidth;
|
||||
rightWidth = rightNaturalWidth;
|
||||
}
|
||||
|
||||
this.button = new Button.Button("Activities", PANEL_BUTTON_COLOR, PRESSED_BUTTON_BACKGROUND_COLOR, PANEL_FOREGROUND_COLOR, true, null, PANEL_HEIGHT, DEFAULT_FONT);
|
||||
let x;
|
||||
let childBox = new Clutter.ActorBox();
|
||||
childBox.x1 = box.x1;
|
||||
childBox.y1 = box.y1;
|
||||
childBox.x2 = x = childBox.x1 + leftWidth;
|
||||
childBox.y2 = box.y2;
|
||||
this._leftBox.allocate(childBox, flags);
|
||||
|
||||
box.append(this.button.button, Big.BoxPackFlags.NONE);
|
||||
let centerNaturalX = Math.floor((box.x2 - box.x1) / 2 - (centerWidth / 2));
|
||||
/* Check left side */
|
||||
if (x < centerNaturalX) {
|
||||
/* We didn't overflow the left, use the natural. */
|
||||
x = centerNaturalX;
|
||||
}
|
||||
/* Check right side */
|
||||
if (x + centerWidth > (box.x2 - rightWidth)) {
|
||||
x = box.x2 - rightWidth - centerWidth;
|
||||
}
|
||||
childBox = new Clutter.ActorBox();
|
||||
childBox.x1 = x;
|
||||
childBox.y1 = box.y1;
|
||||
childBox.x2 = x = childBox.x1 + centerWidth;
|
||||
childBox.y2 = box.y2;
|
||||
this._centerBox.allocate(childBox, flags);
|
||||
|
||||
let hotCorner = new Clutter.Rectangle({ width: 1,
|
||||
height: 1,
|
||||
opacity: 0,
|
||||
reactive: true });
|
||||
childBox = new Clutter.ActorBox();
|
||||
childBox.x1 = box.x2 - rightWidth;
|
||||
childBox.y1 = box.y1;
|
||||
childBox.x2 = box.x2;
|
||||
childBox.y2 = box.y2;
|
||||
this._rightBox.allocate(childBox, flags);
|
||||
}));
|
||||
|
||||
/* left side */
|
||||
|
||||
this.button = new Button.Button(_("Activities"), PANEL_BUTTON_COLOR, PRESSED_BUTTON_BACKGROUND_COLOR,
|
||||
PANEL_FOREGROUND_COLOR, DEFAULT_FONT);
|
||||
this.button.actor.height = PANEL_HEIGHT;
|
||||
|
||||
this._leftBox.append(this.button.actor, Big.BoxPackFlags.NONE);
|
||||
|
||||
// We use this flag to mark the case where the user has entered the
|
||||
// hot corner and has not left both the hot corner and a surrounding
|
||||
// guard area (the "environs"). This avoids triggering the hot corner
|
||||
// multiple times due to an accidental jitter.
|
||||
this._hotCornerEntered = false;
|
||||
|
||||
this._hotCornerEnvirons = new Clutter.Rectangle({ width: 3,
|
||||
height: 3,
|
||||
opacity: 0,
|
||||
reactive: true });
|
||||
|
||||
this._hotCorner = new Clutter.Rectangle({ width: 1,
|
||||
height: 1,
|
||||
opacity: 0,
|
||||
reactive: true });
|
||||
|
||||
this._hotCornerActivationTime = 0;
|
||||
|
||||
this._hotCornerEnvirons.connect('leave-event',
|
||||
Lang.bind(this, this._onHotCornerEnvironsLeft));
|
||||
// Clicking on the hot corner environs should result in the same bahavior
|
||||
// as clicking on the hot corner.
|
||||
this._hotCornerEnvirons.connect('button-release-event',
|
||||
Lang.bind(this, this._onHotCornerClicked));
|
||||
|
||||
// In addition to being triggered by the mouse enter event, the hot corner
|
||||
// can be triggered by clicking on it. This is useful if the user wants to
|
||||
// undo the effect of triggering the hot corner once in the hot corner.
|
||||
hotCorner.connect('enter-event',
|
||||
Lang.bind(this, this._onHotCornerTriggered));
|
||||
hotCorner.connect('button-release-event',
|
||||
Lang.bind(this, this._onHotCornerTriggered));
|
||||
this._hotCorner.connect('enter-event',
|
||||
Lang.bind(this, this._onHotCornerEntered));
|
||||
this._hotCorner.connect('button-release-event',
|
||||
Lang.bind(this, this._onHotCornerClicked));
|
||||
this._hotCorner.connect('leave-event',
|
||||
Lang.bind(this, this._onHotCornerLeft));
|
||||
|
||||
box.add_actor(hotCorner);
|
||||
this._leftBox.append(this._hotCornerEnvirons, Big.BoxPackFlags.FIXED);
|
||||
this._leftBox.append(this._hotCorner, Big.BoxPackFlags.FIXED);
|
||||
|
||||
let statusbox = new Big.Box();
|
||||
let statusmenu = this._statusmenu = new Shell.StatusMenu();
|
||||
statusmenu.get_icon().hide();
|
||||
statusmenu.get_name().fontName = DEFAULT_FONT;
|
||||
statusmenu.get_name().color = PANEL_FOREGROUND_COLOR;
|
||||
statusbox.append(this._statusmenu, Big.BoxPackFlags.NONE);
|
||||
let statusbutton = new Button.Button(statusbox,
|
||||
PANEL_BUTTON_COLOR,
|
||||
PRESSED_BUTTON_BACKGROUND_COLOR,
|
||||
PANEL_FOREGROUND_COLOR,
|
||||
true, null, PANEL_HEIGHT);
|
||||
statusbutton.button.connect('button-press-event', function (b, e) {
|
||||
statusmenu.toggle(e);
|
||||
return false;
|
||||
});
|
||||
box.append(statusbutton.button, Big.BoxPackFlags.END);
|
||||
// We get a deactivated event when the popup disappears
|
||||
this._statusmenu.connect('deactivated', function (sm) {
|
||||
statusbutton.release();
|
||||
});
|
||||
let appMenu = new AppPanelMenu();
|
||||
this._leftBox.append(appMenu.actor, Big.BoxPackFlags.NONE);
|
||||
|
||||
/* center */
|
||||
|
||||
let clockButton = new St.Button({ style_class: "panel-button",
|
||||
toggle_mode: true });
|
||||
this._centerBox.append(clockButton, Big.BoxPackFlags.NONE);
|
||||
clockButton.connect('clicked', Lang.bind(this, this._toggleCalendar));
|
||||
|
||||
this._clock = new Clutter.Text({ font_name: DEFAULT_FONT,
|
||||
color: PANEL_FOREGROUND_COLOR,
|
||||
text: "" });
|
||||
let clockbox = new Big.Box({ y_align: Big.BoxAlignment.CENTER,
|
||||
padding_left: 4,
|
||||
padding_right: 4 });
|
||||
clockbox.append(this._clock, Big.BoxPackFlags.NONE);
|
||||
backBox.append(clockbox, Big.BoxPackFlags.EXPAND);
|
||||
clockButton.add_actor(this._clock);
|
||||
|
||||
this._calendarPopup = null;
|
||||
|
||||
/* right */
|
||||
|
||||
// The tray icons live in trayBox within trayContainer.
|
||||
// The trayBox is hidden when there are no tray icons.
|
||||
let trayContainer = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
y_align: Big.BoxAlignment.START });
|
||||
box.append(trayContainer, Big.BoxPackFlags.END);
|
||||
this._rightBox.append(trayContainer, Big.BoxPackFlags.NONE);
|
||||
let trayBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
height: TRAY_HEIGHT,
|
||||
padding: TRAY_PADDING,
|
||||
@ -164,22 +375,58 @@ Panel.prototype = {
|
||||
}));
|
||||
this._traymanager.manage_stage(global.stage);
|
||||
|
||||
// TODO: decide what to do with the rest of the panel in the overlay mode (make it fade-out, become non-reactive, etc.)
|
||||
// We get into the overlay mode on button-press-event as opposed to button-release-event because eventually we'll probably
|
||||
// have the overlay act like a menu that allows the user to release the mouse on the activity the user wants
|
||||
let statusbox = new Big.Box();
|
||||
let statusmenu = this._statusmenu = new Shell.StatusMenu();
|
||||
statusmenu.get_icon().hide();
|
||||
statusmenu.get_name().fontName = DEFAULT_FONT;
|
||||
statusmenu.get_name().color = PANEL_FOREGROUND_COLOR;
|
||||
statusbox.append(this._statusmenu, Big.BoxPackFlags.NONE);
|
||||
let statusbutton = new Button.Button(statusbox,
|
||||
PANEL_BUTTON_COLOR,
|
||||
PRESSED_BUTTON_BACKGROUND_COLOR,
|
||||
PANEL_FOREGROUND_COLOR);
|
||||
statusbutton.actor.height = PANEL_HEIGHT;
|
||||
statusbutton.actor.connect('button-press-event', function (b, e) {
|
||||
if (e.get_button() == 1 && e.get_click_count() == 1) {
|
||||
statusmenu.toggle(e);
|
||||
// The statusmenu might not pop up if it couldn't get a pointer grab
|
||||
if (statusmenu.is_active())
|
||||
statusbutton.actor.active = true;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
this._rightBox.append(statusbutton.actor, Big.BoxPackFlags.NONE);
|
||||
// We get a deactivated event when the popup disappears
|
||||
this._statusmenu.connect('deactivated', function (sm) {
|
||||
statusbutton.actor.active = false;
|
||||
});
|
||||
|
||||
// TODO: decide what to do with the rest of the panel in the Overview mode (make it fade-out, become non-reactive, etc.)
|
||||
// We get into the Overview mode on button-press-event as opposed to button-release-event because eventually we'll probably
|
||||
// have the Overview act like a menu that allows the user to release the mouse on the activity the user wants
|
||||
// to switch to.
|
||||
this.button.button.connect('button-press-event',
|
||||
Lang.bind(Main.overlay, Main.overlay.toggle));
|
||||
// In addition to pressing the button, the overlay can be entered and exited by other means, such as
|
||||
// pressing the System key, Alt+F1 or Esc. We want the button to be pressed in when the overlay is entered
|
||||
this.button.actor.connect('button-press-event', Lang.bind(this, function(b, e) {
|
||||
if (e.get_button() == 1 && e.get_click_count() == 1 && !Main.overview.animationInProgress) {
|
||||
this._maybeToggleOverviewOnClick();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
// In addition to pressing the button, the Overview can be entered and exited by other means, such as
|
||||
// pressing the System key, Alt+F1 or Esc. We want the button to be pressed in when the Overview is entered
|
||||
// and to be released when it is exited regardless of how it was triggered.
|
||||
Main.overlay.connect('showing', Lang.bind(this.button, this.button.pressIn));
|
||||
Main.overlay.connect('hiding', Lang.bind(this.button, this.button.release));
|
||||
Main.overview.connect('showing', Lang.bind(this, function() {
|
||||
this.button.actor.active = true;
|
||||
}));
|
||||
Main.overview.connect('hiding', Lang.bind(this, function() {
|
||||
this.button.actor.active = false;
|
||||
}));
|
||||
|
||||
this.actor.add_actor(box);
|
||||
|
||||
Main.chrome.addActor(this.actor, box);
|
||||
Main.chrome.setVisibleInOverlay(this.actor, true);
|
||||
Main.chrome.addActor(this.actor);
|
||||
Main.chrome.setVisibleInOverview(this.actor, true);
|
||||
|
||||
// Start the clock
|
||||
this._updateClock();
|
||||
@ -213,15 +460,111 @@ Panel.prototype = {
|
||||
displayDate.setMinutes(displayDate.getMinutes() + 1);
|
||||
msecRemaining += 60000;
|
||||
}
|
||||
this._clock.set_text(displayDate.toLocaleFormat("%a %l:%M %p"));
|
||||
/* Translators: This is a time format. */
|
||||
this._clock.set_text(displayDate.toLocaleFormat(_("%a %l:%M %p")));
|
||||
Mainloop.timeout_add(msecRemaining, Lang.bind(this, this._updateClock));
|
||||
return false;
|
||||
},
|
||||
|
||||
_onHotCornerTriggered : function() {
|
||||
if (!Main.overlay.animationInProgress) {
|
||||
Main.overlay.toggle();
|
||||
_toggleCalendar: function(clockButton) {
|
||||
if (clockButton.checked) {
|
||||
if (this._calendarPopup == null)
|
||||
this._calendarPopup = new CalendarPopup();
|
||||
this._calendarPopup.show();
|
||||
} else {
|
||||
this._calendarPopup.hide();
|
||||
}
|
||||
},
|
||||
|
||||
_onHotCornerEntered : function() {
|
||||
if (!this._hotCornerEntered) {
|
||||
this._hotCornerEntered = true;
|
||||
if (!Main.overview.animationInProgress) {
|
||||
this._hotCornerActivationTime = Date.now() / 1000;
|
||||
Main.overview.toggle();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
_onHotCornerClicked : function() {
|
||||
if (!Main.overview.animationInProgress) {
|
||||
this._maybeToggleOverviewOnClick();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_onHotCornerLeft : function(actor, event) {
|
||||
if (event.get_related() != this._hotCornerEnvirons) {
|
||||
this._hotCornerEntered = false;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_onHotCornerEnvironsLeft : function(actor, event) {
|
||||
if (event.get_related() != this._hotCorner) {
|
||||
this._hotCornerEntered = false;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
// Toggles the overview unless this is the first click on the Activities button within the HOT_CORNER_ACTIVATION_TIMEOUT time
|
||||
// of the hot corner being triggered. This check avoids opening and closing the overview if the user both triggered the hot corner
|
||||
// and clicked the Activities button.
|
||||
_maybeToggleOverviewOnClick: function() {
|
||||
if (this._hotCornerActivationTime == 0 || Date.now() / 1000 - this._hotCornerActivationTime > HOT_CORNER_ACTIVATION_TIMEOUT)
|
||||
Main.overview.toggle();
|
||||
this._hotCornerActivationTime = 0;
|
||||
}
|
||||
};
|
||||
|
||||
function CalendarPopup() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
CalendarPopup.prototype = {
|
||||
_init: function() {
|
||||
let panelActor = Main.panel.actor;
|
||||
|
||||
this.actor = new St.BoxLayout({ name: 'calendarPopup' });
|
||||
|
||||
this.calendar = new Calendar.Calendar();
|
||||
this.actor.add(this.calendar.actor);
|
||||
|
||||
// Directly adding the actor to Main.chrome.actor is a hack to
|
||||
// work around the fact that there is no way to add an actor that
|
||||
// affects the input region but not the shape.
|
||||
// See: https://bugzilla.gnome.org/show_bug.cgi?id=597044
|
||||
Main.chrome.actor.add_actor(this.actor);
|
||||
Main.chrome.addInputRegionActor(this.actor);
|
||||
this.actor.y = (panelActor.y + panelActor.height - this.actor.height);
|
||||
},
|
||||
|
||||
show: function() {
|
||||
let panelActor = Main.panel.actor;
|
||||
|
||||
// Reset the calendar to today's date
|
||||
this.calendar.setDate(new Date());
|
||||
|
||||
this.actor.x = Math.round(panelActor.x + (panelActor.width - this.actor.width) / 2);
|
||||
this.actor.lower(panelActor);
|
||||
this.actor.show();
|
||||
Tweener.addTween(this.actor,
|
||||
{ y: panelActor.y + panelActor.height,
|
||||
time: 0.2,
|
||||
transition: "easeOutQuad"
|
||||
});
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
let panelActor = Main.panel.actor;
|
||||
|
||||
Tweener.addTween(this.actor,
|
||||
{ y: panelActor.y + panelActor.height - this.actor.height,
|
||||
time: 0.2,
|
||||
transition: "easeOutQuad",
|
||||
onComplete: function() { this.actor.hide(); },
|
||||
onCompleteScope: this
|
||||
});
|
||||
}
|
||||
};
|
||||
|
234
js/ui/places.js
@ -9,31 +9,67 @@ const Shell = imports.gi.Shell;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Signals = imports.signals;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const DND = imports.ui.dnd;
|
||||
const Main = imports.ui.main;
|
||||
const GenericDisplay = imports.ui.genericDisplay;
|
||||
|
||||
const NAUTILUS_PREFS_DIR = '/apps/nautilus/preferences';
|
||||
const DESKTOP_IS_HOME_KEY = NAUTILUS_PREFS_DIR + '/desktop_is_home_dir';
|
||||
|
||||
const PLACES_VSPACING = 8;
|
||||
const PLACES_ICON_SIZE = 16;
|
||||
|
||||
function PlaceDisplay(name, icon, onActivate) {
|
||||
this._init(name, icon, onActivate);
|
||||
/**
|
||||
* An entry in the places menu.
|
||||
* @name: String title
|
||||
* @iconFactory: A JavaScript callback which will create an icon texture
|
||||
* @onActivate: A JavaScript callback to launch the entry
|
||||
*/
|
||||
function PlaceDisplay(name, iconFactory, onActivate) {
|
||||
this._init(name, iconFactory, onActivate);
|
||||
}
|
||||
|
||||
PlaceDisplay.prototype = {
|
||||
_init : function(name, iconTexture, onActivate) {
|
||||
_init : function(name, iconFactory, onActivate) {
|
||||
this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
reactive: true,
|
||||
spacing: 4 });
|
||||
this.actor.connect('button-press-event', Lang.bind(this, function (b, e) {
|
||||
this.actor.connect('button-release-event', Lang.bind(this, function (b, e) {
|
||||
onActivate(this);
|
||||
Main.overview.hide();
|
||||
}));
|
||||
let text = new Clutter.Text({ font_name: "Sans 14px",
|
||||
ellipsize: Pango.EllipsizeMode.END,
|
||||
color: GenericDisplay.ITEM_DISPLAY_NAME_COLOR,
|
||||
text: name });
|
||||
this.actor.append(iconTexture, Big.BoxPackFlags.NONE);
|
||||
let iconBox = new Big.Box({ y_align: Big.BoxAlignment.CENTER });
|
||||
this._icon = iconFactory();
|
||||
iconBox.append(this._icon, Big.BoxPackFlags.NONE);
|
||||
this.actor.append(iconBox, Big.BoxPackFlags.NONE);
|
||||
this.actor.append(text, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
this._iconFactory = iconFactory;
|
||||
this._onActivate = onActivate;
|
||||
|
||||
this.actor._delegate = this;
|
||||
let draggable = DND.makeDraggable(this.actor);
|
||||
},
|
||||
|
||||
getDragActorSource: function() {
|
||||
return this._icon;
|
||||
},
|
||||
|
||||
getDragActor: function(stageX, stageY) {
|
||||
return this._iconFactory();
|
||||
},
|
||||
|
||||
//// Drag and drop methods ////
|
||||
|
||||
shellWorkspaceLaunch : function() {
|
||||
this._onActivate();
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(PlaceDisplay.prototype);
|
||||
@ -44,26 +80,78 @@ function Places() {
|
||||
|
||||
Places.prototype = {
|
||||
_init : function() {
|
||||
// Places is divided semi-arbitrarily into left and right; a grid would
|
||||
// look better in that there would be an even number of items left+right,
|
||||
// but it seems like we want some sort of differentiation between actions
|
||||
// like "Connect to server..." and regular folders
|
||||
this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
spacing: 4 });
|
||||
this._menuBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
spacing: PLACES_VSPACING });
|
||||
this.actor.append(this._menuBox, Big.BoxPackFlags.EXPAND);
|
||||
this._leftBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL });
|
||||
this.actor.append(this._leftBox, Big.BoxPackFlags.EXPAND);
|
||||
this._rightBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL });
|
||||
this.actor.append(this._rightBox, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
// Subdivide left into actions and devices
|
||||
this._actionsBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
spacing: PLACES_VSPACING });
|
||||
this._leftBox.append(this._actionsBox, Big.BoxPackFlags.NONE);
|
||||
this._devBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
spacing: PLACES_VSPACING,
|
||||
padding_top: 6 });
|
||||
this._leftBox.append(this._devBox, Big.BoxPackFlags.NONE);
|
||||
|
||||
// Right is bookmarks
|
||||
this._dirsBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
spacing: PLACES_VSPACING });
|
||||
this.actor.append(this._dirsBox, Big.BoxPackFlags.EXPAND);
|
||||
this._rightBox.append(this._dirsBox, Big.BoxPackFlags.NONE);
|
||||
|
||||
let gconf = Shell.GConf.get_default();
|
||||
gconf.watch_directory(NAUTILUS_PREFS_DIR);
|
||||
|
||||
let homeFile = Gio.file_new_for_path (GLib.get_home_dir());
|
||||
let homeUri = homeFile.get_uri();
|
||||
let homeLabel = Shell.util_get_label_for_uri (homeUri);
|
||||
let homeIcon = Shell.util_get_icon_for_uri (homeUri);
|
||||
let homeTexture = Shell.TextureCache.get_default().load_gicon(homeIcon, PLACES_ICON_SIZE);
|
||||
let home = new PlaceDisplay(homeLabel, homeTexture, Lang.bind(this, function() {
|
||||
Main.overlay.hide();
|
||||
Gio.app_info_launch_default_for_uri(homeUri, Main.createAppLaunchContext());
|
||||
}));
|
||||
let home = new PlaceDisplay(homeLabel,
|
||||
function() {
|
||||
return Shell.TextureCache.get_default().load_gicon(homeIcon, PLACES_ICON_SIZE);
|
||||
},
|
||||
function() {
|
||||
Gio.app_info_launch_default_for_uri(homeUri, Main.createAppLaunchContext());
|
||||
});
|
||||
|
||||
this._menuBox.append(home.actor, Big.BoxPackFlags.NONE);
|
||||
this._actionsBox.append(home.actor, Big.BoxPackFlags.NONE);
|
||||
|
||||
let desktopPath = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DESKTOP);
|
||||
let desktopFile = Gio.file_new_for_path (desktopPath);
|
||||
let desktopUri = desktopFile.get_uri();
|
||||
let desktopLabel = Shell.util_get_label_for_uri (desktopUri);
|
||||
let desktopIcon = Shell.util_get_icon_for_uri (desktopUri);
|
||||
this._desktopMenu = new PlaceDisplay(desktopLabel,
|
||||
function() {
|
||||
return Shell.TextureCache.get_default().load_gicon(desktopIcon, PLACES_ICON_SIZE);
|
||||
},
|
||||
function() {
|
||||
Gio.app_info_launch_default_for_uri(desktopUri, Main.createAppLaunchContext());
|
||||
});
|
||||
this._actionsBox.append(this._desktopMenu.actor, Big.BoxPackFlags.NONE);
|
||||
this._updateDesktopMenuVisibility();
|
||||
gconf.connect('changed::' + DESKTOP_IS_HOME_KEY, Lang.bind(this, this._updateDesktopMenuVisibility));
|
||||
|
||||
/*
|
||||
* Show devices, code more or less ported from nautilus-places-sidebar.c
|
||||
*/
|
||||
this._volumeMonitor = Gio.VolumeMonitor.get();
|
||||
this._volumeMonitor.connect('volume-added', Lang.bind(this, this._updateDevices));
|
||||
this._volumeMonitor.connect('volume-removed',Lang.bind(this, this._updateDevices));
|
||||
this._volumeMonitor.connect('volume-changed', Lang.bind(this, this._updateDevices));
|
||||
this._volumeMonitor.connect('mount-added', Lang.bind(this, this._updateDevices));
|
||||
this._volumeMonitor.connect('mount-removed', Lang.bind(this, this._updateDevices));
|
||||
this._volumeMonitor.connect('mount-changed', Lang.bind(this, this._updateDevices));
|
||||
this._volumeMonitor.connect('drive-connected', Lang.bind(this, this._updateDevices));
|
||||
this._volumeMonitor.connect('drive-disconnected', Lang.bind(this, this._updateDevices));
|
||||
this._volumeMonitor.connect('drive-changed', Lang.bind(this, this._updateDevices));
|
||||
this._updateDevices();
|
||||
|
||||
let networkApp = null;
|
||||
try {
|
||||
@ -77,31 +165,35 @@ Places.prototype = {
|
||||
}
|
||||
|
||||
if (networkApp != null) {
|
||||
let networkIcon = networkApp.create_icon_texture(PLACES_ICON_SIZE);
|
||||
let network = new PlaceDisplay(networkApp.get_name(), networkIcon, Lang.bind(this, function () {
|
||||
Main.overlay.hide();
|
||||
networkApp.launch();
|
||||
}));
|
||||
this._menuBox.append(network.actor, Big.BoxPackFlags.NONE);
|
||||
let network = new PlaceDisplay(networkApp.get_name(),
|
||||
function() {
|
||||
return networkApp.create_icon_texture(PLACES_ICON_SIZE);
|
||||
},
|
||||
function () {
|
||||
networkApp.launch();
|
||||
});
|
||||
this._actionsBox.append(network.actor, Big.BoxPackFlags.NONE);
|
||||
}
|
||||
|
||||
let connectIcon = Shell.TextureCache.get_default().load_icon_name("applications-internet", PLACES_ICON_SIZE);
|
||||
let connect = new PlaceDisplay('Connect to...', connectIcon, Lang.bind(this, function () {
|
||||
Main.overlay.hide();
|
||||
new Shell.Process({ args: ['nautilus-connect-server'] }).run();
|
||||
}));
|
||||
this._menuBox.append(connect.actor, Big.BoxPackFlags.NONE);
|
||||
let connect = new PlaceDisplay(_("Connect to..."),
|
||||
function () {
|
||||
return Shell.TextureCache.get_default().load_icon_name("applications-internet", PLACES_ICON_SIZE);
|
||||
},
|
||||
function () {
|
||||
new Shell.Process({ args: ['nautilus-connect-server'] }).run();
|
||||
});
|
||||
this._actionsBox.append(connect.actor, Big.BoxPackFlags.NONE);
|
||||
|
||||
this._bookmarksPath = GLib.build_filenamev([GLib.get_home_dir(), ".gtk-bookmarks"]);
|
||||
this._bookmarksFile = Gio.file_new_for_path(this._bookmarksPath);
|
||||
let monitor = this._bookmarksFile.monitor_file(Gio.FileMonitorFlags.NONE, null);
|
||||
let timeoutId = 0;
|
||||
this._bookmarkTimeoutId = 0;
|
||||
monitor.connect('changed', Lang.bind(this, function () {
|
||||
if (timeoutId > 0)
|
||||
if (this._bookmarkTimeoutId > 0)
|
||||
return;
|
||||
/* Defensive event compression */
|
||||
timeoutId = Mainloop.timeout_add(100, Lang.bind(this, function () {
|
||||
this._timeoutId = 0;
|
||||
this._bookmarkTimeoutId = Mainloop.timeout_add(100, Lang.bind(this, function () {
|
||||
this._bookmarkTimeoutId = 0;
|
||||
this._reloadBookmarks();
|
||||
return false;
|
||||
}));
|
||||
@ -114,6 +206,9 @@ Places.prototype = {
|
||||
|
||||
this._dirsBox.remove_all();
|
||||
|
||||
if (!GLib.file_test(this._bookmarksPath, GLib.FileTest.EXISTS))
|
||||
return;
|
||||
|
||||
let [success, bookmarksContent, len] = GLib.file_get_contents(this._bookmarksPath);
|
||||
|
||||
if (!success)
|
||||
@ -147,13 +242,80 @@ Places.prototype = {
|
||||
if (label == null)
|
||||
continue;
|
||||
let icon = Shell.util_get_icon_for_uri(bookmark);
|
||||
let iconTexture = Shell.TextureCache.get_default().load_gicon(icon, PLACES_ICON_SIZE);
|
||||
let item = new PlaceDisplay(label, iconTexture, Lang.bind(this, function() {
|
||||
Main.overlay.hide();
|
||||
Gio.app_info_launch_default_for_uri(bookmark, Main.createAppLaunchContext());
|
||||
}));
|
||||
|
||||
let item = new PlaceDisplay(label,
|
||||
function() {
|
||||
return Shell.TextureCache.get_default().load_gicon(icon, PLACES_ICON_SIZE);
|
||||
},
|
||||
function() {
|
||||
Gio.app_info_launch_default_for_uri(bookmark, Main.createAppLaunchContext());
|
||||
});
|
||||
this._dirsBox.append(item.actor, Big.BoxPackFlags.NONE);
|
||||
}
|
||||
},
|
||||
|
||||
_updateDevices: function() {
|
||||
this._devBox.remove_all();
|
||||
|
||||
/* 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 mount = volumes[j].get_mount();
|
||||
if(mount != null) {
|
||||
this._addMount(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 mount = volumes[i].get_mount();
|
||||
if(mount != null) {
|
||||
this._addMount(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;
|
||||
|
||||
this._addMount(mounts[i]);
|
||||
}
|
||||
},
|
||||
|
||||
_addMount: function(mount) {
|
||||
let mountLabel = mount.get_name();
|
||||
let mountIcon = mount.get_icon();
|
||||
let root = mount.get_root();
|
||||
let mountUri = root.get_uri();
|
||||
let devItem = new PlaceDisplay(mountLabel,
|
||||
function() {
|
||||
return Shell.TextureCache.get_default().load_gicon(mountIcon, PLACES_ICON_SIZE);
|
||||
},
|
||||
function() {
|
||||
Gio.app_info_launch_default_for_uri(mountUri, Main.createAppLaunchContext());
|
||||
});
|
||||
this._devBox.append(devItem.actor, Big.BoxPackFlags.NONE);
|
||||
},
|
||||
|
||||
_updateDesktopMenuVisibility: function() {
|
||||
let gconf = Shell.GConf.get_default();
|
||||
let desktopIsHome = gconf.get_boolean(DESKTOP_IS_HOME_KEY);
|
||||
if (desktopIsHome)
|
||||
this._desktopMenu.actor.hide();
|
||||
else
|
||||
this._desktopMenu.actor.show();
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(Places.prototype);
|
||||
|
@ -2,24 +2,28 @@
|
||||
|
||||
const Big = imports.gi.Big;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const Lightbox = imports.ui.lightbox;
|
||||
const Main = imports.ui.main;
|
||||
|
||||
const OVERLAY_COLOR = new Clutter.Color();
|
||||
OVERLAY_COLOR.from_pixel(0x00000044);
|
||||
|
||||
const BOX_BACKGROUND_COLOR = new Clutter.Color();
|
||||
BOX_BACKGROUND_COLOR.from_pixel(0x000000cc);
|
||||
|
||||
const BOX_TEXT_COLOR = new Clutter.Color();
|
||||
BOX_TEXT_COLOR.from_pixel(0xffffffff);
|
||||
|
||||
const BOX_WIDTH = 320;
|
||||
const BOX_HEIGHT = 56;
|
||||
const DIALOG_WIDTH = 320;
|
||||
const DIALOG_PADDING = 6;
|
||||
const ICON_SIZE = 24;
|
||||
const ICON_BOX_SIZE = 36;
|
||||
|
||||
function RunDialog() {
|
||||
this._init();
|
||||
@ -27,72 +31,114 @@ function RunDialog() {
|
||||
|
||||
RunDialog.prototype = {
|
||||
_init : function() {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
this._isOpen = false;
|
||||
|
||||
let gconf = Shell.GConf.get_default();
|
||||
gconf.connect('changed::development_tools', Lang.bind(this, function () {
|
||||
this._enableInternalCommands = gconf.get_boolean('development_tools');
|
||||
}));
|
||||
this._enableInternalCommands = gconf.get_boolean('development_tools');
|
||||
|
||||
this._internalCommands = { 'lg':
|
||||
Lang.bind(this, function() {
|
||||
Mainloop.idle_add(function() { Main.createLookingGlass().open(); });
|
||||
Main.createLookingGlass().open();
|
||||
}),
|
||||
|
||||
'restart': Lang.bind(this, function() {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
'r': Lang.bind(this, function() {
|
||||
global.reexec_self();
|
||||
}),
|
||||
|
||||
// Developer brain backwards compatibility
|
||||
'restart': Lang.bind(this, function() {
|
||||
global.reexec_self();
|
||||
}),
|
||||
|
||||
'debugexit': Lang.bind(this, function() {
|
||||
Meta.exit(Meta.ExitCode.ERROR);
|
||||
})
|
||||
};
|
||||
|
||||
// All actors are inside _group. We create it initially
|
||||
// hidden then show it in show()
|
||||
this._group = new Clutter.Group({ visible: false });
|
||||
this._group = new Clutter.Group({ visible: false,
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: global.screen_width,
|
||||
height: global.screen_height });
|
||||
global.stage.add_actor(this._group);
|
||||
|
||||
this._overlay = new Clutter.Rectangle({ color: OVERLAY_COLOR,
|
||||
width: global.screen_width,
|
||||
height: global.screen_height,
|
||||
border_width: 0,
|
||||
reactive: true });
|
||||
this._group.add_actor(this._overlay);
|
||||
let lightbox = new Lightbox.Lightbox(this._group);
|
||||
|
||||
let boxGroup = new Clutter.Group();
|
||||
boxGroup.set_position((global.screen_width - BOX_WIDTH) / 2,
|
||||
(global.screen_height - BOX_HEIGHT) / 2);
|
||||
this._group.add_actor(boxGroup);
|
||||
this._boxH = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
x_align: Big.BoxAlignment.CENTER,
|
||||
y_align: Big.BoxAlignment.CENTER });
|
||||
|
||||
let box = new Big.Box({ background_color: BOX_BACKGROUND_COLOR,
|
||||
corner_radius: 4,
|
||||
reactive: false,
|
||||
width: BOX_WIDTH,
|
||||
height: BOX_HEIGHT
|
||||
});
|
||||
boxGroup.add_actor(box);
|
||||
this._group.add_actor(this._boxH);
|
||||
lightbox.highlight(this._boxH);
|
||||
|
||||
let boxV = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
y_align: Big.BoxAlignment.CENTER });
|
||||
|
||||
this._boxH.append(boxV, Big.BoxPackFlags.NONE);
|
||||
|
||||
|
||||
let dialogBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
background_color: BOX_BACKGROUND_COLOR,
|
||||
corner_radius: 4,
|
||||
reactive: false,
|
||||
padding: DIALOG_PADDING,
|
||||
width: DIALOG_WIDTH });
|
||||
|
||||
this._boxH.append(dialogBox, Big.BoxPackFlags.NONE);
|
||||
|
||||
let label = new Clutter.Text({ color: BOX_TEXT_COLOR,
|
||||
font_name: '18px Sans',
|
||||
text: 'Please enter a command:' });
|
||||
label.set_position(6, 6);
|
||||
boxGroup.add_actor(label);
|
||||
text: _("Please enter a command:") });
|
||||
|
||||
dialogBox.append(label, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
this._entry = new Clutter.Text({ color: BOX_TEXT_COLOR,
|
||||
font_name: '20px Sans Bold',
|
||||
editable: true,
|
||||
activatable: true,
|
||||
singleLineMode: true,
|
||||
text: '',
|
||||
width: BOX_WIDTH - 12,
|
||||
height: BOX_HEIGHT - 12 });
|
||||
// TODO: Implement relative positioning using Tidy.
|
||||
this._entry.set_position(6, 30);
|
||||
boxGroup.add_actor(this._entry);
|
||||
singleLineMode: true });
|
||||
|
||||
dialogBox.append(this._entry, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
this._errorBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
padding_top: DIALOG_PADDING });
|
||||
|
||||
dialogBox.append(this._errorBox, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
let iconBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
y_align: Big.BoxAlignment.CENTER,
|
||||
x_align: Big.BoxAlignment.CENTER,
|
||||
width: ICON_BOX_SIZE,
|
||||
height: ICON_BOX_SIZE });
|
||||
|
||||
this._errorBox.append(iconBox, Big.BoxPackFlags.NONE);
|
||||
|
||||
this._commandError = false;
|
||||
|
||||
let errorIcon = Shell.TextureCache.get_default().load_icon_name("gtk-dialog-error", ICON_SIZE);
|
||||
iconBox.append(errorIcon, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
this._errorMessage = new Clutter.Text({ color: BOX_TEXT_COLOR,
|
||||
font_name: '18px Sans Bold',
|
||||
line_wrap: true });
|
||||
|
||||
this._errorBox.append(this._errorMessage, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
this._errorBox.hide();
|
||||
|
||||
this._entry.connect('activate', Lang.bind(this, function (o, e) {
|
||||
this._run(o.get_text());
|
||||
this.close();
|
||||
return false;
|
||||
if (!this._commandError)
|
||||
this.close();
|
||||
}));
|
||||
|
||||
|
||||
this._entry.connect('key-press-event', Lang.bind(this, function(o, e) {
|
||||
let symbol = Shell.get_event_key_symbol(e);
|
||||
let symbol = e.get_key_symbol();
|
||||
if (symbol == Clutter.Escape) {
|
||||
this.close();
|
||||
return true;
|
||||
@ -102,16 +148,31 @@ RunDialog.prototype = {
|
||||
},
|
||||
|
||||
_run : function(command) {
|
||||
let f = this._internalCommands[command];
|
||||
this._commandError = false;
|
||||
let f;
|
||||
if (this._enableInternalCommands)
|
||||
f = this._internalCommands[command];
|
||||
else
|
||||
f = null;
|
||||
if (f) {
|
||||
f();
|
||||
} else if (command) {
|
||||
var p = new Shell.Process({'args' : [command]});
|
||||
try {
|
||||
let [ok, len, args] = GLib.shell_parse_argv(command);
|
||||
let p = new Shell.Process({'args' : args});
|
||||
p.run();
|
||||
} catch (e) {
|
||||
// TODO: Give the user direct feedback.
|
||||
log('Could not run command ' + command + '.');
|
||||
this._commandError = true;
|
||||
/*
|
||||
* The exception contains an error string like:
|
||||
* Error invoking Shell.run: Failed to execute child process "foo"
|
||||
* (No such file or directory)
|
||||
* We are only interested in the actual error, so parse that out.
|
||||
*/
|
||||
let m = /.+\((.+)\)/.exec(e);
|
||||
let errorStr = _("Execution of '%s' failed:").format(command) + "\n" + m[1];
|
||||
this._errorMessage.set_text(errorStr);
|
||||
this._errorBox.show();
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -120,13 +181,18 @@ RunDialog.prototype = {
|
||||
if (this._isOpen) // Already shown
|
||||
return;
|
||||
|
||||
if (!Main.startModal())
|
||||
if (!Main.pushModal(this._group))
|
||||
return;
|
||||
|
||||
|
||||
// Position the dialog on the current monitor
|
||||
let monitor = global.get_focus_monitor();
|
||||
|
||||
this._boxH.set_position(monitor.x, monitor.y);
|
||||
this._boxH.set_size(monitor.width, monitor.height);
|
||||
|
||||
this._isOpen = true;
|
||||
this._group.show();
|
||||
|
||||
let global = Shell.Global.get();
|
||||
global.stage.set_key_focus(this._entry);
|
||||
},
|
||||
|
||||
@ -136,10 +202,13 @@ RunDialog.prototype = {
|
||||
|
||||
this._isOpen = false;
|
||||
|
||||
this._errorBox.hide();
|
||||
this._commandError = false;
|
||||
|
||||
this._group.hide();
|
||||
this._entry.text = '';
|
||||
|
||||
Main.endModal();
|
||||
Main.popModal(this._group);
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(RunDialog.prototype);
|
||||
|
72
js/ui/shellDBus.js
Normal file
@ -0,0 +1,72 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const DBus = imports.dbus;
|
||||
const Lang = imports.lang;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Mainloop = imports.mainloop;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
|
||||
const GnomeShellIface = {
|
||||
name: "org.gnome.Shell",
|
||||
methods: [{ name: "Eval",
|
||||
inSignature: "s",
|
||||
outSignature: "bs"
|
||||
}
|
||||
],
|
||||
signals: [],
|
||||
properties: [{ name: "OverviewActive",
|
||||
signature: "b",
|
||||
access: "readwrite" }]
|
||||
};
|
||||
|
||||
function GnomeShell() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
GnomeShell.prototype = {
|
||||
_init: function() {
|
||||
DBus.session.exportObject('/org/gnome/Shell', this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Eval:
|
||||
* @code: A string containing JavaScript code
|
||||
*
|
||||
* This function executes arbitrary code in the main
|
||||
* loop, and returns a boolean success and
|
||||
* JSON representation of the object as a string.
|
||||
*
|
||||
* If evaluation completes without throwing an exception,
|
||||
* then the return value will be [true, JSON.stringify(result)].
|
||||
* If evaluation fails, then the return value will be
|
||||
* [false, JSON.stringify(exception)];
|
||||
*
|
||||
*/
|
||||
Eval: function(code) {
|
||||
let returnValue;
|
||||
let success;
|
||||
try {
|
||||
returnValue = JSON.stringify(eval(code));
|
||||
success = true;
|
||||
} catch (e) {
|
||||
returnValue = JSON.stringify(e);
|
||||
success = false;
|
||||
}
|
||||
return [success, returnValue];
|
||||
},
|
||||
|
||||
get OverviewActive() {
|
||||
return Main.overview.visible;
|
||||
},
|
||||
|
||||
set OverviewActive(visible) {
|
||||
if (visible)
|
||||
Main.overview.show();
|
||||
else
|
||||
Main.overview.hide();
|
||||
}
|
||||
};
|
||||
|
||||
DBus.conformExport(GnomeShell.prototype, GnomeShellIface);
|
||||
|
@ -21,21 +21,12 @@ const SIDEBAR_PADDING = 4;
|
||||
const SIDEBAR_COLLAPSED_WIDTH = Widget.COLLAPSED_WIDTH + 3 * WidgetBox.WIDGETBOX_PADDING + SIDEBAR_PADDING;
|
||||
const SIDEBAR_EXPANDED_WIDTH = Widget.EXPANDED_WIDTH + 3 * WidgetBox.WIDGETBOX_PADDING + SIDEBAR_PADDING;
|
||||
|
||||
// The maximum height of the sidebar would be extending from just
|
||||
// below the panel to just above the taskbar. Since the taskbar is
|
||||
// just a temporary hack and it would be too hard to do this the right
|
||||
// way, we just hardcode its size.
|
||||
const HARDCODED_TASKBAR_HEIGHT = 24;
|
||||
const MAXIMUM_SIDEBAR_HEIGHT = Shell.Global.get().screen_height - Panel.PANEL_HEIGHT - HARDCODED_TASKBAR_HEIGHT;
|
||||
|
||||
function Sidebar() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
Sidebar.prototype = {
|
||||
_init : function() {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
// The top-left corner of the sidebar is fixed at:
|
||||
// x = -WidgetBox.WIDGETBOX_PADDING, y = Panel.PANEL_HEIGHT.
|
||||
// (The negative X is so that we don't see the rounded
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Signals = imports.signals;
|
||||
@ -41,9 +42,17 @@ const Tweener = imports.tweener.tweener;
|
||||
// calls any of these is almost certainly wrong anyway, because they
|
||||
// affect the entire application.)
|
||||
|
||||
let slowDownFactor = 1.0;
|
||||
|
||||
// Called from Main.start
|
||||
function init() {
|
||||
let slowdownEnv = GLib.getenv("GNOME_SHELL_SLOWDOWN_FACTOR");
|
||||
if (slowdownEnv) {
|
||||
let factor = parseFloat(slowdownEnv);
|
||||
if (!isNaN(factor) && factor > 0.0)
|
||||
slowDownFactor = factor;
|
||||
}
|
||||
|
||||
Tweener.setFrameTicker(new ClutterFrameTicker());
|
||||
}
|
||||
|
||||
@ -208,11 +217,10 @@ ClutterFrameTicker.prototype = {
|
||||
this._startTime = -1;
|
||||
this._currentTime = -1;
|
||||
|
||||
let me = this;
|
||||
this._timeline.connect('new-frame',
|
||||
this._timeline.connect('new-frame', Lang.bind(this,
|
||||
function(timeline, frame) {
|
||||
me._onNewFrame(frame);
|
||||
});
|
||||
this._onNewFrame(frame);
|
||||
}));
|
||||
},
|
||||
|
||||
_onNewFrame : function(frame) {
|
||||
@ -225,7 +233,7 @@ ClutterFrameTicker.prototype = {
|
||||
this._startTime = this._timeline.get_elapsed_time();
|
||||
|
||||
// currentTime is in milliseconds
|
||||
this._currentTime = this._timeline.get_elapsed_time() - this._startTime;
|
||||
this._currentTime = (this._timeline.get_elapsed_time() - this._startTime) / slowDownFactor;
|
||||
this.emit('prepare-frame');
|
||||
},
|
||||
|
||||
|
@ -9,6 +9,8 @@ const Lang = imports.lang;
|
||||
const Pango = imports.gi.Pango;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const DocInfo = imports.misc.docInfo;
|
||||
|
||||
@ -156,11 +158,11 @@ ClockWidget.prototype = {
|
||||
},
|
||||
|
||||
_updateText: function(time) {
|
||||
this.actor.set_text(time.toLocaleFormat("%H:%M"));
|
||||
// Translators: This is a time format.
|
||||
this.actor.set_text(time.toLocaleFormat(_("%H:%M")));
|
||||
},
|
||||
|
||||
_updateCairo: function(time) {
|
||||
let global = Shell.Global.get();
|
||||
Shell.draw_clock(this.collapsedActor,
|
||||
time.getHours() % 12,
|
||||
time.getMinutes());
|
||||
@ -311,7 +313,7 @@ AppsWidget.prototype = {
|
||||
_init : function() {
|
||||
Widget.prototype._init.apply(this, arguments);
|
||||
|
||||
this.title = "Applications";
|
||||
this.title = _("Applications");
|
||||
this.actor = new Big.Box({ spacing: 2 });
|
||||
this.collapsedActor = new Big.Box({ spacing: 2});
|
||||
|
||||
@ -336,7 +338,7 @@ RecentDocsWidget.prototype = {
|
||||
_init : function() {
|
||||
Widget.prototype._init.apply(this, arguments);
|
||||
|
||||
this.title = "Recent Documents";
|
||||
this.title = _("Recent Documents");
|
||||
this.actor = new Big.Box({ spacing: 2 });
|
||||
|
||||
this._recentManager = Gtk.RecentManager.get_default();
|
||||
|
@ -296,7 +296,7 @@ WidgetBox.prototype = {
|
||||
this.state == Widget.STATE_POPPING_OUT)) {
|
||||
// If moving into another actor within this._hbox, let the
|
||||
// event be propagated
|
||||
let into = Shell.get_event_related(event);
|
||||
let into = event.get_related();
|
||||
while (into) {
|
||||
if (into == this._hbox)
|
||||
return false;
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Shell = imports.gi.Shell;
|
||||
@ -17,10 +18,8 @@ function WindowManager() {
|
||||
|
||||
WindowManager.prototype = {
|
||||
_init : function() {
|
||||
let me = this;
|
||||
let shellwm = global.window_manager;
|
||||
|
||||
this._global = Shell.Global.get();
|
||||
this._shellwm = this._global.window_manager;
|
||||
this._minimizing = [];
|
||||
this._maximizing = [];
|
||||
this._unmaximizing = [];
|
||||
@ -28,64 +27,25 @@ WindowManager.prototype = {
|
||||
this._destroying = [];
|
||||
|
||||
this._switchData = null;
|
||||
this._shellwm.connect('switch-workspace',
|
||||
function(o, from, to, direction) {
|
||||
let actors = me._shellwm.get_switch_workspace_actors();
|
||||
me._switchWorkspace(actors, from, to, direction);
|
||||
});
|
||||
this._shellwm.connect('kill-switch-workspace',
|
||||
function(o) {
|
||||
me._switchWorkspaceDone();
|
||||
});
|
||||
this._shellwm.connect('minimize',
|
||||
function(o, actor) {
|
||||
me._minimizeWindow(actor);
|
||||
});
|
||||
this._shellwm.connect('kill-minimize',
|
||||
function(o, actor) {
|
||||
me._minimizeWindowDone(actor);
|
||||
});
|
||||
this._shellwm.connect('maximize',
|
||||
function(o, actor, tx, ty, tw, th) {
|
||||
me._maximizeWindow(actor, tx, ty, tw, th);
|
||||
});
|
||||
this._shellwm.connect('kill-maximize',
|
||||
function(o, actor) {
|
||||
me._maximizeWindowDone(actor);
|
||||
});
|
||||
this._shellwm.connect('unmaximize',
|
||||
function(o, actor, tx, ty, tw, th) {
|
||||
me._unmaximizeWindow(actor, tx, ty, tw, th);
|
||||
});
|
||||
this._shellwm.connect('kill-unmaximize',
|
||||
function(o, actor) {
|
||||
me._unmaximizeWindowDone(actor);
|
||||
});
|
||||
this._shellwm.connect('map',
|
||||
function(o, actor) {
|
||||
me._mapWindow(actor);
|
||||
});
|
||||
this._shellwm.connect('kill-map',
|
||||
function(o, actor) {
|
||||
me._mapWindowDone(actor);
|
||||
});
|
||||
this._shellwm.connect('destroy',
|
||||
function(o, actor) {
|
||||
me._destroyWindow(actor);
|
||||
});
|
||||
this._shellwm.connect('kill-destroy',
|
||||
function(o, actor) {
|
||||
me._destroyWindowDone(actor);
|
||||
});
|
||||
shellwm.connect('switch-workspace', Lang.bind(this, this._switchWorkspace));
|
||||
shellwm.connect('kill-switch-workspace', Lang.bind(this, this._switchWorkspaceDone));
|
||||
shellwm.connect('minimize', Lang.bind(this, this._minimizeWindow));
|
||||
shellwm.connect('kill-minimize', Lang.bind(this, this._minimizeWindowDone));
|
||||
shellwm.connect('maximize', Lang.bind(this, this._maximizeWindow));
|
||||
shellwm.connect('kill-maximize', Lang.bind(this, this._maximizeWindowDone));
|
||||
shellwm.connect('unmaximize', Lang.bind(this, this._unmaximizeWindow));
|
||||
shellwm.connect('kill-unmaximize', Lang.bind(this, this._unmaximizeWindowDone));
|
||||
shellwm.connect('map', Lang.bind(this, this._mapWindow));
|
||||
shellwm.connect('kill-map', Lang.bind(this, this._mapWindowDone));
|
||||
shellwm.connect('destroy', Lang.bind(this, this._destroyWindow));
|
||||
shellwm.connect('kill-destroy', Lang.bind(this, this._destroyWindowDone));
|
||||
|
||||
this._shellwm.connect('begin-alt-tab',
|
||||
function(o, handler) {
|
||||
me._beginAltTab(handler);
|
||||
});
|
||||
shellwm.takeover_keybinding('switch_windows');
|
||||
shellwm.connect('keybinding::switch_windows', Lang.bind(this, this._startAppSwitcher));
|
||||
},
|
||||
|
||||
_shouldAnimate : function(actor) {
|
||||
if (Main.overlay.visible)
|
||||
if (Main.overview.visible)
|
||||
return false;
|
||||
if (actor && (actor.get_window_type() != Meta.CompWindowType.NORMAL))
|
||||
return false;
|
||||
@ -101,9 +61,9 @@ WindowManager.prototype = {
|
||||
return false;
|
||||
},
|
||||
|
||||
_minimizeWindow : function(actor) {
|
||||
_minimizeWindow : function(shellwm, actor) {
|
||||
if (!this._shouldAnimate(actor)) {
|
||||
this._shellwm.completed_minimize(actor);
|
||||
shellwm.completed_minimize(actor);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -121,86 +81,49 @@ WindowManager.prototype = {
|
||||
transition: "easeOutQuad",
|
||||
onComplete: this._minimizeWindowDone,
|
||||
onCompleteScope: this,
|
||||
onCompleteParams: [actor],
|
||||
onCompleteParams: [shellwm, actor],
|
||||
onOverwrite: this._minimizeWindowOverwritten,
|
||||
onOverwriteScope: this,
|
||||
onOverwriteParams: [actor]
|
||||
onOverwriteParams: [shellwm, actor]
|
||||
});
|
||||
},
|
||||
|
||||
_minimizeWindowDone : function(actor) {
|
||||
_minimizeWindowDone : function(shellwm, actor) {
|
||||
if (this._removeEffect(this._minimizing, actor)) {
|
||||
Tweener.removeTweens(actor);
|
||||
actor.set_scale(1.0, 1.0);
|
||||
actor.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_WEST);
|
||||
|
||||
this._shellwm.completed_minimize(actor);
|
||||
shellwm.completed_minimize(actor);
|
||||
}
|
||||
},
|
||||
|
||||
_minimizeWindowOverwritten : function(actor) {
|
||||
_minimizeWindowOverwritten : function(shellwm, actor) {
|
||||
if (this._removeEffect(this._minimizing, actor)) {
|
||||
this._shellwm.completed_minimize(actor);
|
||||
shellwm.completed_minimize(actor);
|
||||
}
|
||||
},
|
||||
|
||||
_maximizeWindow : function(actor, targetX, targetY, targetWidth, targetHeight) {
|
||||
_maximizeWindow : function(shellwm, actor, targetX, targetY, targetWidth, targetHeight) {
|
||||
shellwm.completed_maximize(actor);
|
||||
},
|
||||
|
||||
_maximizeWindowDone : function(shellwm, actor) {
|
||||
},
|
||||
|
||||
_maximizeWindowOverwrite : function(shellwm, actor) {
|
||||
},
|
||||
|
||||
_unmaximizeWindow : function(shellwm, actor, targetX, targetY, targetWidth, targetHeight) {
|
||||
shellwm.completed_unmaximize(actor);
|
||||
},
|
||||
|
||||
_unmaximizeWindowDone : function(shellwm, actor) {
|
||||
},
|
||||
|
||||
_mapWindow : function(shellwm, actor) {
|
||||
if (!this._shouldAnimate(actor)) {
|
||||
this._shellwm.completed_maximize(actor);
|
||||
return;
|
||||
}
|
||||
|
||||
/* this doesn't work very well, as simply scaling up the existing
|
||||
* window contents doesn't produce anything like the same results as
|
||||
* actually maximizing the window.
|
||||
*/
|
||||
let scaleX = targetWidth / actor.width;
|
||||
let scaleY = targetHeight / actor.height;
|
||||
let anchorX = (actor.x - targetX) * actor.width/(targetWidth - actor.width);
|
||||
let anchorY = (actor.y - targetY) * actor.height/(targetHeight - actor.height);
|
||||
|
||||
actor.move_anchor_point(anchorX, anchorY);
|
||||
|
||||
this._maximizing.push(actor);
|
||||
Tweener.addTween(actor,
|
||||
{ scale_x: scaleX,
|
||||
scale_y: scaleY,
|
||||
time: WINDOW_ANIMATION_TIME,
|
||||
transition: "easeOutQuad",
|
||||
onComplete: this._maximizeWindowDone,
|
||||
onCompleteScope: this,
|
||||
onCompleteParams: [actor],
|
||||
onOverwrite: this._maximizeWindowOverwrite,
|
||||
onOverwriteScope: this,
|
||||
onOverwriteParams: [actor]
|
||||
});
|
||||
},
|
||||
|
||||
_maximizeWindowDone : function(actor) {
|
||||
if (this._removeEffect(this._maximizing, actor)) {
|
||||
Tweener.removeTweens(actor);
|
||||
actor.set_scale(1.0, 1.0);
|
||||
actor.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_WEST);
|
||||
this._shellwm.completed_maximize(actor);
|
||||
}
|
||||
},
|
||||
|
||||
_maximizeWindowOverwrite : function(actor) {
|
||||
if (this._removeEffect(this._maximizing, actor)) {
|
||||
this._shellwm.completed_maximize(actor);
|
||||
}
|
||||
},
|
||||
|
||||
_unmaximizeWindow : function(actor, targetX, targetY, targetWidth, targetHeight) {
|
||||
this._shellwm.completed_unmaximize(actor);
|
||||
},
|
||||
|
||||
_unmaximizeWindowDone : function(actor) {
|
||||
},
|
||||
|
||||
_mapWindow : function(actor) {
|
||||
if (!this._shouldAnimate(actor)) {
|
||||
this._shellwm.completed_map(actor);
|
||||
shellwm.completed_map(actor);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -217,72 +140,43 @@ WindowManager.prototype = {
|
||||
transition: "easeOutQuad",
|
||||
onComplete: this._mapWindowDone,
|
||||
onCompleteScope: this,
|
||||
onCompleteParams: [actor],
|
||||
onCompleteParams: [shellwm, actor],
|
||||
onOverwrite: this._mapWindowOverwrite,
|
||||
onOverwriteScope: this,
|
||||
onOverwriteParams: [actor]
|
||||
onOverwriteParams: [shellwm, actor]
|
||||
});
|
||||
},
|
||||
|
||||
_mapWindowDone : function(actor) {
|
||||
_mapWindowDone : function(shellwm, actor) {
|
||||
if (this._removeEffect(this._mapping, actor)) {
|
||||
Tweener.removeTweens(actor);
|
||||
actor.set_scale(1.0, 1.0);
|
||||
actor.move_anchor_point_from_gravity(Clutter.Gravity.NORTH_WEST);
|
||||
this._shellwm.completed_map(actor);
|
||||
shellwm.completed_map(actor);
|
||||
}
|
||||
},
|
||||
|
||||
_mapWindowOverwrite : function(actor) {
|
||||
_mapWindowOverwrite : function(shellwm, actor) {
|
||||
if (this._removeEffect(this._mapping, actor)) {
|
||||
this._shellwm.completed_map(actor);
|
||||
shellwm.completed_map(actor);
|
||||
}
|
||||
},
|
||||
|
||||
_destroyWindow : function(actor) {
|
||||
if (!this._shouldAnimate(actor)) {
|
||||
this._shellwm.completed_destroy(actor);
|
||||
return;
|
||||
}
|
||||
|
||||
actor.move_anchor_point_from_gravity(Clutter.Gravity.CENTER);
|
||||
|
||||
/* anachronistic 'tv-like' effect - squash on y axis, leave x alone */
|
||||
this._destroying.push(actor);
|
||||
Tweener.addTween(actor,
|
||||
{ scale_x: 1.0,
|
||||
scale_y: 0.0,
|
||||
time: WINDOW_ANIMATION_TIME,
|
||||
transition: "easeOutQuad",
|
||||
onComplete: this._destroyWindowDone,
|
||||
onCompleteScope: this,
|
||||
onCompleteParams: [actor],
|
||||
onOverwrite: this._destroyWindowOverwrite,
|
||||
onOverwriteScope: this,
|
||||
onOverwriteParams: [actor]
|
||||
});
|
||||
_destroyWindow : function(shellwm, actor) {
|
||||
shellwm.completed_destroy(actor);
|
||||
},
|
||||
|
||||
_destroyWindowDone : function(actor) {
|
||||
if (this._removeEffect(this._destroying, actor)) {
|
||||
this._shellwm.completed_destroy(actor);
|
||||
Tweener.removeTweens(actor);
|
||||
actor.set_scale(1.0, 1.0);
|
||||
}
|
||||
_destroyWindowDone : function(shellwm, actor) {
|
||||
},
|
||||
|
||||
_destroyWindowOverwrite : function(actor) {
|
||||
if (this._removeEffect(this._destroying, actor)) {
|
||||
this._shellwm.completed_destroy(actor);
|
||||
}
|
||||
},
|
||||
|
||||
_switchWorkspace : function(windows, from, to, direction) {
|
||||
_switchWorkspace : function(shellwm, from, to, direction) {
|
||||
if (!this._shouldAnimate()) {
|
||||
this._shellwm.completed_switch_workspace();
|
||||
shellwm.completed_switch_workspace();
|
||||
return;
|
||||
}
|
||||
|
||||
let windows = shellwm.get_switch_workspace_actors();
|
||||
|
||||
/* @direction is the direction that the "camera" moves, so the
|
||||
* screen contents have to move one screen's worth in the
|
||||
* opposite direction.
|
||||
@ -292,20 +186,20 @@ WindowManager.prototype = {
|
||||
if (direction == Meta.MotionDirection.UP ||
|
||||
direction == Meta.MotionDirection.UP_LEFT ||
|
||||
direction == Meta.MotionDirection.UP_RIGHT)
|
||||
yDest = this._global.screen_height;
|
||||
yDest = global.screen_height;
|
||||
else if (direction == Meta.MotionDirection.DOWN ||
|
||||
direction == Meta.MotionDirection.DOWN_LEFT ||
|
||||
direction == Meta.MotionDirection.DOWN_RIGHT)
|
||||
yDest = -this._global.screen_height;
|
||||
yDest = -global.screen_height;
|
||||
|
||||
if (direction == Meta.MotionDirection.LEFT ||
|
||||
direction == Meta.MotionDirection.UP_LEFT ||
|
||||
direction == Meta.MotionDirection.DOWN_LEFT)
|
||||
xDest = this._global.screen_width;
|
||||
xDest = global.screen_width;
|
||||
else if (direction == Meta.MotionDirection.RIGHT ||
|
||||
direction == Meta.MotionDirection.UP_RIGHT ||
|
||||
direction == Meta.MotionDirection.DOWN_RIGHT)
|
||||
xDest = -this._global.screen_width;
|
||||
xDest = -global.screen_width;
|
||||
|
||||
let switchData = {};
|
||||
this._switchData = switchData;
|
||||
@ -313,7 +207,7 @@ WindowManager.prototype = {
|
||||
switchData.outGroup = new Clutter.Group();
|
||||
switchData.windows = [];
|
||||
|
||||
let wgroup = this._global.window_group;
|
||||
let wgroup = global.window_group;
|
||||
wgroup.add_actor(switchData.inGroup);
|
||||
wgroup.add_actor(switchData.outGroup);
|
||||
|
||||
@ -344,7 +238,8 @@ WindowManager.prototype = {
|
||||
time: WINDOW_ANIMATION_TIME,
|
||||
transition: "easeOutQuad",
|
||||
onComplete: this._switchWorkspaceDone,
|
||||
onCompleteScope: this
|
||||
onCompleteScope: this,
|
||||
onCompleteParams: [shellwm]
|
||||
});
|
||||
Tweener.addTween(switchData.inGroup,
|
||||
{ x: 0,
|
||||
@ -354,7 +249,7 @@ WindowManager.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
_switchWorkspaceDone : function() {
|
||||
_switchWorkspaceDone : function(shellwm) {
|
||||
let switchData = this._switchData;
|
||||
if (!switchData)
|
||||
return;
|
||||
@ -373,15 +268,13 @@ WindowManager.prototype = {
|
||||
switchData.inGroup.destroy();
|
||||
switchData.outGroup.destroy();
|
||||
|
||||
this._shellwm.completed_switch_workspace();
|
||||
shellwm.completed_switch_workspace();
|
||||
},
|
||||
|
||||
_beginAltTab : function(handler) {
|
||||
let popup = new AltTab.AltTabPopup();
|
||||
_startAppSwitcher : function(shellwm, binding, window, backwards) {
|
||||
let tabPopup = new AltTab.AltTabPopup();
|
||||
|
||||
handler.connect('window-added', function(handler, window) { popup.addWindow(window); });
|
||||
handler.connect('show', function(handler, initialSelection) { popup.show(initialSelection); });
|
||||
handler.connect('destroy', function() { popup.destroy(); });
|
||||
handler.connect('notify::selected', function() { popup.select(handler.selected); });
|
||||
}
|
||||
if (!tabPopup.show(backwards))
|
||||
tabPopup.destroy();
|
||||
}
|
||||
};
|
||||
|
22
po/LINGUAS
Normal file
@ -0,0 +1,22 @@
|
||||
ar
|
||||
ca
|
||||
cs
|
||||
da
|
||||
de
|
||||
en_GB
|
||||
es
|
||||
fr
|
||||
ga
|
||||
gl
|
||||
hu
|
||||
it
|
||||
ko
|
||||
nb
|
||||
nl
|
||||
pa
|
||||
pl
|
||||
pt_BR
|
||||
sl
|
||||
sv
|
||||
tr
|
||||
zh_CN
|
9
po/POTFILES.in
Normal file
@ -0,0 +1,9 @@
|
||||
data/gnome-shell.desktop.in.in
|
||||
js/ui/panel.js
|
||||
js/ui/dash.js
|
||||
js/ui/overview.js
|
||||
js/ui/runDialog.js
|
||||
src/gdmuser/gdm-user.c
|
||||
src/shell-global.c
|
||||
src/shell-status-menu.c
|
||||
src/shell-uri-util.c
|
1
po/POTFILES.skip
Normal file
@ -0,0 +1 @@
|
||||
data/gnome-shell.desktop.in
|
204
po/ar.po
Normal file
@ -0,0 +1,204 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# Khaled Hosny <khaledhosny@eglug.org>, 2009.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: HEAD\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2009-10-03 19:19+0200\n"
|
||||
"PO-Revision-Date: 2009-10-03 19:20+0300\n"
|
||||
"Last-Translator: Khaled Hosny <khaledhosny@eglug.org>\n"
|
||||
"Language-Team: Arabic <doc@arabeyes.org>\n"
|
||||
"Language: ar\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
|
||||
"&& n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
|
||||
"X-Generator: Virtaal 0.4.0\n"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:1
|
||||
msgid "GNOME Shell"
|
||||
msgstr "صدفة جنوم"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:2
|
||||
msgid "Window management and application launching"
|
||||
msgstr "إدارة النوافذ وإطلاق التطبيقات"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:271
|
||||
msgid "Activities"
|
||||
msgstr "الأنشطة"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:461
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%A %Ol:%OM %p"
|
||||
|
||||
#: ../js/ui/dash.js:283
|
||||
msgid "Find..."
|
||||
msgstr "ابحث..."
|
||||
|
||||
#: ../js/ui/dash.js:400
|
||||
msgid "More"
|
||||
msgstr "المزيد"
|
||||
|
||||
#: ../js/ui/dash.js:543
|
||||
msgid "(see all)"
|
||||
msgstr "(انظر الكل)"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:763 ../js/ui/dash.js:825
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "التطبيقات"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:783
|
||||
msgid "PLACES"
|
||||
msgstr "الأماكن"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:790 ../js/ui/dash.js:835
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "المستندات الحديثة"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:815 ../js/ui/dash.js:955
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "نتائج البحث"
|
||||
|
||||
#: ../js/ui/dash.js:830
|
||||
msgid "PREFERENCES"
|
||||
msgstr "التفضيلات"
|
||||
|
||||
#: ../js/ui/runDialog.js:96
|
||||
msgid "Please enter a command:"
|
||||
msgstr "من فضلك اكتب أمرا:"
|
||||
|
||||
#: ../src/shell-global.c:812
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "منذ أقل من دقيقة"
|
||||
|
||||
#: ../src/shell-global.c:815
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "منذ أقل من دقيقة"
|
||||
msgstr[1] "منذ دقيقة"
|
||||
msgstr[2] "منذ دقيقتين"
|
||||
msgstr[3] "منذ %d دقائق"
|
||||
msgstr[4] "منذ %d دقيقة"
|
||||
msgstr[5] "منذ %d دقيقة"
|
||||
|
||||
#: ../src/shell-global.c:818
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "منذ أقل من ساعة"
|
||||
msgstr[1] "منذ ساعة"
|
||||
msgstr[2] "منذ ساعتين"
|
||||
msgstr[3] "منذ %d ساعات"
|
||||
msgstr[4] "منذ %d ساعة"
|
||||
msgstr[5] "منذ %d ساعة"
|
||||
|
||||
#: ../src/shell-global.c:821
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "منذ أقل من يوم"
|
||||
msgstr[1] "منذ يوم"
|
||||
msgstr[2] "منذ يومين"
|
||||
msgstr[3] "منذ %d أيام"
|
||||
msgstr[4] "منذ %d يوما"
|
||||
msgstr[5] "منذ %d يوم"
|
||||
|
||||
#: ../src/shell-global.c:824
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
msgstr[0] "منذ أقل من أسبوع"
|
||||
msgstr[1] "منذ أسبوع"
|
||||
msgstr[2] "منذ أسبوعين"
|
||||
msgstr[3] "منذ %d أسابيع"
|
||||
msgstr[4] "منذ %d أسبوعا"
|
||||
msgstr[5] "منذ %d أسبوع"
|
||||
|
||||
#: ../src/shell-status-menu.c:156
|
||||
msgid "Unknown"
|
||||
msgstr "مجهول"
|
||||
|
||||
#: ../src/shell-status-menu.c:212
|
||||
#, c-format
|
||||
msgid "Can't lock screen: %s"
|
||||
msgstr "تعذّر إيصاد الشاشة: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:227
|
||||
#, c-format
|
||||
msgid "Can't temporarily set screensaver to blank screen: %s"
|
||||
msgstr "تعذّر ضبك حافظة الشاشة مؤقتا لتكون شاشة خالية: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:351
|
||||
#, c-format
|
||||
msgid "Can't logout: %s"
|
||||
msgstr "تعذّر الخروج: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:492
|
||||
msgid "Account Information..."
|
||||
msgstr "معلومات الحساب..."
|
||||
|
||||
#: ../src/shell-status-menu.c:502
|
||||
msgid "Sidebar"
|
||||
msgstr "الشريط الجانبي"
|
||||
|
||||
#: ../src/shell-status-menu.c:510
|
||||
msgid "System Preferences..."
|
||||
msgstr "تفضيلات النظام..."
|
||||
|
||||
#: ../src/shell-status-menu.c:525
|
||||
msgid "Lock Screen"
|
||||
msgstr "أوصد الشاشة"
|
||||
|
||||
#: ../src/shell-status-menu.c:535
|
||||
msgid "Switch User"
|
||||
msgstr "بدّل المستخدم"
|
||||
|
||||
#. Only show switch user if there are other users
|
||||
#. Log Out
|
||||
#: ../src/shell-status-menu.c:546
|
||||
msgid "Log Out..."
|
||||
msgstr "اخرج..."
|
||||
|
||||
#. Shut down
|
||||
#: ../src/shell-status-menu.c:557
|
||||
msgid "Shut Down..."
|
||||
msgstr "أطفئ..."
|
||||
|
||||
#: ../src/shell-uri-util.c:87
|
||||
msgid "Home Folder"
|
||||
msgstr "مجلد المنزل"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-uri-util.c:102
|
||||
msgid "File System"
|
||||
msgstr "نظام الملفات"
|
||||
|
||||
#: ../src/shell-uri-util.c:248
|
||||
msgid "Search"
|
||||
msgstr "ابحث"
|
||||
|
||||
#. Translators: the first string is the name of a gvfs
|
||||
#. * method, and the second string is a path. For
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-uri-util.c:298
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
||||
|
||||
#~ msgid "Browse"
|
||||
#~ msgstr "استعرض"
|
187
po/ca.po
Normal file
@ -0,0 +1,187 @@
|
||||
# Catalan gnome-shell translation.
|
||||
# Copyright (C) 2009 Siegfried-Angel Gevatter Pujals <rainct@ubuntu.com>
|
||||
# This file is distributed under the same license as the gnome-shell package.
|
||||
#
|
||||
# Siegfried-Angel Gevatter Pujals <rainct@ubuntu.com>, 2009.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: HEAD\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2009-10-01 23:16+0200\n"
|
||||
"PO-Revision-Date: 2009-10-01 23:20+0100\n"
|
||||
"Last-Translator: Siegfried-Angel Gevatter Pujals <rainct@ubuntu.com>\n"
|
||||
"Language-Team: \n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:1
|
||||
msgid "GNOME Shell"
|
||||
msgstr "GNOME Shell"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:2
|
||||
msgid "Window management and application launching"
|
||||
msgstr "Gestió de finestres i execució d'aplicacions"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:271
|
||||
msgid "Activities"
|
||||
msgstr "Activitats"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:461
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %H:%M"
|
||||
|
||||
#: ../js/ui/dash.js:283
|
||||
msgid "Find..."
|
||||
msgstr "Cerca..."
|
||||
|
||||
#: ../js/ui/dash.js:400
|
||||
msgid "More"
|
||||
msgstr "Més"
|
||||
|
||||
#: ../js/ui/dash.js:543
|
||||
msgid "(see all)"
|
||||
msgstr "(mostra tot)"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:763
|
||||
#: ../js/ui/dash.js:825
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "APLICACIONS"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:783
|
||||
msgid "PLACES"
|
||||
msgstr "LLOCS"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:790
|
||||
#: ../js/ui/dash.js:835
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "DOCUMENTS RECENTS"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:815
|
||||
#: ../js/ui/dash.js:958
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "RESULTATS DE LA CERCA"
|
||||
|
||||
#: ../js/ui/dash.js:830
|
||||
msgid "PREFERENCES"
|
||||
msgstr "PREFERÈNCIES"
|
||||
|
||||
#: ../js/ui/runDialog.js:96
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Introduïu una ordre:"
|
||||
|
||||
#: ../src/shell-global.c:812
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Fa menys d'un minut"
|
||||
|
||||
#: ../src/shell-global.c:815
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "Fa %d minut"
|
||||
msgstr[1] "Fa %d minuts"
|
||||
|
||||
#: ../src/shell-global.c:818
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "Fa %d hora"
|
||||
msgstr[1] "Fa %d hores"
|
||||
|
||||
#: ../src/shell-global.c:821
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "Fa %d dia"
|
||||
msgstr[1] "Fa %d dies"
|
||||
|
||||
#: ../src/shell-global.c:824
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
msgstr[0] "Fa %d setmana"
|
||||
msgstr[1] "Fa %d setmanes"
|
||||
|
||||
#: ../src/shell-status-menu.c:156
|
||||
msgid "Unknown"
|
||||
msgstr "Desconegut"
|
||||
|
||||
#: ../src/shell-status-menu.c:212
|
||||
#, c-format
|
||||
msgid "Can't lock screen: %s"
|
||||
msgstr "No es pot blocar la pantalla: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:227
|
||||
#, c-format
|
||||
msgid "Can't temporarily set screensaver to blank screen: %s"
|
||||
msgstr "No es pot establir temporalment l'estalvi de pantalla a pantalla negra: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:351
|
||||
#, c-format
|
||||
msgid "Can't logout: %s"
|
||||
msgstr "No es pot sortir: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:492
|
||||
msgid "Account Information..."
|
||||
msgstr "Informació del compte..."
|
||||
|
||||
#: ../src/shell-status-menu.c:502
|
||||
msgid "Sidebar"
|
||||
msgstr "Barra lateral"
|
||||
|
||||
#: ../src/shell-status-menu.c:510
|
||||
msgid "System Preferences..."
|
||||
msgstr "Preferències del sistema..."
|
||||
|
||||
#: ../src/shell-status-menu.c:525
|
||||
msgid "Lock Screen"
|
||||
msgstr "Bloca la pantalla"
|
||||
|
||||
#: ../src/shell-status-menu.c:535
|
||||
msgid "Switch User"
|
||||
msgstr "Canvia d'usuari"
|
||||
|
||||
#. Only show switch user if there are other users
|
||||
#. Log Out
|
||||
#: ../src/shell-status-menu.c:546
|
||||
msgid "Log Out..."
|
||||
msgstr "Surt..."
|
||||
|
||||
#. Shut down
|
||||
#: ../src/shell-status-menu.c:557
|
||||
msgid "Shut Down..."
|
||||
msgstr "Atura..."
|
||||
|
||||
#: ../src/shell-uri-util.c:87
|
||||
msgid "Home Folder"
|
||||
msgstr "Carpeta d'inici"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-uri-util.c:102
|
||||
msgid "File System"
|
||||
msgstr "Sistema de fitxers"
|
||||
|
||||
#: ../src/shell-uri-util.c:248
|
||||
msgid "Search"
|
||||
msgstr "Cerca"
|
||||
|
||||
#. Translators: the first string is the name of a gvfs
|
||||
#. * method, and the second string is a path. For
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-uri-util.c:298
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
||||
|
193
po/cs.po
Normal file
@ -0,0 +1,193 @@
|
||||
# Czech translation of gnome-shell.
|
||||
# Copyright (C) 2009 the author(s) of gnome-shell.
|
||||
# This file is distributed under the same license as the gnome-shell package.
|
||||
# Andre Klapper <ak-47@gmx.net>, 2009.
|
||||
# Petr Kovar <pknbe@volny.cz>, 2009.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2009-09-22 13:36+0200\n"
|
||||
"PO-Revision-Date: 2009-09-22 13:37+0200\n"
|
||||
"Last-Translator: Andre Klapper <ak-47@gmx.net>, 2009\n"
|
||||
"Language-Team: Czech <gnome-cs-list@gnome.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:1
|
||||
msgid "GNOME Shell"
|
||||
msgstr "Prostředí GNOME Shell"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:2
|
||||
msgid "Window management and application launching"
|
||||
msgstr "Správa oken a spouštění aplikací"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:269
|
||||
msgid "Activities"
|
||||
msgstr "Činnosti"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:452
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a, %H:%M"
|
||||
|
||||
#: ../js/ui/dash.js:283
|
||||
msgid "Find..."
|
||||
msgstr "Najít..."
|
||||
|
||||
#: ../js/ui/dash.js:400
|
||||
msgid "Browse"
|
||||
msgstr "Procházet"
|
||||
|
||||
#: ../js/ui/dash.js:536
|
||||
msgid "(see all)"
|
||||
msgstr "(zobrazit vše)"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:753 ../js/ui/dash.js:809
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "APLIKACE"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:773
|
||||
msgid "PLACES"
|
||||
msgstr "MÍSTA"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:780 ../js/ui/dash.js:819
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "NEDÁVNÉ DOKUMENTY"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:799 ../js/ui/dash.js:931
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "VÝSLEDKY HLEDÁNÍ"
|
||||
|
||||
#: ../js/ui/dash.js:814
|
||||
msgid "PREFERENCES"
|
||||
msgstr "NASTAVENÍ"
|
||||
|
||||
#: ../js/ui/runDialog.js:101
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Zadejte prosím příkaz:"
|
||||
|
||||
#: ../src/shell-global.c:799
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Před méně než minutou"
|
||||
|
||||
#: ../src/shell-global.c:802
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "Před %d minutou"
|
||||
msgstr[1] "Před %d minutami"
|
||||
msgstr[2] "Před %d minutami"
|
||||
|
||||
#: ../src/shell-global.c:805
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "Před %d hodinou"
|
||||
msgstr[1] "Před %d hodinami"
|
||||
msgstr[2] "Před %d hodinami"
|
||||
|
||||
#: ../src/shell-global.c:808
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "Před %d dnem"
|
||||
msgstr[1] "Před %d dny"
|
||||
msgstr[2] "Před %d dny"
|
||||
|
||||
#: ../src/shell-global.c:811
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
msgstr[0] "Před %d týdnem"
|
||||
msgstr[1] "Před %d týdny"
|
||||
msgstr[2] "Před %d týdny"
|
||||
|
||||
#: ../src/shell-status-menu.c:156
|
||||
msgid "Unknown"
|
||||
msgstr "Neznámé"
|
||||
|
||||
#: ../src/shell-status-menu.c:212
|
||||
#, c-format
|
||||
msgid "Can't lock screen: %s"
|
||||
msgstr "Nelze uzamknout obrazovku: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:227
|
||||
#, c-format
|
||||
msgid "Can't temporarily set screensaver to blank screen: %s"
|
||||
msgstr "Šetřič obrazovky nelze dočasně nastavit na prázdnou obrazovku: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:351
|
||||
#, c-format
|
||||
msgid "Can't logout: %s"
|
||||
msgstr "Nelze se odhlásit: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:492
|
||||
msgid "Account Information..."
|
||||
msgstr "Informace o účtu..."
|
||||
|
||||
#: ../src/shell-status-menu.c:502
|
||||
msgid "Sidebar"
|
||||
msgstr "Postranní lišta"
|
||||
|
||||
#: ../src/shell-status-menu.c:510
|
||||
msgid "System Preferences..."
|
||||
msgstr "Předvolby systému..."
|
||||
|
||||
#: ../src/shell-status-menu.c:525
|
||||
msgid "Lock Screen"
|
||||
msgstr "Uzamknout obrazovku"
|
||||
|
||||
#: ../src/shell-status-menu.c:535
|
||||
msgid "Switch User"
|
||||
msgstr "Přepnout uživatele"
|
||||
|
||||
#. Only show switch user if there are other users
|
||||
#. Log Out
|
||||
#: ../src/shell-status-menu.c:546
|
||||
msgid "Log Out..."
|
||||
msgstr "Odhlásit..."
|
||||
|
||||
#. Shut down
|
||||
#: ../src/shell-status-menu.c:557
|
||||
msgid "Shut Down..."
|
||||
msgstr "Vypnout..."
|
||||
|
||||
#: ../src/shell-uri-util.c:87
|
||||
msgid "Home Folder"
|
||||
msgstr "Domovská složka"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-uri-util.c:102
|
||||
msgid "File System"
|
||||
msgstr "Systém souborů"
|
||||
|
||||
#: ../src/shell-uri-util.c:248
|
||||
msgid "Search"
|
||||
msgstr "Hledat"
|
||||
|
||||
#. Translators: the first string is the name of a gvfs
|
||||
#. * method, and the second string is a path. For
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-uri-util.c:298
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
||||
|
||||
#~ msgid "Manager"
|
||||
#~ msgstr "Správce"
|
||||
|
||||
#~ msgid "The user manager object this user is controlled by."
|
||||
#~ msgstr "Objekt správce uživatele, kterým je tento uživatel ovládán."
|
188
po/da.po
Normal file
@ -0,0 +1,188 @@
|
||||
# Danish translation of gnome-shell
|
||||
# Copyright (C) 2009 gnome-shell
|
||||
# This file is distributed under the same license as the gnome-shell package.
|
||||
# Kris Thomsen <lakristho@gmail.com>, 2009.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2009-09-04 01:26+0200\n"
|
||||
"PO-Revision-Date: 2009-09-01 21:48+0200\n"
|
||||
"Last-Translator: Kris Thomsen <lakristho@gmail.com>\n"
|
||||
"Language-Team: Danish <dansk@dansk-gruppen.dk>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:1
|
||||
msgid "GNOME Shell"
|
||||
msgstr "Skal til GNOME"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:2
|
||||
msgid "Window management and application launching"
|
||||
msgstr "Vinduehåndtering og åbning af programmer"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:271
|
||||
msgid "Activities"
|
||||
msgstr "Aktiviteter"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:454
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %H:%M"
|
||||
|
||||
#: ../js/ui/dash.js:256
|
||||
msgid "Find..."
|
||||
msgstr "Find..."
|
||||
|
||||
#: ../js/ui/dash.js:374
|
||||
msgid "Browse"
|
||||
msgstr "Gennemse"
|
||||
|
||||
#: ../js/ui/dash.js:511
|
||||
msgid "(see all)"
|
||||
msgstr "(se alle)"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:705 ../js/ui/dash.js:761 ../js/ui/dash.js:893
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "PROGRAMMER"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:725
|
||||
msgid "PLACES"
|
||||
msgstr "STEDER"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:732 ../js/ui/dash.js:773 ../js/ui/dash.js:867
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "SENESTE DOKUMENTER"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:751 ../js/ui/dash.js:856 ../js/ui/dash.js:882
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "SØGERESULTATER"
|
||||
|
||||
#: ../js/ui/runDialog.js:82
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Indtast en kommando:"
|
||||
|
||||
#: ../src/shell-global.c:840
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Mindre end et minut siden"
|
||||
|
||||
#: ../src/shell-global.c:843
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "%d minut siden"
|
||||
msgstr[1] "%d minutter siden"
|
||||
|
||||
#: ../src/shell-global.c:846
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "%d time siden"
|
||||
msgstr[1] "%d timer siden"
|
||||
|
||||
#: ../src/shell-global.c:849
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "%d dag siden"
|
||||
msgstr[1] "%d dage siden"
|
||||
|
||||
#: ../src/shell-global.c:852
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
msgstr[0] "%d uge siden"
|
||||
msgstr[1] "%d uger siden"
|
||||
|
||||
#: ../src/shell-status-menu.c:156
|
||||
msgid "Unknown"
|
||||
msgstr "Ukendt"
|
||||
|
||||
#: ../src/shell-status-menu.c:212
|
||||
#, c-format
|
||||
msgid "Can't lock screen: %s"
|
||||
msgstr "Kan ikke låse skærm: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:227
|
||||
#, c-format
|
||||
msgid "Can't temporarily set screensaver to blank screen: %s"
|
||||
msgstr "Kan ikke midlertidigt sætte pauseskærm til blank skærm: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:351
|
||||
#, c-format
|
||||
msgid "Can't logout: %s"
|
||||
msgstr "Kan ikke logge ud: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:492
|
||||
msgid "Account Information..."
|
||||
msgstr "Kontoinformation..."
|
||||
|
||||
#: ../src/shell-status-menu.c:502
|
||||
msgid "Sidebar"
|
||||
msgstr "Sidebjælke"
|
||||
|
||||
#: ../src/shell-status-menu.c:510
|
||||
msgid "System Preferences..."
|
||||
msgstr "Systemindstillinger..."
|
||||
|
||||
#: ../src/shell-status-menu.c:525
|
||||
msgid "Lock Screen"
|
||||
msgstr "Lås skærm"
|
||||
|
||||
#: ../src/shell-status-menu.c:535
|
||||
msgid "Switch User"
|
||||
msgstr "Skift bruger"
|
||||
|
||||
#. Only show switch user if there are other users
|
||||
#. Log Out
|
||||
#: ../src/shell-status-menu.c:546
|
||||
msgid "Log Out..."
|
||||
msgstr "Log ud..."
|
||||
|
||||
#. Shut down
|
||||
#: ../src/shell-status-menu.c:557
|
||||
msgid "Shut Down..."
|
||||
msgstr "Luk ned..."
|
||||
|
||||
#: ../src/shell-uri-util.c:87
|
||||
msgid "Home Folder"
|
||||
msgstr "Hjemmemappe"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-uri-util.c:102
|
||||
msgid "File System"
|
||||
msgstr "Filsystem"
|
||||
|
||||
#: ../src/shell-uri-util.c:248
|
||||
msgid "Search"
|
||||
msgstr "Søg"
|
||||
|
||||
#. Translators: the first string is the name of a gvfs
|
||||
#. * method, and the second string is a path. For
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-uri-util.c:298
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
||||
|
||||
#~ msgid "Find apps or documents"
|
||||
#~ msgstr "Find programmer eller dokumenter"
|
||||
|
||||
#~ msgid "Manager"
|
||||
#~ msgstr "Håndtering"
|
||||
|
||||
#~ msgid "The user manager object this user is controlled by."
|
||||
#~ msgstr "Brugerhåndteringsobjektet, denne bruger er styret af."
|
201
po/de.po
Normal file
@ -0,0 +1,201 @@
|
||||
# German gnome-shell translation.
|
||||
# Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
# This file is distributed under the same license as the gnome-shell package.
|
||||
#
|
||||
# Hendrik Brandt <heb@gnome-de.org>, 2009.
|
||||
# Hendrik Richter <hendrikr@gnome.org>, 2009.
|
||||
# Christian Kirbach <Christian.Kirbach@googlemail.com>, 2009.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: HEAD\n"
|
||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
|
||||
"shell&component=general\n"
|
||||
"POT-Creation-Date: 2009-10-01 22:22+0000\n"
|
||||
"PO-Revision-Date: 2009-10-01 14:32+0200\n"
|
||||
"Last-Translator: Christian Kirbach <Christian.Kirbach@googlemail.com>\n"
|
||||
"Language-Team: German <gnome-de@gnome.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:1
|
||||
msgid "GNOME Shell"
|
||||
msgstr "GNOME-Shell"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:2
|
||||
msgid "Window management and application launching"
|
||||
msgstr "Fenster verwalten und Anwendungen starten"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:271
|
||||
msgid "Activities"
|
||||
msgstr "Aktivitäten"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:461
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %H:%M"
|
||||
|
||||
#: ../js/ui/dash.js:283
|
||||
msgid "Find..."
|
||||
msgstr "Suchen …"
|
||||
|
||||
#: ../js/ui/dash.js:400
|
||||
msgid "More"
|
||||
msgstr "Mehr"
|
||||
|
||||
#: ../js/ui/dash.js:543
|
||||
msgid "(see all)"
|
||||
msgstr "(alle sehen)"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:763 ../js/ui/dash.js:825
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "ANWENDUNGEN"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:783
|
||||
msgid "PLACES"
|
||||
msgstr "ORTE"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:790 ../js/ui/dash.js:835
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "ZULETZT GEÖFFNETE DOKUMENTE"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:815 ../js/ui/dash.js:955
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "SUCHERGEBNISSE"
|
||||
|
||||
#: ../js/ui/dash.js:830
|
||||
msgid "PREFERENCES"
|
||||
msgstr "EINSTELLUNGEN"
|
||||
|
||||
#: ../js/ui/runDialog.js:96
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Bitte geben Sie einen Befehl ein:"
|
||||
|
||||
#: ../src/shell-global.c:812
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Vor weniger als einer Minute"
|
||||
|
||||
#: ../src/shell-global.c:815
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "Vor %d Minute"
|
||||
msgstr[1] "Vor %d Minuten"
|
||||
|
||||
#: ../src/shell-global.c:818
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "Vor %d Stunde"
|
||||
msgstr[1] "Vor %d Stunden"
|
||||
|
||||
#: ../src/shell-global.c:821
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "Vor %d Tag"
|
||||
msgstr[1] "Vor %d Tagen"
|
||||
|
||||
#: ../src/shell-global.c:824
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
msgstr[0] "Vor %d Woche"
|
||||
msgstr[1] "Vor %d Wochen"
|
||||
|
||||
#: ../src/shell-status-menu.c:156
|
||||
msgid "Unknown"
|
||||
msgstr "Unbekannt"
|
||||
|
||||
#: ../src/shell-status-menu.c:212
|
||||
#, c-format
|
||||
msgid "Can't lock screen: %s"
|
||||
msgstr "Bildschirm kann nicht gesperrt werden: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:227
|
||||
#, c-format
|
||||
msgid "Can't temporarily set screensaver to blank screen: %s"
|
||||
msgstr ""
|
||||
"Der Bildschirmschoner kann vorübergehend nicht auf einen leeren Schirm "
|
||||
"gesetzt werden: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:351
|
||||
#, c-format
|
||||
msgid "Can't logout: %s"
|
||||
msgstr "Abmelden ist nicht möglich: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:492
|
||||
msgid "Account Information..."
|
||||
msgstr "Benutzerinformationen …"
|
||||
|
||||
#: ../src/shell-status-menu.c:502
|
||||
msgid "Sidebar"
|
||||
msgstr "Seitenleiste"
|
||||
|
||||
#: ../src/shell-status-menu.c:510
|
||||
msgid "System Preferences..."
|
||||
msgstr "Systemeinstellungen …"
|
||||
|
||||
#: ../src/shell-status-menu.c:525
|
||||
msgid "Lock Screen"
|
||||
msgstr "Bildschirm sperren"
|
||||
|
||||
#: ../src/shell-status-menu.c:535
|
||||
msgid "Switch User"
|
||||
msgstr "Benutzer wechseln"
|
||||
|
||||
#. Only show switch user if there are other users
|
||||
#. Log Out
|
||||
#: ../src/shell-status-menu.c:546
|
||||
msgid "Log Out..."
|
||||
msgstr "Abmelden …"
|
||||
|
||||
#. Shut down
|
||||
#: ../src/shell-status-menu.c:557
|
||||
msgid "Shut Down..."
|
||||
msgstr "Ausschalten …"
|
||||
|
||||
#: ../src/shell-uri-util.c:87
|
||||
msgid "Home Folder"
|
||||
msgstr "Persönlicher Ordner"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-uri-util.c:102
|
||||
msgid "File System"
|
||||
msgstr "Dateisystem"
|
||||
|
||||
#: ../src/shell-uri-util.c:248
|
||||
msgid "Search"
|
||||
msgstr "Suchen"
|
||||
|
||||
#. Translators: the first string is the name of a gvfs
|
||||
#. * method, and the second string is a path. For
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-uri-util.c:298
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
||||
|
||||
#~ msgid "Find apps or documents"
|
||||
#~ msgstr "Anwendungen oder Dokumente suchen"
|
||||
|
||||
#~ msgid "Browse"
|
||||
#~ msgstr "Durchsuchen"
|
||||
|
||||
#~ msgid "Manager"
|
||||
#~ msgstr "Verwaltung"
|
||||
|
||||
#~ msgid "The user manager object this user is controlled by."
|
||||
#~ msgstr "Das Benutzerverwaltungsobjekt welches diesen Benutzer überwacht."
|
184
po/en_GB.po
Normal file
@ -0,0 +1,184 @@
|
||||
# British English translation for gnome-shell.
|
||||
# Copyright (C) 2009 gnome-shell's COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the gnome-shell package.
|
||||
# Philip Withnall <philip@tecnocode.co.uk>, 2009.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell master\n"
|
||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
|
||||
"shell&component=general\n"
|
||||
"POT-Creation-Date: 2009-09-12 12:41+0000\n"
|
||||
"PO-Revision-Date: 2009-09-12 12:41+0000\n"
|
||||
"Last-Translator: Philip Withnall <philip@tecnocode.co.uk>\n"
|
||||
"Language-Team: British English <en_GB@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:1
|
||||
msgid "GNOME Shell"
|
||||
msgstr "GNOME Shell"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:2
|
||||
msgid "Window management and application launching"
|
||||
msgstr "Window management and application launching"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:269
|
||||
msgid "Activities"
|
||||
msgstr "Activities"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:452
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %l:%M %p"
|
||||
|
||||
#: ../js/ui/dash.js:283
|
||||
msgid "Find..."
|
||||
msgstr "Find…"
|
||||
|
||||
#: ../js/ui/dash.js:400
|
||||
msgid "Browse"
|
||||
msgstr "Browse"
|
||||
|
||||
#: ../js/ui/dash.js:536
|
||||
msgid "(see all)"
|
||||
msgstr "(see all)"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:753 ../js/ui/dash.js:809
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "APPLICATIONS"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:773
|
||||
msgid "PLACES"
|
||||
msgstr "PLACES"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:780 ../js/ui/dash.js:819
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "RECENT DOCUMENTS"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:799 ../js/ui/dash.js:931
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "SEARCH RESULTS"
|
||||
|
||||
#: ../js/ui/dash.js:814
|
||||
msgid "PREFERENCES"
|
||||
msgstr "PREFERENCES"
|
||||
|
||||
#: ../js/ui/runDialog.js:90
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Please enter a command:"
|
||||
|
||||
#: ../src/shell-global.c:799
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Less than a minute ago"
|
||||
|
||||
#: ../src/shell-global.c:802
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "%d minute ago"
|
||||
msgstr[1] "%d minutes ago"
|
||||
|
||||
#: ../src/shell-global.c:805
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "%d hour ago"
|
||||
msgstr[1] "%d hours ago"
|
||||
|
||||
#: ../src/shell-global.c:808
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "%d day ago"
|
||||
msgstr[1] "%d days ago"
|
||||
|
||||
#: ../src/shell-global.c:811
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
msgstr[0] "%d week ago"
|
||||
msgstr[1] "%d weeks ago"
|
||||
|
||||
#: ../src/shell-status-menu.c:156
|
||||
msgid "Unknown"
|
||||
msgstr "Unknown"
|
||||
|
||||
#: ../src/shell-status-menu.c:212
|
||||
#, c-format
|
||||
msgid "Can't lock screen: %s"
|
||||
msgstr "Can't lock screen: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:227
|
||||
#, c-format
|
||||
msgid "Can't temporarily set screensaver to blank screen: %s"
|
||||
msgstr "Can't temporarily set screensaver to blank screen: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:351
|
||||
#, c-format
|
||||
msgid "Can't logout: %s"
|
||||
msgstr "Can't logout: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:492
|
||||
msgid "Account Information..."
|
||||
msgstr "Account Information…"
|
||||
|
||||
#: ../src/shell-status-menu.c:502
|
||||
msgid "Sidebar"
|
||||
msgstr "Sidebar"
|
||||
|
||||
#: ../src/shell-status-menu.c:510
|
||||
msgid "System Preferences..."
|
||||
msgstr "System Preferences…"
|
||||
|
||||
#: ../src/shell-status-menu.c:525
|
||||
msgid "Lock Screen"
|
||||
msgstr "Lock Screen"
|
||||
|
||||
#: ../src/shell-status-menu.c:535
|
||||
msgid "Switch User"
|
||||
msgstr "Switch User"
|
||||
|
||||
#. Only show switch user if there are other users
|
||||
#. Log Out
|
||||
#: ../src/shell-status-menu.c:546
|
||||
msgid "Log Out..."
|
||||
msgstr "Log Out…"
|
||||
|
||||
#. Shut down
|
||||
#: ../src/shell-status-menu.c:557
|
||||
msgid "Shut Down..."
|
||||
msgstr "Shut Down…"
|
||||
|
||||
#: ../src/shell-uri-util.c:87
|
||||
msgid "Home Folder"
|
||||
msgstr "Home Folder"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-uri-util.c:102
|
||||
msgid "File System"
|
||||
msgstr "File System"
|
||||
|
||||
#: ../src/shell-uri-util.c:248
|
||||
msgid "Search"
|
||||
msgstr "Search"
|
||||
|
||||
#. Translators: the first string is the name of a gvfs
|
||||
#. * method, and the second string is a path. For
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-uri-util.c:298
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
202
po/es.po
Normal file
@ -0,0 +1,202 @@
|
||||
# Spanish translation of gnome-shell.
|
||||
# Copyright (C) 2009 gnome-shell's COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the gnome-shell package.
|
||||
#
|
||||
# Jorge González <jorgegonz@svn.gnome.org>, 2009.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell master\n"
|
||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
|
||||
"shell&component=general\n"
|
||||
"POT-Creation-Date: 2009-09-27 16:05+0000\n"
|
||||
"PO-Revision-Date: 2009-09-28 21:58+0200\n"
|
||||
"Last-Translator: Jorge González <jorgegonz@svn.gnome.org>\n"
|
||||
"Language-Team: Español <gnome-es-list@gnome.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: UTF-8\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:1
|
||||
msgid "GNOME Shell"
|
||||
msgstr "GNOME Shell"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:2
|
||||
msgid "Window management and application launching"
|
||||
msgstr "Gestión de ventanas e inicio de aplicaciones"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:269
|
||||
msgid "Activities"
|
||||
msgstr "Actividades"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:452
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %H:%M"
|
||||
|
||||
#: ../js/ui/dash.js:283
|
||||
msgid "Find..."
|
||||
msgstr "Buscar…"
|
||||
|
||||
#: ../js/ui/dash.js:400
|
||||
msgid "More"
|
||||
msgstr "Más"
|
||||
|
||||
#: ../js/ui/dash.js:543
|
||||
msgid "(see all)"
|
||||
msgstr "(ver todo)"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:763 ../js/ui/dash.js:825
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "APLICACIONES"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:783
|
||||
msgid "PLACES"
|
||||
msgstr "LUGARES"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:790 ../js/ui/dash.js:835
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "DOCUMENTOS RECIENTES"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:815 ../js/ui/dash.js:958
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "RESULTADOS DE LA BÚSQUEDA"
|
||||
|
||||
#: ../js/ui/dash.js:830
|
||||
msgid "PREFERENCES"
|
||||
msgstr "PREFERENCIAS"
|
||||
|
||||
#: ../js/ui/runDialog.js:94
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Introduzca un comando:"
|
||||
|
||||
#: ../src/shell-global.c:799
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Hace menos de un minuto"
|
||||
|
||||
#: ../src/shell-global.c:802
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "Hace %d minuto"
|
||||
msgstr[1] "Hace %d minutos"
|
||||
|
||||
#: ../src/shell-global.c:805
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "Hace %d hora"
|
||||
msgstr[1] "Hace %d horas"
|
||||
|
||||
#: ../src/shell-global.c:808
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "Hace %d día"
|
||||
msgstr[1] "Hace %d días"
|
||||
|
||||
#: ../src/shell-global.c:811
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
msgstr[0] "Hace %d semana"
|
||||
msgstr[1] "Hace %d semanas"
|
||||
|
||||
#: ../src/shell-status-menu.c:156
|
||||
msgid "Unknown"
|
||||
msgstr "Desconocido"
|
||||
|
||||
#: ../src/shell-status-menu.c:212
|
||||
#, c-format
|
||||
msgid "Can't lock screen: %s"
|
||||
msgstr "No se puede bloquear la pantalla: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:227
|
||||
#, c-format
|
||||
msgid "Can't temporarily set screensaver to blank screen: %s"
|
||||
msgstr ""
|
||||
"No se puede establecer temporalmente el salvapantallas a oscurecer pantalla: "
|
||||
"%s"
|
||||
|
||||
#: ../src/shell-status-menu.c:351
|
||||
#, c-format
|
||||
msgid "Can't logout: %s"
|
||||
msgstr "No se puede salir de la sesión: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:492
|
||||
msgid "Account Information..."
|
||||
msgstr "Información de la cuenta…"
|
||||
|
||||
#: ../src/shell-status-menu.c:502
|
||||
msgid "Sidebar"
|
||||
msgstr "Barra lateral"
|
||||
|
||||
#: ../src/shell-status-menu.c:510
|
||||
msgid "System Preferences..."
|
||||
msgstr "Preferencias del sistema…"
|
||||
|
||||
#: ../src/shell-status-menu.c:525
|
||||
msgid "Lock Screen"
|
||||
msgstr "Bloquear la pantalla"
|
||||
|
||||
#: ../src/shell-status-menu.c:535
|
||||
msgid "Switch User"
|
||||
msgstr "Cambiar de usuario"
|
||||
|
||||
#. Only show switch user if there are other users
|
||||
#. Log Out
|
||||
#: ../src/shell-status-menu.c:546
|
||||
msgid "Log Out..."
|
||||
msgstr "Salir…"
|
||||
|
||||
#. Shut down
|
||||
#: ../src/shell-status-menu.c:557
|
||||
msgid "Shut Down..."
|
||||
msgstr "Apagar…"
|
||||
|
||||
#: ../src/shell-uri-util.c:87
|
||||
msgid "Home Folder"
|
||||
msgstr "Carpeta personal"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-uri-util.c:102
|
||||
msgid "File System"
|
||||
msgstr "Sistema de archivos"
|
||||
|
||||
#: ../src/shell-uri-util.c:248
|
||||
msgid "Search"
|
||||
msgstr "Buscar"
|
||||
|
||||
#. Translators: the first string is the name of a gvfs
|
||||
#. * method, and the second string is a path. For
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-uri-util.c:298
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
||||
|
||||
#~ msgid "Browse"
|
||||
#~ msgstr "Examine"
|
||||
|
||||
#~ msgid "Find apps or documents"
|
||||
#~ msgstr "Encuentre aplicaciones o documentos"
|
||||
|
||||
#~| msgid "RECENT DOCUMENTS"
|
||||
#~ msgid "DOCUMENTS"
|
||||
#~ msgstr "DOCUMENTOS"
|
||||
|
||||
#~ msgid "Manager"
|
||||
#~ msgstr "Gestor"
|
||||
|
||||
#~ msgid "The user manager object this user is controlled by."
|
||||
#~ msgstr "El objeto de gestión de usuarios que controla a este usuario."
|
182
po/fr.po
Normal file
@ -0,0 +1,182 @@
|
||||
# French translations for gnome-shell package.
|
||||
# Copyright (C) 2009 THE gnome-shell'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the gnome-shell package.
|
||||
#
|
||||
# Mathieu Bridon <bochecha@fedoraproject.org>, 2009.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: HEAD\n"
|
||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
|
||||
"shell&component=general\n"
|
||||
"POT-Creation-Date: 2009-09-09 21:30+0000\n"
|
||||
"PO-Revision-Date: 2009-09-11 21:40+0200\n"
|
||||
"Last-Translator: Mathieu Bridon <bochecha@fedoraproject.org>\n"
|
||||
"Language-Team: GNOME French Team\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:1
|
||||
msgid "GNOME Shell"
|
||||
msgstr "GNOME Shell"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:2
|
||||
msgid "Window management and application launching"
|
||||
msgstr "Gestion des fenêtres et lancement des applications"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:269
|
||||
msgid "Activities"
|
||||
msgstr "Activités"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:452
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %H:%M"
|
||||
|
||||
#: ../js/ui/dash.js:255
|
||||
msgid "Find..."
|
||||
msgstr "Rechercher..."
|
||||
|
||||
#: ../js/ui/dash.js:372
|
||||
msgid "Browse"
|
||||
msgstr "Parcourir"
|
||||
|
||||
#: ../js/ui/dash.js:508
|
||||
msgid "(see all)"
|
||||
msgstr "(tout afficher)"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:700 ../js/ui/dash.js:756 ../js/ui/dash.js:887
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "APPLICATIONS"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:720
|
||||
msgid "PLACES"
|
||||
msgstr "RACCOURCIS"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:727 ../js/ui/dash.js:768 ../js/ui/dash.js:861
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "DOCUMENTS RÉCENTS"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:746 ../js/ui/dash.js:850 ../js/ui/dash.js:876
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "RÉSULTATS DE LA RECHERCHE"
|
||||
|
||||
#: ../js/ui/runDialog.js:90
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Veuillez saisir une commande :"
|
||||
|
||||
#: ../src/shell-global.c:799
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Il y a moins d'une minute"
|
||||
|
||||
#: ../src/shell-global.c:802
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "Il y a %d minute"
|
||||
msgstr[1] "Il y a %d minutes"
|
||||
|
||||
#: ../src/shell-global.c:805
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "Il y a %d heure"
|
||||
msgstr[1] "Il y a %d heures"
|
||||
|
||||
#: ../src/shell-global.c:808
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "Il y a %d jour"
|
||||
msgstr[1] "Il y a %d jours"
|
||||
|
||||
#: ../src/shell-global.c:811
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
msgstr[0] "Il y a %d semaine"
|
||||
msgstr[1] "Il y a %d semaines"
|
||||
|
||||
#: ../src/shell-status-menu.c:156
|
||||
msgid "Unknown"
|
||||
msgstr "Inconnu"
|
||||
|
||||
#: ../src/shell-status-menu.c:212
|
||||
#, c-format
|
||||
msgid "Can't lock screen: %s"
|
||||
msgstr "Impossible de verrouiller l'écran : %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:227
|
||||
#, c-format
|
||||
msgid "Can't temporarily set screensaver to blank screen: %s"
|
||||
msgstr ""
|
||||
"Impossible de régler temporairement l'écran de veille sur un écran vide : %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:351
|
||||
#, c-format
|
||||
msgid "Can't logout: %s"
|
||||
msgstr "Impossible de fermer la session : %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:492
|
||||
msgid "Account Information..."
|
||||
msgstr "Informations personnelles..."
|
||||
|
||||
#: ../src/shell-status-menu.c:502
|
||||
msgid "Sidebar"
|
||||
msgstr "Barre latérale"
|
||||
|
||||
#: ../src/shell-status-menu.c:510
|
||||
msgid "System Preferences..."
|
||||
msgstr "Préférences du système..."
|
||||
|
||||
#: ../src/shell-status-menu.c:525
|
||||
msgid "Lock Screen"
|
||||
msgstr "Verrouiller l'écran"
|
||||
|
||||
#: ../src/shell-status-menu.c:535
|
||||
msgid "Switch User"
|
||||
msgstr "Changer d'utilisateur"
|
||||
|
||||
#. Only show switch user if there are other users
|
||||
#. Log Out
|
||||
#: ../src/shell-status-menu.c:546
|
||||
msgid "Log Out..."
|
||||
msgstr "Fermer la session..."
|
||||
|
||||
#. Shut down
|
||||
#: ../src/shell-status-menu.c:557
|
||||
msgid "Shut Down..."
|
||||
msgstr "Éteindre..."
|
||||
|
||||
#: ../src/shell-uri-util.c:87
|
||||
msgid "Home Folder"
|
||||
msgstr "Dossier personnel"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-uri-util.c:102
|
||||
msgid "File System"
|
||||
msgstr "Système de fichiers"
|
||||
|
||||
#: ../src/shell-uri-util.c:248
|
||||
msgid "Search"
|
||||
msgstr "Recherche"
|
||||
|
||||
#. Translators: the first string is the name of a gvfs
|
||||
#. * method, and the second string is a path. For
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-uri-util.c:298
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s : %2$s"
|
181
po/ga.po
Normal file
@ -0,0 +1,181 @@
|
||||
# Irish translations for gnome-shell package.
|
||||
# Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
# This file is distributed under the same license as the gnome-shell package.
|
||||
# Seán de Búrca <leftmostcat@gmail.com>, 2009.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell.master\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2009-08-15 06:01-0600\n"
|
||||
"PO-Revision-Date: 2009-08-15 06:01-0600\n"
|
||||
"Last-Translator: Seán de Búrca <leftmostcat@gmail.com>\n"
|
||||
"Language-Team: Irish <gaeilge-gnulinux@lists.sourceforge.net>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=5; plural=n==1 ? 0 : (n%10==1 || n%10==2) ? 1 : (n%"
|
||||
"10>=3 && n%10<= 6) ? 2 : ((n%10>=7 && n%10<=9) || n==10) ? 3 : 4;\n"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:266
|
||||
msgid "Activities"
|
||||
msgstr "Gníomhartha"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:412
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %l:%M %p"
|
||||
|
||||
#: ../js/ui/dash.js:235
|
||||
msgid "Find apps or documents"
|
||||
msgstr "Aimsigh feidhmchláir nó cáipéisí"
|
||||
|
||||
#: ../js/ui/dash.js:336
|
||||
msgid "Browse"
|
||||
msgstr "Brabhsáil"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:472 ../js/ui/dash.js:545
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "FEIDHMCHLÁIR"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:477 ../js/ui/dash.js:570
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "CÁIPÉISÍ IS DÉANAÍ"
|
||||
|
||||
#. **** Places ****
|
||||
#: ../js/ui/dash.js:563
|
||||
msgid "PLACES"
|
||||
msgstr "ÁITEANNA"
|
||||
|
||||
#: ../js/ui/runDialog.js:74
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Iontráil ordú, le do thoil:"
|
||||
|
||||
#: ../src/gdmuser/gdm-user.c:242
|
||||
msgid "Manager"
|
||||
msgstr "Bainisteoir"
|
||||
|
||||
#: ../src/gdmuser/gdm-user.c:243
|
||||
msgid "The user manager object this user is controlled by."
|
||||
msgstr "An réad bhainisteoir úsáideoirí a rialaíonn an t-úsáideoir seo."
|
||||
|
||||
#: ../src/shell-global.c:841
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Níos lú ná nóiméad ó shin"
|
||||
|
||||
#: ../src/shell-global.c:844
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "%d nóiméad ó shin"
|
||||
msgstr[1] "%d nóiméad ó shin"
|
||||
msgstr[2] "%d nóiméad ó shin"
|
||||
msgstr[3] "%d nóiméad ó shin"
|
||||
msgstr[4] "%d nóiméad ó shin"
|
||||
|
||||
#: ../src/shell-global.c:847
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "%d uair ó shin"
|
||||
msgstr[1] "%d uair ó shin"
|
||||
msgstr[2] "%d uaire ó shin"
|
||||
msgstr[3] "%d n-uaire ó shin"
|
||||
msgstr[4] "%d uair ó shin"
|
||||
|
||||
#: ../src/shell-global.c:850
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "%d lá ó shin"
|
||||
msgstr[1] "%d lá ó shin"
|
||||
msgstr[2] "%d lá ó shin"
|
||||
msgstr[3] "%d lá ó shin"
|
||||
msgstr[4] "%d lá ó shin"
|
||||
|
||||
#: ../src/shell-global.c:853
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
msgstr[0] "%d seachtain ó shin"
|
||||
msgstr[1] "%d sheachtain ó shin"
|
||||
msgstr[2] "%d sheachtain ó shin"
|
||||
msgstr[3] "%d seachtain ó shin"
|
||||
msgstr[4] "%d seachtain ó shin"
|
||||
|
||||
#: ../src/shell-status-menu.c:156
|
||||
msgid "Unknown"
|
||||
msgstr "Anaithnid"
|
||||
|
||||
#: ../src/shell-status-menu.c:212
|
||||
#, c-format
|
||||
msgid "Can't lock screen: %s"
|
||||
msgstr "Ní féidir scáileán a chur faoi ghlas: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:227
|
||||
#, c-format
|
||||
msgid "Can't temporarily set screensaver to blank screen: %s"
|
||||
msgstr "Ní féidir spárálaí scáileáin a shocrú chun scáileán a bhánú: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:351
|
||||
#, c-format
|
||||
msgid "Can't logout: %s"
|
||||
msgstr "Ní féidir logáil amach: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:492
|
||||
msgid "Account Information..."
|
||||
msgstr "Eolas Cuntais..."
|
||||
|
||||
#: ../src/shell-status-menu.c:502
|
||||
msgid "Sidebar"
|
||||
msgstr "Barra Taoibh"
|
||||
|
||||
#: ../src/shell-status-menu.c:510
|
||||
msgid "System Preferences..."
|
||||
msgstr "Sainroghanna an Chórais..."
|
||||
|
||||
#: ../src/shell-status-menu.c:525
|
||||
msgid "Lock Screen"
|
||||
msgstr "Cuir Scáileán Faoi Ghlas"
|
||||
|
||||
#: ../src/shell-status-menu.c:535
|
||||
msgid "Switch User"
|
||||
msgstr "Athraigh Úsáideoir"
|
||||
|
||||
#. Only show switch user if there are other users
|
||||
#. Log Out
|
||||
#: ../src/shell-status-menu.c:546
|
||||
msgid "Log Out..."
|
||||
msgstr "Logáil Amach..."
|
||||
|
||||
#. Shut down
|
||||
#: ../src/shell-status-menu.c:557
|
||||
msgid "Shut Down..."
|
||||
msgstr "Múch..."
|
||||
|
||||
#: ../src/shell-uri-util.c:87
|
||||
msgid "Home Folder"
|
||||
msgstr "Fillteán Baile"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-uri-util.c:102
|
||||
msgid "File System"
|
||||
msgstr "Córas Comhad"
|
||||
|
||||
#: ../src/shell-uri-util.c:248
|
||||
msgid "Search"
|
||||
msgstr "Cuardaigh"
|
||||
|
||||
#. Translators: the first string is the name of a gvfs
|
||||
#. * method, and the second string is a path. For
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-uri-util.c:298
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
194
po/gl.po
Normal file
@ -0,0 +1,194 @@
|
||||
# Galician translation for gnome-shell.
|
||||
# Copyright (C) 2009 gnome-shell's COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the gnome-shell package.
|
||||
# Fran Diéguez <fran.dieguez@mabishu.com>, 2009.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell master\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2009-09-15 23:06+0200\n"
|
||||
"PO-Revision-Date: 2009-09-10 22:32+0100\n"
|
||||
"Last-Translator: Fran Diéguez <fran.dieguez@glug.es>\n"
|
||||
"Language-Team: Galician <gnome@mancomun.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:1
|
||||
msgid "GNOME Shell"
|
||||
msgstr "GNOME Shell"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:2
|
||||
msgid "Window management and application launching"
|
||||
msgstr "Xestor de xanelas e lanzado de aplicativos"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:269
|
||||
msgid "Activities"
|
||||
msgstr "Actividades"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:452
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %l:%M %p"
|
||||
|
||||
#: ../js/ui/dash.js:283
|
||||
msgid "Find..."
|
||||
msgstr "Buscar..."
|
||||
|
||||
#: ../js/ui/dash.js:400
|
||||
msgid "Browse"
|
||||
msgstr "Explorar"
|
||||
|
||||
#: ../js/ui/dash.js:536
|
||||
msgid "(see all)"
|
||||
msgstr "(ver todos)"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:753 ../js/ui/dash.js:809
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "APLICATIVOS"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:773
|
||||
msgid "PLACES"
|
||||
msgstr "LUGARES"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:780 ../js/ui/dash.js:819
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "DOCUMENTOS RECENTES"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:799 ../js/ui/dash.js:931
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "RESULTADOS DA BÚSQUEDA"
|
||||
|
||||
#: ../js/ui/dash.js:814
|
||||
msgid "PREFERENCES"
|
||||
msgstr ""
|
||||
|
||||
#: ../js/ui/runDialog.js:96
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Insira unha orde:"
|
||||
|
||||
#: ../src/shell-global.c:799
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Menos de un minuto"
|
||||
|
||||
#: ../src/shell-global.c:802
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "fai %d minuto"
|
||||
msgstr[1] "fai %d minutos"
|
||||
|
||||
#: ../src/shell-global.c:805
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "fai %d hora"
|
||||
msgstr[1] "fai %d horas"
|
||||
|
||||
#: ../src/shell-global.c:808
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "fai %d día"
|
||||
msgstr[1] "fai %d días"
|
||||
|
||||
#: ../src/shell-global.c:811
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
msgstr[0] "fai %d semana"
|
||||
msgstr[1] "fai %d semanas"
|
||||
|
||||
#: ../src/shell-status-menu.c:156
|
||||
msgid "Unknown"
|
||||
msgstr "Descoñecido"
|
||||
|
||||
#: ../src/shell-status-menu.c:212
|
||||
#, c-format
|
||||
msgid "Can't lock screen: %s"
|
||||
msgstr "Non foi posíbel bloquear a pantalla: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:227
|
||||
#, c-format
|
||||
msgid "Can't temporarily set screensaver to blank screen: %s"
|
||||
msgstr ""
|
||||
"Non foi posíbel establecer o salvapantallas a unha pantalla en branco: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:351
|
||||
#, c-format
|
||||
msgid "Can't logout: %s"
|
||||
msgstr "Non foi posíbel pechar a sesión: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:492
|
||||
msgid "Account Information..."
|
||||
msgstr "Información da conta..."
|
||||
|
||||
#: ../src/shell-status-menu.c:502
|
||||
msgid "Sidebar"
|
||||
msgstr "Barra lateral"
|
||||
|
||||
#: ../src/shell-status-menu.c:510
|
||||
msgid "System Preferences..."
|
||||
msgstr "Preferenzas do sistema..."
|
||||
|
||||
#: ../src/shell-status-menu.c:525
|
||||
msgid "Lock Screen"
|
||||
msgstr "Bloquear pantalla"
|
||||
|
||||
#: ../src/shell-status-menu.c:535
|
||||
msgid "Switch User"
|
||||
msgstr "Cambiar de usuario"
|
||||
|
||||
#. Only show switch user if there are other users
|
||||
#. Log Out
|
||||
#: ../src/shell-status-menu.c:546
|
||||
msgid "Log Out..."
|
||||
msgstr "Pechar sesión..."
|
||||
|
||||
#. Shut down
|
||||
#: ../src/shell-status-menu.c:557
|
||||
msgid "Shut Down..."
|
||||
msgstr "Apagar..."
|
||||
|
||||
#: ../src/shell-uri-util.c:87
|
||||
msgid "Home Folder"
|
||||
msgstr "Cartafol persoal"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-uri-util.c:102
|
||||
msgid "File System"
|
||||
msgstr "Sistema de ficheiros"
|
||||
|
||||
#: ../src/shell-uri-util.c:248
|
||||
msgid "Search"
|
||||
msgstr "Buscar"
|
||||
|
||||
#. Translators: the first string is the name of a gvfs
|
||||
#. * method, and the second string is a path. For
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-uri-util.c:298
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
||||
|
||||
#~ msgid "Find apps or documents"
|
||||
#~ msgstr "Atopar aplicativos ou documentos"
|
||||
|
||||
#, fuzzy
|
||||
#~ msgid "DOCUMENTS"
|
||||
#~ msgstr "DOCUMENTOS RECENTES"
|
||||
|
||||
#~ msgid "Manager"
|
||||
#~ msgstr "Xestor"
|
187
po/hu.po
Normal file
@ -0,0 +1,187 @@
|
||||
# Hungarian translation of gnome-shell
|
||||
# Copyright 2009. Free Software Foundation, Inc.
|
||||
# This file is distributed under the same license as the gnome-shell package.
|
||||
#
|
||||
# Gabor Kelemen <kelemeng at gnome dot hu>, 2009.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell master\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2009-09-28 13:41+0200\n"
|
||||
"PO-Revision-Date: 2009-09-28 13:42+0200\n"
|
||||
"Last-Translator: Gabor Kelemen <kelemeng at gnome dot hu>\n"
|
||||
"Language-Team: Hungarian <gnome at fsf dot hu>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: KBabel 1.11.4\n"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:1
|
||||
msgid "GNOME Shell"
|
||||
msgstr "GNOME Shell"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:2
|
||||
msgid "Window management and application launching"
|
||||
msgstr "Ablakkezelés és alkalmazásindítás"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:269
|
||||
msgid "Activities"
|
||||
msgstr "Tevékenységek"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:452
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a., %k.%M"
|
||||
|
||||
#: ../js/ui/dash.js:283
|
||||
msgid "Find..."
|
||||
msgstr "Keresés…"
|
||||
|
||||
#: ../js/ui/dash.js:400
|
||||
msgid "More"
|
||||
msgstr "Több"
|
||||
|
||||
#: ../js/ui/dash.js:543
|
||||
msgid "(see all)"
|
||||
msgstr "(összes megjelenítése)"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:763 ../js/ui/dash.js:825
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "ALKALMAZÁSOK"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:783
|
||||
msgid "PLACES"
|
||||
msgstr "HELYEK"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:790 ../js/ui/dash.js:835
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "LEGUTÓBBI DOKUMENTUMOK"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:815 ../js/ui/dash.js:958
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "TALÁLATOK"
|
||||
|
||||
#: ../js/ui/dash.js:830
|
||||
msgid "PREFERENCES"
|
||||
msgstr "BEÁLLÍTÁSOK"
|
||||
|
||||
#: ../js/ui/runDialog.js:94
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Adjon meg egy parancsot:"
|
||||
|
||||
#: ../src/shell-global.c:799
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Kevesebb, mint egy perce"
|
||||
|
||||
#: ../src/shell-global.c:802
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "%d perce"
|
||||
msgstr[1] "%d perce"
|
||||
|
||||
#: ../src/shell-global.c:805
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "%d órája"
|
||||
msgstr[1] "%d órája"
|
||||
|
||||
#: ../src/shell-global.c:808
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "%d napja"
|
||||
msgstr[1] "%d napja"
|
||||
|
||||
#: ../src/shell-global.c:811
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
msgstr[0] "%d hete"
|
||||
msgstr[1] "%d hete"
|
||||
|
||||
#: ../src/shell-status-menu.c:156
|
||||
msgid "Unknown"
|
||||
msgstr "Ismeretlen"
|
||||
|
||||
#: ../src/shell-status-menu.c:212
|
||||
#, c-format
|
||||
msgid "Can't lock screen: %s"
|
||||
msgstr "Nem lehet zárolni a képernyőt: %s "
|
||||
|
||||
#: ../src/shell-status-menu.c:227
|
||||
#, c-format
|
||||
msgid "Can't temporarily set screensaver to blank screen: %s"
|
||||
msgstr ""
|
||||
"Átmenetileg nem lehet beállítani a képernyővédőt a képernyő elsötétítésére: %"
|
||||
"s"
|
||||
|
||||
#: ../src/shell-status-menu.c:351
|
||||
#, c-format
|
||||
msgid "Can't logout: %s"
|
||||
msgstr "Nem lehet kijelentkezni: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:492
|
||||
msgid "Account Information..."
|
||||
msgstr "Fiókinformációk…"
|
||||
|
||||
#: ../src/shell-status-menu.c:502
|
||||
msgid "Sidebar"
|
||||
msgstr "Oldalsáv"
|
||||
|
||||
#: ../src/shell-status-menu.c:510
|
||||
msgid "System Preferences..."
|
||||
msgstr "Rendszerbeállítások…"
|
||||
|
||||
#: ../src/shell-status-menu.c:525
|
||||
msgid "Lock Screen"
|
||||
msgstr "Képernyő zárolása"
|
||||
|
||||
#: ../src/shell-status-menu.c:535
|
||||
msgid "Switch User"
|
||||
msgstr "Felhasználóváltás"
|
||||
|
||||
#. Only show switch user if there are other users
|
||||
#. Log Out
|
||||
#: ../src/shell-status-menu.c:546
|
||||
msgid "Log Out..."
|
||||
msgstr "Kijelentkezés…"
|
||||
|
||||
#. Shut down
|
||||
#: ../src/shell-status-menu.c:557
|
||||
msgid "Shut Down..."
|
||||
msgstr "Leállítás…"
|
||||
|
||||
#: ../src/shell-uri-util.c:87
|
||||
msgid "Home Folder"
|
||||
msgstr "Saját mappa"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-uri-util.c:102
|
||||
msgid "File System"
|
||||
msgstr "Fájlrendszer"
|
||||
|
||||
#: ../src/shell-uri-util.c:248
|
||||
msgid "Search"
|
||||
msgstr "Oldalsáv"
|
||||
|
||||
#. Translators: the first string is the name of a gvfs
|
||||
#. * method, and the second string is a path. For
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-uri-util.c:298
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
||||
|
197
po/it.po
Normal file
@ -0,0 +1,197 @@
|
||||
# Italian translations for gnome-shell package.
|
||||
# Copyright (C) 2009 the gnome-shell copyright holder
|
||||
# This file is distributed under the same license as the gnome-shell package.
|
||||
# Milo Casagrande <milo@ubuntu.com>, 2009.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell\n"
|
||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
|
||||
"shell&component=general\n"
|
||||
"POT-Creation-Date: 2009-09-05 00:19+0000\n"
|
||||
"PO-Revision-Date: 2009-09-06 18:31+0200\n"
|
||||
"Last-Translator: Milo Casagrande <milo@ubuntu.com>\n"
|
||||
"Language-Team: Italian <tp@lists.linux.it>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:1
|
||||
msgid "GNOME Shell"
|
||||
msgstr "GNOME Shell"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:2
|
||||
msgid "Window management and application launching"
|
||||
msgstr "Gestione finestre e avvio applicazioni"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:271
|
||||
msgid "Activities"
|
||||
msgstr "Attività"
|
||||
|
||||
# (ndt) proviamo col k, se non funge, sappiamo il perché...
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:454
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %k.%M"
|
||||
|
||||
#: ../js/ui/dash.js:256
|
||||
msgid "Find..."
|
||||
msgstr "Trova..."
|
||||
|
||||
#: ../js/ui/dash.js:374
|
||||
msgid "Browse"
|
||||
msgstr "Esplora"
|
||||
|
||||
#: ../js/ui/dash.js:511
|
||||
msgid "(see all)"
|
||||
msgstr "(vedi tutto)"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:705 ../js/ui/dash.js:761 ../js/ui/dash.js:893
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "Applicazioni"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:725
|
||||
msgid "PLACES"
|
||||
msgstr "Risorse"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:732 ../js/ui/dash.js:773 ../js/ui/dash.js:867
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "Documenti recenti"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:751 ../js/ui/dash.js:856 ../js/ui/dash.js:882
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "Risultati ricerca"
|
||||
|
||||
#: ../js/ui/runDialog.js:82
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Inserire un comando:"
|
||||
|
||||
#: ../src/shell-global.c:840
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Meno di un minuto fa"
|
||||
|
||||
#: ../src/shell-global.c:843
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "%d minuto fa"
|
||||
msgstr[1] "%d minuti fa"
|
||||
|
||||
#: ../src/shell-global.c:846
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "%d ora fa"
|
||||
msgstr[1] "%d ore fa"
|
||||
|
||||
#: ../src/shell-global.c:849
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "%d giorno fa"
|
||||
msgstr[1] "%d giorni fa"
|
||||
|
||||
#: ../src/shell-global.c:852
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
msgstr[0] "%d settimana fa"
|
||||
msgstr[1] "%d settimane fa"
|
||||
|
||||
# (ndt) valutare se vada al femminile
|
||||
#: ../src/shell-status-menu.c:156
|
||||
msgid "Unknown"
|
||||
msgstr "Sconosciuto"
|
||||
|
||||
#: ../src/shell-status-menu.c:212
|
||||
#, c-format
|
||||
msgid "Can't lock screen: %s"
|
||||
msgstr "Impossibile bloccare lo schermo: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:227
|
||||
#, c-format
|
||||
msgid "Can't temporarily set screensaver to blank screen: %s"
|
||||
msgstr ""
|
||||
"Impossibile impostare temporaneamente il salva schermo a schermo nero: %s "
|
||||
|
||||
#: ../src/shell-status-menu.c:351
|
||||
#, c-format
|
||||
msgid "Can't logout: %s"
|
||||
msgstr "Impossibile terminare la sessione: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:492
|
||||
msgid "Account Information..."
|
||||
msgstr "Informazioni account..."
|
||||
|
||||
#: ../src/shell-status-menu.c:502
|
||||
msgid "Sidebar"
|
||||
msgstr "Barra laterale"
|
||||
|
||||
#: ../src/shell-status-menu.c:510
|
||||
msgid "System Preferences..."
|
||||
msgstr "Preferenze di sistema..."
|
||||
|
||||
#: ../src/shell-status-menu.c:525
|
||||
msgid "Lock Screen"
|
||||
msgstr "Blocca schermo"
|
||||
|
||||
#: ../src/shell-status-menu.c:535
|
||||
msgid "Switch User"
|
||||
msgstr "Cambia utente"
|
||||
|
||||
#. Only show switch user if there are other users
|
||||
#. Log Out
|
||||
#: ../src/shell-status-menu.c:546
|
||||
msgid "Log Out..."
|
||||
msgstr "Termina sessione..."
|
||||
|
||||
# (ndt) da valutare... pare che ora anche Windows usi 'Arresta...'...
|
||||
#. Shut down
|
||||
#: ../src/shell-status-menu.c:557
|
||||
msgid "Shut Down..."
|
||||
msgstr "Spegni..."
|
||||
|
||||
#: ../src/shell-uri-util.c:87
|
||||
msgid "Home Folder"
|
||||
msgstr "Cartella home"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-uri-util.c:102
|
||||
msgid "File System"
|
||||
msgstr "File system"
|
||||
|
||||
#: ../src/shell-uri-util.c:248
|
||||
msgid "Search"
|
||||
msgstr "Cerca"
|
||||
|
||||
# (ndt) valutare...
|
||||
#. Translators: the first string is the name of a gvfs
|
||||
#. * method, and the second string is a path. For
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-uri-util.c:298
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
||||
|
||||
# (ndt) è da valutare se è troppo lunga, è in una casella di ricerca
|
||||
#~ msgid "Find apps or documents"
|
||||
#~ msgstr "Trova programmi e documenti"
|
||||
|
||||
# (ndt) no idea...
|
||||
#~ msgid "Manager"
|
||||
#~ msgstr "Manager"
|
||||
|
||||
# (ndt) no idea...
|
||||
#~ msgid "The user manager object this user is controlled by."
|
||||
#~ msgstr "L'oggetto user manager che controlla questo utente."
|
166
po/ko.po
Normal file
@ -0,0 +1,166 @@
|
||||
# gnome-shell korean translation.
|
||||
# Copyright (C) 2009 THE gnome-shell'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the gnome-shell package.
|
||||
# Young-Ho Cha <ganadist@gmail.com>, 2009.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2009-08-21 10:09+0900\n"
|
||||
"PO-Revision-Date: 2009-08-21 10:10+0900\n"
|
||||
"Last-Translator: Young-Ho Cha <ganadist@gmail.com>\n"
|
||||
"Language-Team: GNOME Korea <gnome-kr-hackers@lists.kldp.net>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:1
|
||||
msgid "GNOME Shell"
|
||||
msgstr "그놈 쉘"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:2
|
||||
msgid "Window management and application launching"
|
||||
msgstr "창 관리와 프로그램 시작"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:266
|
||||
msgid "Activities"
|
||||
msgstr ""
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:433
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%A %p %l:%M"
|
||||
|
||||
#: ../js/ui/dash.js:250
|
||||
msgid "Find apps or documents"
|
||||
msgstr "프로그램과 문서를 찾습니다"
|
||||
|
||||
#: ../js/ui/dash.js:368
|
||||
msgid "Browse"
|
||||
msgstr "찾아보기"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:504 ../js/ui/dash.js:577
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "프로그램"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:509 ../js/ui/dash.js:604
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "최근 문서"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:597
|
||||
msgid "PLACES"
|
||||
msgstr "위치"
|
||||
|
||||
#: ../js/ui/runDialog.js:75
|
||||
msgid "Please enter a command:"
|
||||
msgstr "명령을 입력하십시오:"
|
||||
|
||||
#: ../src/shell-global.c:841
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "1분 이내"
|
||||
|
||||
#: ../src/shell-global.c:844
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "%d분 전"
|
||||
|
||||
#: ../src/shell-global.c:847
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "%d시간 전"
|
||||
|
||||
#: ../src/shell-global.c:850
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "%d일 전"
|
||||
|
||||
#: ../src/shell-global.c:853
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
msgstr[0] "%d주 전"
|
||||
|
||||
#: ../src/shell-status-menu.c:156
|
||||
msgid "Unknown"
|
||||
msgstr "알 수 없음"
|
||||
|
||||
#: ../src/shell-status-menu.c:212
|
||||
#, c-format
|
||||
msgid "Can't lock screen: %s"
|
||||
msgstr "화면을 잠글 수 없습니다: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:227
|
||||
#, c-format
|
||||
msgid "Can't temporarily set screensaver to blank screen: %s"
|
||||
msgstr "임시로 화면보호기를 빈 화면으로 설정할 수 없습니다: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:351
|
||||
#, c-format
|
||||
msgid "Can't logout: %s"
|
||||
msgstr "로그아웃 할 수 없습니다: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:492
|
||||
msgid "Account Information..."
|
||||
msgstr "계정 정보..."
|
||||
|
||||
#: ../src/shell-status-menu.c:502
|
||||
msgid "Sidebar"
|
||||
msgstr "사이드바"
|
||||
|
||||
#: ../src/shell-status-menu.c:510
|
||||
msgid "System Preferences..."
|
||||
msgstr "시스템 설정..."
|
||||
|
||||
#: ../src/shell-status-menu.c:525
|
||||
msgid "Lock Screen"
|
||||
msgstr "화면 잠그기"
|
||||
|
||||
#: ../src/shell-status-menu.c:535
|
||||
msgid "Switch User"
|
||||
msgstr "사용자 바꾸기"
|
||||
|
||||
#. Only show switch user if there are other users
|
||||
#. Log Out
|
||||
#: ../src/shell-status-menu.c:546
|
||||
msgid "Log Out..."
|
||||
msgstr "로그아웃..."
|
||||
|
||||
#. Shut down
|
||||
#: ../src/shell-status-menu.c:557
|
||||
msgid "Shut Down..."
|
||||
msgstr "컴퓨터 끄기..."
|
||||
|
||||
#: ../src/shell-uri-util.c:87
|
||||
msgid "Home Folder"
|
||||
msgstr "내 폴더"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-uri-util.c:102
|
||||
msgid "File System"
|
||||
msgstr "파일시스템"
|
||||
|
||||
#: ../src/shell-uri-util.c:248
|
||||
msgid "Search"
|
||||
msgstr "찾기"
|
||||
|
||||
#. Translators: the first string is the name of a gvfs
|
||||
#. * method, and the second string is a path. For
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-uri-util.c:298
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%s: %s"
|
183
po/nb.po
Normal file
@ -0,0 +1,183 @@
|
||||
# Norwegian bokmål translation of gnome-shell.
|
||||
# Copyright (C) 2009 THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the gnome-shell package.
|
||||
# Kjartan Maraas <kmaraas@broadpark.no>, 2009.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell 0.4\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2009-10-03 10:47+0200\n"
|
||||
"PO-Revision-Date: 2009-10-03 10:48+0200\n"
|
||||
"Last-Translator: Kjartan Maraas <kmaraas@broadpark.no>\n"
|
||||
"Language-Team: Norwegian bokmål <i18n-nb@lister.ping.uio.no>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:1
|
||||
msgid "GNOME Shell"
|
||||
msgstr "GNOME Shell"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:2
|
||||
msgid "Window management and application launching"
|
||||
msgstr "Vindushåndtering og oppstart av programmer"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:271
|
||||
msgid "Activities"
|
||||
msgstr "Aktiviteter"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:461
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %l:%M"
|
||||
|
||||
#: ../js/ui/dash.js:283
|
||||
msgid "Find..."
|
||||
msgstr "Finn..."
|
||||
|
||||
#: ../js/ui/dash.js:400
|
||||
msgid "More"
|
||||
msgstr "Mer"
|
||||
|
||||
#: ../js/ui/dash.js:543
|
||||
msgid "(see all)"
|
||||
msgstr "(se alle)"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:763 ../js/ui/dash.js:825
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "PROGRAMMER"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:783
|
||||
msgid "PLACES"
|
||||
msgstr "STEDER"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:790 ../js/ui/dash.js:835
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "SISTE DOKUMENTER"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:815 ../js/ui/dash.js:955
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "SØKERESULTATER"
|
||||
|
||||
#: ../js/ui/dash.js:830
|
||||
msgid "PREFERENCES"
|
||||
msgstr "BRUKERVALG"
|
||||
|
||||
#: ../js/ui/runDialog.js:96
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Oppgi en kommando:"
|
||||
|
||||
#: ../src/shell-global.c:812
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Mindre enn ett minutt siden"
|
||||
|
||||
#: ../src/shell-global.c:815
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "%d minutt siden"
|
||||
msgstr[1] "%d minutter siden"
|
||||
|
||||
#: ../src/shell-global.c:818
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "%d time siden"
|
||||
msgstr[1] "%d timer siden"
|
||||
|
||||
#: ../src/shell-global.c:821
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "%d dag siden"
|
||||
msgstr[1] "%d dager siden"
|
||||
|
||||
#: ../src/shell-global.c:824
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
msgstr[0] "%d uke siden"
|
||||
msgstr[1] "%d uker siden"
|
||||
|
||||
#: ../src/shell-status-menu.c:156
|
||||
msgid "Unknown"
|
||||
msgstr "Ukjent"
|
||||
|
||||
#: ../src/shell-status-menu.c:212
|
||||
#, c-format
|
||||
msgid "Can't lock screen: %s"
|
||||
msgstr "Kan ikke låse skjermen: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:227
|
||||
#, c-format
|
||||
msgid "Can't temporarily set screensaver to blank screen: %s"
|
||||
msgstr "Kan ikke sette skjermsparer midlertidig til blank skjerm: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:351
|
||||
#, c-format
|
||||
msgid "Can't logout: %s"
|
||||
msgstr "Kan ikke logge ut: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:492
|
||||
msgid "Account Information..."
|
||||
msgstr "Kontoinformasjon..."
|
||||
|
||||
#: ../src/shell-status-menu.c:502
|
||||
msgid "Sidebar"
|
||||
msgstr "Sidelinje"
|
||||
|
||||
#: ../src/shell-status-menu.c:510
|
||||
msgid "System Preferences..."
|
||||
msgstr "Brukervalg for systemet..."
|
||||
|
||||
#: ../src/shell-status-menu.c:525
|
||||
msgid "Lock Screen"
|
||||
msgstr "Lås skjerm"
|
||||
|
||||
#: ../src/shell-status-menu.c:535
|
||||
msgid "Switch User"
|
||||
msgstr "Bytt bruker"
|
||||
|
||||
#. Only show switch user if there are other users
|
||||
#. Log Out
|
||||
#: ../src/shell-status-menu.c:546
|
||||
msgid "Log Out..."
|
||||
msgstr "Logg ut..."
|
||||
|
||||
#. Shut down
|
||||
#: ../src/shell-status-menu.c:557
|
||||
msgid "Shut Down..."
|
||||
msgstr "Slå av..."
|
||||
|
||||
#: ../src/shell-uri-util.c:87
|
||||
msgid "Home Folder"
|
||||
msgstr "Hjemmemappe"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-uri-util.c:102
|
||||
msgid "File System"
|
||||
msgstr "Filsystem"
|
||||
|
||||
#: ../src/shell-uri-util.c:248
|
||||
msgid "Search"
|
||||
msgstr "Søk"
|
||||
|
||||
#. Translators: the first string is the name of a gvfs
|
||||
#. * method, and the second string is a path. For
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-uri-util.c:298
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
179
po/nl.po
Normal file
@ -0,0 +1,179 @@
|
||||
# Dutch translation for gnome-shell
|
||||
#
|
||||
# This file is distributed under the same license as the gnome-shell package.
|
||||
#
|
||||
# Sander Dijkhuis <sander.dijkhuis@gmail.com>, 2009.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell master\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2009-08-29 14:37+0200\n"
|
||||
"PO-Revision-Date: 2009-08-29 15:10+0200\n"
|
||||
"Last-Translator: Sander Dijkhuis <sander.dijkhuis@gmail.com>\n"
|
||||
"Language-Team: Dutch <vertaling@vrijschrift.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:1
|
||||
msgid "GNOME Shell"
|
||||
msgstr "GNOME Shell"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:2
|
||||
msgid "Window management and application launching"
|
||||
msgstr "Vensterbeheer en toepassingen starten"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:271
|
||||
msgid "Activities"
|
||||
msgstr "Activiteiten"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:451
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %k:%M"
|
||||
|
||||
#: ../js/ui/dash.js:256
|
||||
msgid "Find..."
|
||||
msgstr "Zoeken…"
|
||||
|
||||
#: ../js/ui/dash.js:374
|
||||
msgid "Browse"
|
||||
msgstr "Bladeren"
|
||||
|
||||
#: ../js/ui/dash.js:451
|
||||
msgid "(see all)"
|
||||
msgstr "(alles tonen)"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:634 ../js/ui/dash.js:682
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "TOEPASSINGEN"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:654
|
||||
msgid "PLACES"
|
||||
msgstr "LOCATIES"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:661 ../js/ui/dash.js:694
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "RECENTE DOCUMENTEN"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:680
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "ZOEKRESULTATEN"
|
||||
|
||||
#: ../js/ui/runDialog.js:82
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Voer een opdracht in:"
|
||||
|
||||
#: ../src/shell-global.c:840
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Korter dan een minuut geleden"
|
||||
|
||||
#: ../src/shell-global.c:843
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "%d minuut geleden"
|
||||
msgstr[1] "%d minuten geleden"
|
||||
|
||||
#: ../src/shell-global.c:846
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "%d uur geleden"
|
||||
msgstr[1] "%d uur geleden"
|
||||
|
||||
#: ../src/shell-global.c:849
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "%d dag geleden"
|
||||
msgstr[1] "%d dagen geleden"
|
||||
|
||||
#: ../src/shell-global.c:852
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
msgstr[0] "%d week geleden"
|
||||
msgstr[1] "%d weken geleden"
|
||||
|
||||
#: ../src/shell-status-menu.c:156
|
||||
msgid "Unknown"
|
||||
msgstr "Onbekend"
|
||||
|
||||
#: ../src/shell-status-menu.c:212
|
||||
#, c-format
|
||||
msgid "Can't lock screen: %s"
|
||||
msgstr "Kan het scherm niet vergrendelen: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:227
|
||||
#, c-format
|
||||
msgid "Can't temporarily set screensaver to blank screen: %s"
|
||||
msgstr "Kan de schermbeveiliging niet tijdelijk als zwart scherm instellen: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:351
|
||||
#, c-format
|
||||
msgid "Can't logout: %s"
|
||||
msgstr "Kan niet afmelden: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:492
|
||||
msgid "Account Information..."
|
||||
msgstr "Account-informatie…"
|
||||
|
||||
#: ../src/shell-status-menu.c:502
|
||||
msgid "Sidebar"
|
||||
msgstr "Zijbalk"
|
||||
|
||||
#: ../src/shell-status-menu.c:510
|
||||
msgid "System Preferences..."
|
||||
msgstr "Systeemvoorkeuren…"
|
||||
|
||||
#: ../src/shell-status-menu.c:525
|
||||
msgid "Lock Screen"
|
||||
msgstr "Scherm vergrendelen"
|
||||
|
||||
#: ../src/shell-status-menu.c:535
|
||||
msgid "Switch User"
|
||||
msgstr "Gebruiker wisselen"
|
||||
|
||||
#. Only show switch user if there are other users
|
||||
#. Log Out
|
||||
#: ../src/shell-status-menu.c:546
|
||||
msgid "Log Out..."
|
||||
msgstr "Afmelden…"
|
||||
|
||||
#. Shut down
|
||||
#: ../src/shell-status-menu.c:557
|
||||
msgid "Shut Down..."
|
||||
msgstr "Afsluiten…"
|
||||
|
||||
#: ../src/shell-uri-util.c:87
|
||||
msgid "Home Folder"
|
||||
msgstr "Persoonlijke map"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-uri-util.c:102
|
||||
msgid "File System"
|
||||
msgstr "Bestandssysteem"
|
||||
|
||||
#: ../src/shell-uri-util.c:248
|
||||
msgid "Search"
|
||||
msgstr "Zoeken"
|
||||
|
||||
#. Translators: the first string is the name of a gvfs
|
||||
#. * method, and the second string is a path. For
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-uri-util.c:298
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
182
po/pa.po
Normal file
@ -0,0 +1,182 @@
|
||||
# Punjabi translation for gnome-shell.
|
||||
# Copyright (C) 2009 gnome-shell's COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the gnome-shell package.
|
||||
#
|
||||
# A S Alam <aalam@users.sf.net>, 2009.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell master\n"
|
||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug."
|
||||
"cgi?product=gnome-shell&component=general\n"
|
||||
"POT-Creation-Date: 2009-08-31 22:31+0000\n"
|
||||
"PO-Revision-Date: 2009-09-01 06:51+0530\n"
|
||||
"Last-Translator: A S Alam <aalam@users.sf.net>\n"
|
||||
"Language-Team: Punjabi/Panjabi <punjabi-users@lists.sf.net>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"X-Generator: Lokalize 1.0\n"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:1
|
||||
msgid "GNOME Shell"
|
||||
msgstr "ਗਨੋਮ ਸ਼ੈਲ"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:2
|
||||
msgid "Window management and application launching"
|
||||
msgstr "ਵਿੰਡੋ ਪਰਬੰਧ ਅਤੇ ਐਪਲੀਕੇਸ਼ਨ ਚਲਾਓ"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:271
|
||||
msgid "Activities"
|
||||
msgstr "ਸਰਗਰਮੀਆਂ"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:454
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %l:%M %p"
|
||||
|
||||
#: ../js/ui/dash.js:256
|
||||
msgid "Find..."
|
||||
msgstr "ਖੋਜ..."
|
||||
|
||||
#: ../js/ui/dash.js:374
|
||||
msgid "Browse"
|
||||
msgstr "ਝਲਕ"
|
||||
|
||||
#: ../js/ui/dash.js:451
|
||||
msgid "(see all)"
|
||||
msgstr "(ਸਭ ਵੇਖੋ)"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:633 ../js/ui/dash.js:681
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "ਐਪਲੀਕੇਸ਼ਨ"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:653
|
||||
msgid "PLACES"
|
||||
msgstr "ਥਾਵਾਂ"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:660 ../js/ui/dash.js:692
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "ਤਾਜ਼ਾ ਡੌਕੂਮੈਂਟ"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:679
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "ਖੋਜ ਨਤੀਜੇ"
|
||||
|
||||
#: ../js/ui/runDialog.js:82
|
||||
msgid "Please enter a command:"
|
||||
msgstr "ਕਮਾਂਡ ਦਿਓ ਜੀ:"
|
||||
|
||||
#: ../src/shell-global.c:840
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "ਇੱਕ ਮਿੰਟ ਤੋਂ ਘੱਟ ਚਿਰ ਪਹਿਲਾਂ"
|
||||
|
||||
#: ../src/shell-global.c:843
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "%d ਮਿੰਟ ਪਹਿਲਾਂ"
|
||||
msgstr[1] "%d ਮਿੰਟ ਪਹਿਲਾਂ"
|
||||
|
||||
#: ../src/shell-global.c:846
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "%d ਘੰਟਾ ਪਹਿਲਾਂ"
|
||||
msgstr[1] "%d ਘੰਟੇ ਪਹਿਲਾਂ"
|
||||
|
||||
#: ../src/shell-global.c:849
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "%d ਦਿਨ ਪਹਿਲਾਂ"
|
||||
msgstr[1] "%d ਦਿਨ ਪਹਿਲਾਂ"
|
||||
|
||||
#: ../src/shell-global.c:852
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
msgstr[0] "%d ਹਫ਼ਤਾ ਪਹਿਲਾਂ"
|
||||
msgstr[1] "%d ਹਫ਼ਤੇ ਪਹਿਲਾਂ"
|
||||
|
||||
#: ../src/shell-status-menu.c:156
|
||||
msgid "Unknown"
|
||||
msgstr "ਅਣਜਾਣ"
|
||||
|
||||
#: ../src/shell-status-menu.c:212
|
||||
#, c-format
|
||||
msgid "Can't lock screen: %s"
|
||||
msgstr "ਸਕਰੀਨ ਲਾਕ ਨਹੀਂ ਹੋ ਸਕਦੀ: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:227
|
||||
#, c-format
|
||||
msgid "Can't temporarily set screensaver to blank screen: %s"
|
||||
msgstr "ਸਕਰੀਨ ਬੰਦ ਕਰਨ ਲਈ ਆਰਜ਼ੀ ਰੂਪ ਵਿੱਚ ਸਕਰੀਨ-ਸੇਵਰ ਨਹੀਂ ਸੈੱਟ ਕੀਤਾ ਜਾ ਸਕਦਾ: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:351
|
||||
#, c-format
|
||||
msgid "Can't logout: %s"
|
||||
msgstr "ਲਾਗਆਉਟ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:492
|
||||
msgid "Account Information..."
|
||||
msgstr "ਅਕਾਊਂਟ ਜਾਣਕਾਰੀ..."
|
||||
|
||||
#: ../src/shell-status-menu.c:502
|
||||
msgid "Sidebar"
|
||||
msgstr "ਬਾਹੀ"
|
||||
|
||||
#: ../src/shell-status-menu.c:510
|
||||
msgid "System Preferences..."
|
||||
msgstr "ਸਿਸਟਮ ਪਸੰਦ..."
|
||||
|
||||
#: ../src/shell-status-menu.c:525
|
||||
msgid "Lock Screen"
|
||||
msgstr "ਸਕਰੀਨ ਲਾਕ ਕਰੋ"
|
||||
|
||||
#: ../src/shell-status-menu.c:535
|
||||
msgid "Switch User"
|
||||
msgstr "ਯੂਜ਼ਰ ਬਦਲੋ"
|
||||
|
||||
#. Only show switch user if there are other users
|
||||
#. Log Out
|
||||
#: ../src/shell-status-menu.c:546
|
||||
msgid "Log Out..."
|
||||
msgstr "ਲਾਗਆਉਟ..."
|
||||
|
||||
#. Shut down
|
||||
#: ../src/shell-status-menu.c:557
|
||||
msgid "Shut Down..."
|
||||
msgstr "ਬੰਦ ਕਰੋ..."
|
||||
|
||||
#: ../src/shell-uri-util.c:87
|
||||
msgid "Home Folder"
|
||||
msgstr "ਘਰ ਫੋਲਡਰ"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-uri-util.c:102
|
||||
msgid "File System"
|
||||
msgstr "ਫਾਇਲ ਸਿਸਟਮ"
|
||||
|
||||
#: ../src/shell-uri-util.c:248
|
||||
msgid "Search"
|
||||
msgstr "ਖੋਜ"
|
||||
|
||||
#. Translators: the first string is the name of a gvfs
|
||||
#. * method, and the second string is a path. For
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-uri-util.c:298
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
||||
|
188
po/pl.po
Normal file
@ -0,0 +1,188 @@
|
||||
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
# Aviary.pl
|
||||
# Jeśli masz jakiekolwiek uwagi odnoszące się do tłumaczenia lub chcesz
|
||||
# pomóc w jego rozwijaniu i pielęgnowaniu, napisz do nas:
|
||||
# gnomepl@aviary.pl
|
||||
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2009-09-09 03:06+0200\n"
|
||||
"PO-Revision-Date: 2009-09-09 03:02+0100\n"
|
||||
"Last-Translator: Tomasz Dominikowski <dominikowski@gmail.com>\n"
|
||||
"Language-Team: Polish <gnomepl@aviary.pl>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
|
||||
"|| n%100>=20) ? 1 : 2);\n"
|
||||
"X-Poedit-Language: Polish\n"
|
||||
"X-Poedit-Country: Poland\n"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:1
|
||||
msgid "GNOME Shell"
|
||||
msgstr "Powłoka środowiska GNOME"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:2
|
||||
msgid "Window management and application launching"
|
||||
msgstr "Zarządzanie oknami i uruchamianiem programów"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:269
|
||||
msgid "Activities"
|
||||
msgstr "Czynności"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:452
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a, %H:%M"
|
||||
|
||||
#: ../js/ui/dash.js:255
|
||||
msgid "Find..."
|
||||
msgstr "Znajdź..."
|
||||
|
||||
#: ../js/ui/dash.js:372
|
||||
msgid "Browse"
|
||||
msgstr "Przeglądaj"
|
||||
|
||||
#: ../js/ui/dash.js:508
|
||||
msgid "(see all)"
|
||||
msgstr "(wyświetl wszystko)"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:700 ../js/ui/dash.js:756 ../js/ui/dash.js:887
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "Programy"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:720
|
||||
msgid "PLACES"
|
||||
msgstr "Miejsca"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:727 ../js/ui/dash.js:768 ../js/ui/dash.js:861
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "Ostatnie dokumenty"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:746 ../js/ui/dash.js:850 ../js/ui/dash.js:876
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "Wyniki wyszukiwania"
|
||||
|
||||
#: ../js/ui/runDialog.js:90
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Proszę wprowadzić polecenie:"
|
||||
|
||||
#: ../src/shell-global.c:799
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Mniej niż minutę temu"
|
||||
|
||||
#: ../src/shell-global.c:802
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "%d minuta temu"
|
||||
msgstr[1] "%d minuty temu"
|
||||
msgstr[2] "%d minut temu"
|
||||
|
||||
#: ../src/shell-global.c:805
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "%d godzina temu"
|
||||
msgstr[1] "%d godziny temu"
|
||||
msgstr[2] "%d godzin temu"
|
||||
|
||||
#: ../src/shell-global.c:808
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "%d dzień temu"
|
||||
msgstr[1] "%d dni temu"
|
||||
msgstr[2] "%d dni temu"
|
||||
|
||||
#: ../src/shell-global.c:811
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
msgstr[0] "%d tydzień temu"
|
||||
msgstr[1] "%d tygodnie temu"
|
||||
msgstr[2] "%d tygodni temu"
|
||||
|
||||
#: ../src/shell-status-menu.c:156
|
||||
msgid "Unknown"
|
||||
msgstr "Nieznane"
|
||||
|
||||
#: ../src/shell-status-menu.c:212
|
||||
#, c-format
|
||||
msgid "Can't lock screen: %s"
|
||||
msgstr "Nie można zablokować ekranu: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:227
|
||||
#, c-format
|
||||
msgid "Can't temporarily set screensaver to blank screen: %s"
|
||||
msgstr ""
|
||||
"Nie można tymczasowo ustawić wygaszacza ekranu na wygaszenie ekranu: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:351
|
||||
#, c-format
|
||||
msgid "Can't logout: %s"
|
||||
msgstr "Nie można się wylogować: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:492
|
||||
msgid "Account Information..."
|
||||
msgstr "Informacje o koncie..."
|
||||
|
||||
#: ../src/shell-status-menu.c:502
|
||||
msgid "Sidebar"
|
||||
msgstr "Panel boczny"
|
||||
|
||||
#: ../src/shell-status-menu.c:510
|
||||
msgid "System Preferences..."
|
||||
msgstr "Preferencje systemu..."
|
||||
|
||||
#: ../src/shell-status-menu.c:525
|
||||
msgid "Lock Screen"
|
||||
msgstr "Zablokuj ekran"
|
||||
|
||||
#: ../src/shell-status-menu.c:535
|
||||
msgid "Switch User"
|
||||
msgstr "Przełącz użytkownika"
|
||||
|
||||
#. Only show switch user if there are other users
|
||||
#. Log Out
|
||||
#: ../src/shell-status-menu.c:546
|
||||
msgid "Log Out..."
|
||||
msgstr "Wyloguj się..."
|
||||
|
||||
#. Shut down
|
||||
#: ../src/shell-status-menu.c:557
|
||||
msgid "Shut Down..."
|
||||
msgstr "Wyłącz komputer..."
|
||||
|
||||
#: ../src/shell-uri-util.c:87
|
||||
msgid "Home Folder"
|
||||
msgstr "Katalog domowy"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-uri-util.c:102
|
||||
msgid "File System"
|
||||
msgstr "System plików"
|
||||
|
||||
#: ../src/shell-uri-util.c:248
|
||||
msgid "Search"
|
||||
msgstr "Wyszukaj"
|
||||
|
||||
#. Translators: the first string is the name of a gvfs
|
||||
#. * method, and the second string is a path. For
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-uri-util.c:298
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
193
po/pt_BR.po
Normal file
@ -0,0 +1,193 @@
|
||||
# Portuguese translations for gnome-shell package.
|
||||
# Copyright (C) 2009 THE gnome-shell'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the gnome-shell package.
|
||||
# Og Maciel <ogmaciel@gnome.org>, 2009.
|
||||
# Rodrigo Flores <mail@rodrigoflores.org>, 2009.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2009-09-21 08:39-0300\n"
|
||||
"PO-Revision-Date: 2009-09-20 08:41-0300\n"
|
||||
"Last-Translator: Rodrigo Flores <mail@rodrigoflores.org>\n"
|
||||
"Language-Team: Brazilian Portuguese <gnome-pt_br-list@gnome.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:1
|
||||
msgid "GNOME Shell"
|
||||
msgstr "GNOME Shell"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:2
|
||||
msgid "Window management and application launching"
|
||||
msgstr "Gerenciamento de janelas e lançador de aplicações"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:269
|
||||
msgid "Activities"
|
||||
msgstr "Atividades"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:452
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %l:%M %p"
|
||||
|
||||
#: ../js/ui/dash.js:283
|
||||
msgid "Find..."
|
||||
msgstr "Encontre..."
|
||||
|
||||
#: ../js/ui/dash.js:400
|
||||
msgid "Browse"
|
||||
msgstr "Navegar"
|
||||
|
||||
#: ../js/ui/dash.js:536
|
||||
msgid "(see all)"
|
||||
msgstr "(veja todos)"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:753 ../js/ui/dash.js:809
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "APLICATIVOS"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:773
|
||||
msgid "PLACES"
|
||||
msgstr "LOCAIS"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:780 ../js/ui/dash.js:819
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "DOCUMENTOS RECENTES"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:799 ../js/ui/dash.js:931
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "RESULTADOS DA BUSCA"
|
||||
|
||||
#: ../js/ui/dash.js:814
|
||||
msgid "PREFERENCES"
|
||||
msgstr "PREFERÊNCIAS"
|
||||
|
||||
#: ../js/ui/runDialog.js:101
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Por favor digite um comando:"
|
||||
|
||||
#: ../src/shell-global.c:799
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Menos de um minuto atrás"
|
||||
|
||||
#: ../src/shell-global.c:802
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "%d minuto atrás"
|
||||
msgstr[1] "%d minutos atrás"
|
||||
|
||||
#: ../src/shell-global.c:805
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "%d hora atrás"
|
||||
msgstr[1] "%d horas atrás"
|
||||
|
||||
#: ../src/shell-global.c:808
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "%d dia atrás"
|
||||
msgstr[1] "%d dias atrás"
|
||||
|
||||
#: ../src/shell-global.c:811
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
msgstr[0] "%d semana atrás"
|
||||
msgstr[1] "%d semanas atrás"
|
||||
|
||||
#: ../src/shell-status-menu.c:156
|
||||
msgid "Unknown"
|
||||
msgstr "Desconhecido"
|
||||
|
||||
#: ../src/shell-status-menu.c:212
|
||||
#, c-format
|
||||
msgid "Can't lock screen: %s"
|
||||
msgstr "Não foi possível travar a tela: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:227
|
||||
#, c-format
|
||||
msgid "Can't temporarily set screensaver to blank screen: %s"
|
||||
msgstr "Não foi possível definir a proteção de tela para uma tela vazia: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:351
|
||||
#, c-format
|
||||
msgid "Can't logout: %s"
|
||||
msgstr "Não foi possível encerrar a sessão: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:492
|
||||
msgid "Account Information..."
|
||||
msgstr "Informação da conta..."
|
||||
|
||||
#: ../src/shell-status-menu.c:502
|
||||
msgid "Sidebar"
|
||||
msgstr "Barra lateral"
|
||||
|
||||
#: ../src/shell-status-menu.c:510
|
||||
msgid "System Preferences..."
|
||||
msgstr "Preferências do sistema..."
|
||||
|
||||
#: ../src/shell-status-menu.c:525
|
||||
msgid "Lock Screen"
|
||||
msgstr "Travar a tela"
|
||||
|
||||
#: ../src/shell-status-menu.c:535
|
||||
msgid "Switch User"
|
||||
msgstr "Alternar usuário"
|
||||
|
||||
#. Only show switch user if there are other users
|
||||
#. Log Out
|
||||
#: ../src/shell-status-menu.c:546
|
||||
msgid "Log Out..."
|
||||
msgstr "Encerrar sessão..."
|
||||
|
||||
#. Shut down
|
||||
#: ../src/shell-status-menu.c:557
|
||||
msgid "Shut Down..."
|
||||
msgstr "Desligar..."
|
||||
|
||||
#: ../src/shell-uri-util.c:87
|
||||
msgid "Home Folder"
|
||||
msgstr "Pasta home"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-uri-util.c:102
|
||||
msgid "File System"
|
||||
msgstr "Sistema de arquivos"
|
||||
|
||||
#: ../src/shell-uri-util.c:248
|
||||
msgid "Search"
|
||||
msgstr "Procurar"
|
||||
|
||||
#. Translators: the first string is the name of a gvfs
|
||||
#. * method, and the second string is a path. For
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-uri-util.c:298
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
||||
|
||||
#~ msgid "Find apps or documents"
|
||||
#~ msgstr "Localizar aplicativos ou documentos"
|
||||
|
||||
#~ msgid "Manager"
|
||||
#~ msgstr "Gerenciador"
|
||||
|
||||
#~ msgid "The user manager object this user is controlled by."
|
||||
#~ msgstr "O objeto gerenciador de usuários que controla este usuário."
|
198
po/sl.po
Normal file
@ -0,0 +1,198 @@
|
||||
# Slovenian translation for gnome-shell.
|
||||
# This file is distributed under the same license as the gnome-shell package.
|
||||
# Matej Urbančič <mateju@svn.gnome.org>, 2009.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell master\n"
|
||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-shell&component=general\n"
|
||||
"POT-Creation-Date: 2009-09-21 22:38+0000\n"
|
||||
"PO-Revision-Date: 2009-09-22 10:36+0100\n"
|
||||
"Last-Translator: Matej Urbančič <mateju@svn.gnome.org>\n"
|
||||
"Language-Team: Slovenian <gnome-si@googlegroups.com>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: Slovenian\n"
|
||||
"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n%100==4 ? 3 : 0);\n"
|
||||
"X-Poedit-Language: Slovenian\n"
|
||||
"X-Poedit-Country: SLOVENIA\n"
|
||||
"X-Poedit-SourceCharset: utf-8\n"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:1
|
||||
msgid "GNOME Shell"
|
||||
msgstr "Gnome lupina"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:2
|
||||
msgid "Window management and application launching"
|
||||
msgstr "Upravljanje oken in zaganjanje programov"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:269
|
||||
msgid "Activities"
|
||||
msgstr "Dejavnosti"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:452
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a, %H:%M"
|
||||
|
||||
#: ../js/ui/dash.js:283
|
||||
msgid "Find..."
|
||||
msgstr "Poišči ..."
|
||||
|
||||
#: ../js/ui/dash.js:400
|
||||
msgid "Browse"
|
||||
msgstr "Prebrskaj"
|
||||
|
||||
#: ../js/ui/dash.js:536
|
||||
msgid "(see all)"
|
||||
msgstr "(poglej vse)"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:753
|
||||
#: ../js/ui/dash.js:809
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "Programi"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:773
|
||||
msgid "PLACES"
|
||||
msgstr "Mesta"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:780
|
||||
#: ../js/ui/dash.js:819
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "Nedavni dokumenti"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:799
|
||||
#: ../js/ui/dash.js:931
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "Rezultati iskanja"
|
||||
|
||||
#: ../js/ui/dash.js:814
|
||||
msgid "PREFERENCES"
|
||||
msgstr "Lastnosti"
|
||||
|
||||
#: ../js/ui/runDialog.js:101
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Prosim, vnesite ukaz:"
|
||||
|
||||
#: ../src/shell-global.c:799
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Pred manj kot eno minuto"
|
||||
|
||||
#: ../src/shell-global.c:802
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "Pred %d minutami"
|
||||
msgstr[1] "Pred %d minuto"
|
||||
msgstr[2] "Pred %d minutama"
|
||||
msgstr[3] "Pred %d minutami"
|
||||
|
||||
#: ../src/shell-global.c:805
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "Pred %d urami"
|
||||
msgstr[1] "Pred %d uro"
|
||||
msgstr[2] "Pred %d urama"
|
||||
msgstr[3] "Pred %d urami"
|
||||
|
||||
#: ../src/shell-global.c:808
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "Pred %d dnevi"
|
||||
msgstr[1] "Pred %d dnevom"
|
||||
msgstr[2] "Pred %d dnevoma"
|
||||
msgstr[3] "Pred %d dnevi"
|
||||
|
||||
#: ../src/shell-global.c:811
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
msgstr[0] "Pred %d tedni"
|
||||
msgstr[1] "Pred %d tednom"
|
||||
msgstr[2] "Pred %d tednoma"
|
||||
msgstr[3] "Pred %d tedni"
|
||||
|
||||
#: ../src/shell-status-menu.c:156
|
||||
msgid "Unknown"
|
||||
msgstr "Neznano"
|
||||
|
||||
#: ../src/shell-status-menu.c:212
|
||||
#, c-format
|
||||
msgid "Can't lock screen: %s"
|
||||
msgstr "Ni mogoče zakleniti zaslona: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:227
|
||||
#, c-format
|
||||
msgid "Can't temporarily set screensaver to blank screen: %s"
|
||||
msgstr "Ni mogoče začasno nastaviti črnega zaslona za ohranjevalnik zaslona: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:351
|
||||
#, c-format
|
||||
msgid "Can't logout: %s"
|
||||
msgstr "Ni se mogoče odjaviti: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:492
|
||||
msgid "Account Information..."
|
||||
msgstr "Podrobnosti računa ..."
|
||||
|
||||
#: ../src/shell-status-menu.c:502
|
||||
msgid "Sidebar"
|
||||
msgstr "_Stranska vrstica"
|
||||
|
||||
#: ../src/shell-status-menu.c:510
|
||||
msgid "System Preferences..."
|
||||
msgstr "Sistemske lastnosti ..."
|
||||
|
||||
#: ../src/shell-status-menu.c:525
|
||||
msgid "Lock Screen"
|
||||
msgstr "Zakleni zaslon"
|
||||
|
||||
#: ../src/shell-status-menu.c:535
|
||||
msgid "Switch User"
|
||||
msgstr "Preklop uporabnika"
|
||||
|
||||
#. Only show switch user if there are other users
|
||||
#. Log Out
|
||||
#: ../src/shell-status-menu.c:546
|
||||
msgid "Log Out..."
|
||||
msgstr "Odjava ..."
|
||||
|
||||
#. Shut down
|
||||
#: ../src/shell-status-menu.c:557
|
||||
msgid "Shut Down..."
|
||||
msgstr "Izklop ..."
|
||||
|
||||
#: ../src/shell-uri-util.c:87
|
||||
msgid "Home Folder"
|
||||
msgstr "Domača mapa"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-uri-util.c:102
|
||||
msgid "File System"
|
||||
msgstr "Datotečni sistem"
|
||||
|
||||
#: ../src/shell-uri-util.c:248
|
||||
msgid "Search"
|
||||
msgstr "Iskanje"
|
||||
|
||||
#. Translators: the first string is the name of a gvfs
|
||||
#. * method, and the second string is a path. For
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-uri-util.c:298
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
||||
|
196
po/sv.po
Normal file
@ -0,0 +1,196 @@
|
||||
# Swedish translation for gnome-shell.
|
||||
# Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
# This file is distributed under the same license as the gnome-shell package.
|
||||
# Daniel Nylander <po@danielnylander.se>, 2009.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2009-09-18 13:02+0200\n"
|
||||
"PO-Revision-Date: 2009-09-18 13:02+0100\n"
|
||||
"Last-Translator: Daniel Nylander <po@danielnylander.se>\n"
|
||||
"Language-Team: Swedish <tp-sv@listor.tp-sv.se>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:1
|
||||
msgid "GNOME Shell"
|
||||
msgstr "GNOME-skal"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:2
|
||||
msgid "Window management and application launching"
|
||||
msgstr "Fönsterhantering och programstarter"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:269
|
||||
msgid "Activities"
|
||||
msgstr "Aktiviteter"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:452
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %H.%M"
|
||||
|
||||
#: ../js/ui/dash.js:283
|
||||
msgid "Find..."
|
||||
msgstr "Sök..."
|
||||
|
||||
#: ../js/ui/dash.js:400
|
||||
msgid "Browse"
|
||||
msgstr "Bläddra"
|
||||
|
||||
#: ../js/ui/dash.js:536
|
||||
msgid "(see all)"
|
||||
msgstr "(se alla)"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:753
|
||||
#: ../js/ui/dash.js:809
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "PROGRAM"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:773
|
||||
msgid "PLACES"
|
||||
msgstr "PLATSER"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:780
|
||||
#: ../js/ui/dash.js:819
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "SENASTE DOKUMENT"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:799
|
||||
#: ../js/ui/dash.js:931
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "SÖKRESULTAT"
|
||||
|
||||
#: ../js/ui/dash.js:814
|
||||
msgid "PREFERENCES"
|
||||
msgstr "INSTÄLLNINGAR"
|
||||
|
||||
#: ../js/ui/runDialog.js:101
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Ange ett kommando:"
|
||||
|
||||
#: ../src/shell-global.c:799
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Mindre än en minut sedan"
|
||||
|
||||
#: ../src/shell-global.c:802
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "%d minut sedan"
|
||||
msgstr[1] "%d minuter sedan"
|
||||
|
||||
#: ../src/shell-global.c:805
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "%d timme sedan"
|
||||
msgstr[1] "%d timmar sedan"
|
||||
|
||||
#: ../src/shell-global.c:808
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "%d dag sedan"
|
||||
msgstr[1] "%d dagar sedan"
|
||||
|
||||
#: ../src/shell-global.c:811
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
msgstr[0] "%d vecka sedan"
|
||||
msgstr[1] "%d veckor sedan"
|
||||
|
||||
#: ../src/shell-status-menu.c:156
|
||||
msgid "Unknown"
|
||||
msgstr "Okänt"
|
||||
|
||||
#: ../src/shell-status-menu.c:212
|
||||
#, c-format
|
||||
msgid "Can't lock screen: %s"
|
||||
msgstr "Kan inte låsa skärmen: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:227
|
||||
#, c-format
|
||||
msgid "Can't temporarily set screensaver to blank screen: %s"
|
||||
msgstr "Kan inte temporärt ställa in skärmsläckaren till blank skärm: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:351
|
||||
#, c-format
|
||||
msgid "Can't logout: %s"
|
||||
msgstr "Kan inte logga ut: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:492
|
||||
msgid "Account Information..."
|
||||
msgstr "Kontoinformation..."
|
||||
|
||||
#: ../src/shell-status-menu.c:502
|
||||
msgid "Sidebar"
|
||||
msgstr "Sidopanel"
|
||||
|
||||
#: ../src/shell-status-menu.c:510
|
||||
msgid "System Preferences..."
|
||||
msgstr "Systeminställningar..."
|
||||
|
||||
#: ../src/shell-status-menu.c:525
|
||||
msgid "Lock Screen"
|
||||
msgstr "Lås skärmen"
|
||||
|
||||
#: ../src/shell-status-menu.c:535
|
||||
msgid "Switch User"
|
||||
msgstr "Växla användare"
|
||||
|
||||
#. Only show switch user if there are other users
|
||||
#. Log Out
|
||||
#: ../src/shell-status-menu.c:546
|
||||
msgid "Log Out..."
|
||||
msgstr "Logga ut..."
|
||||
|
||||
#. Shut down
|
||||
#: ../src/shell-status-menu.c:557
|
||||
msgid "Shut Down..."
|
||||
msgstr "Stäng av..."
|
||||
|
||||
#: ../src/shell-uri-util.c:87
|
||||
msgid "Home Folder"
|
||||
msgstr "Hemmapp"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-uri-util.c:102
|
||||
msgid "File System"
|
||||
msgstr "Filsystem"
|
||||
|
||||
#: ../src/shell-uri-util.c:248
|
||||
msgid "Search"
|
||||
msgstr "Sök"
|
||||
|
||||
#. Translators: the first string is the name of a gvfs
|
||||
#. * method, and the second string is a path. For
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-uri-util.c:298
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
||||
|
||||
#~ msgid "Find apps or documents"
|
||||
#~ msgstr "Hitta program eller dokument"
|
||||
#~ msgid "DOCUMENTS"
|
||||
#~ msgstr "DOKUMENT"
|
||||
#~ msgid "Manager"
|
||||
#~ msgstr "Hanterare"
|
||||
#~ msgid "The user manager object this user is controlled by."
|
||||
#~ msgstr "Användarhanteringsobjektet som denna användare styrs av."
|
||||
|
166
po/tr.po
Normal file
@ -0,0 +1,166 @@
|
||||
# gnome-shell
|
||||
# Copyright (C) 2009
|
||||
# This file is distributed under the same license as the gnome-shell package.
|
||||
#
|
||||
# Baris Cicek <baris@teamforce.name.tr>, 2009.
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2009-08-21 00:41+0300\n"
|
||||
"PO-Revision-Date: 2009-08-21 00:40+0300\n"
|
||||
"Last-Translator: Baris Cicek <baris@teamforce.name.tr>\n"
|
||||
"Language-Team: Turkish <gnome-turk@gnome.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:1
|
||||
msgid "GNOME Shell"
|
||||
msgstr "GNOME Kabuğu"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:2
|
||||
msgid "Window management and application launching"
|
||||
msgstr "Pencere yönetimi ve uygulama başlatma"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:266
|
||||
msgid "Activities"
|
||||
msgstr "Etkinlikler"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:433
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %H:%M"
|
||||
|
||||
#: ../js/ui/dash.js:251
|
||||
msgid "Find apps or documents"
|
||||
msgstr "Uygulamalar ve belgeler bul"
|
||||
|
||||
#: ../js/ui/dash.js:369
|
||||
msgid "Browse"
|
||||
msgstr "Göz at"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:505 ../js/ui/dash.js:578
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "UYGULAMALAR"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:510 ../js/ui/dash.js:605
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "SON ERİŞİLEN BELGELER"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:598
|
||||
msgid "PLACES"
|
||||
msgstr "YERLER"
|
||||
|
||||
#: ../js/ui/runDialog.js:75
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Lütfen bir komut girin:"
|
||||
|
||||
#: ../src/shell-global.c:841
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Bir dakikadan daha az süre önce"
|
||||
|
||||
#: ../src/shell-global.c:844
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "%d dakika önce"
|
||||
|
||||
#: ../src/shell-global.c:847
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "%d saat önce"
|
||||
|
||||
#: ../src/shell-global.c:850
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "%d gün önce"
|
||||
|
||||
#: ../src/shell-global.c:853
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
msgstr[0] "%d hafta önce"
|
||||
|
||||
#: ../src/shell-status-menu.c:156
|
||||
msgid "Unknown"
|
||||
msgstr "Bilinmeyen"
|
||||
|
||||
#: ../src/shell-status-menu.c:212
|
||||
#, c-format
|
||||
msgid "Can't lock screen: %s"
|
||||
msgstr "Ekran kilitlenemedi: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:227
|
||||
#, c-format
|
||||
msgid "Can't temporarily set screensaver to blank screen: %s"
|
||||
msgstr "Ekran koruyucu geçici olarak boş ekran olarak atanamadı: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:351
|
||||
#, c-format
|
||||
msgid "Can't logout: %s"
|
||||
msgstr "Çıkış yapılamadı: %s"
|
||||
|
||||
#: ../src/shell-status-menu.c:492
|
||||
msgid "Account Information..."
|
||||
msgstr "Hesap Bilgisi..."
|
||||
|
||||
#: ../src/shell-status-menu.c:502
|
||||
msgid "Sidebar"
|
||||
msgstr "Kenar Çubuğu"
|
||||
|
||||
#: ../src/shell-status-menu.c:510
|
||||
msgid "System Preferences..."
|
||||
msgstr "Sistem Tercihleri..."
|
||||
|
||||
#: ../src/shell-status-menu.c:525
|
||||
msgid "Lock Screen"
|
||||
msgstr "Ekrani Kilitle"
|
||||
|
||||
#: ../src/shell-status-menu.c:535
|
||||
msgid "Switch User"
|
||||
msgstr "Kullanıcı Değiştir"
|
||||
|
||||
#. Only show switch user if there are other users
|
||||
#. Log Out
|
||||
#: ../src/shell-status-menu.c:546
|
||||
msgid "Log Out..."
|
||||
msgstr "Çıkış..."
|
||||
|
||||
#. Shut down
|
||||
#: ../src/shell-status-menu.c:557
|
||||
msgid "Shut Down..."
|
||||
msgstr "Kapat..."
|
||||
|
||||
#: ../src/shell-uri-util.c:87
|
||||
msgid "Home Folder"
|
||||
msgstr "Ev Klasörü"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-uri-util.c:102
|
||||
msgid "File System"
|
||||
msgstr "Dosya Sistemi"
|
||||
|
||||
#: ../src/shell-uri-util.c:248
|
||||
msgid "Search"
|
||||
msgstr "Arama"
|
||||
|
||||
#. Translators: the first string is the name of a gvfs
|
||||
#. * method, and the second string is a path. For
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-uri-util.c:298
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
176
po/zh_CN.po
Normal file
@ -0,0 +1,176 @@
|
||||
# Chinese (China) translation for gnome-shell.
|
||||
# Copyright (C) 2009 gnome-shell's COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the gnome-shell package.
|
||||
# Ray Wang <raywang@gnome.org>, 2009.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell master\n"
|
||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
|
||||
"shell&component=general\n"
|
||||
"POT-Creation-Date: 2009-08-29 19:32+0000\n"
|
||||
"PO-Revision-Date: 2009-08-30 00:08+0800\n"
|
||||
"Last-Translator: Ray Wang <raywang@gnome.org>\n"
|
||||
"Language-Team: Chinese (Simplified) <i18n-zh@googlegroups.com>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: utf-8\n"
|
||||
"Plural-Forms: nplurals=1; plural=0;\n"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:1
|
||||
msgid "GNOME Shell"
|
||||
msgstr "GNOME Shell"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:2
|
||||
msgid "Window management and application launching"
|
||||
msgstr "窗口管理和应用程序启动"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:271
|
||||
msgid "Activities"
|
||||
msgstr "活动"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:454
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%A %H:%M"
|
||||
|
||||
#: ../js/ui/dash.js:256
|
||||
msgid "Find..."
|
||||
msgstr "查找..."
|
||||
|
||||
#: ../js/ui/dash.js:374
|
||||
msgid "Browse"
|
||||
msgstr "浏览"
|
||||
|
||||
#: ../js/ui/dash.js:451
|
||||
msgid "(see all)"
|
||||
msgstr "(查看所有)"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:633 ../js/ui/dash.js:681
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "应用程序"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:653
|
||||
msgid "PLACES"
|
||||
msgstr "位置"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:660 ../js/ui/dash.js:692
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "最近的文档"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:679
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "搜索结果"
|
||||
|
||||
#: ../js/ui/runDialog.js:82
|
||||
msgid "Please enter a command:"
|
||||
msgstr "请输入一个命令:"
|
||||
|
||||
#: ../src/shell-global.c:840
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "少于一分钟前"
|
||||
|
||||
#: ../src/shell-global.c:843
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "%d 分钟前"
|
||||
|
||||
#: ../src/shell-global.c:846
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "%d 小时前"
|
||||
|
||||
#: ../src/shell-global.c:849
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "%d 天前"
|
||||
|
||||
#: ../src/shell-global.c:852
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
msgstr[0] "%d 周前"
|
||||
|
||||
#: ../src/shell-status-menu.c:156
|
||||
msgid "Unknown"
|
||||
msgstr "未知"
|
||||
|
||||
#: ../src/shell-status-menu.c:212
|
||||
#, c-format
|
||||
msgid "Can't lock screen: %s"
|
||||
msgstr "不能锁住屏幕:%s"
|
||||
|
||||
#: ../src/shell-status-menu.c:227
|
||||
#, c-format
|
||||
msgid "Can't temporarily set screensaver to blank screen: %s"
|
||||
msgstr "不能临时将屏幕保护设置成空白屏幕:%s"
|
||||
|
||||
#: ../src/shell-status-menu.c:351
|
||||
#, c-format
|
||||
msgid "Can't logout: %s"
|
||||
msgstr "不能退出:%s"
|
||||
|
||||
#: ../src/shell-status-menu.c:492
|
||||
msgid "Account Information..."
|
||||
msgstr "帐户信息..."
|
||||
|
||||
#: ../src/shell-status-menu.c:502
|
||||
msgid "Sidebar"
|
||||
msgstr "侧边栏"
|
||||
|
||||
#: ../src/shell-status-menu.c:510
|
||||
msgid "System Preferences..."
|
||||
msgstr "系统首选项..."
|
||||
|
||||
#: ../src/shell-status-menu.c:525
|
||||
msgid "Lock Screen"
|
||||
msgstr "锁住屏幕"
|
||||
|
||||
#: ../src/shell-status-menu.c:535
|
||||
msgid "Switch User"
|
||||
msgstr "切换用户"
|
||||
|
||||
#. Only show switch user if there are other users
|
||||
#. Log Out
|
||||
#: ../src/shell-status-menu.c:546
|
||||
msgid "Log Out..."
|
||||
msgstr "退出..."
|
||||
|
||||
#. Shut down
|
||||
#: ../src/shell-status-menu.c:557
|
||||
msgid "Shut Down..."
|
||||
msgstr "关机..."
|
||||
|
||||
#: ../src/shell-uri-util.c:87
|
||||
msgid "Home Folder"
|
||||
msgstr "主文件夹"
|
||||
|
||||
#. Translators: this is the same string as the one found in
|
||||
#. * nautilus
|
||||
#: ../src/shell-uri-util.c:102
|
||||
msgid "File System"
|
||||
msgstr "文件系统"
|
||||
|
||||
#: ../src/shell-uri-util.c:248
|
||||
msgid "Search"
|
||||
msgstr "搜索"
|
||||
|
||||
#. Translators: the first string is the name of a gvfs
|
||||
#. * method, and the second string is a path. For
|
||||
#. * example, "Trash: some-directory". It means that the
|
||||
#. * directory called "some-directory" is in the trash.
|
||||
#.
|
||||
#: ../src/shell-uri-util.c:298
|
||||
#, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
@ -36,18 +36,18 @@ stamp-big-enum-types.h: $(big_source_h) big/big-enum-types.h.in
|
||||
$(AM_V_GEN) ( cd $(srcdir) && \
|
||||
$(GLIB_MKENUMS) \
|
||||
--template $(srcdir)/big/big-enum-types.h.in \
|
||||
$(big_source_h) ) >> xgen-teth && \
|
||||
(cmp -s xgen-teth big-enum-types.h || cp xgen-teth big-enum-types.h) && \
|
||||
rm -f xgen-teth && \
|
||||
$(big_source_h) ) >> xgen-beth && \
|
||||
(cmp -s xgen-beth big-enum-types.h || cp xgen-beth big-enum-types.h) && \
|
||||
rm -f xgen-beth && \
|
||||
echo timestamp > $(@F)
|
||||
|
||||
big-enum-types.c: stamp-big-enum-types.h big/big-enum-types.c.in
|
||||
$(AM_V_GEN) ( cd $(srcdir) && \
|
||||
$(GLIB_MKENUMS) \
|
||||
--template $(srcdir)/big/big-enum-types.c.in \
|
||||
$(big_source_h) ) >> xgen-tetc && \
|
||||
cp xgen-tetc big-enum-types.c && \
|
||||
rm -f xgen-tetc
|
||||
$(big_source_h) ) >> xgen-betc && \
|
||||
cp xgen-betc big-enum-types.c && \
|
||||
rm -f xgen-betc
|
||||
|
||||
noinst_LTLIBRARIES += libbig-1.0.la
|
||||
|
||||
|
148
src/Makefile-st.am
Normal file
@ -0,0 +1,148 @@
|
||||
st_cflags = \
|
||||
-I$(top_srcdir)/src \
|
||||
-DPREFIX=\""$(prefix)"\" \
|
||||
-DLIBDIR=\""$(libdir)"\" \
|
||||
-DG_DISABLE_DEPRECATED \
|
||||
-DG_LOG_DOMAIN=\"St\" \
|
||||
-DST_COMPILATION \
|
||||
-DPACKAGE_DATA_DIR=\"$(pkgdatadir)\" \
|
||||
$(ST_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
st_built_sources = \
|
||||
st-enum-types.h \
|
||||
st-enum-types.c \
|
||||
st-marshal.h \
|
||||
st-marshal.c
|
||||
|
||||
BUILT_SOURCES += $(st_built_sources)
|
||||
|
||||
EXTRA_DIST += \
|
||||
st/test-theme.css \
|
||||
st/st-marshal.list \
|
||||
st/st-enum-types.h.in \
|
||||
st/st-enum-types.c.in
|
||||
|
||||
CLEANFILES += stamp-st-marshal.h stamp-st-enum-types.h
|
||||
|
||||
st-marshal.h: stamp-st-marshal.h
|
||||
@true
|
||||
stamp-st-marshal.h: Makefile st/st-marshal.list
|
||||
$(AM_V_GEN) $(GLIB_GENMARSHAL) \
|
||||
--prefix=_st_marshal \
|
||||
--header \
|
||||
$(srcdir)/st/st-marshal.list > $@.tmp && \
|
||||
(cmp -s $@.tmp st-marshal.h || cp -f $@.tmp st-marshal.h) && \
|
||||
rm -f $@.tmp && \
|
||||
echo timestamp > $(@F)
|
||||
|
||||
st-marshal.c: Makefile st/st-marshal.list
|
||||
$(AM_V_GEN) (echo "#include \"st-marshal.h\"" ; \
|
||||
$(GLIB_GENMARSHAL) \
|
||||
--prefix=_st_marshal \
|
||||
--body \
|
||||
$(srcdir)/st/st-marshal.list ) > $@.tmp && \
|
||||
cp -f $@.tmp st-marshal.c && \
|
||||
rm -f $@.tmp
|
||||
|
||||
st-enum-types.h: stamp-st-enum-types.h Makefile
|
||||
@true
|
||||
stamp-st-enum-types.h: $(source_h) st/st-enum-types.h.in
|
||||
$(AM_V_GEN) ( cd $(srcdir) && \
|
||||
$(GLIB_MKENUMS) \
|
||||
--template st/st-enum-types.h.in \
|
||||
$(st_source_h) ) >> $@.tmp && \
|
||||
(cmp -s $@.tmp st-enum-types.h || cp $@.tmp st-enum-types.h) && \
|
||||
rm -f $@.tmp && \
|
||||
echo timestamp > $(@F)
|
||||
|
||||
st-enum-types.c: stamp-st-enum-types.h st/st-enum-types.c.in
|
||||
$(AM_V_GEN) ( cd $(srcdir) && \
|
||||
$(GLIB_MKENUMS) \
|
||||
--template st/st-enum-types.c.in \
|
||||
$(st_source_h) ) >> $@.tmp && \
|
||||
cp $@.tmp $@ && \
|
||||
rm -f $@.tmp
|
||||
|
||||
# please, keep this sorted alphabetically
|
||||
st_source_h = \
|
||||
st/st-adjustment.h \
|
||||
st/st-bin.h \
|
||||
st/st-border-image.h \
|
||||
st/st-box-layout.h \
|
||||
st/st-box-layout-child.h \
|
||||
st/st-button.h \
|
||||
st/st-clipboard.h \
|
||||
st/st-entry.h \
|
||||
st/st-im-text.h \
|
||||
st/st-label.h \
|
||||
st/st-private.h \
|
||||
st/st-scrollable.h \
|
||||
st/st-scroll-bar.h \
|
||||
st/st-scroll-view.h \
|
||||
st/st-subtexture.h \
|
||||
st/st-table.h \
|
||||
st/st-table-child.h \
|
||||
st/st-table-private.h \
|
||||
st/st-texture-cache.h \
|
||||
st/st-texture-frame.h \
|
||||
st/st-theme.h \
|
||||
st/st-theme-context.h \
|
||||
st/st-theme-node.h \
|
||||
st/st-theme-private.h \
|
||||
st/st-tooltip.h \
|
||||
st/st-types.h \
|
||||
st/st-widget.h \
|
||||
$(NULL)
|
||||
|
||||
st_source_private_h = \
|
||||
st/st-private.h \
|
||||
st/st-table-private.h \
|
||||
st/st-theme-private.h
|
||||
|
||||
# please, keep this sorted alphabetically
|
||||
st_source_c = \
|
||||
st/st-adjustment.c \
|
||||
st/st-bin.c \
|
||||
st/st-border-image.c \
|
||||
st/st-box-layout.c \
|
||||
st/st-box-layout-child.c \
|
||||
st/st-button.c \
|
||||
st/st-clipboard.c \
|
||||
st/st-entry.c \
|
||||
st/st-im-text.c \
|
||||
st/st-label.c \
|
||||
st/st-private.c \
|
||||
st/st-scrollable.c \
|
||||
st/st-scroll-bar.c \
|
||||
st/st-scroll-view.c \
|
||||
st/st-subtexture.c \
|
||||
st/st-table.c \
|
||||
st/st-table-child.c \
|
||||
st/st-texture-cache.c \
|
||||
st/st-texture-frame.c \
|
||||
st/st-theme.c \
|
||||
st/st-theme-context.c \
|
||||
st/st-theme-node.c \
|
||||
st/st-tooltip.c \
|
||||
st/st-widget.c \
|
||||
$(NULL)
|
||||
|
||||
noinst_LTLIBRARIES += libst-1.0.la
|
||||
|
||||
libst_1_0_la_LIBADD = $(ST_LIBS)
|
||||
libst_1_0_la_SOURCES = \
|
||||
$(st_source_c) \
|
||||
$(st_source_private_c) \
|
||||
$(st_source_h) \
|
||||
$(st_built_sources) \
|
||||
$(NULL)
|
||||
libst_1_0_la_CPPFLAGS = $(st_cflags)
|
||||
libst_1_0_la_LDFLAGS = $(LDADD)
|
||||
|
||||
noinst_PROGRAMS += test-theme
|
||||
|
||||
test_theme_CPPFLAGS = $(st_cflags)
|
||||
test_theme_LDADD = libst-1.0.la
|
||||
|
||||
test_theme_SOURCES = st/test-theme.c
|
@ -1,89 +0,0 @@
|
||||
tidy_cflags = \
|
||||
-I$(top_srcdir)/src \
|
||||
-DPREFIX=\""$(prefix)"\" \
|
||||
-DLIBDIR=\""$(libdir)"\" \
|
||||
-DG_DISABLE_DEPRECATED \
|
||||
-DG_LOG_DOMAIN=\"Tidy\" \
|
||||
$(MUTTER_PLUGIN_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
tidy_built_sources = \
|
||||
tidy-enum-types.h \
|
||||
tidy-enum-types.c \
|
||||
tidy-marshal.h \
|
||||
tidy-marshal.c
|
||||
|
||||
BUILT_SOURCES += $(tidy_built_sources)
|
||||
|
||||
TIDY_STAMP_FILES = stamp-tidy-marshal.h stamp-tidy-enum-types.h
|
||||
|
||||
# please, keep this sorted alphabetically
|
||||
tidy_source_h = \
|
||||
tidy/tidy-grid.h \
|
||||
$(NULL)
|
||||
|
||||
tidy_source_h_priv = \
|
||||
$(NULL)
|
||||
|
||||
# please, keep this sorted alphabetically
|
||||
tidy_source_c = \
|
||||
tidy/tidy-grid.c \
|
||||
$(NULL)
|
||||
|
||||
tidy-marshal.h: stamp-tidy-marshal.h
|
||||
@true
|
||||
stamp-tidy-marshal.h: Makefile tidy/tidy-marshal.list
|
||||
$(AM_V_GEN) $(GLIB_GENMARSHAL) \
|
||||
--prefix=_tidy_marshal \
|
||||
--header \
|
||||
$(srcdir)/tidy/tidy-marshal.list > xgen-tmh && \
|
||||
(cmp -s xgen-tmh tidy-marshal.h || cp -f xgen-tmh tidy-marshal.h) && \
|
||||
rm -f xgen-tmh && \
|
||||
echo timestamp > $(@F)
|
||||
|
||||
tidy-marshal.c: Makefile tidy/tidy-marshal.list
|
||||
$(AM_V_GEN) (echo "#include \"tidy-marshal.h\"" ; \
|
||||
$(GLIB_GENMARSHAL) \
|
||||
--prefix=_tidy_marshal \
|
||||
--body \
|
||||
$(srcdir)/tidy/tidy-marshal.list ) > xgen-tmc && \
|
||||
cp -f xgen-tmc tidy-marshal.c && \
|
||||
rm -f xgen-tmc
|
||||
|
||||
tidy-enum-types.h: stamp-tidy-enum-types.h Makefile
|
||||
@true
|
||||
stamp-tidy-enum-types.h: $(tidy_source_h) tidy/tidy-enum-types.h.in
|
||||
$(AM_V_GEN) ( cd $(srcdir) && \
|
||||
$(GLIB_MKENUMS) \
|
||||
--template $(srcdir)/tidy/tidy-enum-types.h.in \
|
||||
$(tidy_source_h) ) >> xgen-teth && \
|
||||
(cmp -s xgen-teth tidy-enum-types.h || cp xgen-teth tidy-enum-types.h) && \
|
||||
rm -f xgen-teth && \
|
||||
echo timestamp > $(@F)
|
||||
|
||||
tidy-enum-types.c: stamp-tidy-enum-types.h tidy/tidy-enum-types.c.in
|
||||
$(AM_V_GEN) ( cd $(srcdir) && \
|
||||
$(GLIB_MKENUMS) \
|
||||
--template $(srcdir)/tidy/tidy-enum-types.c.in \
|
||||
$(tidy_source_h) ) >> xgen-tetc && \
|
||||
cp xgen-tetc tidy-enum-types.c && \
|
||||
rm -f xgen-tetc
|
||||
|
||||
noinst_LTLIBRARIES += libtidy-1.0.la
|
||||
|
||||
libtidy_1_0_la_LIBADD = $(TIDY_LIBS)
|
||||
libtidy_1_0_la_SOURCES = \
|
||||
$(tidy_source_c) \
|
||||
$(tidy_source_h) \
|
||||
$(tidy_source_h_priv) \
|
||||
$(tidy_built_sources) \
|
||||
$(NULL)
|
||||
libtidy_1_0_la_CPPFLAGS = $(tidy_cflags)
|
||||
libtidy_1_0_la_LDFLAGS = $(LDADD)
|
||||
|
||||
CLEANFILES += $(TIDY_STAMP_FILES) $(BUILT_SOURCES)
|
||||
|
||||
EXTRA_DIST += \
|
||||
tidy/tidy-enum-types.h.in \
|
||||
tidy/tidy-enum-types.c.in \
|
||||
tidy/tidy-marshal.list
|
@ -1,9 +1,12 @@
|
||||
NULL =
|
||||
BUILT_SOURCES =
|
||||
CLEANFILES =
|
||||
EXTRA_DIST =
|
||||
EXTRA_DIST =
|
||||
libexec_PROGRAMS =
|
||||
noinst_LTLIBRARIES =
|
||||
noinst_LTLIBRARIES =
|
||||
noinst_PROGRAMS =
|
||||
|
||||
.AUTOPARALLEL:
|
||||
|
||||
bin_SCRIPTS = gnome-shell
|
||||
|
||||
@ -14,21 +17,23 @@ gnome-shell: gnome-shell.in
|
||||
-e "s|@libexecdir[@]|$(libexecdir)|" \
|
||||
-e "s|@libdir[@]|$(libdir)|" \
|
||||
-e "s|@pkgdatadir[@]|$(pkgdatadir)|" \
|
||||
-e "s|@PYTHON[@]|$(PYTHON)|" \
|
||||
-e "s|@sysconfdir[@]|$(sysconfdir)|" \
|
||||
$< > $@ && chmod a+x $@
|
||||
CLEANFILES += gnome-shell
|
||||
EXTRA_DIST += gnome-shell.in
|
||||
|
||||
include Makefile-tidy.am
|
||||
include Makefile-big.am
|
||||
include Makefile-gdmuser.am
|
||||
include Makefile-st.am
|
||||
include Makefile-tray.am
|
||||
|
||||
gnome_shell_cflags = \
|
||||
$(MUTTER_PLUGIN_CFLAGS) \
|
||||
$(LIBGNOMEUI_CFLAGS) \
|
||||
-I$(srcdir)/tray \
|
||||
-DGETTEXT_PACKAGE=gnome-shell \
|
||||
-DGETTEXT_PACKAGE=\"gnome-shell\" \
|
||||
-DLOCALEDIR=\"$(datadir)/locale\" \
|
||||
-DGNOME_SHELL_DATADIR=\"$(pkgdatadir)\" \
|
||||
-DGNOME_SHELL_PKGLIBDIR=\"$(pkglibdir)\" \
|
||||
-DJSDIR=\"$(pkgdatadir)/js\"
|
||||
@ -49,14 +54,14 @@ CLEANFILES += $(SHELL_STAMP_FILES)
|
||||
libgnome_shell_la_SOURCES = \
|
||||
$(shell_built_sources) \
|
||||
gnome-shell-plugin.c \
|
||||
shell-alttab.c \
|
||||
shell-alttab.h \
|
||||
shell-app-monitor.c \
|
||||
shell-app-monitor.h \
|
||||
shell-app-system.c \
|
||||
shell-app-system.h \
|
||||
shell-arrow.c \
|
||||
shell-arrow.h \
|
||||
shell-button-box.c \
|
||||
shell-button-box.h \
|
||||
shell-drawing.c \
|
||||
shell-drawing.h \
|
||||
shell-drawing-area.c \
|
||||
@ -70,6 +75,8 @@ libgnome_shell_la_SOURCES = \
|
||||
shell-generic-container.h \
|
||||
shell-gtk-embed.c \
|
||||
shell-gtk-embed.h \
|
||||
shell-menu.c \
|
||||
shell-menu.h \
|
||||
shell-overflow-list.c \
|
||||
shell-overflow-list.h \
|
||||
shell-process.c \
|
||||
@ -89,7 +96,7 @@ libgnome_shell_la_SOURCES = \
|
||||
shell-wm.c \
|
||||
shell-wm.h
|
||||
|
||||
non_gir_sources = \
|
||||
non_gir_sources = \
|
||||
shell-embedded-window-private.h
|
||||
|
||||
shell_recorder_sources = \
|
||||
@ -107,7 +114,7 @@ if BUILD_RECORDER
|
||||
libgnome_shell_la_SOURCES += $(shell_recorder_sources)
|
||||
non_gir_sources += $(shell_recorder_non_gir_sources)
|
||||
|
||||
noinst_PROGRAMS = test-recorder
|
||||
noinst_PROGRAMS += test-recorder
|
||||
|
||||
test_recorder_CPPFLAGS = $(TEST_SHELL_RECORDER_CFLAGS)
|
||||
test_recorder_LDADD = $(TEST_SHELL_RECORDER_LIBS)
|
||||
@ -126,9 +133,9 @@ stamp-shell-marshal.h: Makefile shell-marshal.list
|
||||
$(AM_V_GEN) $(GLIB_GENMARSHAL) \
|
||||
--prefix=_shell_marshal \
|
||||
--header \
|
||||
$(srcdir)/shell-marshal.list > xgen-tmh && \
|
||||
(cmp -s xgen-tmh shell-marshal.h || cp -f xgen-tmh shell-marshal.h) && \
|
||||
rm -f xgen-tmh && \
|
||||
$(srcdir)/shell-marshal.list > xgen-smh && \
|
||||
(cmp -s xgen-smh shell-marshal.h || cp -f xgen-smh shell-marshal.h) && \
|
||||
rm -f xgen-smh && \
|
||||
echo timestamp > $(@F)
|
||||
|
||||
shell-marshal.c: Makefile shell-marshal.list
|
||||
@ -136,32 +143,34 @@ shell-marshal.c: Makefile shell-marshal.list
|
||||
$(GLIB_GENMARSHAL) \
|
||||
--prefix=_shell_marshal \
|
||||
--body \
|
||||
$(srcdir)/shell-marshal.list ) > xgen-tmc && \
|
||||
cp -f xgen-tmc shell-marshal.c && \
|
||||
rm -f xgen-tmc
|
||||
$(srcdir)/shell-marshal.list ) > xgen-smc && \
|
||||
cp -f xgen-smc shell-marshal.c && \
|
||||
rm -f xgen-smc
|
||||
|
||||
libgnome_shell_la_LDFLAGS = -avoid-version -module
|
||||
libgnome_shell_la_LIBADD = \
|
||||
$(MUTTER_PLUGIN_LIBS) \
|
||||
$(LIBGNOMEUI_LIBS) \
|
||||
libbig-1.0.la \
|
||||
libst-1.0.la \
|
||||
libgdmuser-1.0.la \
|
||||
libtidy-1.0.la \
|
||||
libtray.la
|
||||
libgnome_shell_la_CPPFLAGS = $(gnome_shell_cflags)
|
||||
|
||||
typelibdir = $(pkglibdir)
|
||||
typelib_DATA = Shell-0.1.typelib Tidy-1.0.typelib Big-1.0.typelib
|
||||
typelib_DATA = Shell-0.1.typelib Big-1.0.typelib St-1.0.typelib
|
||||
|
||||
Shell-0.1.gir: $(mutter) $(G_IR_SCANNER) Big-1.0.gir libgnome-shell.la Makefile
|
||||
Shell-0.1.gir: $(mutter) $(G_IR_SCANNER) Big-1.0.gir St-1.0.gir libgnome-shell.la Makefile
|
||||
$(AM_V_GEN) $(G_IR_SCANNER) \
|
||||
--namespace=Shell \
|
||||
--nsversion=0.1 \
|
||||
--add-include-path=$(MUTTER_LIB_DIR)/mutter/ \
|
||||
--include=Clutter-1.0 \
|
||||
--include=Meta-2.27 \
|
||||
--include=Meta-2.28 \
|
||||
--libtool="$(LIBTOOL)" \
|
||||
--add-include-path=$(builddir) \
|
||||
--include=Big-1.0 \
|
||||
--include=St-1.0 \
|
||||
--program=mutter \
|
||||
--program-arg=--mutter-plugins=$$(pwd)/libgnome-shell.la \
|
||||
$(addprefix $(srcdir)/,$(libgnome_shell_la_gir_sources)) \
|
||||
@ -172,33 +181,20 @@ CLEANFILES += Shell-0.1.gir
|
||||
# The dependency on libgnome-shell.la here is because g-ir-compiler opens it
|
||||
# (not the fake library, since we've already done the rewriting)
|
||||
Shell-0.1.typelib: libgnome-shell.la Shell-0.1.gir Big-1.0.gir
|
||||
LD_LIBRARY_PATH=$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}. g-ir-compiler --includedir=$(builddir) --includedir=$(MUTTER_LIB_DIR)/mutter/ Shell-0.1.gir -o $@
|
||||
$(AM_V_GEN) \
|
||||
$(G_IR_COMPILER) \
|
||||
--includedir=. \
|
||||
--includedir=$(MUTTER_LIB_DIR)/mutter/ \
|
||||
Shell-0.1.gir -o $@
|
||||
CLEANFILES += Shell-0.1.typelib
|
||||
|
||||
Tidy-1.0.gir: $(mutter) $(G_IR_SCANNER) libgnome-shell.la libtidy-1.0.la Makefile
|
||||
$(AM_V_GEN) $(G_IR_SCANNER) \
|
||||
--namespace=Tidy \
|
||||
--nsversion=1.0 \
|
||||
--include=Clutter-1.0 \
|
||||
--program=mutter \
|
||||
--program-arg=--mutter-plugins=$$(pwd)/libgnome-shell.la \
|
||||
$(addprefix $(srcdir)/,$(tidy_source_h)) \
|
||||
$(addprefix $(srcdir)/,$(tidy_source_c)) \
|
||||
$(srcdir)/tidy-enum-types.h \
|
||||
$(tidy_cflags) \
|
||||
-o $@
|
||||
CLEANFILES += Tidy-1.0.gir
|
||||
|
||||
Tidy-1.0.typelib: libtidy-1.0.la Tidy-1.0.gir
|
||||
LD_LIBRARY_PATH=$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}. g-ir-compiler Tidy-1.0.gir -o $@
|
||||
CLEANFILES += Tidy-1.0.typelib
|
||||
|
||||
Big-1.0.gir: $(mutter) $(G_IR_SCANNER) libgnome-shell.la libbig-1.0.la Makefile
|
||||
$(AM_V_GEN) $(G_IR_SCANNER) \
|
||||
--namespace=Big \
|
||||
--nsversion=1.0 \
|
||||
--include=Clutter-1.0 \
|
||||
--include=GdkPixbuf-2.0 \
|
||||
--libtool="$(LIBTOOL)" \
|
||||
--program=mutter \
|
||||
--program-arg=--mutter-plugins=$$(pwd)/libgnome-shell.la \
|
||||
$(addprefix $(srcdir)/,$(big_source_h)) \
|
||||
@ -209,5 +205,28 @@ Big-1.0.gir: $(mutter) $(G_IR_SCANNER) libgnome-shell.la libbig-1.0.la Makefile
|
||||
CLEANFILES += Big-1.0.gir
|
||||
|
||||
Big-1.0.typelib: libbig-1.0.la Big-1.0.gir
|
||||
LD_LIBRARY_PATH=$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}. g-ir-compiler Big-1.0.gir -o $@
|
||||
$(AM_V_GEN) $(G_IR_COMPILER) Big-1.0.gir -o $@
|
||||
CLEANFILES += Big-1.0.typelib
|
||||
|
||||
St-1.0.gir: $(mutter) $(G_IR_SCANNER) libgnome-shell.la libst-1.0.la Makefile
|
||||
$(AM_V_GEN) $(G_IR_SCANNER) \
|
||||
--namespace=St \
|
||||
--nsversion=1.0 \
|
||||
--include=Clutter-1.0 \
|
||||
--add-include-path=$(builddir) \
|
||||
--libtool="$(LIBTOOL)" \
|
||||
--program=mutter \
|
||||
--program-arg=--mutter-plugins=$$(pwd)/libgnome-shell.la \
|
||||
-DST_COMPILATION \
|
||||
$(addprefix $(srcdir)/,$(st_source_h)) \
|
||||
$(addprefix $(srcdir)/,$(st_source_c)) \
|
||||
$(srcdir)/st-enum-types.h \
|
||||
$(st_cflags) \
|
||||
-o $@
|
||||
CLEANFILES += St-1.0.gir
|
||||
|
||||
St-1.0.typelib: St-1.0.gir
|
||||
$(AM_V_GEN) $(G_IR_COMPILER) \
|
||||
$< -o $@
|
||||
|
||||
CLEANFILES += St-1.0.typelib
|
||||
|
@ -268,6 +268,52 @@ corner_get(guint radius,
|
||||
return corner;
|
||||
}
|
||||
|
||||
/* To match the CSS specification, we want the border to look like it was
|
||||
* drawn over the background. But actually drawing the border over the
|
||||
* background will produce slightly bad antialiasing at the edges, so
|
||||
* compute the effective border color instead.
|
||||
*/
|
||||
#define NORM(x) (t = (x) + 127, (t + (t >> 8)) >> 8)
|
||||
#define MULT(c,a) NORM(c*a)
|
||||
|
||||
static void
|
||||
premultiply (ClutterColor *color)
|
||||
{
|
||||
guint t;
|
||||
color->red = MULT (color->red, color->alpha);
|
||||
color->green = MULT (color->green, color->alpha);
|
||||
color->blue = MULT (color->blue, color->alpha);
|
||||
}
|
||||
|
||||
static void
|
||||
unpremultiply (ClutterColor *color)
|
||||
{
|
||||
if (color->alpha != 0) {
|
||||
color->red = (color->red * 255 + 127) / color->alpha;
|
||||
color->green = (color->green * 255 + 127) / color->alpha;
|
||||
color->blue = (color->blue * 255 + 127) / color->alpha;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
over (const ClutterColor *source,
|
||||
const ClutterColor *destination,
|
||||
ClutterColor *result)
|
||||
{
|
||||
guint t;
|
||||
ClutterColor src = *source;
|
||||
ClutterColor dst = *destination;
|
||||
premultiply (&src);
|
||||
premultiply (&dst);
|
||||
|
||||
result->alpha = src.alpha + NORM ((255 - src.alpha) * dst.alpha);
|
||||
result->red = src.red + NORM ((255 - src.alpha) * dst.red);
|
||||
result->green = src.green + NORM ((255 - src.alpha) * dst.green);
|
||||
result->blue = src.blue + NORM ((255 - src.alpha) * dst.blue);
|
||||
|
||||
unpremultiply (result);
|
||||
}
|
||||
|
||||
static void
|
||||
big_rectangle_update_corners(BigRectangle *rectangle)
|
||||
{
|
||||
@ -278,6 +324,7 @@ big_rectangle_update_corners(BigRectangle *rectangle)
|
||||
if (rectangle->radius != 0) {
|
||||
ClutterColor *color;
|
||||
ClutterColor *border_color;
|
||||
ClutterColor effective_border;
|
||||
guint border_width;
|
||||
|
||||
g_object_get(rectangle,
|
||||
@ -286,10 +333,12 @@ big_rectangle_update_corners(BigRectangle *rectangle)
|
||||
"color", &color,
|
||||
NULL);
|
||||
|
||||
over (border_color, color, &effective_border);
|
||||
|
||||
corner = corner_get(rectangle->radius,
|
||||
color,
|
||||
border_width,
|
||||
border_color);
|
||||
&effective_border);
|
||||
|
||||
clutter_color_free(border_color);
|
||||
clutter_color_free(color);
|
||||
@ -329,12 +378,10 @@ big_rectangle_paint(ClutterActor *actor)
|
||||
|
||||
rectangle = BIG_RECTANGLE(actor);
|
||||
|
||||
if (rectangle->radius == 0) {
|
||||
/* In that case we are no different than our parent class,
|
||||
* so don't bother */
|
||||
CLUTTER_ACTOR_CLASS(big_rectangle_parent_class)->paint(actor);
|
||||
return;
|
||||
}
|
||||
/* We can't chain up, even when we the radius is 0, because of the different
|
||||
* interpretation of the border/background relationship here than for
|
||||
* ClutterRectangle.
|
||||
*/
|
||||
|
||||
if (rectangle->corners_dirty)
|
||||
big_rectangle_update_corners(rectangle);
|
||||
@ -345,6 +392,9 @@ big_rectangle_paint(ClutterActor *actor)
|
||||
"color", &color,
|
||||
NULL);
|
||||
|
||||
if (border_color->alpha == 0 && color->alpha == 0)
|
||||
goto out;
|
||||
|
||||
actor_opacity = clutter_actor_get_paint_opacity (actor);
|
||||
|
||||
clutter_actor_get_allocation_box(actor, &box);
|
||||
@ -358,6 +408,11 @@ big_rectangle_paint(ClutterActor *actor)
|
||||
|
||||
radius = rectangle->radius;
|
||||
|
||||
/* Optimization; if the border is transparent, it just looks like part of
|
||||
* the background */
|
||||
if (radius == 0 && border_color->alpha == 0)
|
||||
border_width = 0;
|
||||
|
||||
max = MAX(border_width, radius);
|
||||
|
||||
if (radius != 0) {
|
||||
@ -393,33 +448,54 @@ big_rectangle_paint(ClutterActor *actor)
|
||||
}
|
||||
|
||||
if (border_width != 0) {
|
||||
ClutterColor effective_border;
|
||||
over (border_color, color, &effective_border);
|
||||
|
||||
if (!rectangle->border_material)
|
||||
rectangle->border_material = cogl_material_new ();
|
||||
|
||||
cogl_color_set_from_4ub(&tmp_color,
|
||||
border_color->red,
|
||||
border_color->green,
|
||||
border_color->blue,
|
||||
actor_opacity * border_color->alpha / 255);
|
||||
effective_border.red,
|
||||
effective_border.green,
|
||||
effective_border.blue,
|
||||
actor_opacity * effective_border.alpha / 255);
|
||||
cogl_color_premultiply (&tmp_color);
|
||||
cogl_material_set_color(rectangle->border_material, &tmp_color);
|
||||
cogl_set_source(rectangle->border_material);
|
||||
|
||||
/* NORTH */
|
||||
cogl_rectangle(max, 0,
|
||||
width - max, border_width);
|
||||
if (radius > 0) { /* skip corners */
|
||||
/* NORTH */
|
||||
cogl_rectangle(max, 0,
|
||||
width - max, border_width);
|
||||
|
||||
/* EAST */
|
||||
cogl_rectangle(width - border_width, max,
|
||||
width, height - max);
|
||||
/* EAST */
|
||||
cogl_rectangle(width - border_width, max,
|
||||
width, height - max);
|
||||
|
||||
/* SOUTH */
|
||||
cogl_rectangle(max, height - border_width,
|
||||
width - max, height);
|
||||
/* SOUTH */
|
||||
cogl_rectangle(max, height - border_width,
|
||||
width - max, height);
|
||||
|
||||
/* WEST */
|
||||
cogl_rectangle(0, max,
|
||||
border_width, height - max);
|
||||
/* WEST */
|
||||
cogl_rectangle(0, max,
|
||||
border_width, height - max);
|
||||
} else { /* include corners */
|
||||
/* NORTH */
|
||||
cogl_rectangle(0, 0,
|
||||
width, border_width);
|
||||
|
||||
/* EAST */
|
||||
cogl_rectangle(width - border_width, border_width,
|
||||
width, height - border_width);
|
||||
|
||||
/* SOUTH */
|
||||
cogl_rectangle(0, height - border_width,
|
||||
width, height);
|
||||
|
||||
/* WEST */
|
||||
cogl_rectangle(0, border_width,
|
||||
border_width, height - border_width);
|
||||
}
|
||||
}
|
||||
|
||||
if (!rectangle->background_material)
|
||||
@ -455,6 +531,7 @@ big_rectangle_paint(ClutterActor *actor)
|
||||
cogl_rectangle(border_width, max,
|
||||
width - border_width, height - max);
|
||||
|
||||
out:
|
||||
clutter_color_free(border_color);
|
||||
clutter_color_free(color);
|
||||
}
|
||||
|
@ -35,7 +35,8 @@
|
||||
#endif /* HAVE_PATHS_H */
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib/gi18n.h>
|
||||
/* Note on sync with gdm; need to use -lib here */
|
||||
#include <glib/gi18n-lib.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include <glib-object.h>
|
||||
#include <gio/gio.h>
|
||||
|
@ -26,7 +26,8 @@
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
/* Note on sync with gdm; need to use -lib here */
|
||||
#include <glib/gi18n-lib.h>
|
||||
#include <gio/gio.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
@ -239,8 +240,8 @@ gdm_user_class_init (GdmUserClass *class)
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_MANAGER,
|
||||
g_param_spec_object ("manager",
|
||||
_("Manager"),
|
||||
_("The user manager object this user is controlled by."),
|
||||
"Manager",
|
||||
"The user manager object this user is controlled by.",
|
||||
GDM_TYPE_USER_MANAGER,
|
||||
(G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY)));
|
||||
|
@ -153,6 +153,9 @@ gnome_shell_plugin_constructed (GObject *object)
|
||||
ClutterBackend *backend;
|
||||
cairo_font_options_t *font_options;
|
||||
|
||||
bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
|
||||
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
||||
|
||||
/* Disable text mipmapping; it causes problems on pre-GEM Intel
|
||||
* drivers and we should just be rendering text at the right
|
||||
* size rather than scaling it. If we do effects where we dynamically
|
||||
@ -189,13 +192,6 @@ gnome_shell_plugin_constructed (GObject *object)
|
||||
shell_plugin->gjs_context = gjs_context_new_with_search_path(search_path);
|
||||
g_strfreev(search_path);
|
||||
|
||||
shell_plugin->panel_action = XInternAtom (meta_display_get_xdisplay (display),
|
||||
"_GNOME_PANEL_ACTION", FALSE);
|
||||
shell_plugin->panel_action_run_dialog = XInternAtom (meta_display_get_xdisplay (display),
|
||||
"_GNOME_PANEL_ACTION_RUN_DIALOG", FALSE);
|
||||
shell_plugin->panel_action_main_menu = XInternAtom (meta_display_get_xdisplay (display),
|
||||
"_GNOME_PANEL_ACTION_MAIN_MENU", FALSE);
|
||||
|
||||
if (!gjs_context_eval (shell_plugin->gjs_context,
|
||||
"const Main = imports.ui.main; Main.start();",
|
||||
-1,
|
||||
@ -315,48 +311,10 @@ gnome_shell_plugin_kill_effect (MutterPlugin *plugin,
|
||||
actor, events);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
handle_panel_event (GnomeShellPlugin *shell_plugin,
|
||||
XEvent *xev)
|
||||
{
|
||||
MutterPlugin *plugin = MUTTER_PLUGIN (shell_plugin);
|
||||
MetaScreen *screen;
|
||||
MetaDisplay *display;
|
||||
XClientMessageEvent *xev_client;
|
||||
Window root;
|
||||
|
||||
screen = mutter_plugin_get_screen (plugin);
|
||||
display = meta_screen_get_display (screen);
|
||||
|
||||
if (xev->type != ClientMessage)
|
||||
return FALSE;
|
||||
|
||||
root = meta_screen_get_xroot (screen);
|
||||
|
||||
xev_client = (XClientMessageEvent*) xev;
|
||||
if (!(xev_client->window == root &&
|
||||
xev_client->message_type == shell_plugin->panel_action &&
|
||||
xev_client->format == 32))
|
||||
return FALSE;
|
||||
|
||||
if (xev_client->data.l[0] == shell_plugin->panel_action_run_dialog)
|
||||
g_signal_emit_by_name (shell_global_get (), "panel-run-dialog",
|
||||
(guint32) xev_client->data.l[1]);
|
||||
else if (xev_client->data.l[0] == shell_plugin->panel_action_main_menu)
|
||||
g_signal_emit_by_name (shell_global_get (), "panel-main-menu",
|
||||
(guint32) xev_client->data.l[1]);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gnome_shell_plugin_xevent_filter (MutterPlugin *plugin,
|
||||
XEvent *xev)
|
||||
{
|
||||
GnomeShellPlugin *shell_plugin = GNOME_SHELL_PLUGIN (plugin);
|
||||
|
||||
if (handle_panel_event (shell_plugin, xev))
|
||||
return TRUE;
|
||||
return clutter_x11_handle_event (xev) != CLUTTER_X11_FILTER_CONTINUE;
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/usr/bin/python
|
||||
#!@PYTHON@
|
||||
|
||||
import atexit
|
||||
import optparse
|
||||
@ -13,44 +13,6 @@ import tempfile
|
||||
import termios
|
||||
import time
|
||||
import errno
|
||||
import dbus
|
||||
|
||||
def find_cmd (cmd_list):
|
||||
"""
|
||||
Takes a list of command candidates and returns the first one that exists.
|
||||
Raises a system exit if none of the commands exist.
|
||||
"""
|
||||
for cmd in cmd_list:
|
||||
if os.path.exists(cmd):
|
||||
return cmd
|
||||
|
||||
raise SystemExit("None of the commands %s exist" % cmd_list)
|
||||
|
||||
def pidof(command):
|
||||
pidof_cmd = find_cmd(["/sbin/pidof", "/bin/pidof", "/usr/bin/pidof"])
|
||||
pidof = subprocess.Popen([pidof_cmd, command], stdout=subprocess.PIPE)
|
||||
pids = pidof.communicate()[0].split()
|
||||
pidof.wait()
|
||||
|
||||
# pidof doesn't have a "current user only" option, so we may have
|
||||
# gotten the pids of other users' processes. Fix that.
|
||||
for pid in pids:
|
||||
try:
|
||||
os.kill(int(pid), 0)
|
||||
return pid
|
||||
except Exception, e:
|
||||
pass
|
||||
return None
|
||||
|
||||
def kill_gnome_panel(pid):
|
||||
if options.verbose:
|
||||
print "Terminating panel process %s" % pid
|
||||
devnull = open("/dev/null", "w")
|
||||
subprocess.call(["gdb", "-batch-silent",
|
||||
"-ex", "call panel_session_do_not_restart()",
|
||||
"-ex", "call exit(0)",
|
||||
"-p", pid], stdout=devnull, stderr=devnull)
|
||||
devnull.close()
|
||||
|
||||
def start_xephyr():
|
||||
tmpdir = tempfile.mkdtemp("", "gnome-shell.")
|
||||
@ -190,11 +152,47 @@ def start_shell():
|
||||
else:
|
||||
args = []
|
||||
|
||||
args.extend(['mutter', '--mutter-plugins=' + plugin, '--replace'])
|
||||
args.extend(['mutter', '--mutter-plugins=' + plugin])
|
||||
if options.replace:
|
||||
args.append('--replace')
|
||||
if options.sync:
|
||||
args.append('--sync')
|
||||
return subprocess.Popen(args, env=env)
|
||||
|
||||
def restore_gnome():
|
||||
# Do imports lazily to save time and memory
|
||||
import gio
|
||||
import gconf
|
||||
|
||||
# We don't want to start the new gnome-panel in the current
|
||||
# directory; $HOME is better for stuff launched from it
|
||||
os.chdir(os.path.expanduser("~"))
|
||||
|
||||
def launch_component(gconf_path):
|
||||
client = gconf.client_get_default()
|
||||
component = client.get_string(gconf_path)
|
||||
|
||||
if component == None or component == "":
|
||||
return
|
||||
|
||||
# See gnome-session/gsm-util.c:gsm_util_find_desktop_file_for_app_name()
|
||||
# The one difference is that we don't search the autostart directories,
|
||||
# and just search normal application search path. (Gio doesnt' know
|
||||
# how to search the autostart dirs, so we'd have to do that ourselves.)
|
||||
appinfo = None
|
||||
try:
|
||||
appinfo = gio.unix.DesktopAppInfo(component + ".desktop")
|
||||
except:
|
||||
try:
|
||||
appinfo = gio.unix.DesktopAppInfo("gnome-" + component + ".desktop")
|
||||
except:
|
||||
pass
|
||||
|
||||
if appinfo:
|
||||
appinfo.launch()
|
||||
|
||||
launch_component("/desktop/gnome/session/required_components/windowmanager")
|
||||
launch_component("/desktop/gnome/session/required_components/panel")
|
||||
|
||||
# Main program
|
||||
|
||||
@ -207,6 +205,8 @@ parser.add_option("", "--debug-command", metavar="COMMAND",
|
||||
help="Command to use for debugging (defaults to 'gdb --args')")
|
||||
parser.add_option("-v", "--verbose", action="store_true")
|
||||
parser.add_option("", "--sync", action="store_true")
|
||||
parser.add_option("", "--xephyr", action="store_true",
|
||||
help="Run a debugging instance inside Xephyr")
|
||||
parser.add_option("", "--geometry", metavar="GEOMETRY",
|
||||
help="Specify Xephyr screen geometry",
|
||||
default="1024x768");
|
||||
@ -227,27 +227,6 @@ elif options.debug:
|
||||
if options.wide:
|
||||
options.geometry = "1280x800"
|
||||
|
||||
metacity_pid = pidof("metacity")
|
||||
compiz_pid = pidof("compiz.real") or pidof("compiz")
|
||||
|
||||
# In Gnome 2.26 the panel grabs a dbus name and allows replacement; use that.
|
||||
bus = dbus.Interface(dbus.SessionBus().get_object('org.freedesktop.DBus', '/org/freedesktop/DBus'),
|
||||
'org.freedesktop.DBus')
|
||||
names = bus.ListNames()
|
||||
gnome_panel_dbus = 'org.gnome.Panel' in names
|
||||
if gnome_panel_dbus:
|
||||
gnome_panel_pid = None
|
||||
else:
|
||||
gnome_panel_pid = pidof("gnome-panel")
|
||||
|
||||
# Run in Xephyr if gnome-panel is already running and the user didn't
|
||||
# specify --replace. Otherwise, run fullscreen
|
||||
if options.replace:
|
||||
run_in_xephyr = False
|
||||
else:
|
||||
run_in_xephyr = (metacity_pid != None or compiz_pid != None or
|
||||
gnome_panel_pid != None)
|
||||
|
||||
# Figure out whether or not to use GL_EXT_texture_from_pixmap. By default
|
||||
# we use it iff we aren't running Xephyr, but we allow the user to
|
||||
# explicitly disable it.
|
||||
@ -258,7 +237,7 @@ if 'GNOME_SHELL_DISABLE_TFP' in os.environ and \
|
||||
use_tfp = False
|
||||
else:
|
||||
# tfp does not work correctly in Xephyr
|
||||
use_tfp = not run_in_xephyr
|
||||
use_tfp = not options.xephyr
|
||||
|
||||
if options.verbose:
|
||||
print "Starting shell"
|
||||
@ -268,23 +247,26 @@ if options.debug:
|
||||
# later, in case we kill gdb at a bad time
|
||||
termattrs = termios.tcgetattr(0);
|
||||
|
||||
# We only respawn the previous environment on abnormal exit;
|
||||
# for a clean exit, we assume that gnome-shell was replaced with
|
||||
# something else.
|
||||
normal_exit = False
|
||||
|
||||
try:
|
||||
if run_in_xephyr:
|
||||
shell = start_xephyr()
|
||||
shell = None
|
||||
if options.xephyr:
|
||||
xephyr = start_xephyr()
|
||||
# This makes us not grab the org.gnome.Panel name
|
||||
os.environ['GNOME_SHELL_NO_REPLACE_PANEL'] = '1'
|
||||
start_shell()
|
||||
shell = start_shell()
|
||||
else:
|
||||
if gnome_panel_pid is not None:
|
||||
kill_gnome_panel(gnome_panel_pid)
|
||||
xephyr = None
|
||||
shell = start_shell()
|
||||
|
||||
# Wait for shell to exit
|
||||
if options.verbose:
|
||||
print "Waiting for shell to exit"
|
||||
shell.wait()
|
||||
if options.verbose:
|
||||
print "Shell is dead"
|
||||
|
||||
except KeyboardInterrupt, e:
|
||||
try:
|
||||
@ -292,29 +274,31 @@ except KeyboardInterrupt, e:
|
||||
except:
|
||||
pass
|
||||
shell.wait()
|
||||
if options.verbose:
|
||||
print "Shell killed"
|
||||
|
||||
finally:
|
||||
# Clean up Xephyr if it outlived the shell
|
||||
if xephyr:
|
||||
try:
|
||||
os.kill(xephyr.pid, signal.SIGKILL)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
if shell is None:
|
||||
print "Failed to start shell"
|
||||
elif shell.returncode == 0:
|
||||
normal_exit = True
|
||||
if options.verbose:
|
||||
print "Shell exited normally"
|
||||
elif shell.returncode < 0:
|
||||
# Python has no mapping for strsignal; not worth using
|
||||
# ctypes for this.
|
||||
print "Shell killed with signal %d" % - shell.returncode
|
||||
else:
|
||||
# Normal reason here would be losing connection the X server
|
||||
if options.verbose:
|
||||
print "Shell exited with return code %d" % shell.returncode
|
||||
|
||||
if options.debug:
|
||||
termios.tcsetattr(0, termios.TCSANOW, termattrs);
|
||||
|
||||
if not run_in_xephyr:
|
||||
# Restart gnome-panel and window manager
|
||||
|
||||
# We don't want to start the new gnome-panel in the current
|
||||
# directory; $HOME is better for stuff launched from it
|
||||
os.chdir(os.path.expanduser("~"))
|
||||
|
||||
if metacity_pid:
|
||||
if options.verbose:
|
||||
print "Restarting Metacity"
|
||||
subprocess.Popen(["/usr/bin/metacity"])
|
||||
elif compiz_pid:
|
||||
if options.verbose:
|
||||
print "Restarting Compiz"
|
||||
subprocess.Popen(["/usr/bin/compiz"])
|
||||
if gnome_panel_dbus or gnome_panel_pid:
|
||||
if options.verbose:
|
||||
print "Restarting gnome-panel"
|
||||
subprocess.Popen(["/usr/bin/gnome-panel"])
|
||||
if not options.xephyr and options.replace and not normal_exit:
|
||||
restore_gnome()
|
||||
|
@ -1,64 +0,0 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include <mutter-plugin.h>
|
||||
|
||||
ClutterActor *
|
||||
mutter_plugin_get_overlay_group (MutterPlugin *plugin)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ClutterActor *
|
||||
mutter_plugin_get_stage (MutterPlugin *plugin)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GList *
|
||||
mutter_plugin_get_windows (MutterPlugin *plugin)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
mutter_plugin_query_screen_size (MutterPlugin *plugin,
|
||||
int *width,
|
||||
int *height)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
mutter_plugin_set_stage_input_area (MutterPlugin *plugin,
|
||||
gint x, gint y, gint width, gint height)
|
||||
{
|
||||
}
|
||||
|
||||
MetaScreen *
|
||||
mutter_plugin_get_screen (MutterPlugin *plugin)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ClutterActor *
|
||||
mutter_plugin_get_window_group (MutterPlugin *plugin)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Display *
|
||||
meta_display_get_xdisplay (MetaDisplay *display)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MetaDisplay *
|
||||
meta_screen_get_display (MetaScreen *display)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Window
|
||||
meta_screen_get_xroot (MetaScreen *display)
|
||||
{
|
||||
return None;
|
||||
}
|
@ -1,236 +0,0 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include "shell-alttab.h"
|
||||
#include "shell-global.h"
|
||||
#include "shell-wm.h"
|
||||
#include <mutter-plugin.h>
|
||||
|
||||
/* Our MetaAltTabHandler implementation; ideally we would implement
|
||||
* this directly from JavaScript, but for now we can't. So we register
|
||||
* this glue class as our MetaAltTabHandler and then when mutter
|
||||
* creates one, we pass it on to ShellWM, which emits a signal to hand
|
||||
* it off to javascript code, which then connects to the signals on
|
||||
* this object.
|
||||
*/
|
||||
|
||||
static void shell_alt_tab_handler_interface_init (MetaAltTabHandlerInterface *handler_iface);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (ShellAltTabHandler, shell_alt_tab_handler, G_TYPE_OBJECT,
|
||||
G_IMPLEMENT_INTERFACE (META_TYPE_ALT_TAB_HANDLER,
|
||||
shell_alt_tab_handler_interface_init))
|
||||
|
||||
/* Signals */
|
||||
enum
|
||||
{
|
||||
WINDOW_ADDED,
|
||||
SHOW,
|
||||
DESTROY,
|
||||
|
||||
LAST_SIGNAL
|
||||
};
|
||||
static guint signals [LAST_SIGNAL] = { 0 };
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_SELECTED = 1,
|
||||
PROP_SCREEN,
|
||||
PROP_IMMEDIATE
|
||||
};
|
||||
|
||||
static void
|
||||
shell_alt_tab_handler_init (ShellAltTabHandler *sth)
|
||||
{
|
||||
sth->windows = g_ptr_array_new ();
|
||||
sth->selected = -1;
|
||||
}
|
||||
|
||||
static void
|
||||
shell_alt_tab_handler_constructed (GObject *object)
|
||||
{
|
||||
ShellGlobal *global = shell_global_get ();
|
||||
ShellWM *wm;
|
||||
|
||||
g_object_get (G_OBJECT (global), "window-manager", &wm, NULL);
|
||||
_shell_wm_begin_alt_tab (wm, SHELL_ALT_TAB_HANDLER (object));
|
||||
g_object_unref (wm);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_alt_tab_handler_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ShellAltTabHandler *sth = SHELL_ALT_TAB_HANDLER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SCREEN:
|
||||
/* We don't care */
|
||||
break;
|
||||
case PROP_IMMEDIATE:
|
||||
sth->immediate_mode = g_value_get_boolean (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
shell_alt_tab_handler_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ShellAltTabHandler *sth = SHELL_ALT_TAB_HANDLER (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SELECTED:
|
||||
g_value_set_int (value, sth->selected);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
shell_alt_tab_handler_finalize (GObject *object)
|
||||
{
|
||||
ShellAltTabHandler *sth = SHELL_ALT_TAB_HANDLER (object);
|
||||
|
||||
g_ptr_array_free (sth->windows, FALSE);
|
||||
|
||||
G_OBJECT_CLASS (shell_alt_tab_handler_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_alt_tab_handler_add_window (MetaAltTabHandler *handler,
|
||||
MetaWindow *window)
|
||||
{
|
||||
ShellAltTabHandler *sth = SHELL_ALT_TAB_HANDLER (handler);
|
||||
|
||||
g_ptr_array_add (sth->windows, window);
|
||||
g_signal_emit (handler, signals[WINDOW_ADDED], 0,
|
||||
meta_window_get_compositor_private (window));
|
||||
}
|
||||
|
||||
static void
|
||||
shell_alt_tab_handler_show (MetaAltTabHandler *handler,
|
||||
MetaWindow *initial_selection)
|
||||
{
|
||||
ShellAltTabHandler *sth = SHELL_ALT_TAB_HANDLER (handler);
|
||||
int i;
|
||||
|
||||
sth->selected = -1;
|
||||
for (i = 0; i < sth->windows->len; i++)
|
||||
{
|
||||
if (sth->windows->pdata[i] == (gpointer)initial_selection)
|
||||
{
|
||||
sth->selected = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_signal_emit (handler, signals[SHOW], 0, sth->selected);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_alt_tab_handler_destroy (MetaAltTabHandler *handler)
|
||||
{
|
||||
g_signal_emit (handler, signals[DESTROY], 0);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_alt_tab_handler_forward (MetaAltTabHandler *handler)
|
||||
{
|
||||
ShellAltTabHandler *sth = SHELL_ALT_TAB_HANDLER (handler);
|
||||
|
||||
if (sth->selected == sth->windows->len - 1)
|
||||
sth->selected = 0;
|
||||
else
|
||||
sth->selected++;
|
||||
g_object_notify (G_OBJECT (handler), "selected");
|
||||
}
|
||||
|
||||
static void
|
||||
shell_alt_tab_handler_backward (MetaAltTabHandler *handler)
|
||||
{
|
||||
ShellAltTabHandler *sth = SHELL_ALT_TAB_HANDLER (handler);
|
||||
|
||||
if (sth->selected == 0)
|
||||
sth->selected = sth->windows->len - 1;
|
||||
else
|
||||
sth->selected--;
|
||||
g_object_notify (G_OBJECT (handler), "selected");
|
||||
}
|
||||
|
||||
static MetaWindow *
|
||||
shell_alt_tab_handler_get_selected (MetaAltTabHandler *handler)
|
||||
{
|
||||
ShellAltTabHandler *sth = SHELL_ALT_TAB_HANDLER (handler);
|
||||
|
||||
if (sth->selected > -1)
|
||||
return sth->windows->pdata[sth->selected];
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
shell_alt_tab_handler_class_init (ShellAltTabHandlerClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->constructed = shell_alt_tab_handler_constructed;
|
||||
object_class->set_property = shell_alt_tab_handler_set_property;
|
||||
object_class->get_property = shell_alt_tab_handler_get_property;
|
||||
object_class->finalize = shell_alt_tab_handler_finalize;
|
||||
|
||||
g_object_class_override_property (object_class, PROP_SCREEN, "screen");
|
||||
g_object_class_override_property (object_class, PROP_IMMEDIATE, "immediate");
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_SELECTED,
|
||||
g_param_spec_int ("selected",
|
||||
"Selected",
|
||||
"Selected window",
|
||||
-1, G_MAXINT, -1,
|
||||
G_PARAM_READABLE));
|
||||
|
||||
|
||||
signals[WINDOW_ADDED] = g_signal_new ("window-added",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1,
|
||||
MUTTER_TYPE_COMP_WINDOW);
|
||||
signals[SHOW] = g_signal_new ("show",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__INT,
|
||||
G_TYPE_NONE, 1,
|
||||
G_TYPE_INT);
|
||||
signals[DESTROY] = g_signal_new ("destroy",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_alt_tab_handler_interface_init (MetaAltTabHandlerInterface *handler_iface)
|
||||
{
|
||||
handler_iface->add_window = shell_alt_tab_handler_add_window;
|
||||
handler_iface->show = shell_alt_tab_handler_show;
|
||||
handler_iface->destroy = shell_alt_tab_handler_destroy;
|
||||
handler_iface->forward = shell_alt_tab_handler_forward;
|
||||
handler_iface->backward = shell_alt_tab_handler_backward;
|
||||
handler_iface->get_selected = shell_alt_tab_handler_get_selected;
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#ifndef SHELL_ALT_TAB_HANDLER_H
|
||||
#define SHELL_ALT_TAB_HANDLER_H
|
||||
|
||||
#include <alttabhandler.h>
|
||||
|
||||
#define SHELL_TYPE_ALT_TAB_HANDLER (shell_alt_tab_handler_get_type ())
|
||||
#define SHELL_ALT_TAB_HANDLER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_ALT_TAB_HANDLER, ShellAltTabHandler))
|
||||
#define SHELL_ALT_TAB_HANDLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_ALT_TAB_HANDLER, ShellAltTabHandlerClass))
|
||||
#define SHELL_IS_ALT_TAB_HANDLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_ALT_TAB_HANDLER_TYPE))
|
||||
#define SHELL_IS_ALT_TAB_HANDLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_ALT_TAB_HANDLER))
|
||||
#define SHELL_ALT_TAB_HANDLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_ALT_TAB_HANDLER, ShellAltTabHandlerClass))
|
||||
|
||||
typedef struct _ShellAltTabHandler ShellAltTabHandler;
|
||||
typedef struct _ShellAltTabHandlerClass ShellAltTabHandlerClass;
|
||||
|
||||
struct _ShellAltTabHandler {
|
||||
GObject parent_instance;
|
||||
|
||||
GPtrArray *windows;
|
||||
int selected;
|
||||
gboolean immediate_mode;
|
||||
};
|
||||
|
||||
struct _ShellAltTabHandlerClass {
|
||||
GObjectClass parent_class;
|
||||
|
||||
};
|
||||
|
||||
GType shell_alt_tab_handler_get_type (void);
|
||||
|
||||
#endif
|
||||
|
@ -11,12 +11,18 @@
|
||||
#include <gconf/gconf-client.h>
|
||||
#include <dbus/dbus-glib.h>
|
||||
|
||||
#define SN_API_NOT_YET_FROZEN 1
|
||||
#include <libsn/sn.h>
|
||||
|
||||
#include "shell-texture-cache.h"
|
||||
#include "shell-app-monitor.h"
|
||||
#include "shell-app-system.h"
|
||||
#include "shell-global.h"
|
||||
#include "shell-marshal.h"
|
||||
|
||||
#include "display.h"
|
||||
#include "window.h"
|
||||
#include "group.h"
|
||||
|
||||
/* This file includes modified code from
|
||||
* desktop-data-engine/engine-dbus/hippo-application-monitor.c
|
||||
@ -86,13 +92,13 @@ static struct
|
||||
const char *pattern;
|
||||
GRegex *regex;
|
||||
} title_patterns[] = {
|
||||
{"mozilla-firefox", ".* - Mozilla Firefox", NULL}, \
|
||||
{"openoffice.org-writer", ".* - OpenOffice.org Writer$", NULL}, \
|
||||
{"openoffice.org-calc", ".* - OpenOffice.org Calc$", NULL}, \
|
||||
{"openoffice.org-impress", ".* - OpenOffice.org Impress$", NULL}, \
|
||||
{"openoffice.org-draw", ".* - OpenOffice.org Draw$", NULL}, \
|
||||
{"openoffice.org-base", ".* - OpenOffice.org Base$", NULL}, \
|
||||
{"openoffice.org-math", ".* - OpenOffice.org Math$", NULL}, \
|
||||
{"mozilla-firefox.desktop", ".* - Mozilla Firefox", NULL}, \
|
||||
{"openoffice.org-writer.desktop", ".* - OpenOffice.org Writer$", NULL}, \
|
||||
{"openoffice.org-calc.desktop", ".* - OpenOffice.org Calc$", NULL}, \
|
||||
{"openoffice.org-impress.desktop", ".* - OpenOffice.org Impress$", NULL}, \
|
||||
{"openoffice.org-draw.desktop", ".* - OpenOffice.org Draw$", NULL}, \
|
||||
{"openoffice.org-base.desktop", ".* - OpenOffice.org Base$", NULL}, \
|
||||
{"openoffice.org-math.desktop", ".* - OpenOffice.org Math$", NULL}, \
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
@ -135,6 +141,11 @@ G_DEFINE_TYPE (ShellAppMonitor, shell_app_monitor, G_TYPE_OBJECT);
|
||||
/* Represents an application record for a given context */
|
||||
struct AppUsage
|
||||
{
|
||||
/* Whether the application we're tracking is "transient", see
|
||||
* shell_app_info_is_transient.
|
||||
*/
|
||||
gboolean transient;
|
||||
|
||||
gdouble score; /* Based on the number of times we'e seen the app and normalized */
|
||||
long last_seen; /* Used to clear old apps we've only seen a few times */
|
||||
|
||||
@ -150,7 +161,11 @@ struct AppUsage
|
||||
};
|
||||
|
||||
enum {
|
||||
CHANGED,
|
||||
APP_ADDED,
|
||||
APP_REMOVED,
|
||||
WINDOW_ADDED,
|
||||
WINDOW_REMOVED,
|
||||
STARTUP_SEQUENCE_CHANGED,
|
||||
|
||||
LAST_SIGNAL
|
||||
};
|
||||
@ -166,6 +181,9 @@ static AppUsage * get_app_usage_for_context_and_id (ShellAppMonitor *monitor,
|
||||
const char *context,
|
||||
const char *appid);
|
||||
|
||||
static void track_window (ShellAppMonitor *monitor, MetaWindow *window);
|
||||
static void disassociate_window (ShellAppMonitor *monitor, MetaWindow *window);
|
||||
|
||||
static gboolean idle_save_application_usage (gpointer data);
|
||||
|
||||
static void restore_from_file (ShellAppMonitor *monitor);
|
||||
@ -191,13 +209,49 @@ static void shell_app_monitor_class_init(ShellAppMonitorClass *klass)
|
||||
|
||||
gobject_class->finalize = shell_app_monitor_finalize;
|
||||
|
||||
signals[CHANGED] = g_signal_new ("changed",
|
||||
signals[APP_ADDED] = g_signal_new ("app-added",
|
||||
SHELL_TYPE_APP_MONITOR,
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
_shell_marshal_VOID__BOXED,
|
||||
G_TYPE_NONE, 1,
|
||||
SHELL_TYPE_APP_INFO);
|
||||
signals[APP_REMOVED] = g_signal_new ("app-removed",
|
||||
SHELL_TYPE_APP_MONITOR,
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
_shell_marshal_VOID__BOXED,
|
||||
G_TYPE_NONE, 1,
|
||||
SHELL_TYPE_APP_INFO);
|
||||
|
||||
signals[WINDOW_ADDED] = g_signal_new ("window-added",
|
||||
SHELL_TYPE_APP_MONITOR,
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
_shell_marshal_VOID__BOXED_OBJECT,
|
||||
G_TYPE_NONE, 2,
|
||||
SHELL_TYPE_APP_INFO,
|
||||
META_TYPE_WINDOW);
|
||||
signals[WINDOW_REMOVED] = g_signal_new ("window-removed",
|
||||
SHELL_TYPE_APP_MONITOR,
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
_shell_marshal_VOID__BOXED_OBJECT,
|
||||
G_TYPE_NONE, 2,
|
||||
SHELL_TYPE_APP_INFO,
|
||||
META_TYPE_WINDOW);
|
||||
|
||||
signals[STARTUP_SEQUENCE_CHANGED] = g_signal_new ("startup-sequence-changed",
|
||||
SHELL_TYPE_APP_MONITOR,
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
g_cclosure_marshal_VOID__BOXED,
|
||||
G_TYPE_NONE, 1, SHELL_TYPE_STARTUP_SEQUENCE);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -206,15 +260,20 @@ destroy_usage (AppUsage *usage)
|
||||
g_free (usage);
|
||||
}
|
||||
|
||||
static char *
|
||||
get_wmclass_for_window (MetaWindow *window)
|
||||
/**
|
||||
* get_app_id_from_title:
|
||||
*
|
||||
* Use a window's "title" property to determine an application ID.
|
||||
* This is a temporary crutch for a few applications until we get
|
||||
* them correctly setting their WM_CLASS.
|
||||
*/
|
||||
static const char *
|
||||
get_app_id_from_title (MetaWindow *window)
|
||||
{
|
||||
static gboolean patterns_initialized = FALSE;
|
||||
const char *wm_class;
|
||||
char *title;
|
||||
int i;
|
||||
|
||||
wm_class = meta_window_get_wm_class (window);
|
||||
g_object_get (window, "title", &title, NULL);
|
||||
|
||||
if (!patterns_initialized) /* Generate match patterns once for all */
|
||||
@ -234,15 +293,15 @@ get_wmclass_for_window (MetaWindow *window)
|
||||
{
|
||||
if (g_regex_match (title_patterns[i].regex, title, 0, NULL))
|
||||
{
|
||||
g_free (title);
|
||||
/* Set a pseudo WM class, handled like true ones */
|
||||
wm_class = title_patterns[i].app_id;
|
||||
break;
|
||||
return title_patterns[i].app_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_free (title);
|
||||
return g_strdup (wm_class);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -255,44 +314,115 @@ get_wmclass_for_window (MetaWindow *window)
|
||||
static char *
|
||||
get_cleaned_wmclass_for_window (MetaWindow *window)
|
||||
{
|
||||
char *wmclass;
|
||||
const char *wmclass;
|
||||
char *cleaned_wmclass;
|
||||
|
||||
if (meta_window_get_window_type (window) != META_WINDOW_NORMAL)
|
||||
return NULL;
|
||||
|
||||
wmclass = get_wmclass_for_window (window);
|
||||
wmclass = meta_window_get_wm_class (window);
|
||||
if (!wmclass)
|
||||
return NULL;
|
||||
|
||||
cleaned_wmclass = g_utf8_strdown (wmclass, -1);
|
||||
g_free (wmclass);
|
||||
|
||||
/* This handles "Fedora Eclipse", probably others.
|
||||
* Note g_strdelimit is modify-in-place. */
|
||||
g_strdelimit (cleaned_wmclass, " ", '-');
|
||||
wmclass = g_strdup (cleaned_wmclass);
|
||||
g_free (cleaned_wmclass);
|
||||
return wmclass;
|
||||
|
||||
return cleaned_wmclass;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_app_for_window:
|
||||
* window_is_tracked:
|
||||
*
|
||||
* Returns the application associated with a window, or %NULL if
|
||||
* we're unable to determine one.
|
||||
* Returns: %TRUE iff we want to scan this window for application association
|
||||
*/
|
||||
static gboolean
|
||||
window_is_tracked (MetaWindow *window)
|
||||
{
|
||||
if (meta_window_is_override_redirect (window))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_app_monitor_is_window_usage_tracked:
|
||||
*
|
||||
* Determine if it makes sense to track the given window for application
|
||||
* usage. An example of a window we don't want to track is the root
|
||||
* desktop window. We skip all override-redirect types, and also
|
||||
* exclude other window types like tooltip explicitly, though generally
|
||||
* most of these should be override-redirect.
|
||||
*
|
||||
* The usage data is also currently used to return the list of user-interesting
|
||||
* windows associated with an application.
|
||||
*
|
||||
* Returns: %TRUE iff we want to record focus time spent in this window
|
||||
*/
|
||||
gboolean
|
||||
shell_app_monitor_is_window_usage_tracked (MetaWindow *window)
|
||||
{
|
||||
if (!window_is_tracked (window))
|
||||
return FALSE;
|
||||
|
||||
if (meta_window_is_skip_taskbar (window))
|
||||
return FALSE;
|
||||
|
||||
switch (meta_window_get_window_type (window))
|
||||
{
|
||||
/* Definitely ignore these. */
|
||||
case META_WINDOW_DESKTOP:
|
||||
case META_WINDOW_DOCK:
|
||||
case META_WINDOW_SPLASHSCREEN:
|
||||
/* Should have already been handled by override_redirect above,
|
||||
* but explicitly list here so we get the "unhandled enum"
|
||||
* warning if in the future anything is added.*/
|
||||
case META_WINDOW_DROPDOWN_MENU:
|
||||
case META_WINDOW_POPUP_MENU:
|
||||
case META_WINDOW_TOOLTIP:
|
||||
case META_WINDOW_NOTIFICATION:
|
||||
case META_WINDOW_COMBO:
|
||||
case META_WINDOW_DND:
|
||||
case META_WINDOW_OVERRIDE_OTHER:
|
||||
return FALSE;
|
||||
case META_WINDOW_NORMAL:
|
||||
case META_WINDOW_DIALOG:
|
||||
case META_WINDOW_MODAL_DIALOG:
|
||||
case META_WINDOW_MENU:
|
||||
case META_WINDOW_TOOLBAR:
|
||||
case META_WINDOW_UTILITY:
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static ShellAppInfo *
|
||||
create_transient_app_for_window (MetaWindow *window)
|
||||
{
|
||||
return shell_app_system_create_from_window (shell_app_system_get_default (), window);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_app_for_window_direct:
|
||||
*
|
||||
* Looks only at the given window, and attempts to determine
|
||||
* an application based on WM_CLASS. If that fails, then
|
||||
* a "transient" application is created.
|
||||
*
|
||||
* Return value: (transfer full): A newly-referenced #ShellAppInfo
|
||||
*/
|
||||
static ShellAppInfo *
|
||||
get_app_for_window (MetaWindow *window)
|
||||
get_app_for_window_direct (MetaWindow *window)
|
||||
{
|
||||
char *wmclass;
|
||||
char *with_desktop;
|
||||
ShellAppInfo *result;
|
||||
ShellAppSystem *appsys;
|
||||
char *wmclass;
|
||||
char *with_desktop;
|
||||
|
||||
wmclass = get_cleaned_wmclass_for_window (window);
|
||||
|
||||
if (!wmclass)
|
||||
return NULL;
|
||||
return create_transient_app_for_window (window);
|
||||
|
||||
with_desktop = g_strjoin (NULL, wmclass, ".desktop", NULL);
|
||||
g_free (wmclass);
|
||||
@ -301,9 +431,71 @@ get_app_for_window (MetaWindow *window)
|
||||
result = shell_app_system_lookup_heuristic_basename (appsys, with_desktop);
|
||||
g_free (with_desktop);
|
||||
|
||||
if (result == NULL)
|
||||
{
|
||||
const char *id = get_app_id_from_title (window);
|
||||
|
||||
if (id != NULL)
|
||||
result = shell_app_system_load_from_desktop_file (appsys, id, NULL);
|
||||
}
|
||||
if (result == NULL)
|
||||
result = create_transient_app_for_window (window);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_app_for_window:
|
||||
*
|
||||
* Determines the application associated with a window, using
|
||||
* all available information such as the window's MetaGroup,
|
||||
* and what we know about other windows.
|
||||
*/
|
||||
static ShellAppInfo *
|
||||
get_app_for_window (ShellAppMonitor *monitor,
|
||||
MetaWindow *window)
|
||||
{
|
||||
ShellAppInfo *result;
|
||||
MetaWindow *source_window;
|
||||
GSList *group_windows;
|
||||
MetaGroup *group;
|
||||
GSList *iter;
|
||||
|
||||
group = meta_window_get_group (window);
|
||||
if (group == NULL)
|
||||
group_windows = g_slist_prepend (NULL, window);
|
||||
else
|
||||
group_windows = meta_group_list_windows (group);
|
||||
|
||||
source_window = window;
|
||||
|
||||
result = NULL;
|
||||
/* Try finding a window in the group of type NORMAL; if we
|
||||
* succeed, use that as our source. */
|
||||
for (iter = group_windows; iter; iter = iter->next)
|
||||
{
|
||||
MetaWindow *group_window = iter->data;
|
||||
|
||||
if (meta_window_get_window_type (group_window) != META_WINDOW_NORMAL)
|
||||
continue;
|
||||
|
||||
source_window = group_window;
|
||||
result = g_hash_table_lookup (monitor->window_to_app, group_window);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
|
||||
g_slist_free (group_windows);
|
||||
|
||||
if (result != NULL)
|
||||
{
|
||||
shell_app_info_ref (result);
|
||||
return result;
|
||||
}
|
||||
|
||||
return get_app_for_window_direct (source_window);
|
||||
}
|
||||
|
||||
static const char *
|
||||
get_window_context (MetaWindow *window)
|
||||
{
|
||||
@ -368,9 +560,15 @@ get_active_window (ShellAppMonitor *monitor)
|
||||
{
|
||||
MetaScreen *screen;
|
||||
MetaDisplay *display;
|
||||
MetaWindow *window;
|
||||
|
||||
screen = shell_global_get_screen (shell_global_get ());
|
||||
display = meta_screen_get_display (screen);
|
||||
return meta_display_get_focus_window (display);
|
||||
window = meta_display_get_focus_window (display);
|
||||
|
||||
if (window != NULL && shell_app_monitor_is_window_usage_tracked (window))
|
||||
return window;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
@ -462,13 +660,6 @@ increment_usage_for_window_at_time (ShellAppMonitor *self,
|
||||
guint usage_count;
|
||||
|
||||
usage = get_app_usage_from_window (self, window);
|
||||
if (usage == NULL)
|
||||
{
|
||||
/* This could in theory happen if we lost the app tracking, i.e.
|
||||
* the window changed WM_CLASS. In that case, time for a punt.
|
||||
*/
|
||||
return;
|
||||
}
|
||||
|
||||
usage->last_seen = time;
|
||||
|
||||
@ -491,6 +682,62 @@ increment_usage_for_window (ShellAppMonitor *self,
|
||||
increment_usage_for_window_at_time (self, window, curtime);
|
||||
}
|
||||
|
||||
/**
|
||||
* reset_usage:
|
||||
*
|
||||
* For non-transient applications, just reset the "seen sequence".
|
||||
*
|
||||
* For transient ones, we don't want to keep an AppUsage around, so
|
||||
* remove it entirely.
|
||||
*/
|
||||
static void
|
||||
reset_usage (ShellAppMonitor *self,
|
||||
const char *context,
|
||||
const char *appid,
|
||||
AppUsage *usage)
|
||||
{
|
||||
if (!usage->transient)
|
||||
{
|
||||
usage->initially_seen_sequence = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
GHashTable *usages;
|
||||
usages = g_hash_table_lookup (self->app_usages_for_context, context);
|
||||
g_hash_table_remove (usages, appid);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_transient_window_title_changed (MetaWindow *window,
|
||||
GParamSpec *spec,
|
||||
ShellAppMonitor *self)
|
||||
{
|
||||
ShellAppSystem *appsys;
|
||||
ShellAppInfo *current_app;
|
||||
ShellAppInfo *new_app;
|
||||
const char *id;
|
||||
|
||||
current_app = g_hash_table_lookup (self->window_to_app, window);
|
||||
/* Can't have lost the app */
|
||||
g_assert (current_app != NULL);
|
||||
|
||||
/* Check if we now have a mapping using the window title */
|
||||
id = get_app_id_from_title (window);
|
||||
if (id == NULL)
|
||||
return;
|
||||
|
||||
appsys = shell_app_system_get_default ();
|
||||
new_app = shell_app_system_load_from_desktop_file (appsys, id, NULL);
|
||||
if (new_app == NULL)
|
||||
return;
|
||||
shell_app_info_unref (new_app);
|
||||
|
||||
/* It's simplest to just treat this as a remove + add. */
|
||||
disassociate_window (self, window);
|
||||
track_window (self, window);
|
||||
}
|
||||
|
||||
static void
|
||||
track_window (ShellAppMonitor *self,
|
||||
MetaWindow *window)
|
||||
@ -498,23 +745,49 @@ track_window (ShellAppMonitor *self,
|
||||
ShellAppInfo *app;
|
||||
AppUsage *usage;
|
||||
|
||||
app = get_app_for_window (window);
|
||||
if (!window_is_tracked (window))
|
||||
return;
|
||||
|
||||
app = get_app_for_window (self, window);
|
||||
if (!app)
|
||||
return;
|
||||
|
||||
/* At this point we've stored the association from window -> application */
|
||||
g_hash_table_insert (self->window_to_app, window, app);
|
||||
|
||||
usage = get_app_usage_from_window (self, window);
|
||||
/* However, we don't want to record usage for all kinds of windows;
|
||||
* the desktop window is a prime example. If a window isn't usage
|
||||
* tracked it doesn't count for the purposes of an application
|
||||
* running.
|
||||
*/
|
||||
if (!shell_app_monitor_is_window_usage_tracked (window))
|
||||
return;
|
||||
|
||||
/* Ephemerally keep track of the number of windows open for this app,
|
||||
* when it switches between 0 and 1 we emit a changed signal.
|
||||
usage = get_app_usage_from_window (self, window);
|
||||
usage->transient = shell_app_info_is_transient (app);
|
||||
|
||||
if (usage->transient)
|
||||
{
|
||||
/* For a transient application, it's possible one of our title regexps
|
||||
* will match at a later time, i.e. the application may not have set
|
||||
* its title fully at the time it initially maps a window. Watch
|
||||
* for title changes and recompute the app.
|
||||
*/
|
||||
g_signal_connect (window, "notify::title", G_CALLBACK (on_transient_window_title_changed), self);
|
||||
}
|
||||
|
||||
/* Keep track of the number of windows open for this app, when it
|
||||
* switches between 0 and 1 we emit an app-added signal.
|
||||
*/
|
||||
usage->window_count++;
|
||||
if (usage->initially_seen_sequence == 0)
|
||||
usage->initially_seen_sequence = ++self->initially_seen_sequence;
|
||||
usage->last_seen = get_time ();
|
||||
if (usage->window_count == 1)
|
||||
g_signal_emit (self, signals[CHANGED], 0);
|
||||
g_signal_emit (self, signals[APP_ADDED], 0, app);
|
||||
|
||||
/* Emit window-added after app-added */
|
||||
g_signal_emit (self, signals[WINDOW_ADDED], 0, app, window);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -527,33 +800,53 @@ shell_app_monitor_on_window_added (MetaWorkspace *workspace,
|
||||
track_window (self, window);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
shell_app_monitor_on_window_removed (MetaWorkspace *workspace,
|
||||
MetaWindow *window,
|
||||
gpointer user_data)
|
||||
disassociate_window (ShellAppMonitor *self,
|
||||
MetaWindow *window)
|
||||
{
|
||||
ShellAppMonitor *self = SHELL_APP_MONITOR (user_data);
|
||||
ShellAppInfo *app;
|
||||
AppUsage *usage;
|
||||
|
||||
app = g_hash_table_lookup (self->window_to_app, window);
|
||||
if (!app)
|
||||
return;
|
||||
|
||||
usage = get_app_usage_from_window (self, window);
|
||||
shell_app_info_ref (app);
|
||||
|
||||
if (window == self->watched_window)
|
||||
self->watched_window = NULL;
|
||||
|
||||
usage->window_count--;
|
||||
/* Remove before emitting */
|
||||
g_hash_table_remove (self->window_to_app, window);
|
||||
|
||||
if (usage->window_count == 0)
|
||||
if (shell_app_monitor_is_window_usage_tracked (window))
|
||||
{
|
||||
usage->initially_seen_sequence = 0;
|
||||
g_signal_emit (self, signals[CHANGED], 0);
|
||||
AppUsage *usage;
|
||||
const char *context;
|
||||
|
||||
context = get_window_context (window);
|
||||
usage = get_app_usage_from_window (self, window);
|
||||
usage->window_count--;
|
||||
|
||||
g_hash_table_remove (self->window_to_app, window);
|
||||
|
||||
g_signal_emit (self, signals[WINDOW_REMOVED], 0, app, window);
|
||||
|
||||
if (usage->window_count == 0)
|
||||
{
|
||||
g_signal_emit (self, signals[APP_REMOVED], 0, app);
|
||||
reset_usage (self, context, shell_app_info_get_id (app), usage);
|
||||
}
|
||||
}
|
||||
else
|
||||
g_hash_table_remove (self->window_to_app, window);
|
||||
|
||||
shell_app_info_unref (app);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_app_monitor_on_window_removed (MetaWorkspace *workspace,
|
||||
MetaWindow *window,
|
||||
gpointer user_data)
|
||||
{
|
||||
disassociate_window (SHELL_APP_MONITOR (user_data), window);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -621,6 +914,8 @@ on_session_status_changed (DBusGProxy *proxy,
|
||||
* @self:
|
||||
* @appid: Find windows for this id
|
||||
*
|
||||
* Returns the normal toplevel windows associated with the given application.
|
||||
*
|
||||
* Returns: (transfer container) (element-type MetaWindow): List of #MetaWindow corresponding to appid
|
||||
*/
|
||||
GSList *
|
||||
@ -639,6 +934,9 @@ shell_app_monitor_get_windows_for_app (ShellAppMonitor *self,
|
||||
ShellAppInfo *app = value;
|
||||
const char *id = shell_app_info_get_id (app);
|
||||
|
||||
if (!shell_app_monitor_is_window_usage_tracked (window))
|
||||
continue;
|
||||
|
||||
if (strcmp (id, appid) != 0)
|
||||
continue;
|
||||
|
||||
@ -694,9 +992,19 @@ init_window_monitoring (ShellAppMonitor *self)
|
||||
shell_app_monitor_on_n_workspaces_changed (screen, NULL, self);
|
||||
}
|
||||
|
||||
static void
|
||||
on_startup_sequence_changed (MetaScreen *screen,
|
||||
SnStartupSequence *sequence,
|
||||
ShellAppMonitor *self)
|
||||
{
|
||||
/* Just proxy the signal */
|
||||
g_signal_emit (G_OBJECT (self), signals[STARTUP_SEQUENCE_CHANGED], 0, sequence);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_app_monitor_init (ShellAppMonitor *self)
|
||||
{
|
||||
MetaScreen *screen;
|
||||
GdkDisplay *display;
|
||||
char *path;
|
||||
char *shell_config_dir;
|
||||
@ -704,6 +1012,7 @@ shell_app_monitor_init (ShellAppMonitor *self)
|
||||
|
||||
/* FIXME: should we create as many monitors as there are GdkScreens? */
|
||||
display = gdk_display_get_default ();
|
||||
screen = shell_global_get_screen (shell_global_get ());
|
||||
|
||||
session_bus = dbus_g_bus_get (DBUS_BUS_SESSION, NULL);
|
||||
self->session_proxy = dbus_g_proxy_new_for_name (session_bus, "org.gnome.SessionManager",
|
||||
@ -730,11 +1039,15 @@ shell_app_monitor_init (ShellAppMonitor *self)
|
||||
path = g_build_filename (shell_config_dir, DATA_FILENAME, NULL);
|
||||
g_free (shell_config_dir);
|
||||
self->configfile = g_file_new_for_path (path);
|
||||
g_free (path);
|
||||
restore_from_file (self);
|
||||
|
||||
load_initial_windows (self);
|
||||
init_window_monitoring (self);
|
||||
|
||||
g_signal_connect (G_OBJECT (screen), "startup-sequence-changed",
|
||||
G_CALLBACK (on_startup_sequence_changed), self);
|
||||
|
||||
self->gconf_client = gconf_client_get_default ();
|
||||
gconf_client_add_dir (self->gconf_client, APP_MONITOR_GCONF_DIR,
|
||||
GCONF_CLIENT_PRELOAD_NONE, NULL);
|
||||
@ -793,13 +1106,20 @@ shell_app_monitor_get_most_used_apps (ShellAppMonitor *monitor,
|
||||
* @monitor: An app monitor instance
|
||||
* @metawin: A #MetaWindow
|
||||
*
|
||||
* Returns: Desktop file id associated with window
|
||||
* Returns: Application associated with window
|
||||
*/
|
||||
ShellAppInfo *
|
||||
shell_app_monitor_get_window_app (ShellAppMonitor *monitor,
|
||||
MetaWindow *metawin)
|
||||
{
|
||||
ShellAppInfo *info = g_hash_table_lookup (monitor->window_to_app, metawin);
|
||||
MetaWindow *transient_for;
|
||||
ShellAppInfo *info;
|
||||
|
||||
transient_for = meta_window_get_transient_for (metawin);
|
||||
if (transient_for != NULL)
|
||||
metawin = transient_for;
|
||||
|
||||
info = g_hash_table_lookup (monitor->window_to_app, metawin);
|
||||
if (info)
|
||||
shell_app_info_ref (info);
|
||||
return info;
|
||||
@ -816,8 +1136,10 @@ sort_apps_by_open_sequence (gconstpointer a,
|
||||
gpointer datap)
|
||||
{
|
||||
AppOpenSequenceSortData *data = datap;
|
||||
const char *id_a = a;
|
||||
const char *id_b = b;
|
||||
ShellAppInfo *app_a = (ShellAppInfo*)a;
|
||||
ShellAppInfo *app_b = (ShellAppInfo*)b;
|
||||
const char *id_a = shell_app_info_get_id (app_a);
|
||||
const char *id_b = shell_app_info_get_id (app_b);
|
||||
AppUsage *usage_a;
|
||||
AppUsage *usage_b;
|
||||
|
||||
@ -831,38 +1153,51 @@ sort_apps_by_open_sequence (gconstpointer a,
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_app_monitor_get_running_app_ids:
|
||||
* shell_app_monitor_get_running_apps:
|
||||
* @monitor: An app monitor instance
|
||||
* @context: Activity identifier
|
||||
*
|
||||
* Returns the set of applications which currently have at least one open
|
||||
* window in the given context.
|
||||
*
|
||||
* Returns: (element-type utf8) (transfer container): List of application desktop
|
||||
* identifiers
|
||||
* Returns: (element-type ShellAppInfo) (transfer container): Active applications
|
||||
*/
|
||||
GSList *
|
||||
shell_app_monitor_get_running_app_ids (ShellAppMonitor *monitor,
|
||||
const char *context)
|
||||
shell_app_monitor_get_running_apps (ShellAppMonitor *monitor,
|
||||
const char *context)
|
||||
{
|
||||
UsageIterator iter;
|
||||
const char *cur_context;
|
||||
const char *id;
|
||||
AppUsage *usage;
|
||||
GHashTableIter iter;
|
||||
gpointer key, value;
|
||||
GSList *ret;
|
||||
AppOpenSequenceSortData data;
|
||||
GHashTable *unique_apps;
|
||||
|
||||
usage_iterator_init (monitor, &iter);
|
||||
unique_apps = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
|
||||
g_hash_table_iter_init (&iter, monitor->window_to_app);
|
||||
|
||||
ret = NULL;
|
||||
while (usage_iterator_next (monitor, &iter, &cur_context, &id, &usage))
|
||||
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||
{
|
||||
if (strcmp (cur_context, context) != 0)
|
||||
MetaWindow *window = key;
|
||||
ShellAppInfo *app = value;
|
||||
const char *id;
|
||||
|
||||
if (strcmp (get_window_context (window), context) != 0)
|
||||
continue;
|
||||
|
||||
if (usage->window_count > 0)
|
||||
ret = g_slist_prepend (ret, (char*)id);
|
||||
if (!shell_app_monitor_is_window_usage_tracked (window))
|
||||
continue;
|
||||
|
||||
id = shell_app_info_get_id (app);
|
||||
|
||||
if (g_hash_table_lookup (unique_apps, id))
|
||||
continue;
|
||||
g_hash_table_insert (unique_apps, (gpointer)id, (gpointer)id);
|
||||
|
||||
ret = g_slist_prepend (ret, app);
|
||||
}
|
||||
g_hash_table_destroy (unique_apps);
|
||||
|
||||
data.self = monitor;
|
||||
data.context_id = context;
|
||||
@ -875,7 +1210,8 @@ idle_handle_focus_change (gpointer data)
|
||||
ShellAppMonitor *monitor = data;
|
||||
long curtime = get_time ();
|
||||
|
||||
increment_usage_for_window (monitor, monitor->watched_window);
|
||||
if (monitor->watched_window != NULL)
|
||||
increment_usage_for_window (monitor, monitor->watched_window);
|
||||
|
||||
monitor->watched_window = get_active_window (monitor);
|
||||
monitor->watch_start_time = curtime;
|
||||
@ -1038,7 +1374,6 @@ idle_save_application_usage (gpointer data)
|
||||
GDataOutputStream *data_output;
|
||||
GError *error = NULL;
|
||||
|
||||
|
||||
monitor->save_id = 0;
|
||||
|
||||
/* Parent directory is already created by shell-global */
|
||||
@ -1062,6 +1397,10 @@ idle_save_application_usage (gpointer data)
|
||||
current_context = NULL;
|
||||
while (usage_iterator_next (monitor, &iter, &context, &id, &usage))
|
||||
{
|
||||
/* Don't save the fake apps we create for windows */
|
||||
if (usage->transient)
|
||||
continue;
|
||||
|
||||
if (context != current_context)
|
||||
{
|
||||
if (current_context != NULL)
|
||||
@ -1323,7 +1662,10 @@ update_enable_monitoring (ShellAppMonitor *monitor)
|
||||
{
|
||||
monitor->watched_window = NULL;
|
||||
if (monitor->save_id)
|
||||
g_source_remove (monitor->save_id);
|
||||
{
|
||||
g_source_remove (monitor->save_id);
|
||||
monitor->save_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
monitor->enable_monitoring = enable;
|
||||
@ -1339,6 +1681,90 @@ on_enable_monitoring_key_changed (GConfClient *client,
|
||||
update_enable_monitoring ((ShellAppMonitor *) monitor);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* shell_app_monitor_get_startup_sequences:
|
||||
* @self:
|
||||
*
|
||||
* Returns: (transfer none) (element-type ShellStartupSequence): Currently active startup sequences
|
||||
*/
|
||||
GSList *
|
||||
shell_app_monitor_get_startup_sequences (ShellAppMonitor *self)
|
||||
{
|
||||
ShellGlobal *global = shell_global_get ();
|
||||
MetaScreen *screen = shell_global_get_screen (global);
|
||||
return meta_screen_get_startup_sequences (screen);
|
||||
}
|
||||
|
||||
/* sn_startup_sequence_ref returns void, so make a
|
||||
* wrapper which returns self */
|
||||
static SnStartupSequence *
|
||||
sequence_ref (SnStartupSequence *sequence)
|
||||
{
|
||||
sn_startup_sequence_ref (sequence);
|
||||
return sequence;
|
||||
}
|
||||
|
||||
GType
|
||||
shell_startup_sequence_get_type (void)
|
||||
{
|
||||
static GType gtype = G_TYPE_INVALID;
|
||||
if (gtype == G_TYPE_INVALID)
|
||||
{
|
||||
gtype = g_boxed_type_register_static ("ShellStartupSequence",
|
||||
(GBoxedCopyFunc)sequence_ref,
|
||||
(GBoxedFreeFunc)sn_startup_sequence_unref);
|
||||
}
|
||||
return gtype;
|
||||
}
|
||||
|
||||
const char *
|
||||
shell_startup_sequence_get_id (ShellStartupSequence *sequence)
|
||||
{
|
||||
return sn_startup_sequence_get_id ((SnStartupSequence*)sequence);
|
||||
}
|
||||
|
||||
const char *
|
||||
shell_startup_sequence_get_name (ShellStartupSequence *sequence)
|
||||
{
|
||||
return sn_startup_sequence_get_name ((SnStartupSequence*)sequence);
|
||||
}
|
||||
|
||||
gboolean
|
||||
shell_startup_sequence_get_completed (ShellStartupSequence *sequence)
|
||||
{
|
||||
return sn_startup_sequence_get_completed ((SnStartupSequence*)sequence);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_startup_sequence_create_icon:
|
||||
* @sequence:
|
||||
* @size: Size in pixels of icon
|
||||
*
|
||||
* Returns: (transfer none): A new #ClutterTexture containing an icon for the sequence
|
||||
*/
|
||||
ClutterActor *
|
||||
shell_startup_sequence_create_icon (ShellStartupSequence *sequence, guint size)
|
||||
{
|
||||
GThemedIcon *themed;
|
||||
const char *icon_name;
|
||||
ClutterActor *texture;
|
||||
|
||||
icon_name = sn_startup_sequence_get_icon_name ((SnStartupSequence*)sequence);
|
||||
if (!icon_name)
|
||||
{
|
||||
texture = clutter_texture_new ();
|
||||
clutter_actor_set_size (texture, size, size);
|
||||
return texture;
|
||||
}
|
||||
|
||||
themed = (GThemedIcon*)g_themed_icon_new (icon_name);
|
||||
texture = shell_texture_cache_load_gicon (shell_texture_cache_get_default (),
|
||||
G_ICON (themed), size);
|
||||
g_object_unref (G_OBJECT (themed));
|
||||
return texture;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_app_monitor_get_default:
|
||||
*
|
||||
|
@ -30,8 +30,6 @@ struct _ShellAppMonitorClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (*apps_changed)(ShellAppMonitor *menuwrapper,
|
||||
gpointer data);
|
||||
};
|
||||
|
||||
GType shell_app_monitor_get_type (void) G_GNUC_CONST;
|
||||
@ -46,8 +44,22 @@ GList *shell_app_monitor_get_most_used_apps (ShellAppMonitor *monitor,
|
||||
|
||||
GSList *shell_app_monitor_get_windows_for_app (ShellAppMonitor *monitor, const char *appid);
|
||||
|
||||
gboolean shell_app_monitor_is_window_usage_tracked (MetaWindow *window);
|
||||
|
||||
/* Get whatever's running right now */
|
||||
GSList *shell_app_monitor_get_running_app_ids (ShellAppMonitor *monitor, const char *context);
|
||||
GSList *shell_app_monitor_get_running_apps (ShellAppMonitor *monitor, const char *context);
|
||||
|
||||
GSList *shell_app_monitor_get_startup_sequences (ShellAppMonitor *monitor);
|
||||
|
||||
/* Hidden typedef for SnStartupSequence */
|
||||
typedef struct _ShellStartupSequence ShellStartupSequence;
|
||||
#define SHELL_TYPE_STARTUP_SEQUENCE (shell_startup_sequence_get_type ())
|
||||
GType shell_startup_sequence_get_type (void);
|
||||
|
||||
const char *shell_startup_sequence_get_id (ShellStartupSequence *sequence);
|
||||
const char *shell_startup_sequence_get_name (ShellStartupSequence *sequence);
|
||||
gboolean shell_startup_sequence_get_completed (ShellStartupSequence *sequence);
|
||||
ClutterActor *shell_startup_sequence_create_icon (ShellStartupSequence *sequence, guint size);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <gtk/gtk.h>
|
||||
#include <gconf/gconf.h>
|
||||
#include <gconf/gconf-client.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include "shell-global.h"
|
||||
#include "shell-texture-cache.h"
|
||||
@ -18,6 +19,13 @@
|
||||
|
||||
#define SHELL_APP_FAVORITES_KEY "/desktop/gnome/shell/favorite_apps"
|
||||
|
||||
/* Vendor prefixes are something that can be preprended to a .desktop
|
||||
* file name. Undo this.
|
||||
*/
|
||||
static const char*const known_vendor_prefixes[] = { "gnome",
|
||||
"fedora",
|
||||
"mozilla" };
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
|
||||
@ -37,6 +45,7 @@ struct _ShellAppSystemPrivate {
|
||||
|
||||
GHashTable *app_id_to_app;
|
||||
|
||||
GHashTable *cached_menu_contents; /* <char *id, GSList<ShellAppInfo*>> */
|
||||
GSList *cached_app_menus; /* ShellAppMenuEntry */
|
||||
|
||||
GSList *cached_settings; /* ShellAppInfo */
|
||||
@ -44,10 +53,14 @@ struct _ShellAppSystemPrivate {
|
||||
GList *cached_favorites; /* utf8 */
|
||||
|
||||
gint app_monitor_id;
|
||||
|
||||
guint app_change_timeout_id;
|
||||
};
|
||||
|
||||
static void free_appinfo_gslist (gpointer list);
|
||||
static void shell_app_system_finalize (GObject *object);
|
||||
static void on_tree_changed (GMenuTree *tree, gpointer user_data);
|
||||
static gboolean on_tree_changed (gpointer user_data);
|
||||
static void on_tree_changed_cb (GMenuTree *tree, gpointer user_data);
|
||||
static void reread_menus (ShellAppSystem *self);
|
||||
static void on_favorite_apps_changed (GConfClient *client, guint id, GConfEntry *entry, gpointer user_data);
|
||||
static void reread_favorite_apps (ShellAppSystem *system);
|
||||
@ -56,7 +69,8 @@ G_DEFINE_TYPE(ShellAppSystem, shell_app_system, G_TYPE_OBJECT);
|
||||
|
||||
typedef enum {
|
||||
SHELL_APP_INFO_TYPE_ENTRY,
|
||||
SHELL_APP_INFO_TYPE_DESKTOP_FILE
|
||||
SHELL_APP_INFO_TYPE_DESKTOP_FILE,
|
||||
SHELL_APP_INFO_TYPE_WINDOW
|
||||
} ShellAppInfoType;
|
||||
|
||||
struct _ShellAppInfo {
|
||||
@ -74,6 +88,9 @@ struct _ShellAppInfo {
|
||||
|
||||
GKeyFile *keyfile;
|
||||
char *keyfile_path;
|
||||
|
||||
MetaWindow *window;
|
||||
char *window_id;
|
||||
};
|
||||
|
||||
ShellAppInfo*
|
||||
@ -97,6 +114,10 @@ shell_app_info_unref (ShellAppInfo *info)
|
||||
g_key_file_free (info->keyfile);
|
||||
g_free (info->keyfile_path);
|
||||
break;
|
||||
case SHELL_APP_INFO_TYPE_WINDOW:
|
||||
g_object_unref (info->window);
|
||||
g_free (info->window_id);
|
||||
break;
|
||||
}
|
||||
g_slice_free (ShellAppInfo, info);
|
||||
}
|
||||
@ -116,6 +137,23 @@ shell_app_info_new_from_tree_item (GMenuTreeItem *item)
|
||||
return info;
|
||||
}
|
||||
|
||||
static ShellAppInfo *
|
||||
shell_app_info_new_from_window (MetaWindow *window)
|
||||
{
|
||||
ShellAppInfo *info;
|
||||
|
||||
info = g_slice_alloc (sizeof (ShellAppInfo));
|
||||
info->type = SHELL_APP_INFO_TYPE_WINDOW;
|
||||
info->refcount = 1;
|
||||
info->window = g_object_ref (window);
|
||||
/* For windows, its id is simply its pointer address as a string.
|
||||
* There are various other alternatives, but the address is unique
|
||||
* and unchanging, which is pretty much the best we can do.
|
||||
*/
|
||||
info->window_id = g_strdup_printf ("window:%p", window);
|
||||
return info;
|
||||
}
|
||||
|
||||
static ShellAppInfo *
|
||||
shell_app_info_new_from_keyfile_take_ownership (GKeyFile *keyfile,
|
||||
const char *path)
|
||||
@ -193,6 +231,9 @@ shell_app_system_init (ShellAppSystem *self)
|
||||
priv->app_id_to_app = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
NULL, (GDestroyNotify) shell_app_info_unref);
|
||||
|
||||
priv->cached_menu_contents = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
g_free, free_appinfo_gslist);
|
||||
|
||||
/* For now, we want to pick up Evince, Nautilus, etc. We'll
|
||||
* handle NODISPLAY semantics at a higher level or investigate them
|
||||
* case by case.
|
||||
@ -200,8 +241,10 @@ shell_app_system_init (ShellAppSystem *self)
|
||||
priv->apps_tree = gmenu_tree_lookup ("applications.menu", GMENU_TREE_FLAGS_INCLUDE_NODISPLAY);
|
||||
priv->settings_tree = gmenu_tree_lookup ("settings.menu", GMENU_TREE_FLAGS_NONE);
|
||||
|
||||
gmenu_tree_add_monitor (priv->apps_tree, on_tree_changed, self);
|
||||
gmenu_tree_add_monitor (priv->settings_tree, on_tree_changed, self);
|
||||
priv->app_change_timeout_id = 0;
|
||||
|
||||
gmenu_tree_add_monitor (priv->apps_tree, on_tree_changed_cb, self);
|
||||
gmenu_tree_add_monitor (priv->settings_tree, on_tree_changed_cb, self);
|
||||
|
||||
reread_menus (self);
|
||||
|
||||
@ -218,12 +261,14 @@ shell_app_system_finalize (GObject *object)
|
||||
ShellAppSystem *self = SHELL_APP_SYSTEM (object);
|
||||
ShellAppSystemPrivate *priv = self->priv;
|
||||
|
||||
gmenu_tree_remove_monitor (priv->apps_tree, on_tree_changed, self);
|
||||
gmenu_tree_remove_monitor (priv->settings_tree, on_tree_changed, self);
|
||||
gmenu_tree_remove_monitor (priv->apps_tree, on_tree_changed_cb, self);
|
||||
gmenu_tree_remove_monitor (priv->settings_tree, on_tree_changed_cb, self);
|
||||
|
||||
gmenu_tree_unref (priv->apps_tree);
|
||||
gmenu_tree_unref (priv->settings_tree);
|
||||
|
||||
g_hash_table_destroy (priv->cached_menu_contents);
|
||||
|
||||
g_hash_table_destroy (priv->app_id_to_app);
|
||||
|
||||
g_slist_foreach (priv->cached_app_menus, (GFunc)shell_app_menu_entry_free, NULL);
|
||||
@ -241,6 +286,14 @@ shell_app_system_finalize (GObject *object)
|
||||
G_OBJECT_CLASS (shell_app_system_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void
|
||||
free_appinfo_gslist (gpointer listp)
|
||||
{
|
||||
GSList *list = listp;
|
||||
g_slist_foreach (list, (GFunc) shell_app_info_unref, NULL);
|
||||
g_slist_free (list);
|
||||
}
|
||||
|
||||
static void
|
||||
reread_directories (ShellAppSystem *self, GSList **cache, GMenuTree *tree)
|
||||
{
|
||||
@ -377,14 +430,43 @@ reread_menus (ShellAppSystem *self)
|
||||
cache_by_id (self, self->priv->cached_settings, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
on_tree_changed (GMenuTree *monitor, gpointer user_data)
|
||||
static gboolean
|
||||
on_tree_changed (gpointer user_data)
|
||||
{
|
||||
ShellAppSystem *self = SHELL_APP_SYSTEM (user_data);
|
||||
|
||||
reread_menus (self);
|
||||
g_hash_table_remove_all (self->priv->cached_menu_contents);
|
||||
|
||||
g_signal_emit (self, signals[INSTALLED_CHANGED], 0);
|
||||
|
||||
reread_menus (self);
|
||||
self->priv->app_change_timeout_id = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
on_tree_changed_cb (GMenuTree *monitor, gpointer user_data)
|
||||
{
|
||||
ShellAppSystem *self = SHELL_APP_SYSTEM (user_data);
|
||||
|
||||
/* GMenu currently gives us a separate notification on the entire
|
||||
* menu tree for each node in the tree that might potentially have
|
||||
* changed. (See http://bugzilla.gnome.org/show_bug.cgi?id=172046.)
|
||||
* We need to compress these to avoid doing large extra amounts of
|
||||
* work.
|
||||
*
|
||||
* Even when that bug is fixed, compression is still useful; for one
|
||||
* thing we want to need to compress across notifications of changes
|
||||
* to the settings tree. Second we want to compress if multiple
|
||||
* changes are made to the desktop files at different times but in
|
||||
* short succession.
|
||||
*/
|
||||
|
||||
if (self->priv->app_change_timeout_id != 0)
|
||||
return;
|
||||
self->priv->app_change_timeout_id = g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, 3000,
|
||||
(GSourceFunc) on_tree_changed,
|
||||
self, NULL);
|
||||
}
|
||||
|
||||
static GList *
|
||||
@ -474,26 +556,32 @@ shell_app_menu_entry_get_type (void)
|
||||
* shell_app_system_get_applications_for_menu:
|
||||
*
|
||||
* Traverses a toplevel menu, and returns all items under it. Nested items
|
||||
* are flattened.
|
||||
* are flattened. This value is computed on initial call and cached thereafter
|
||||
* until the set of installed applications changes.
|
||||
*
|
||||
* Return value: (transfer container) (element-type ShellAppInfo): List of applications
|
||||
* Return value: (transfer none) (element-type ShellAppInfo): List of applications
|
||||
*/
|
||||
GSList *
|
||||
shell_app_system_get_applications_for_menu (ShellAppSystem *monitor,
|
||||
shell_app_system_get_applications_for_menu (ShellAppSystem *self,
|
||||
const char *menu)
|
||||
{
|
||||
char *path;
|
||||
GMenuTreeDirectory *menu_entry;
|
||||
GSList *apps;
|
||||
|
||||
path = g_strdup_printf ("/%s", menu);
|
||||
menu_entry = gmenu_tree_get_directory_from_path (monitor->priv->apps_tree, path);
|
||||
g_free (path);
|
||||
g_assert (menu_entry != NULL);
|
||||
apps = g_hash_table_lookup (self->priv->cached_menu_contents, menu);
|
||||
if (!apps)
|
||||
{
|
||||
char *path;
|
||||
GMenuTreeDirectory *menu_entry;
|
||||
path = g_strdup_printf ("/%s", menu);
|
||||
menu_entry = gmenu_tree_get_directory_from_path (self->priv->apps_tree, path);
|
||||
g_free (path);
|
||||
g_assert (menu_entry != NULL);
|
||||
|
||||
apps = gather_entries_recurse (monitor, NULL, menu_entry);
|
||||
apps = gather_entries_recurse (self, NULL, menu_entry);
|
||||
g_hash_table_insert (self->priv->cached_menu_contents, g_strdup (menu), apps);
|
||||
|
||||
gmenu_tree_item_unref (menu_entry);
|
||||
gmenu_tree_item_unref (menu_entry);
|
||||
}
|
||||
|
||||
return apps;
|
||||
}
|
||||
@ -573,8 +661,6 @@ set_gconf_value_string_list (GConfValue *val, GList *items)
|
||||
g_slist_free (tmp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
shell_app_system_add_favorite (ShellAppSystem *system, const char *id)
|
||||
{
|
||||
@ -669,6 +755,21 @@ shell_app_system_load_from_desktop_file (ShellAppSystem *system,
|
||||
return appinfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_app_system_create_from_window:
|
||||
*
|
||||
* In the case where we can't otherwise determine an application
|
||||
* associated with a window, this function can create a "fake"
|
||||
* application just backed by information from the window itself.
|
||||
*
|
||||
* Return value: (transfer full): A new #ShellAppInfo
|
||||
*/
|
||||
ShellAppInfo *
|
||||
shell_app_system_create_from_window (ShellAppSystem *system, MetaWindow *window)
|
||||
{
|
||||
return shell_app_info_new_from_window (window);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_app_system_lookup_heuristic_basename:
|
||||
* @name: Probable application identifier
|
||||
@ -683,28 +784,22 @@ ShellAppInfo *
|
||||
shell_app_system_lookup_heuristic_basename (ShellAppSystem *system,
|
||||
const char *name)
|
||||
{
|
||||
char *tmpid;
|
||||
ShellAppInfo *result;
|
||||
char **vendor_prefixes;
|
||||
|
||||
result = shell_app_system_lookup_cached_app (system, name);
|
||||
if (result != NULL)
|
||||
return result;
|
||||
|
||||
/* These are common "vendor prefixes". But using
|
||||
* WM_CLASS as a source, we don't get the vendor
|
||||
* prefix. So try stripping them.
|
||||
*/
|
||||
tmpid = g_strjoin ("", "gnome-", name, NULL);
|
||||
result = shell_app_system_lookup_cached_app (system, tmpid);
|
||||
g_free (tmpid);
|
||||
if (result != NULL)
|
||||
return result;
|
||||
|
||||
tmpid = g_strjoin ("", "fedora-", name, NULL);
|
||||
result = shell_app_system_lookup_cached_app (system, tmpid);
|
||||
g_free (tmpid);
|
||||
if (result != NULL)
|
||||
return result;
|
||||
for (vendor_prefixes = (char**)known_vendor_prefixes;
|
||||
*vendor_prefixes; vendor_prefixes++)
|
||||
{
|
||||
char *tmpid = g_strjoin (NULL, *vendor_prefixes, "-", name, NULL);
|
||||
result = shell_app_system_lookup_cached_app (system, tmpid);
|
||||
g_free (tmpid);
|
||||
if (result != NULL)
|
||||
return result;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@ -718,6 +813,8 @@ shell_app_info_get_id (ShellAppInfo *info)
|
||||
return gmenu_tree_entry_get_desktop_file_id ((GMenuTreeEntry*)info->entry);
|
||||
case SHELL_APP_INFO_TYPE_DESKTOP_FILE:
|
||||
return info->keyfile_path;
|
||||
case SHELL_APP_INFO_TYPE_WINDOW:
|
||||
return info->window_id;
|
||||
}
|
||||
g_assert_not_reached ();
|
||||
return NULL;
|
||||
@ -734,6 +831,12 @@ shell_app_info_get_name (ShellAppInfo *info)
|
||||
return g_strdup (gmenu_tree_entry_get_name ((GMenuTreeEntry*)info->entry));
|
||||
case SHELL_APP_INFO_TYPE_DESKTOP_FILE:
|
||||
return g_key_file_get_locale_string (info->keyfile, DESKTOP_ENTRY_GROUP, "Name", NULL, NULL);
|
||||
case SHELL_APP_INFO_TYPE_WINDOW:
|
||||
{
|
||||
char *title;
|
||||
g_object_get (info->window, "title", &title, NULL);
|
||||
return title;
|
||||
}
|
||||
}
|
||||
g_assert_not_reached ();
|
||||
return NULL;
|
||||
@ -748,6 +851,8 @@ shell_app_info_get_description (ShellAppInfo *info)
|
||||
return g_strdup (gmenu_tree_entry_get_comment ((GMenuTreeEntry*)info->entry));
|
||||
case SHELL_APP_INFO_TYPE_DESKTOP_FILE:
|
||||
return g_key_file_get_locale_string (info->keyfile, DESKTOP_ENTRY_GROUP, "Comment", NULL, NULL);
|
||||
case SHELL_APP_INFO_TYPE_WINDOW:
|
||||
return NULL;
|
||||
}
|
||||
g_assert_not_reached ();
|
||||
return NULL;
|
||||
@ -762,6 +867,8 @@ shell_app_info_get_executable (ShellAppInfo *info)
|
||||
return g_strdup (gmenu_tree_entry_get_exec ((GMenuTreeEntry*)info->entry));
|
||||
case SHELL_APP_INFO_TYPE_DESKTOP_FILE:
|
||||
return g_key_file_get_string (info->keyfile, DESKTOP_ENTRY_GROUP, "Exec", NULL);
|
||||
case SHELL_APP_INFO_TYPE_WINDOW:
|
||||
return NULL;
|
||||
}
|
||||
g_assert_not_reached ();
|
||||
return NULL;
|
||||
@ -775,13 +882,49 @@ shell_app_info_get_desktop_file_path (ShellAppInfo *info)
|
||||
case SHELL_APP_INFO_TYPE_ENTRY:
|
||||
return g_strdup (gmenu_tree_entry_get_desktop_file_path ((GMenuTreeEntry*)info->entry));
|
||||
case SHELL_APP_INFO_TYPE_DESKTOP_FILE:
|
||||
return g_strdup (info->keyfile_path);;
|
||||
return g_strdup (info->keyfile_path);
|
||||
case SHELL_APP_INFO_TYPE_WINDOW:
|
||||
return NULL;
|
||||
}
|
||||
g_assert_not_reached ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GIcon *
|
||||
static GIcon *
|
||||
themed_icon_from_name (const char *iconname)
|
||||
{
|
||||
GIcon *icon;
|
||||
|
||||
if (!iconname)
|
||||
return NULL;
|
||||
|
||||
if (g_path_is_absolute (iconname))
|
||||
{
|
||||
GFile *file;
|
||||
file = g_file_new_for_path (iconname);
|
||||
icon = G_ICON (g_file_icon_new (file));
|
||||
g_object_unref (file);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *tmp_name, *p;
|
||||
tmp_name = strdup (iconname);
|
||||
/* Work around a common mistake in desktop files */
|
||||
if ((p = strrchr (tmp_name, '.')) != NULL &&
|
||||
(strcmp (p, ".png") == 0 ||
|
||||
strcmp (p, ".xpm") == 0 ||
|
||||
strcmp (p, ".svg") == 0))
|
||||
{
|
||||
*p = 0;
|
||||
}
|
||||
icon = g_themed_icon_new (tmp_name);
|
||||
g_free (tmp_name);
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
static GIcon *
|
||||
shell_app_info_get_icon (ShellAppInfo *info)
|
||||
{
|
||||
char *iconname = NULL;
|
||||
@ -796,43 +939,18 @@ shell_app_info_get_icon (ShellAppInfo *info)
|
||||
switch (info->type)
|
||||
{
|
||||
case SHELL_APP_INFO_TYPE_ENTRY:
|
||||
iconname = g_strdup (gmenu_tree_entry_get_icon ((GMenuTreeEntry*)info->entry));
|
||||
break;
|
||||
return themed_icon_from_name (gmenu_tree_entry_get_icon ((GMenuTreeEntry*)info->entry));
|
||||
case SHELL_APP_INFO_TYPE_DESKTOP_FILE:
|
||||
iconname = g_key_file_get_locale_string (info->keyfile, DESKTOP_ENTRY_GROUP, "Icon", NULL, NULL);
|
||||
icon = themed_icon_from_name (iconname);
|
||||
g_free (iconname);
|
||||
return icon;
|
||||
break;
|
||||
case SHELL_APP_INFO_TYPE_WINDOW:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!iconname)
|
||||
return NULL;
|
||||
|
||||
if (g_path_is_absolute (iconname))
|
||||
{
|
||||
GFile *file;
|
||||
|
||||
file = g_file_new_for_path (iconname);
|
||||
icon = G_ICON (g_file_icon_new (file));
|
||||
g_object_unref (file);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *tmp_name, *p;
|
||||
tmp_name = strdup (iconname);
|
||||
/* Work around a common mistake in desktop files */
|
||||
if ((p = strrchr (tmp_name, '.')) != NULL &&
|
||||
(strcmp (p, ".png") == 0 ||
|
||||
strcmp (p, ".xpm") == 0 ||
|
||||
strcmp (p, ".svg") == 0))
|
||||
{
|
||||
*p = 0;
|
||||
}
|
||||
|
||||
icon = g_themed_icon_new (tmp_name);
|
||||
g_free (tmp_name);
|
||||
}
|
||||
g_free (iconname);
|
||||
|
||||
return icon;
|
||||
g_assert_not_reached ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GSList *
|
||||
@ -847,14 +965,28 @@ shell_app_info_get_is_nodisplay (ShellAppInfo *info)
|
||||
switch (info->type)
|
||||
{
|
||||
case SHELL_APP_INFO_TYPE_ENTRY:
|
||||
return gmenu_tree_entry_get_is_nodisplay ((GMenuTreeEntry*)info);
|
||||
return gmenu_tree_entry_get_is_nodisplay ((GMenuTreeEntry*)info->entry);
|
||||
case SHELL_APP_INFO_TYPE_DESKTOP_FILE:
|
||||
case SHELL_APP_INFO_TYPE_WINDOW:
|
||||
return FALSE;
|
||||
}
|
||||
g_assert_not_reached ();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_app_info_is_transient:
|
||||
*
|
||||
* A "transient" application is one which represents
|
||||
* just an open window, i.e. we don't know how to launch it
|
||||
* again.
|
||||
*/
|
||||
gboolean
|
||||
shell_app_info_is_transient (ShellAppInfo *info)
|
||||
{
|
||||
return info->type == SHELL_APP_INFO_TYPE_WINDOW;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_app_info_create_icon_texture:
|
||||
*
|
||||
@ -869,15 +1001,26 @@ shell_app_info_create_icon_texture (ShellAppInfo *info, float size)
|
||||
GIcon *icon;
|
||||
ClutterActor *ret;
|
||||
|
||||
if (info->type == SHELL_APP_INFO_TYPE_WINDOW)
|
||||
{
|
||||
return shell_texture_cache_bind_pixbuf_property (shell_texture_cache_get_default (),
|
||||
G_OBJECT (info->window),
|
||||
"icon");
|
||||
}
|
||||
|
||||
icon = shell_app_info_get_icon (info);
|
||||
if (!icon)
|
||||
if (icon == NULL)
|
||||
{
|
||||
ret = clutter_texture_new ();
|
||||
g_object_set (ret, "opacity", 0, "width", size, "height", size, NULL);
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = shell_texture_cache_load_gicon (shell_texture_cache_get_default (), icon, (int)size);
|
||||
g_object_unref (icon);
|
||||
}
|
||||
|
||||
return shell_texture_cache_load_gicon (shell_texture_cache_get_default (), icon, (int)size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -907,6 +1050,17 @@ shell_app_info_launch_full (ShellAppInfo *info,
|
||||
if (startup_id)
|
||||
*startup_id = NULL;
|
||||
|
||||
if (info->type == SHELL_APP_INFO_TYPE_WINDOW)
|
||||
{
|
||||
/* We can't pass URIs into a window; shouldn't hit this
|
||||
* code path. If we do, fix the caller to disallow it.
|
||||
*/
|
||||
g_return_val_if_fail (uris == NULL, TRUE);
|
||||
|
||||
meta_window_activate (info->window, timestamp);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
filename = shell_app_info_get_desktop_file_path (info);
|
||||
gapp = g_desktop_app_info_new_from_filename (filename);
|
||||
g_free (filename);
|
||||
@ -922,7 +1076,13 @@ shell_app_info_launch_full (ShellAppInfo *info,
|
||||
display = meta_screen_get_display (screen);
|
||||
|
||||
if (timestamp == 0)
|
||||
timestamp = meta_display_get_current_time (display);
|
||||
timestamp = clutter_get_current_event_time ();
|
||||
|
||||
/* Shell design calls for on application launch, no window is focused,
|
||||
* and we have startup notification displayed.
|
||||
*/
|
||||
meta_display_focus_the_no_focus_window (display, screen, timestamp);
|
||||
|
||||
if (workspace < 0)
|
||||
workspace = meta_screen_get_active_workspace_index (screen);
|
||||
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include <gio/gio.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include "window.h"
|
||||
|
||||
#define SHELL_TYPE_APP_SYSTEM (shell_app_system_get_type ())
|
||||
#define SHELL_APP_SYSTEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_APP_SYSTEM, ShellAppSystem))
|
||||
#define SHELL_APP_SYSTEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_APP_SYSTEM, ShellAppSystemClass))
|
||||
@ -58,10 +60,10 @@ char *shell_app_info_get_name (ShellAppInfo *info);
|
||||
char *shell_app_info_get_description (ShellAppInfo *info);
|
||||
char *shell_app_info_get_executable (ShellAppInfo *info);
|
||||
char *shell_app_info_get_desktop_file_path (ShellAppInfo *info);
|
||||
GIcon *shell_app_info_get_icon (ShellAppInfo *info);
|
||||
ClutterActor *shell_app_info_create_icon_texture (ShellAppInfo *info, float size);
|
||||
GSList *shell_app_info_get_categories (ShellAppInfo *info);
|
||||
gboolean shell_app_info_get_is_nodisplay (ShellAppInfo *info);
|
||||
gboolean shell_app_info_is_transient (ShellAppInfo *info);
|
||||
gboolean shell_app_info_launch_full (ShellAppInfo *info,
|
||||
guint timestamp,
|
||||
GList *uris,
|
||||
@ -77,6 +79,8 @@ ShellAppInfo *shell_app_system_lookup_cached_app (ShellAppSystem *system, const
|
||||
|
||||
ShellAppInfo *shell_app_system_lookup_heuristic_basename (ShellAppSystem *system, const char *id);
|
||||
|
||||
ShellAppInfo *shell_app_system_create_from_window (ShellAppSystem *system, MetaWindow *window);
|
||||
|
||||
GSList *shell_app_system_get_menus (ShellAppSystem *system);
|
||||
|
||||
GSList *shell_app_system_get_all_settings (ShellAppSystem *system);
|
||||
|
317
src/shell-button-box.c
Normal file
@ -0,0 +1,317 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/**
|
||||
* SECTION:shell-button-box
|
||||
* @short_description: A box with properties useful for implementing buttons
|
||||
*
|
||||
* A #BigBox subclass which translates lower-level Clutter button events
|
||||
* into higher level properties which are useful for implementing "button-like"
|
||||
* actors.
|
||||
*/
|
||||
|
||||
#include "shell-button-box.h"
|
||||
|
||||
G_DEFINE_TYPE(ShellButtonBox, shell_button_box, BIG_TYPE_BOX);
|
||||
|
||||
struct _ShellButtonBoxPrivate {
|
||||
gboolean active;
|
||||
gboolean held;
|
||||
gboolean hover;
|
||||
gboolean pressed;
|
||||
};
|
||||
|
||||
/* Signals */
|
||||
enum
|
||||
{
|
||||
ACTIVATE,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
|
||||
PROP_ACTIVE,
|
||||
PROP_HOVER,
|
||||
PROP_PRESSED,
|
||||
};
|
||||
|
||||
static guint shell_button_box_signals [LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void
|
||||
set_active (ShellButtonBox *box,
|
||||
gboolean active)
|
||||
{
|
||||
if (box->priv->active == active)
|
||||
return;
|
||||
box->priv->active = active;
|
||||
g_object_notify (G_OBJECT (box), "active");
|
||||
}
|
||||
|
||||
static void
|
||||
set_hover (ShellButtonBox *box,
|
||||
gboolean hover)
|
||||
{
|
||||
if (box->priv->hover == hover)
|
||||
return;
|
||||
box->priv->hover = hover;
|
||||
g_object_notify (G_OBJECT (box), "hover");
|
||||
}
|
||||
|
||||
static void
|
||||
set_pressed (ShellButtonBox *box,
|
||||
gboolean pressed)
|
||||
{
|
||||
if (box->priv->pressed == pressed)
|
||||
return;
|
||||
box->priv->pressed = pressed;
|
||||
g_object_notify (G_OBJECT (box), "pressed");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
shell_button_box_contains (ShellButtonBox *box,
|
||||
ClutterActor *actor)
|
||||
{
|
||||
while (actor != NULL && actor != (ClutterActor*)box)
|
||||
{
|
||||
actor = clutter_actor_get_parent (actor);
|
||||
}
|
||||
return actor != NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
shell_button_box_enter_event (ClutterActor *actor,
|
||||
ClutterCrossingEvent *event)
|
||||
{
|
||||
ShellButtonBox *box = SHELL_BUTTON_BOX (actor);
|
||||
|
||||
if (shell_button_box_contains (box, event->related))
|
||||
return TRUE;
|
||||
if (!shell_button_box_contains (box, event->source))
|
||||
return TRUE;
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (actor));
|
||||
|
||||
if (box->priv->held)
|
||||
set_pressed (box, TRUE);
|
||||
set_hover (box, TRUE);
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (actor));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
shell_button_box_leave_event (ClutterActor *actor,
|
||||
ClutterCrossingEvent *event)
|
||||
{
|
||||
ShellButtonBox *box = SHELL_BUTTON_BOX (actor);
|
||||
|
||||
if (shell_button_box_contains (box, event->related))
|
||||
return TRUE;
|
||||
|
||||
set_hover (box, FALSE);
|
||||
set_pressed (box, FALSE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
shell_button_box_button_press_event (ClutterActor *actor,
|
||||
ClutterButtonEvent *event)
|
||||
{
|
||||
ShellButtonBox *box = SHELL_BUTTON_BOX (actor);
|
||||
|
||||
if (event->button != 1 || event->click_count != 1)
|
||||
return FALSE;
|
||||
|
||||
if (box->priv->held)
|
||||
return TRUE;
|
||||
|
||||
if (!shell_button_box_contains (box, event->source))
|
||||
return FALSE;
|
||||
|
||||
box->priv->held = TRUE;
|
||||
clutter_grab_pointer (CLUTTER_ACTOR (box));
|
||||
|
||||
set_pressed (box, TRUE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
shell_button_box_button_release_event (ClutterActor *actor,
|
||||
ClutterButtonEvent *event)
|
||||
{
|
||||
ShellButtonBox *box = SHELL_BUTTON_BOX (actor);
|
||||
|
||||
if (event->button != 1 || event->click_count != 1)
|
||||
return FALSE;
|
||||
|
||||
if (!box->priv->held)
|
||||
return TRUE;
|
||||
|
||||
box->priv->held = FALSE;
|
||||
clutter_ungrab_pointer ();
|
||||
|
||||
if (!shell_button_box_contains (box, event->source))
|
||||
return FALSE;
|
||||
|
||||
set_pressed (box, FALSE);
|
||||
|
||||
g_signal_emit (G_OBJECT (box), shell_button_box_signals[ACTIVATE], 0, event);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_button_box_fake_release:
|
||||
* @box:
|
||||
*
|
||||
* If this button box is holding a pointer grab, this function will
|
||||
* will ungrab it, and reset the pressed state. The effect is
|
||||
* similar to if the user had released the mouse button, but without
|
||||
* emitting the activate signal.
|
||||
*
|
||||
* This function is useful if for example you want to do something after the user
|
||||
* is holding the mouse button for a given period of time, breaking the
|
||||
* grab.
|
||||
*/
|
||||
void
|
||||
shell_button_box_fake_release (ShellButtonBox *box)
|
||||
{
|
||||
if (!box->priv->held)
|
||||
return;
|
||||
|
||||
box->priv->held = FALSE;
|
||||
clutter_ungrab_pointer ();
|
||||
|
||||
set_pressed (box, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_button_box_set_property(GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ShellButtonBox *box = SHELL_BUTTON_BOX (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ACTIVE:
|
||||
set_active (box, g_value_get_boolean (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
shell_button_box_get_property(GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ShellButtonBox *box = SHELL_BUTTON_BOX (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ACTIVE:
|
||||
g_value_set_boolean (value, box->priv->active);
|
||||
break;
|
||||
case PROP_PRESSED:
|
||||
g_value_set_boolean (value, box->priv->pressed);
|
||||
break;
|
||||
case PROP_HOVER:
|
||||
g_value_set_boolean (value, box->priv->hover);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
shell_button_box_class_init (ShellButtonBoxClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
||||
|
||||
gobject_class->get_property = shell_button_box_get_property;
|
||||
gobject_class->set_property = shell_button_box_set_property;
|
||||
|
||||
actor_class->enter_event = shell_button_box_enter_event;
|
||||
actor_class->leave_event = shell_button_box_leave_event;
|
||||
actor_class->button_press_event = shell_button_box_button_press_event;
|
||||
actor_class->button_release_event = shell_button_box_button_release_event;
|
||||
|
||||
/**
|
||||
* ShellButtonBox::activate
|
||||
* @box: The #ShellButtonBox
|
||||
* @event: Release event which triggered the activation
|
||||
*
|
||||
* This signal is emitted when the button should take the action
|
||||
* associated with button click+release.
|
||||
*/
|
||||
shell_button_box_signals[ACTIVATE] =
|
||||
g_signal_new ("activate",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 1, CLUTTER_TYPE_EVENT);
|
||||
|
||||
/**
|
||||
* ShellButtonBox:active
|
||||
*
|
||||
* The property allows the button to be used as a "toggle button"; it's up to the
|
||||
* application to update the active property in response to the activate signal;
|
||||
* it doesn't happen automatically.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_ACTIVE,
|
||||
g_param_spec_boolean ("active",
|
||||
"Active",
|
||||
"Whether the button persistently active",
|
||||
FALSE,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* ShellButtonBox:hover
|
||||
*
|
||||
* This property tracks whether the mouse is over the button; note this
|
||||
* state is independent of whether the button is pressed.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_HOVER,
|
||||
g_param_spec_boolean ("hover",
|
||||
"Hovering state",
|
||||
"Whether the mouse is over the button",
|
||||
FALSE,
|
||||
G_PARAM_READABLE));
|
||||
|
||||
/**
|
||||
* ShellButtonBox:pressed
|
||||
*
|
||||
* This property tracks whether the button should have a "pressed in"
|
||||
* effect.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_PRESSED,
|
||||
g_param_spec_boolean ("pressed",
|
||||
"Pressed state",
|
||||
"Whether the button is currently pressed",
|
||||
FALSE,
|
||||
G_PARAM_READABLE));
|
||||
|
||||
g_type_class_add_private (gobject_class, sizeof (ShellButtonBoxPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
shell_button_box_init (ShellButtonBox *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, SHELL_TYPE_BUTTON_BOX,
|
||||
ShellButtonBoxPrivate);
|
||||
}
|
35
src/shell-button-box.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef __SHELL_BUTTON_BOX_H__
|
||||
#define __SHELL_BUTTON_BOX_H__
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include "big/box.h"
|
||||
|
||||
#define SHELL_TYPE_BUTTON_BOX (shell_button_box_get_type ())
|
||||
#define SHELL_BUTTON_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_BUTTON_BOX, ShellButtonBox))
|
||||
#define SHELL_BUTTON_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_BUTTON_BOX, ShellButtonBoxClass))
|
||||
#define SHELL_IS_BUTTON_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_TYPE_BUTTON_BOX))
|
||||
#define SHELL_IS_BUTTON_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_BUTTON_BOX))
|
||||
#define SHELL_BUTTON_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_BUTTON_BOX, ShellButtonBoxClass))
|
||||
|
||||
typedef struct _ShellButtonBox ShellButtonBox;
|
||||
typedef struct _ShellButtonBoxClass ShellButtonBoxClass;
|
||||
|
||||
typedef struct _ShellButtonBoxPrivate ShellButtonBoxPrivate;
|
||||
|
||||
struct _ShellButtonBox
|
||||
{
|
||||
BigBox parent;
|
||||
|
||||
ShellButtonBoxPrivate *priv;
|
||||
};
|
||||
|
||||
struct _ShellButtonBoxClass
|
||||
{
|
||||
BigBoxClass parent_class;
|
||||
};
|
||||
|
||||
GType shell_button_box_get_type (void) G_GNUC_CONST;
|
||||
|
||||
void shell_button_box_fake_release (ShellButtonBox *box);
|
||||
|
||||
#endif /* __SHELL_BUTTON_BOX_H__ */
|
@ -40,8 +40,18 @@ shell_drawing_area_allocate (ClutterActor *self,
|
||||
ShellDrawingArea *area = SHELL_DRAWING_AREA (self);
|
||||
int width = box->x2 - box->x1;
|
||||
int height = box->y2 - box->y1;
|
||||
ClutterActorBox child_box;
|
||||
|
||||
clutter_actor_allocate (CLUTTER_ACTOR (area->priv->texture), box, flags);
|
||||
/* Chain up directly to ClutterActor to set actor->allocation. We explicitly skip our parent class
|
||||
* ClutterGroup here because we want to override the allocate function. */
|
||||
(CLUTTER_ACTOR_CLASS (g_type_class_peek (clutter_actor_get_type ())))->allocate (self, box, flags);
|
||||
|
||||
child_box.x1 = 0;
|
||||
child_box.x2 = width;
|
||||
child_box.y1 = 0;
|
||||
child_box.y2 = height;
|
||||
|
||||
clutter_actor_allocate (CLUTTER_ACTOR (area->priv->texture), &child_box, flags);
|
||||
if (width > 0 && height > 0)
|
||||
{
|
||||
clutter_cairo_texture_set_surface_size (area->priv->texture,
|
||||
|
@ -147,35 +147,59 @@ shell_draw_clock (ClutterCairoTexture *texture,
|
||||
}
|
||||
|
||||
void
|
||||
shell_draw_glow (ClutterCairoTexture *texture,
|
||||
double red,
|
||||
double green,
|
||||
double blue,
|
||||
double alpha)
|
||||
shell_draw_box_pointer (ClutterCairoTexture *texture,
|
||||
ShellPointerDirection direction,
|
||||
ClutterColor *border_color,
|
||||
ClutterColor *background_color)
|
||||
{
|
||||
cairo_t *cr;
|
||||
guint width, height;
|
||||
cairo_pattern_t *gradient;
|
||||
cairo_t *cr;
|
||||
|
||||
clutter_cairo_texture_get_surface_size (texture, &width, &height);
|
||||
|
||||
clutter_cairo_texture_clear (texture);
|
||||
cr = clutter_cairo_texture_create (texture);
|
||||
|
||||
cairo_save (cr);
|
||||
cairo_translate (cr, width / 2.0, height / 2.0);
|
||||
cairo_scale (cr, width / 2.0, height / 2.0);
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
|
||||
gradient = cairo_pattern_create_radial (0.0, 0.0, 0.0, 0.0, 0.0, 1.0);
|
||||
cairo_pattern_add_color_stop_rgba (gradient, 0.0, red, green, blue, alpha);
|
||||
cairo_pattern_add_color_stop_rgba (gradient, 0.7, red, green, blue, alpha * 0.7);
|
||||
cairo_pattern_add_color_stop_rgba (gradient, 1.0, red, green, blue, alpha * 0.3);
|
||||
cairo_set_source (cr, gradient);
|
||||
clutter_cairo_set_source_color (cr, border_color);
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
case SHELL_POINTER_UP:
|
||||
cairo_move_to (cr, 0, height);
|
||||
cairo_line_to (cr, floor (width * 0.5), 0);
|
||||
cairo_line_to (cr, width, height);
|
||||
break;
|
||||
|
||||
case SHELL_POINTER_DOWN:
|
||||
cairo_move_to (cr, width, 0);
|
||||
cairo_line_to (cr, floor (width * 0.5), height);
|
||||
cairo_line_to (cr, 0, 0);
|
||||
break;
|
||||
|
||||
case SHELL_POINTER_LEFT:
|
||||
cairo_move_to (cr, width, height);
|
||||
cairo_line_to (cr, 0, floor (height * 0.5));
|
||||
cairo_line_to (cr, width, 0);
|
||||
break;
|
||||
|
||||
case SHELL_POINTER_RIGHT:
|
||||
cairo_move_to (cr, 0, 0);
|
||||
cairo_line_to (cr, width, floor (height * 0.5));
|
||||
cairo_line_to (cr, 0, height);
|
||||
break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
cairo_stroke_preserve (cr);
|
||||
|
||||
clutter_cairo_set_source_color (cr, background_color);
|
||||
|
||||
cairo_arc (cr, 0.0, 0.0, 1.0, 0.0, 2.0 * M_PI);
|
||||
cairo_fill (cr);
|
||||
cairo_restore (cr);
|
||||
cairo_pattern_destroy (gradient);
|
||||
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
@ -186,25 +210,20 @@ hook_paint_red_border (ClutterActor *actor,
|
||||
CoglColor color;
|
||||
ClutterGeometry geom;
|
||||
float width = 2;
|
||||
float x2;
|
||||
float y2;
|
||||
|
||||
cogl_color_set_from_4ub (&color, 0xff, 0, 0, 0xc4);
|
||||
cogl_set_source_color (&color);
|
||||
|
||||
clutter_actor_get_allocation_geometry (actor, &geom);
|
||||
x2 = geom.x + geom.width;
|
||||
y2 = geom.y + geom.height;
|
||||
|
||||
/** clockwise order **/
|
||||
cogl_rectangle (geom.x, geom.y,
|
||||
x2, geom.y + width);
|
||||
cogl_rectangle (x2 - width, geom.y + width,
|
||||
x2, y2);
|
||||
cogl_rectangle (x2 - width, y2,
|
||||
geom.x, y2 - width);
|
||||
cogl_rectangle (geom.x + width, y2 - width,
|
||||
geom.x, geom.y + width);
|
||||
cogl_rectangle (0, 0, geom.width, width);
|
||||
cogl_rectangle (geom.width - width, width,
|
||||
geom.width, geom.height);
|
||||
cogl_rectangle (0, geom.height,
|
||||
geom.width - width, geom.height - width);
|
||||
cogl_rectangle (0, geom.height - width,
|
||||
width, width);
|
||||
}
|
||||
|
||||
guint
|
||||
|
@ -13,16 +13,22 @@ ClutterCairoTexture *shell_create_vertical_gradient (ClutterColor *top,
|
||||
ClutterCairoTexture *shell_create_horizontal_gradient (ClutterColor *left,
|
||||
ClutterColor *right);
|
||||
|
||||
typedef enum {
|
||||
SHELL_POINTER_UP,
|
||||
SHELL_POINTER_DOWN,
|
||||
SHELL_POINTER_LEFT,
|
||||
SHELL_POINTER_RIGHT
|
||||
} ShellPointerDirection;
|
||||
|
||||
void shell_draw_box_pointer (ClutterCairoTexture *texture,
|
||||
ShellPointerDirection direction,
|
||||
ClutterColor *border_color,
|
||||
ClutterColor *background_color);
|
||||
|
||||
void shell_draw_clock (ClutterCairoTexture *texture,
|
||||
int hour,
|
||||
int minute);
|
||||
|
||||
void shell_draw_glow (ClutterCairoTexture *texture,
|
||||
double red,
|
||||
double blue,
|
||||
double green,
|
||||
double alpha);
|
||||
|
||||
guint shell_add_hook_paint_red_border (ClutterActor *actor);
|
||||
|
||||
G_END_DECLS
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include <unistd.h>
|
||||
#include <dbus/dbus-glib.h>
|
||||
#include <gio/gio.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <glib/gi18n-lib.h>
|
||||
#include <math.h>
|
||||
#include <X11/extensions/Xfixes.h>
|
||||
|
||||
@ -40,7 +40,7 @@ struct _ShellGlobal {
|
||||
|
||||
MutterPlugin *plugin;
|
||||
ShellWM *wm;
|
||||
gboolean keyboard_grabbed;
|
||||
const char *datadir;
|
||||
const char *imagedir;
|
||||
const char *configdir;
|
||||
|
||||
@ -58,6 +58,7 @@ enum {
|
||||
PROP_STAGE,
|
||||
PROP_WINDOW_GROUP,
|
||||
PROP_WINDOW_MANAGER,
|
||||
PROP_DATADIR,
|
||||
PROP_IMAGEDIR,
|
||||
PROP_CONFIGDIR,
|
||||
};
|
||||
@ -129,6 +130,9 @@ shell_global_get_property(GObject *object,
|
||||
case PROP_WINDOW_MANAGER:
|
||||
g_value_set_object (value, global->wm);
|
||||
break;
|
||||
case PROP_DATADIR:
|
||||
g_value_set_string (value, global->datadir);
|
||||
break;
|
||||
case PROP_IMAGEDIR:
|
||||
g_value_set_string (value, global->imagedir);
|
||||
break;
|
||||
@ -150,6 +154,7 @@ shell_global_init (ShellGlobal *global)
|
||||
|
||||
if (!datadir)
|
||||
datadir = GNOME_SHELL_DATADIR;
|
||||
global->datadir = datadir;
|
||||
|
||||
/* We make sure imagedir ends with a '/', since the JS won't have
|
||||
* access to g_build_filename() and so will end up just
|
||||
@ -255,6 +260,13 @@ shell_global_class_init (ShellGlobalClass *klass)
|
||||
"Window management interface",
|
||||
SHELL_TYPE_WM,
|
||||
G_PARAM_READABLE));
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_DATADIR,
|
||||
g_param_spec_string ("datadir",
|
||||
"Data directory",
|
||||
"Directory containing gnome-shell data files",
|
||||
NULL,
|
||||
G_PARAM_READABLE));
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_IMAGEDIR,
|
||||
g_param_spec_string ("imagedir",
|
||||
@ -296,47 +308,6 @@ shell_clutter_texture_set_from_pixbuf (ClutterTexture *texture,
|
||||
0, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_get_event_key_symbol:
|
||||
*
|
||||
* Return value: Clutter key value for the key press and release events,
|
||||
* as specified in clutter-keysyms.h
|
||||
*/
|
||||
guint16
|
||||
shell_get_event_key_symbol(ClutterEvent *event)
|
||||
{
|
||||
g_return_val_if_fail(event->type == CLUTTER_KEY_PRESS ||
|
||||
event->type == CLUTTER_KEY_RELEASE, 0);
|
||||
|
||||
return event->key.keyval;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_get_button_event_click_count:
|
||||
*
|
||||
* Return value: click count for button press and release events
|
||||
*/
|
||||
guint16
|
||||
shell_get_button_event_click_count(ClutterEvent *event)
|
||||
{
|
||||
g_return_val_if_fail(event->type == CLUTTER_BUTTON_PRESS ||
|
||||
event->type == CLUTTER_BUTTON_RELEASE, 0);
|
||||
return event->button.click_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_get_event_related:
|
||||
*
|
||||
* Return value: (transfer none): related actor
|
||||
*/
|
||||
ClutterActor *
|
||||
shell_get_event_related (ClutterEvent *event)
|
||||
{
|
||||
g_return_val_if_fail (event->type == CLUTTER_ENTER ||
|
||||
event->type == CLUTTER_LEAVE, NULL);
|
||||
return event->crossing.related;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_global_get:
|
||||
*
|
||||
@ -475,66 +446,66 @@ _shell_global_set_plugin (ShellGlobal *global,
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_global_grab_keyboard:
|
||||
* shell_global_begin_modal:
|
||||
* @global: a #ShellGlobal
|
||||
*
|
||||
* Grab the keyboard to the stage window. The stage will receive
|
||||
* all keyboard events until shell_global_ungrab_keyboard() is called.
|
||||
* This is appropriate to do when the desktop goes into a special
|
||||
* mode where no normal global key shortcuts or application keyboard
|
||||
* processing should happen.
|
||||
* Grabs the keyboard and mouse to the stage window. The stage will
|
||||
* receive all keyboard and mouse events until shell_global_end_modal()
|
||||
* is called. This is used to implement "modes" for the shell, such as the
|
||||
* overview mode or the "looking glass" debug overlay, that block
|
||||
* application and normal key shortcuts.
|
||||
*
|
||||
* Returns value: %TRUE if we succesfully entered the mode. %FALSE if we couldn't
|
||||
* enter the mode. Failure may occur because an application has the pointer
|
||||
* or keyboard grabbed, because Mutter is in a mode itself like moving a
|
||||
* window or alt-Tab window selection, or because shell_global_begin_modal()
|
||||
* was previouly called.
|
||||
*/
|
||||
gboolean
|
||||
shell_global_grab_keyboard (ShellGlobal *global)
|
||||
shell_global_begin_modal (ShellGlobal *global,
|
||||
guint32 timestamp)
|
||||
{
|
||||
MetaScreen *screen = mutter_plugin_get_screen (global->plugin);
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
Display *xdisplay = meta_display_get_xdisplay (display);
|
||||
ClutterStage *stage = CLUTTER_STAGE (mutter_plugin_get_stage (global->plugin));
|
||||
Window stagewin = clutter_x11_get_stage_window (stage);
|
||||
|
||||
/* FIXME: we need to coordinate with the rest of Metacity or we
|
||||
* may grab the keyboard away from other portions of Metacity
|
||||
* and leave Metacity in a confused state. An X client is allowed
|
||||
* to overgrab itself, though not allowed to grab they keyboard
|
||||
* away from another applications.
|
||||
*/
|
||||
if (global->keyboard_grabbed)
|
||||
return FALSE;
|
||||
|
||||
if (XGrabKeyboard (xdisplay, stagewin,
|
||||
False, /* owner_events - steal events from the rest of metacity */
|
||||
GrabModeAsync, GrabModeAsync,
|
||||
CurrentTime) != Success)
|
||||
return FALSE; /* probably AlreadyGrabbed, some other app has a keyboard grab */
|
||||
|
||||
global->keyboard_grabbed = TRUE;
|
||||
|
||||
return TRUE;
|
||||
return mutter_plugin_begin_modal (global->plugin, stagewin, None, 0, timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_global_ungrab_keyboard:
|
||||
* shell_global_end_modal:
|
||||
* @global: a #ShellGlobal
|
||||
*
|
||||
* Undoes the effect of shell_global_grab_keyboard
|
||||
* Undoes the effect of shell_global_begin_modal().
|
||||
*/
|
||||
void
|
||||
shell_global_ungrab_keyboard (ShellGlobal *global)
|
||||
shell_global_end_modal (ShellGlobal *global,
|
||||
guint32 timestamp)
|
||||
{
|
||||
MetaScreen *screen;
|
||||
MetaDisplay *display;
|
||||
Display *xdisplay;
|
||||
mutter_plugin_end_modal (global->plugin, timestamp);
|
||||
}
|
||||
|
||||
g_return_if_fail (global->keyboard_grabbed);
|
||||
/**
|
||||
* shell_global_display_is_grabbed
|
||||
* @global: a #ShellGlobal
|
||||
*
|
||||
* Determines whether Mutter currently has a grab (keyboard or mouse or
|
||||
* both) on the display. This could be the result of a current window
|
||||
* management operation like a window move, or could be from
|
||||
* shell_global_begin_modal().
|
||||
*
|
||||
* This function is useful to for ad-hoc checks to avoid over-grabbing
|
||||
* the Mutter grab a grab from GTK+. Longer-term we might instead want a
|
||||
* mechanism to make Mutter use GDK grabs instead of raw XGrabPointer().
|
||||
*
|
||||
* Return value: %TRUE if Mutter has a grab on the display
|
||||
*/
|
||||
gboolean
|
||||
shell_global_display_is_grabbed (ShellGlobal *global)
|
||||
{
|
||||
MetaScreen *screen = mutter_plugin_get_screen (global->plugin);
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
|
||||
screen = mutter_plugin_get_screen (global->plugin);
|
||||
display = meta_screen_get_display (screen);
|
||||
xdisplay = meta_display_get_xdisplay (display);
|
||||
|
||||
XUngrabKeyboard (xdisplay, CurrentTime);
|
||||
|
||||
global->keyboard_grabbed = FALSE;
|
||||
return meta_display_get_grab_op (display) != META_GRAB_OP_NONE;
|
||||
}
|
||||
|
||||
/* Code to close all file descriptors before we exec; copied from gspawn.c in GLib.
|
||||
@ -911,3 +882,138 @@ shell_global_create_root_pixmap_actor (ShellGlobal *global)
|
||||
|
||||
return clutter_clone_new (global->root_pixmap);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_global_get_monitors:
|
||||
* @global: the #ShellGlobal
|
||||
*
|
||||
* Gets a list of the bounding boxes of the active screen's monitors.
|
||||
*
|
||||
* Return value: (transfer full) (element-type GdkRectangle): a list
|
||||
* of monitor bounding boxes.
|
||||
*/
|
||||
GSList *
|
||||
shell_global_get_monitors (ShellGlobal *global)
|
||||
{
|
||||
MetaScreen *screen = shell_global_get_screen (global);
|
||||
GSList *monitors = NULL;
|
||||
MetaRectangle rect;
|
||||
int i;
|
||||
|
||||
g_assert (sizeof (MetaRectangle) == sizeof (GdkRectangle) &&
|
||||
G_STRUCT_OFFSET (MetaRectangle, x) == G_STRUCT_OFFSET (GdkRectangle, x) &&
|
||||
G_STRUCT_OFFSET (MetaRectangle, y) == G_STRUCT_OFFSET (GdkRectangle, y) &&
|
||||
G_STRUCT_OFFSET (MetaRectangle, width) == G_STRUCT_OFFSET (GdkRectangle, width) &&
|
||||
G_STRUCT_OFFSET (MetaRectangle, height) == G_STRUCT_OFFSET (GdkRectangle, height));
|
||||
|
||||
for (i = meta_screen_get_n_monitors (screen) - 1; i >= 0; i--)
|
||||
{
|
||||
meta_screen_get_monitor_geometry (screen, i, &rect);
|
||||
monitors = g_slist_prepend (monitors,
|
||||
g_boxed_copy (GDK_TYPE_RECTANGLE, &rect));
|
||||
}
|
||||
return monitors;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_global_get_primary_monitor:
|
||||
* @global: the #ShellGlobal
|
||||
*
|
||||
* Gets the bounding box of the primary monitor (the one that the
|
||||
* panel is on).
|
||||
*
|
||||
* Return value: the bounding box of the primary monitor
|
||||
*/
|
||||
GdkRectangle *
|
||||
shell_global_get_primary_monitor (ShellGlobal *global)
|
||||
{
|
||||
MetaScreen *screen = shell_global_get_screen (global);
|
||||
MetaRectangle rect;
|
||||
|
||||
g_assert (sizeof (MetaRectangle) == sizeof (GdkRectangle) &&
|
||||
G_STRUCT_OFFSET (MetaRectangle, x) == G_STRUCT_OFFSET (GdkRectangle, x) &&
|
||||
G_STRUCT_OFFSET (MetaRectangle, y) == G_STRUCT_OFFSET (GdkRectangle, y) &&
|
||||
G_STRUCT_OFFSET (MetaRectangle, width) == G_STRUCT_OFFSET (GdkRectangle, width) &&
|
||||
G_STRUCT_OFFSET (MetaRectangle, height) == G_STRUCT_OFFSET (GdkRectangle, height));
|
||||
|
||||
meta_screen_get_monitor_geometry (screen, 0, &rect);
|
||||
return g_boxed_copy (GDK_TYPE_RECTANGLE, &rect);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_global_get_focus_monitor:
|
||||
* @global: the #ShellGlobal
|
||||
*
|
||||
* Gets the bounding box of the monitor containing the window that
|
||||
* currently contains the keyboard focus.
|
||||
*
|
||||
* Return value: the bounding box of the focus monitor
|
||||
*/
|
||||
GdkRectangle *
|
||||
shell_global_get_focus_monitor (ShellGlobal *global)
|
||||
{
|
||||
MetaScreen *screen = shell_global_get_screen (global);
|
||||
MetaDisplay *display = meta_screen_get_display (screen);
|
||||
MetaWindow *focus = meta_display_get_focus_window (display);
|
||||
MetaRectangle rect, wrect;
|
||||
int nmonitors, i;
|
||||
|
||||
if (focus)
|
||||
{
|
||||
meta_window_get_outer_rect (focus, &wrect);
|
||||
nmonitors = meta_screen_get_n_monitors (screen);
|
||||
|
||||
/* Find the monitor that the top-left corner of @focus is on. */
|
||||
for (i = 0; i < nmonitors; i++)
|
||||
{
|
||||
meta_screen_get_monitor_geometry (screen, i, &rect);
|
||||
|
||||
if (rect.x < wrect.x && rect.y < wrect.y &&
|
||||
rect.x + rect.width > wrect.x &&
|
||||
rect.y + rect.height > wrect.y)
|
||||
return g_boxed_copy (GDK_TYPE_RECTANGLE, &rect);
|
||||
}
|
||||
}
|
||||
|
||||
meta_screen_get_monitor_geometry (screen, 0, &rect);
|
||||
return g_boxed_copy (GDK_TYPE_RECTANGLE, &rect);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_global_get_modifier_keys:
|
||||
* @global: the #ShellGlobal
|
||||
*
|
||||
* Gets the current set of modifier keys that are pressed down;
|
||||
* this is a wrapper around gdk_display_get_pointer() that strips
|
||||
* out any un-declared modifier flags, to make gjs happy; see
|
||||
* https://bugzilla.gnome.org/show_bug.cgi?id=597292.
|
||||
*
|
||||
* Return value: the current modifiers
|
||||
*/
|
||||
GdkModifierType
|
||||
shell_global_get_modifier_keys (ShellGlobal *global)
|
||||
{
|
||||
GdkModifierType mods;
|
||||
|
||||
gdk_display_get_pointer (gdk_display_get_default (), NULL, NULL, NULL, &mods);
|
||||
return mods & GDK_MODIFIER_MASK;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_get_event_state:
|
||||
* @event: a #ClutterEvent
|
||||
*
|
||||
* Gets the current state of the event (the set of modifier keys that
|
||||
* are pressed down). Thhis is a wrapper around
|
||||
* clutter_event_get_state() that strips out any un-declared modifier
|
||||
* flags, to make gjs happy; see
|
||||
* https://bugzilla.gnome.org/show_bug.cgi?id=597292.
|
||||
*
|
||||
* Return value: the state from the event
|
||||
*/
|
||||
ClutterModifierType
|
||||
shell_get_event_state (ClutterEvent *event)
|
||||
{
|
||||
ClutterModifierType state = clutter_event_get_state (event);
|
||||
return state & CLUTTER_MODIFIER_MASK;
|
||||
}
|
||||
|
@ -36,10 +36,6 @@ GType shell_global_get_type (void) G_GNUC_CONST;
|
||||
gboolean shell_clutter_texture_set_from_pixbuf (ClutterTexture *texture,
|
||||
GdkPixbuf *pixbuf);
|
||||
|
||||
guint16 shell_get_event_key_symbol(ClutterEvent *event);
|
||||
|
||||
guint16 shell_get_button_event_click_count(ClutterEvent *event);
|
||||
|
||||
ClutterActor *shell_get_event_related(ClutterEvent *event);
|
||||
|
||||
ShellGlobal *shell_global_get (void);
|
||||
@ -64,8 +60,12 @@ GList *shell_global_get_windows (ShellGlobal *global);
|
||||
void _shell_global_set_plugin (ShellGlobal *global,
|
||||
MutterPlugin *plugin);
|
||||
|
||||
gboolean shell_global_grab_keyboard (ShellGlobal *global);
|
||||
void shell_global_ungrab_keyboard (ShellGlobal *global);
|
||||
gboolean shell_global_begin_modal (ShellGlobal *global,
|
||||
guint32 timestamp);
|
||||
void shell_global_end_modal (ShellGlobal *global,
|
||||
guint32 timestamp);
|
||||
|
||||
gboolean shell_global_display_is_grabbed (ShellGlobal *global);
|
||||
|
||||
void shell_global_reexec_self (ShellGlobal *global);
|
||||
|
||||
@ -73,6 +73,14 @@ void shell_global_format_time_relative_pretty (ShellGlobal *global, guint delta,
|
||||
|
||||
ClutterActor *shell_global_create_root_pixmap_actor (ShellGlobal *global);
|
||||
|
||||
GSList *shell_global_get_monitors (ShellGlobal *global);
|
||||
GdkRectangle *shell_global_get_primary_monitor (ShellGlobal *global);
|
||||
GdkRectangle *shell_global_get_focus_monitor (ShellGlobal *global);
|
||||
|
||||
GdkModifierType shell_global_get_modifier_keys (ShellGlobal *global);
|
||||
|
||||
ClutterModifierType shell_get_event_state (ClutterEvent *event);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __SHELL_GLOBAL_H__ */
|
||||
|
@ -1,2 +1,5 @@
|
||||
VOID:INT,INT,INT
|
||||
VOID:OBJECT,INT,INT,INT,INT
|
||||
VOID:BOXED
|
||||
VOID:BOXED,OBJECT
|
||||
VOID:STRING,OBJECT,BOOLEAN
|
||||
|
338
src/shell-menu.c
Normal file
@ -0,0 +1,338 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/**
|
||||
* SECTION:shell-menu
|
||||
* @short_description: A box which acts like a popup menu
|
||||
*
|
||||
* A #BigBox subclass which adds methods and signals useful for implementing
|
||||
* popup-menu like actors.
|
||||
*/
|
||||
|
||||
#include "shell-menu.h"
|
||||
|
||||
G_DEFINE_TYPE(ShellMenu, shell_menu, BIG_TYPE_BOX);
|
||||
|
||||
struct _ShellMenuPrivate {
|
||||
gboolean popped_up;
|
||||
gboolean have_grab;
|
||||
guint activating_button;
|
||||
|
||||
gboolean released_on_source;
|
||||
ClutterActor *source_actor;
|
||||
|
||||
ClutterActor *selected;
|
||||
};
|
||||
|
||||
/* Signals */
|
||||
enum
|
||||
{
|
||||
UNSELECTED,
|
||||
SELECTED,
|
||||
ACTIVATE,
|
||||
CANCELLED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint shell_menu_signals [LAST_SIGNAL] = { 0 };
|
||||
|
||||
static gboolean
|
||||
container_contains (ClutterContainer *container,
|
||||
ClutterActor *actor)
|
||||
{
|
||||
while (actor != NULL && actor != (ClutterActor*)container)
|
||||
{
|
||||
actor = clutter_actor_get_parent (actor);
|
||||
}
|
||||
return actor != NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
shell_menu_popdown_nosignal (ShellMenu *box)
|
||||
{
|
||||
box->priv->popped_up = FALSE;
|
||||
if (box->priv->have_grab)
|
||||
clutter_ungrab_pointer ();
|
||||
clutter_actor_hide (CLUTTER_ACTOR (box));
|
||||
}
|
||||
|
||||
static void
|
||||
on_selected_destroy (ClutterActor *actor,
|
||||
ShellMenu *box)
|
||||
{
|
||||
box->priv->selected = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
set_selected (ShellMenu *box,
|
||||
ClutterActor *actor)
|
||||
{
|
||||
if (actor == box->priv->selected)
|
||||
return;
|
||||
if (box->priv->selected)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (box->priv->selected, G_CALLBACK(on_selected_destroy), box);
|
||||
g_signal_emit (G_OBJECT (box), shell_menu_signals[UNSELECTED], 0, box->priv->selected);
|
||||
}
|
||||
box->priv->selected = actor;
|
||||
if (box->priv->selected)
|
||||
{
|
||||
g_signal_connect (box->priv->selected, "destroy", G_CALLBACK(on_selected_destroy), box);
|
||||
g_signal_emit (G_OBJECT (box), shell_menu_signals[SELECTED], 0, box->priv->selected);
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
shell_menu_enter_event (ClutterActor *actor,
|
||||
ClutterCrossingEvent *event)
|
||||
{
|
||||
ShellMenu *box = SHELL_MENU (actor);
|
||||
|
||||
if (!container_contains (CLUTTER_CONTAINER (box), event->source))
|
||||
return TRUE;
|
||||
|
||||
if (event->source == (ClutterActor*)box)
|
||||
return TRUE;
|
||||
|
||||
if (g_object_get_data (G_OBJECT (event->source), "shell-is-separator"))
|
||||
return TRUE;
|
||||
|
||||
set_selected (box, event->source);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
shell_menu_leave_event (ClutterActor *actor,
|
||||
ClutterCrossingEvent *event)
|
||||
{
|
||||
ShellMenu *box = SHELL_MENU (actor);
|
||||
|
||||
set_selected (box, NULL);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
shell_menu_button_release_event (ClutterActor *actor,
|
||||
ClutterButtonEvent *event)
|
||||
{
|
||||
ShellMenu *box = SHELL_MENU (actor);
|
||||
|
||||
/* Until the user releases the button that brought up the menu, we just
|
||||
* ignore other button press/releass.
|
||||
* See https://bugzilla.gnome.org/show_bug.cgi?id=596371
|
||||
*/
|
||||
if (box->priv->activating_button > 0 && box->priv->activating_button != event->button)
|
||||
return FALSE;
|
||||
|
||||
box->priv->activating_button = 0;
|
||||
|
||||
if (box->priv->source_actor && !box->priv->released_on_source)
|
||||
{
|
||||
if (box->priv->source_actor == event->source ||
|
||||
(CLUTTER_IS_CONTAINER (box->priv->source_actor) &&
|
||||
container_contains (CLUTTER_CONTAINER (box->priv->source_actor), event->source)))
|
||||
{
|
||||
/* On the next release, we want to pop down the menu regardless */
|
||||
box->priv->released_on_source = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
shell_menu_popdown_nosignal (box);
|
||||
|
||||
if (!container_contains (CLUTTER_CONTAINER (box), event->source) ||
|
||||
box->priv->selected == NULL)
|
||||
{
|
||||
g_signal_emit (G_OBJECT (box), shell_menu_signals[CANCELLED], 0);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_signal_emit (G_OBJECT (box), shell_menu_signals[ACTIVATE], 0, box->priv->selected);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
shell_menu_popup (ShellMenu *box,
|
||||
guint button,
|
||||
guint32 activate_time)
|
||||
{
|
||||
if (box->priv->popped_up)
|
||||
return;
|
||||
box->priv->activating_button = button;
|
||||
box->priv->popped_up = TRUE;
|
||||
box->priv->have_grab = TRUE;
|
||||
box->priv->released_on_source = FALSE;
|
||||
clutter_grab_pointer (CLUTTER_ACTOR (box));
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_menu_popdown:
|
||||
* @box:
|
||||
*
|
||||
* If the menu is currently active, hide it, emitting the 'cancelled' signal.
|
||||
*/
|
||||
void
|
||||
shell_menu_popdown (ShellMenu *box)
|
||||
{
|
||||
if (!box->priv->popped_up)
|
||||
return;
|
||||
shell_menu_popdown_nosignal (box);
|
||||
g_signal_emit (G_OBJECT (box), shell_menu_signals[CANCELLED], 0);
|
||||
}
|
||||
|
||||
static void
|
||||
on_source_destroyed (ClutterActor *actor,
|
||||
ShellMenu *box)
|
||||
{
|
||||
box->priv->source_actor = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_menu_set_persistent_source:
|
||||
* @box:
|
||||
* @source: Actor to use as menu origin
|
||||
*
|
||||
* This function changes the menu behavior on button release. Normally
|
||||
* when the mouse is released anywhere, the menu "pops down"; when this
|
||||
* function is called, if the mouse is released over the source actor,
|
||||
* the menu stays.
|
||||
*
|
||||
* The given @source actor must be reactive for this function to work.
|
||||
*/
|
||||
void
|
||||
shell_menu_set_persistent_source (ShellMenu *box,
|
||||
ClutterActor *source)
|
||||
{
|
||||
if (box->priv->source_actor)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (G_OBJECT (box->priv->source_actor),
|
||||
G_CALLBACK (on_source_destroyed),
|
||||
box);
|
||||
}
|
||||
box->priv->source_actor = source;
|
||||
if (box->priv->source_actor)
|
||||
{
|
||||
g_signal_connect (G_OBJECT (box->priv->source_actor),
|
||||
"destroy",
|
||||
G_CALLBACK (on_source_destroyed),
|
||||
box);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_menu_append_separator:
|
||||
* @box:
|
||||
* @separator: An actor which functions as a menu separator
|
||||
* @flags: Packing flags
|
||||
*
|
||||
* Actors added to the menu with default functions are treated like
|
||||
* menu items; this function will add an actor that should instead
|
||||
* be treated like a menu separator. The current practical effect
|
||||
* is that the separators will not be selectable.
|
||||
*/
|
||||
void
|
||||
shell_menu_append_separator (ShellMenu *box,
|
||||
ClutterActor *separator,
|
||||
BigBoxPackFlags flags)
|
||||
{
|
||||
g_object_set_data (G_OBJECT (separator), "shell-is-separator", GUINT_TO_POINTER(TRUE));
|
||||
big_box_append (BIG_BOX (box), separator, flags);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_menu_dispose (GObject *gobject)
|
||||
{
|
||||
ShellMenu *self = SHELL_MENU (gobject);
|
||||
|
||||
shell_menu_set_persistent_source (self, NULL);
|
||||
|
||||
G_OBJECT_CLASS (shell_menu_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_menu_class_init (ShellMenuClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
||||
|
||||
gobject_class->dispose = shell_menu_dispose;
|
||||
|
||||
actor_class->enter_event = shell_menu_enter_event;
|
||||
actor_class->leave_event = shell_menu_leave_event;
|
||||
actor_class->button_release_event = shell_menu_button_release_event;
|
||||
|
||||
/**
|
||||
* ShellMenu::unselected
|
||||
* @box: The #ShellMenu
|
||||
* @actor: The previously hovered-over menu item
|
||||
*
|
||||
* This signal is emitted when a menu item transitions to
|
||||
* an unselected state.
|
||||
*/
|
||||
shell_menu_signals[UNSELECTED] =
|
||||
g_signal_new ("unselected",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR);
|
||||
|
||||
/**
|
||||
* ShellMenu::selected
|
||||
* @box: The #ShellMenu
|
||||
* @actor: The hovered-over menu item
|
||||
*
|
||||
* This signal is emitted when a menu item is in a selected state.
|
||||
*/
|
||||
shell_menu_signals[SELECTED] =
|
||||
g_signal_new ("selected",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR);
|
||||
|
||||
/**
|
||||
* ShellMenu::activate
|
||||
* @box: The #ShellMenu
|
||||
* @actor: The clicked menu item
|
||||
*
|
||||
* This signal is emitted when a menu item is selected.
|
||||
*/
|
||||
shell_menu_signals[ACTIVATE] =
|
||||
g_signal_new ("activate",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1, CLUTTER_TYPE_ACTOR);
|
||||
|
||||
/**
|
||||
* ShellMenu::cancelled
|
||||
* @box: The #ShellMenu
|
||||
*
|
||||
* This signal is emitted when the menu is closed without an option selected.
|
||||
*/
|
||||
shell_menu_signals[CANCELLED] =
|
||||
g_signal_new ("cancelled",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
g_type_class_add_private (gobject_class, sizeof (ShellMenuPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
shell_menu_init (ShellMenu *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, SHELL_TYPE_MENU,
|
||||
ShellMenuPrivate);
|
||||
}
|
41
src/shell-menu.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef __SHELL_MENU_H__
|
||||
#define __SHELL_MENU_H__
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include "big/box.h"
|
||||
|
||||
#define SHELL_TYPE_MENU (shell_menu_get_type ())
|
||||
#define SHELL_MENU(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_MENU, ShellMenu))
|
||||
#define SHELL_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_MENU, ShellMenuClass))
|
||||
#define SHELL_IS_MENU(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_TYPE_MENU))
|
||||
#define SHELL_IS_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_MENU))
|
||||
#define SHELL_MENU_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_MENU, ShellMenuClass))
|
||||
|
||||
typedef struct _ShellMenu ShellMenu;
|
||||
typedef struct _ShellMenuClass ShellMenuClass;
|
||||
|
||||
typedef struct _ShellMenuPrivate ShellMenuPrivate;
|
||||
|
||||
struct _ShellMenu
|
||||
{
|
||||
BigBox parent;
|
||||
|
||||
ShellMenuPrivate *priv;
|
||||
};
|
||||
|
||||
struct _ShellMenuClass
|
||||
{
|
||||
BigBoxClass parent_class;
|
||||
};
|
||||
|
||||
GType shell_menu_get_type (void) G_GNUC_CONST;
|
||||
|
||||
void shell_menu_popup (ShellMenu *behavior, guint button, guint32 activate_time);
|
||||
|
||||
void shell_menu_set_persistent_source (ShellMenu *behavior, ClutterActor *source);
|
||||
|
||||
void shell_menu_append_separator (ShellMenu *behavior, ClutterActor *separator, BigBoxPackFlags flags);
|
||||
|
||||
void shell_menu_popdown (ShellMenu *behavior);
|
||||
|
||||
#endif /* __SHELL_MENU_H__ */
|