Compare commits
48 Commits
2.27.1
...
overlay-de
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e191636f34 | ||
|
|
39e31a3aa9 | ||
|
|
8293f3423a | ||
|
|
858a82fcdd | ||
|
|
2ae89f3b36 | ||
|
|
cdee026095 | ||
|
|
340fbfe943 | ||
|
|
c577951ec9 | ||
|
|
d588b083d9 | ||
|
|
e57b7ec335 | ||
|
|
b5988a57fa | ||
|
|
d5a80d3063 | ||
|
|
02a8cd5ce2 | ||
|
|
aa77762d27 | ||
|
|
de3f5dec68 | ||
|
|
84865f416d | ||
|
|
ca3e3df199 | ||
|
|
643febebf8 | ||
|
|
6d002c893d | ||
|
|
5eaed34047 | ||
|
|
8f5b55350f | ||
|
|
c600ebb687 | ||
|
|
9abc062a64 | ||
|
|
81d0474926 | ||
|
|
c41902c188 | ||
|
|
97b9ccbff7 | ||
|
|
282daf768f | ||
|
|
1b057300b0 | ||
|
|
75da772d05 | ||
|
|
df9cf98826 | ||
|
|
d3cb8e5b21 | ||
|
|
71998a6b43 | ||
|
|
2fd2293e4a | ||
|
|
3528eef655 | ||
|
|
f209d6792d | ||
|
|
614e83476e | ||
|
|
4e2a301ef0 | ||
|
|
6def8cf7dd | ||
|
|
1204898d1e | ||
|
|
98530afd87 | ||
|
|
a9fedcce76 | ||
|
|
dae1d94258 | ||
|
|
4a7c328c33 | ||
|
|
2c0d6fdf89 | ||
|
|
12f896eb94 | ||
|
|
230c91b6d4 | ||
|
|
d7dcfe6a06 | ||
|
|
275eba17db |
11
.gitignore
vendored
11
.gitignore
vendored
@@ -16,17 +16,7 @@ config.log
|
||||
config.status
|
||||
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
|
||||
@@ -39,4 +29,3 @@ src/gnome-shell
|
||||
src/test-recorder
|
||||
src/test-recorder.ogg
|
||||
stamp-h1
|
||||
xmldocs.make
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
SUBDIRS = data js src po
|
||||
SUBDIRS = data js src
|
||||
|
||||
EXTRA_DIST = \
|
||||
.project \
|
||||
@@ -7,7 +7,7 @@ EXTRA_DIST = \
|
||||
distcheck-hook:
|
||||
@echo "Checking disted javascript against files in git"
|
||||
@failed=false; \
|
||||
for f in `cd $(srcdir) && git ls-files js` ; do \
|
||||
for f in `cd $(srcdir) && git-ls-files js` ; do \
|
||||
if ! test -e $(distdir)/$$f ; then \
|
||||
echo File missing from distribution: $$f ; \
|
||||
failed=true ; \
|
||||
|
||||
28
autogen.sh
28
autogen.sh
@@ -1,22 +1,8 @@
|
||||
#!/bin/bash
|
||||
# Run this to generate all the initial makefiles, etc.
|
||||
#!/bin/sh
|
||||
|
||||
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
|
||||
(cd `dirname $0`;
|
||||
touch ChangeLog NEWS &&
|
||||
autoreconf --install --symlink &&
|
||||
autoreconf &&
|
||||
./configure --enable-maintainer-mode $@
|
||||
)
|
||||
|
||||
63
configure.ac
63
configure.ac
@@ -1,12 +1,10 @@
|
||||
AC_INIT(gnome-shell, 2.27.1)
|
||||
AC_INIT(gnome-shell, 0.0.1)
|
||||
|
||||
AC_CONFIG_AUX_DIR(config)
|
||||
|
||||
AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip foreign])
|
||||
AM_INIT_AUTOMAKE([dist-bzip2 no-dist-gzip])
|
||||
AM_MAINTAINER_MODE
|
||||
|
||||
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])],)
|
||||
|
||||
AC_CONFIG_HEADERS(config.h)
|
||||
|
||||
AC_DISABLE_STATIC
|
||||
@@ -22,10 +20,6 @@ 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
|
||||
|
||||
# We need at least this, since gst_plugin_register_static() was added
|
||||
@@ -39,23 +33,23 @@ if $PKG_CONFIG --exists gstreamer-0.10 '>=' $GSTREAMER_MIN_VERSION ; then
|
||||
AC_MSG_RESULT(yes)
|
||||
build_recorder=true
|
||||
recorder_modules="gstreamer-0.10 gstreamer-base-0.10 xfixes"
|
||||
PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules clutter-1.0)
|
||||
PKG_CHECK_MODULES(TEST_SHELL_RECORDER, $recorder_modules clutter-0.9)
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(BUILD_RECORDER, $build_recorder)
|
||||
|
||||
# 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.4)
|
||||
PKG_CHECK_MODULES(TIDY, clutter-1.0)
|
||||
PKG_CHECK_MODULES(BIG, clutter-1.0 gtk+-2.0 librsvg-2.0)
|
||||
PKG_CHECK_MODULES(MUTTER_PLUGIN, gtk+-2.0 dbus-glib-1 mutter-plugins gjs-gi-1.0 xscrnsaver libgnome-menu $recorder_modules gconf-2.0 gdk-x11-2.0 clutter-x11-0.9 clutter-glx-0.9)
|
||||
PKG_CHECK_MODULES(TIDY, clutter-0.9)
|
||||
PKG_CHECK_MODULES(BIG, clutter-0.9 gtk+-2.0 librsvg-2.0)
|
||||
PKG_CHECK_MODULES(GDMUSER, dbus-glib-1 gtk+-2.0)
|
||||
PKG_CHECK_MODULES(TRAY, gtk+-2.0)
|
||||
PKG_CHECK_MODULES(TASKPANEL, libwnck-1.0 dbus-glib-1)
|
||||
# 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
|
||||
@@ -86,31 +80,17 @@ AC_SUBST(GIRDIR)
|
||||
TYPELIBDIR="$($PKG_CONFIG --variable=typelibdir gobject-introspection-1.0)"
|
||||
AC_SUBST(TYPELIBDIR)
|
||||
|
||||
# Stay command-line compatible with the gnome-common configure option. Here
|
||||
# minimum/yes/maximum are the same, however.
|
||||
AC_ARG_ENABLE(compile_warnings,
|
||||
AC_HELP_STRING([--enable-compile-warnings=@<:@no/minimum/yes/maximum/error@:>@],
|
||||
[Turn on compiler warnings]),,
|
||||
enable_compile_warnings=error)
|
||||
|
||||
changequote(,)dnl
|
||||
if test "$enable_compile_warnings" != no ; then
|
||||
if test "x$GCC" = "xyes"; then
|
||||
case " $CFLAGS " in
|
||||
*[\ \ ]-Wall[\ \ ]*) ;;
|
||||
*) CFLAGS="$CFLAGS -Wall" ;;
|
||||
esac
|
||||
case " $CFLAGS " in
|
||||
*[\ \ ]-Wmissing-prototypes[\ \ ]*) ;;
|
||||
*) CFLAGS="$CFLAGS -Wmissing-prototypes" ;;
|
||||
esac
|
||||
if test "$enable_compile_warnings" = error ; then
|
||||
case " $CFLAGS " in
|
||||
*[\ \ ]-Werror[\ \ ]*) ;;
|
||||
*) CFLAGS="$CFLAGS -Werror" ;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
if test "x$GCC" = "xyes"; then
|
||||
case " $CFLAGS " in
|
||||
*[\ \ ]-Wall[\ \ ]*) ;;
|
||||
*) CFLAGS="$CFLAGS -Wall" ;;
|
||||
esac
|
||||
|
||||
case " $OBJCFLAGS " in
|
||||
*[\ \ ]-Wall[\ \ ]*) ;;
|
||||
*) OBJCFLAGS="$OBJCFLAGS -Wall" ;;
|
||||
esac
|
||||
fi
|
||||
changequote([,])dnl
|
||||
|
||||
@@ -124,5 +104,4 @@ AC_OUTPUT([
|
||||
js/misc/Makefile
|
||||
js/ui/Makefile
|
||||
src/Makefile
|
||||
po/Makefile.in
|
||||
])
|
||||
|
||||
@@ -1,38 +1,14 @@
|
||||
desktopdir=$(datadir)/applications
|
||||
desktop_DATA = gnome-shell.desktop
|
||||
|
||||
# We substitute in bindir so it works as an autostart
|
||||
# file when built in a non-system prefix
|
||||
gnome-shell.desktop.in: gnome-shell.desktop.in.in
|
||||
$(AM_V_GEN) sed -e "s|@bindir[@]|$(bindir)|" \
|
||||
-e "s|@VERSION[@]|$(VERSION)|" \
|
||||
$< > $@ || rm $@
|
||||
|
||||
# Placeholder until we add intltool
|
||||
gnome-shell.desktop: gnome-shell.desktop.in
|
||||
$(AM_V_GEN) sed s/^_// < $< > $@ || rm $@
|
||||
|
||||
imagedir = $(pkgdatadir)/images
|
||||
|
||||
dist_image_DATA = \
|
||||
add-workspace.svg \
|
||||
close.svg \
|
||||
close-black.svg \
|
||||
info.svg \
|
||||
magnifier.svg \
|
||||
remove-workspace.svg
|
||||
|
||||
schemadir = @GCONF_SCHEMA_FILE_DIR@
|
||||
schema_DATA = gnome-shell.schemas
|
||||
|
||||
install-data-local:
|
||||
GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $(srcdir)/$(schema_DATA)
|
||||
GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $(top_builddir)/data/$(schema_DATA)
|
||||
|
||||
EXTRA_DIST = \
|
||||
gnome-shell.desktop.in.in \
|
||||
EXTRA_DIST = \
|
||||
$(schema_DATA)
|
||||
|
||||
CLEANFILES = \
|
||||
gnome-shell.desktop.in \
|
||||
$(desktop_DATA)
|
||||
|
||||
|
||||
@@ -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="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>
|
||||
|
Before Width: | Height: | Size: 2.3 KiB |
@@ -1,15 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Type=Application
|
||||
_Name=GNOME Shell
|
||||
_Comment=Window management and application launching
|
||||
Exec=@bindir@/gnome-shell
|
||||
X-GNOME-Bugzilla-Bugzilla=GNOME
|
||||
X-GNOME-Bugzilla-Product=gnome-shell
|
||||
X-GNOME-Bugzilla-Component=general
|
||||
X-GNOME-Bugzilla-Version=@VERSION@
|
||||
Categories=GNOME;GTK;Utility;Core;
|
||||
OnlyShowIn=GNOME;
|
||||
NoDisplay=true
|
||||
X-GNOME-Autostart-Phase=WindowManager
|
||||
X-GNOME-Provides=panel;windowmanager;
|
||||
X-GNOME-Autostart-Notify=true
|
||||
@@ -20,7 +20,7 @@
|
||||
<applyto>/desktop/gnome/shell/favorite_apps</applyto>
|
||||
<owner>gnome-shell</owner>
|
||||
<type>list</type>
|
||||
<list_type>string</list_type>
|
||||
<listtype>string</listtype>
|
||||
<default>[mozilla-firefox.desktop,evolution.desktop,openoffice.org-writer.desktop]</default>
|
||||
<locale name="C">
|
||||
<short>List of desktop file IDs for favorite applications</short>
|
||||
@@ -30,49 +30,6 @@
|
||||
</locale>
|
||||
</schema>
|
||||
|
||||
<schema>
|
||||
<key>/schemas/desktop/gnome/shell/sidebar/visible</key>
|
||||
<applyto>/desktop/gnome/shell/sidebar/visible</applyto>
|
||||
<owner>gnome-shell</owner>
|
||||
<type>bool</type>
|
||||
<default>false</default>
|
||||
<locale name="C">
|
||||
<short>Whether or not to display the sidebar</short>
|
||||
<long>
|
||||
Determines whether or not the sidebar is visible.
|
||||
</long>
|
||||
</locale>
|
||||
</schema>
|
||||
|
||||
<schema>
|
||||
<key>/schemas/desktop/gnome/shell/sidebar/expanded</key>
|
||||
<applyto>/desktop/gnome/shell/sidebar/expanded</applyto>
|
||||
<owner>gnome-shell</owner>
|
||||
<type>bool</type>
|
||||
<default>true</default>
|
||||
<locale name="C">
|
||||
<short>Whether the sidebar should be in the expanded (wide) mode</short>
|
||||
<long>
|
||||
Controls the expanded/collapsed state of the sidebar.
|
||||
</long>
|
||||
</locale>
|
||||
</schema>
|
||||
|
||||
<schema>
|
||||
<key>/schemas/desktop/gnome/shell/sidebar/widgets</key>
|
||||
<applyto>/desktop/gnome/shell/sidebar/widgets</applyto>
|
||||
<owner>gnome-shell</owner>
|
||||
<type>list</type>
|
||||
<list_type>string</list_type>
|
||||
<default>[imports.ui.widget.ClockWidget,imports.ui.widget.AppsWidget,imports.ui.widget.RecentDocsWidget]</default>
|
||||
<locale name="C">
|
||||
<short>The widgets to display in the sidebar</short>
|
||||
<long>
|
||||
The widgets to display in the sidebar, in order from top to bottom. Each widget "name" is actually a JavaScript expression referring to a widget constructor object.
|
||||
</long>
|
||||
</locale>
|
||||
</schema>
|
||||
|
||||
</schemalist>
|
||||
|
||||
</gconfschemafile>
|
||||
</gconfschemafile>
|
||||
66
data/view-more-activated.svg
Normal file
66
data/view-more-activated.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="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>
|
||||
|
After Width: | Height: | Size: 2.7 KiB |
@@ -1,6 +1,5 @@
|
||||
<?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#"
|
||||
@@ -9,22 +8,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.0"
|
||||
version="1.1"
|
||||
id="Foreground"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 18 18"
|
||||
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+devel"
|
||||
sodipodi:docname="magnifier.svg"
|
||||
inkscape:version="0.46"
|
||||
sodipodi:docname="search_1.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
|
||||
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"
|
||||
@@ -35,46 +34,46 @@
|
||||
inkscape:window-height="728"
|
||||
inkscape:window-width="1103"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="1"
|
||||
inkscape:pageopacity="0.0"
|
||||
guidetolerance="10.0"
|
||||
gridtolerance="10.0"
|
||||
objecttolerance="10.0"
|
||||
borderopacity="1.0"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#000000"
|
||||
pagecolor="#ffffff"
|
||||
id="base"
|
||||
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
|
||||
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"
|
||||
empspacing="5"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" /></sodipodi:namedview>
|
||||
|
||||
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" />
|
||||
<g
|
||||
id="g5"
|
||||
style="fill:#ffffff;fill-opacity:1"
|
||||
transform="translate(-4,-0.023114)">
|
||||
style="fill:#4669a9;fill-opacity:1">
|
||||
<path
|
||||
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"
|
||||
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"
|
||||
id="path7"
|
||||
style="fill:#ffffff;fill-opacity:1" />
|
||||
style="fill:#4669a9;fill-opacity:1" />
|
||||
<path
|
||||
d="M 9.076,11.937"
|
||||
fill="#FFFFFF"
|
||||
d="M9.076,11.937"
|
||||
id="path9"
|
||||
style="fill:#ffffff;fill-opacity:1" />
|
||||
style="fill:#4669a9;fill-opacity:1" />
|
||||
</g>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
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"
|
||||
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"
|
||||
id="path11"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd" />
|
||||
style="fill:#4669a9;fill-opacity:1" />
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.8 KiB |
@@ -1,4 +1,5 @@
|
||||
jsmiscdir = $(pkgdatadir)/js/misc
|
||||
|
||||
dist_jsmisc_DATA = \
|
||||
appInfo.js \
|
||||
docInfo.js
|
||||
|
||||
134
js/misc/appInfo.js
Normal file
134
js/misc/appInfo.js
Normal file
@@ -0,0 +1,134 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
|
||||
function AppInfo(appId) {
|
||||
this._init(appId);
|
||||
}
|
||||
|
||||
AppInfo.prototype = {
|
||||
_init : function(appId) {
|
||||
this.appId = appId;
|
||||
this._gAppInfo = Gio.DesktopAppInfo.new(appId);
|
||||
if (!this._gAppInfo) {
|
||||
throw new Error('Unknown appId ' + appId);
|
||||
}
|
||||
|
||||
this.id = this._gAppInfo.get_id();
|
||||
this.name = this._gAppInfo.get_name();
|
||||
this.description = this._gAppInfo.get_description();
|
||||
this.executable = this._gAppInfo.get_executable();
|
||||
|
||||
this._gicon = this._gAppInfo.get_icon();
|
||||
},
|
||||
|
||||
createIcon : function(size) {
|
||||
if (this._gicon)
|
||||
return Shell.TextureCache.get_default().load_gicon(this._gicon, size);
|
||||
else
|
||||
return new Clutter.Texture({ width: size, height: size });
|
||||
},
|
||||
|
||||
getIconPath : function(size) {
|
||||
if (this._gicon) {
|
||||
let iconTheme = Gtk.IconTheme.get_default();
|
||||
let previewIconInfo = iconTheme.lookup_by_gicon(this._gicon, size, 0);
|
||||
if (previewIconInfo)
|
||||
return previewIconInfo.get_filename();
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
||||
launch : function() {
|
||||
this._gAppInfo.launch([], Main.createAppLaunchContext());
|
||||
}
|
||||
};
|
||||
|
||||
var _infos = {};
|
||||
|
||||
// getAppInfo:
|
||||
// @appId: an appId
|
||||
//
|
||||
// Gets an #AppInfo for @appId. This is preferable to calling
|
||||
// new AppInfo() directly, because it caches #AppInfos.
|
||||
//
|
||||
// Return value: the new or cached #AppInfo, or %null if @appId
|
||||
// doesn't point to a valid .desktop file
|
||||
function getAppInfo(appId) {
|
||||
let info = _infos[appId];
|
||||
if (info === undefined) {
|
||||
try {
|
||||
info = _infos[appId] = new AppInfo(appId);
|
||||
} catch (e) {
|
||||
info = _infos[appId] = null;
|
||||
}
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
// getTopApps:
|
||||
// @count: maximum number of apps to retrieve
|
||||
//
|
||||
// Gets a list of #AppInfos for the @count most-frequently-used
|
||||
// applications, with explicitly-chosen favorites first.
|
||||
//
|
||||
// Return value: the list of #AppInfo
|
||||
function getTopApps(count) {
|
||||
let appMonitor = Shell.AppMonitor.get_default();
|
||||
|
||||
let matches = [], alreadyAdded = {};
|
||||
|
||||
let favs = getFavorites();
|
||||
for (let i = 0; i < favs.length && favs.length <= count; i++) {
|
||||
let appId = favs[i].appId;
|
||||
|
||||
if (alreadyAdded[appId])
|
||||
continue;
|
||||
alreadyAdded[appId] = true;
|
||||
|
||||
matches.push(favs[i]);
|
||||
}
|
||||
|
||||
// Ask for more apps than we need, since the list of recently used
|
||||
// apps might contain an app we don't have a desktop file for
|
||||
let apps = appMonitor.get_most_used_apps (0, Math.round(count * 1.5));
|
||||
for (let i = 0; i < apps.length && matches.length <= count; i++) {
|
||||
let appId = apps[i] + ".desktop";
|
||||
if (alreadyAdded[appId])
|
||||
continue;
|
||||
alreadyAdded[appId] = true;
|
||||
let appInfo = getAppInfo(appId);
|
||||
if (appInfo) {
|
||||
matches.push(appInfo);
|
||||
}
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
function _idListToInfos(ids) {
|
||||
let infos = [];
|
||||
for (let i = 0; i < ids.length; i++) {
|
||||
let display = getAppInfo(ids[i]);
|
||||
if (display == null)
|
||||
continue;
|
||||
infos.push(display);
|
||||
}
|
||||
return infos;
|
||||
}
|
||||
|
||||
function getFavorites() {
|
||||
let system = Shell.AppSystem.get_default();
|
||||
|
||||
return _idListToInfos(system.get_favorites());
|
||||
}
|
||||
|
||||
function getRunning() {
|
||||
let monitor = Shell.AppMonitor.get_default();
|
||||
return _idListToInfos(monitor.get_running_app_ids());
|
||||
}
|
||||
@@ -5,8 +5,6 @@ const Gio = imports.gi.Gio;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
const Main = imports.ui.main;
|
||||
|
||||
const THUMBNAIL_ICON_MARGIN = 2;
|
||||
@@ -18,17 +16,40 @@ function DocInfo(recentInfo) {
|
||||
DocInfo.prototype = {
|
||||
_init : function(recentInfo) {
|
||||
this._recentInfo = recentInfo;
|
||||
// We actually used get_modified() instead of get_visited()
|
||||
// here, as GtkRecentInfo doesn't updated get_visited()
|
||||
// correctly. See http://bugzilla.gnome.org/show_bug.cgi?id=567094
|
||||
this.timestamp = recentInfo.get_modified().getTime() / 1000;
|
||||
this.name = recentInfo.get_display_name();
|
||||
this.uri = recentInfo.get_uri();
|
||||
this.mimeType = recentInfo.get_mime_type();
|
||||
},
|
||||
|
||||
createIcon : function(size) {
|
||||
return Shell.TextureCache.get_default().load_recent_thumbnail(size, this._recentInfo);
|
||||
let icon = new Clutter.Texture();
|
||||
let iconPixbuf;
|
||||
|
||||
if (this.uri.match("^file://"))
|
||||
iconPixbuf = Shell.get_thumbnail(this.uri, this.mimeType);
|
||||
|
||||
if (iconPixbuf) {
|
||||
// We calculate the width and height of the texture so as
|
||||
// to preserve the aspect ratio of the thumbnail. Because
|
||||
// the images generated based on thumbnails don't have an
|
||||
// internal padding like system icons do, we create a
|
||||
// slightly smaller texture and then create a group around
|
||||
// it for padding purposes
|
||||
|
||||
let scalingFactor = (size - THUMBNAIL_ICON_MARGIN * 2) / Math.max(iconPixbuf.get_width(), iconPixbuf.get_height());
|
||||
icon.set_width(Math.ceil(iconPixbuf.get_width() * scalingFactor));
|
||||
icon.set_height(Math.ceil(iconPixbuf.get_height() * scalingFactor));
|
||||
Shell.clutter_texture_set_from_pixbuf(icon, iconPixbuf);
|
||||
|
||||
let group = new Clutter.Group({ width: size,
|
||||
height: size });
|
||||
group.add_actor(icon);
|
||||
icon.set_position(THUMBNAIL_ICON_MARGIN, THUMBNAIL_ICON_MARGIN);
|
||||
return group;
|
||||
} else {
|
||||
Shell.clutter_texture_set_from_pixbuf(icon, this._recentInfo.get_icon(size));
|
||||
return icon;
|
||||
}
|
||||
},
|
||||
|
||||
launch : function() {
|
||||
@@ -42,7 +63,7 @@ DocInfo.prototype = {
|
||||
if (appInfo != null) {
|
||||
appInfo.launch_uris([this.uri], Main.createAppLaunchContext());
|
||||
} else {
|
||||
log("Failed to get default application info for mime type " + this.mimeType +
|
||||
log("Failed to get default application info for mime type " + mimeType +
|
||||
". Will try to use the last application that registered the document.");
|
||||
let appName = this._recentInfo.last_application();
|
||||
let [success, appExec, count, time] = this._recentInfo.get_application_info(appName);
|
||||
@@ -80,62 +101,14 @@ DocInfo.prototype = {
|
||||
|
||||
exists : function() {
|
||||
return this._recentInfo.exists();
|
||||
},
|
||||
|
||||
lastVisited : function() {
|
||||
// We actually used get_modified() instead of get_visited()
|
||||
// here, as GtkRecentInfo doesn't updated get_visited()
|
||||
// correctly. See
|
||||
// http://bugzilla.gnome.org/show_bug.cgi?id=567094
|
||||
|
||||
return this._recentInfo.get_modified();
|
||||
}
|
||||
};
|
||||
|
||||
var docManagerInstance = null;
|
||||
|
||||
function getDocManager() {
|
||||
if (docManagerInstance == null)
|
||||
docManagerInstance = new DocManager();
|
||||
return docManagerInstance;
|
||||
}
|
||||
|
||||
function DocManager() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
DocManager.prototype = {
|
||||
_init: function() {
|
||||
this._recentManager = Gtk.RecentManager.get_default();
|
||||
this._items = {};
|
||||
this._recentManager.connect('changed', Lang.bind(this, function(recentManager) {
|
||||
this._reload();
|
||||
this.emit('changed');
|
||||
}));
|
||||
this._reload();
|
||||
},
|
||||
|
||||
_reload: function() {
|
||||
let docs = this._recentManager.get_items();
|
||||
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
|
||||
newItems[docInfo.uri] = docInfo;
|
||||
}
|
||||
let deleted = {};
|
||||
for (var uri in this._items) {
|
||||
if (!(uri in newItems))
|
||||
deleted[uri] = this._items[uri];
|
||||
}
|
||||
/* If we'd cached any thumbnail references that no longer exist,
|
||||
dump them here */
|
||||
let texCache = Shell.TextureCache.get_default();
|
||||
for (var uri in deleted) {
|
||||
texCache.evict_recent_thumbnail(this._items[uri]);
|
||||
}
|
||||
this._items = newItems;
|
||||
},
|
||||
|
||||
getItems: function() {
|
||||
return this._items;
|
||||
}
|
||||
}
|
||||
|
||||
Signals.addSignalMethods(DocManager.prototype);
|
||||
|
||||
@@ -3,19 +3,15 @@ jsuidir = $(pkgdatadir)/js/ui
|
||||
dist_jsui_DATA = \
|
||||
altTab.js \
|
||||
appDisplay.js \
|
||||
appIcon.js \
|
||||
button.js \
|
||||
chrome.js \
|
||||
dash.js \
|
||||
dnd.js \
|
||||
docDisplay.js \
|
||||
genericDisplay.js \
|
||||
link.js \
|
||||
lookingGlass.js \
|
||||
main.js \
|
||||
overview.js \
|
||||
overlay.js \
|
||||
panel.js \
|
||||
places.js \
|
||||
runDialog.js \
|
||||
sidebar.js \
|
||||
tweener.js \
|
||||
|
||||
@@ -36,36 +36,38 @@ function AltTabPopup() {
|
||||
|
||||
AltTabPopup.prototype = {
|
||||
_init : function() {
|
||||
let global = Shell.Global.get();
|
||||
let global = Shell.Global.get();
|
||||
|
||||
this.actor = new Big.Box({ background_color : POPUP_BG_COLOR,
|
||||
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 });
|
||||
|
||||
// Icon grid. TODO: Investigate Nbtk.Grid once that lands. Currently
|
||||
// just implemented using a chain of Big.Box.
|
||||
this._grid = new Big.Box({ spacing: POPUP_GRID_SPACING,
|
||||
// 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.actor.append(gcenterbox, Big.BoxPackFlags.NONE);
|
||||
|
||||
// Selected-window label
|
||||
this._label = new Clutter.Text({ font_name: "Sans 16px",
|
||||
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);
|
||||
labelbox.append(this._label, Big.BoxPackFlags.EXPAND);
|
||||
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);
|
||||
this.actor.append(lcenterbox, Big.BoxPackFlags.NONE);
|
||||
|
||||
// Indicator around selected icon
|
||||
this._indicator = new Big.Rectangle({ border_width: POPUP_INDICATOR_WIDTH,
|
||||
@@ -74,10 +76,10 @@ AltTabPopup.prototype = {
|
||||
color: POPUP_TRANSPARENT });
|
||||
this.actor.append(this._indicator, Big.BoxPackFlags.FIXED);
|
||||
|
||||
this._items = [];
|
||||
this._items = [];
|
||||
this._toplevels = global.window_group.get_children();
|
||||
|
||||
global.stage.add_actor(this.actor);
|
||||
global.stage.add_actor(this.actor);
|
||||
|
||||
// Dark translucent window used to cover all but the
|
||||
// currently-selected window while Alt-Tabbing. Actually
|
||||
@@ -140,7 +142,9 @@ AltTabPopup.prototype = {
|
||||
},
|
||||
|
||||
show : function(initialSelection) {
|
||||
let global = Shell.Global.get();
|
||||
let global = Shell.Global.get();
|
||||
|
||||
Main.startModal();
|
||||
|
||||
global.window_group.add_actor(this._overlay);
|
||||
this._overlay.raise_top();
|
||||
@@ -150,16 +154,18 @@ AltTabPopup.prototype = {
|
||||
time: SHOW_TIME,
|
||||
transition: "easeOutQuad" });
|
||||
|
||||
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);
|
||||
this.actor.show_all();
|
||||
this.actor.x = (global.screen_width - this.actor.width) / 2;
|
||||
this.actor.y = (global.screen_height - this.actor.height) / 2;
|
||||
|
||||
this.select(initialSelection);
|
||||
},
|
||||
|
||||
destroy : function() {
|
||||
this.actor.destroy();
|
||||
this.actor.destroy();
|
||||
this._overlay.destroy();
|
||||
|
||||
Main.endModal();
|
||||
},
|
||||
|
||||
select : function(n) {
|
||||
@@ -234,7 +240,7 @@ AltTabPopup.prototype = {
|
||||
},
|
||||
|
||||
_adjust_overlay : function() {
|
||||
let global = Shell.Global.get();
|
||||
let global = Shell.Global.get();
|
||||
|
||||
if (this._selected && this._selected.icon_rect) {
|
||||
// We want to highlight a specific rectangle within the
|
||||
|
||||
@@ -3,28 +3,22 @@
|
||||
const Big = imports.gi.Big;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Pango = imports.gi.Pango;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const 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 AppInfo = imports.misc.appInfo;
|
||||
const DND = imports.ui.dnd;
|
||||
const GenericDisplay = imports.ui.genericDisplay;
|
||||
const Main = imports.ui.main;
|
||||
const Workspaces = imports.ui.workspaces;
|
||||
|
||||
const ENTERED_MENU_COLOR = new Clutter.Color();
|
||||
ENTERED_MENU_COLOR.from_pixel(0x00ff0022);
|
||||
|
||||
const WELL_DEFAULT_COLUMNS = 4;
|
||||
const WELL_ITEM_HSPACING = 0;
|
||||
const WELL_ITEM_VSPACING = 4;
|
||||
const APP_ICON_SIZE = 48;
|
||||
|
||||
const MENU_ICON_SIZE = 24;
|
||||
const MENU_SPACING = 15;
|
||||
@@ -34,23 +28,20 @@ const MAX_ITEMS = 30;
|
||||
/* This class represents a single display item containing information about an application.
|
||||
*
|
||||
* appInfo - AppInfo object containing information about the application
|
||||
* availableWidth - total width available for the item
|
||||
*/
|
||||
function AppDisplayItem(appInfo) {
|
||||
this._init(appInfo);
|
||||
function AppDisplayItem(appInfo, availableWidth) {
|
||||
this._init(appInfo, availableWidth);
|
||||
}
|
||||
|
||||
AppDisplayItem.prototype = {
|
||||
__proto__: GenericDisplay.GenericDisplayItem.prototype,
|
||||
|
||||
_init : function(appInfo) {
|
||||
GenericDisplay.GenericDisplayItem.prototype._init.call(this);
|
||||
_init : function(appInfo, availableWidth) {
|
||||
GenericDisplay.GenericDisplayItem.prototype._init.call(this, availableWidth);
|
||||
this._appInfo = appInfo;
|
||||
|
||||
this._setItemInfo(appInfo.get_name(), appInfo.get_description());
|
||||
},
|
||||
|
||||
getId: function() {
|
||||
return this._appInfo.get_id();
|
||||
this._setItemInfo(appInfo.name, appInfo.description);
|
||||
},
|
||||
|
||||
//// Public method overrides ////
|
||||
@@ -64,16 +55,24 @@ AppDisplayItem.prototype = {
|
||||
|
||||
// Returns an icon for the item.
|
||||
_createIcon : function() {
|
||||
return this._appInfo.create_icon_texture(GenericDisplay.ITEM_DISPLAY_ICON_SIZE);
|
||||
return this._appInfo.createIcon(GenericDisplay.ITEM_DISPLAY_ICON_SIZE);
|
||||
},
|
||||
|
||||
// Returns a preview icon for the item.
|
||||
_createPreviewIcon : function() {
|
||||
return this._appInfo.create_icon_texture(GenericDisplay.PREVIEW_ICON_SIZE);
|
||||
},
|
||||
// Ensures the preview icon is created.
|
||||
_ensurePreviewIconCreated : function() {
|
||||
if (!this._showPreview || this._previewIcon)
|
||||
return;
|
||||
|
||||
shellWorkspaceLaunch: function() {
|
||||
this.launch();
|
||||
let previewIconPath = this._appInfo.getIconPath(GenericDisplay.PREVIEW_ICON_SIZE);
|
||||
if (previewIconPath) {
|
||||
try {
|
||||
this._previewIcon = new Clutter.Texture({ width: GenericDisplay.PREVIEW_ICON_SIZE, height: GenericDisplay.PREVIEW_ICON_SIZE});
|
||||
this._previewIcon.set_from_file(previewIconPath);
|
||||
} catch (e) {
|
||||
// we can get an error here if the file path doesn't exist on the system
|
||||
log('Error loading AppDisplayItem preview icon ' + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -114,28 +113,24 @@ MenuItem.prototype = {
|
||||
}
|
||||
if (pixbuf != null)
|
||||
Shell.clutter_texture_set_from_pixbuf(this._icon, pixbuf);
|
||||
this.actor.append(this._icon, Big.BoxPackFlags.NONE);
|
||||
this.actor.append(this._icon, 0);
|
||||
this._text = new Clutter.Text({ color: GenericDisplay.ITEM_DISPLAY_NAME_COLOR,
|
||||
font_name: "Sans 14px",
|
||||
ellipsize: Pango.EllipsizeMode.END,
|
||||
text: name });
|
||||
this.actor.append(this._text, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
// 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 box = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
y_align: Big.BoxAlignment.CENTER
|
||||
});
|
||||
|
||||
labelBox.append(this._text, Big.BoxPackFlags.NONE);
|
||||
|
||||
this.actor.append(labelBox, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
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_ICON_SIZE/2,
|
||||
surface_height: MENU_ICON_SIZE/2,
|
||||
direction: Gtk.ArrowType.RIGHT,
|
||||
opacity: 0 });
|
||||
arrowBox.append(this._arrow, Big.BoxPackFlags.NONE);
|
||||
this.actor.append(arrowBox, Big.BoxPackFlags.NONE);
|
||||
opacity: 0
|
||||
});
|
||||
box.append(this._arrow, 0);
|
||||
this.actor.append(box, 0);
|
||||
},
|
||||
|
||||
getState: function() {
|
||||
@@ -165,16 +160,19 @@ 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.
|
||||
*
|
||||
* width - width available for the display
|
||||
* height - height available for the display
|
||||
*/
|
||||
function AppDisplay() {
|
||||
this._init();
|
||||
function AppDisplay(width, height, numberOfColumns, columnGap) {
|
||||
this._init(width, height, numberOfColumns, columnGap);
|
||||
}
|
||||
|
||||
AppDisplay.prototype = {
|
||||
__proto__: GenericDisplay.GenericDisplay.prototype,
|
||||
|
||||
_init : function() {
|
||||
GenericDisplay.GenericDisplay.prototype._init.call(this);
|
||||
_init : function(width, height, numberOfColumns, columnGap) {
|
||||
GenericDisplay.GenericDisplay.prototype._init.call(this, width, height, numberOfColumns, columnGap);
|
||||
|
||||
this._menus = [];
|
||||
this._menuDisplays = [];
|
||||
@@ -193,15 +191,12 @@ AppDisplay.prototype = {
|
||||
this._appSystem.connect('favorites-changed', Lang.bind(this, function(appSys) {
|
||||
this._redisplay(false);
|
||||
}));
|
||||
this._appMonitor.connect('app-added', Lang.bind(this, function(monitor) {
|
||||
this._redisplay(false);
|
||||
}));
|
||||
this._appMonitor.connect('app-removed', Lang.bind(this, function(monitor) {
|
||||
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 Overview
|
||||
// Load the GAppInfos now so it doesn't slow down the first
|
||||
// transition into the overlay
|
||||
this._refreshCache();
|
||||
|
||||
this._focusInMenus = true;
|
||||
@@ -216,7 +211,6 @@ AppDisplay.prototype = {
|
||||
this.connect('expanded', Lang.bind(this, function (self) {
|
||||
this._filterReset();
|
||||
}));
|
||||
this._filterReset();
|
||||
},
|
||||
|
||||
moveRight: function() {
|
||||
@@ -236,7 +230,7 @@ AppDisplay.prototype = {
|
||||
},
|
||||
|
||||
// Override genericDisplay.js
|
||||
getNavigationArea: function() {
|
||||
getSideArea: function() {
|
||||
return this._menuDisplay;
|
||||
},
|
||||
|
||||
@@ -257,13 +251,16 @@ AppDisplay.prototype = {
|
||||
// Protected overrides
|
||||
|
||||
_filterActive: function() {
|
||||
// We always have a filter now since a menu must be selected
|
||||
return true;
|
||||
return !!this._search || this._activeMenuIndex >= 0;
|
||||
},
|
||||
|
||||
_filterReset: function() {
|
||||
GenericDisplay.GenericDisplay.prototype._filterReset.call(this);
|
||||
this._selectMenuIndex(0);
|
||||
if (this._activeMenu != null)
|
||||
this._activeMenu.setState(MENU_UNSELECTED);
|
||||
this._activeMenuIndex = -1;
|
||||
this._activeMenu = null;
|
||||
this._focusInMenu = true;
|
||||
},
|
||||
|
||||
//// Private ////
|
||||
@@ -278,53 +275,48 @@ AppDisplay.prototype = {
|
||||
this._menuDisplays[index].setState(MENU_SELECTED);
|
||||
},
|
||||
|
||||
_getMostUsed: function() {
|
||||
let context = "";
|
||||
return this._appMonitor.get_most_used_apps(context, 30).map(Lang.bind(this, function (id) {
|
||||
return this._appSystem.lookup_cached_app(id);
|
||||
})).filter(function (e) { return e != null });
|
||||
},
|
||||
|
||||
_addMenuItem: function(name, id, icon, index) {
|
||||
let display = new MenuItem(name, id, icon);
|
||||
this._menuDisplays.push(display);
|
||||
display.connect('state-changed', Lang.bind(this, function (display) {
|
||||
let activated = display.getState() != MENU_UNSELECTED;
|
||||
if (!activated && display == this._activeMenu) {
|
||||
this._activeMenuIndex = -1;
|
||||
this._activeMenu = null;
|
||||
} else if (activated) {
|
||||
if (display != this._activeMenu && this._activeMenu != null)
|
||||
this._activeMenu.setState(MENU_UNSELECTED);
|
||||
this._activeMenuIndex = index;
|
||||
this._activeMenu = display;
|
||||
if (id == null) {
|
||||
this._activeMenuApps = this._getMostUsed();
|
||||
} else {
|
||||
this._activeMenuApps = this._appSystem.get_applications_for_menu(id);
|
||||
}
|
||||
}
|
||||
this._redisplay(true);
|
||||
}));
|
||||
this._menuDisplay.append(display.actor, 0);
|
||||
},
|
||||
|
||||
_redisplayMenus: function() {
|
||||
this._menuDisplay.remove_all();
|
||||
this._addMenuItem(_("Frequent"), null, 'gtk-select-all');
|
||||
for (let i = 0; i < this._menus.length; i++) {
|
||||
let menu = this._menus[i];
|
||||
this._addMenuItem(menu.name, menu.id, menu.icon, i+1);
|
||||
let display = new MenuItem(menu.name, menu.id, menu.icon);
|
||||
this._menuDisplays.push(display);
|
||||
let menuIndex = i;
|
||||
display.connect('state-changed', Lang.bind(this, function (display) {
|
||||
let activated = display.getState() != MENU_UNSELECTED;
|
||||
if (!activated && display == this._activeMenu) {
|
||||
this._activeMenuIndex = -1;
|
||||
this._activeMenu = null;
|
||||
} else if (activated) {
|
||||
if (display != this._activeMenu && this._activeMenu != null)
|
||||
this._activeMenu.setState(MENU_UNSELECTED);
|
||||
this._activeMenuIndex = menuIndex;
|
||||
this._activeMenu = display;
|
||||
this._activeMenuApps = this._appSystem.get_applications_for_menu(menu.id);
|
||||
}
|
||||
this._redisplay();
|
||||
}));
|
||||
this._menuDisplay.append(display.actor, 0);
|
||||
}
|
||||
},
|
||||
|
||||
_addAppForId: function(appId) {
|
||||
let appInfo = AppInfo.getAppInfo(appId);
|
||||
if (appInfo != null) {
|
||||
this._addApp(appInfo);
|
||||
} else {
|
||||
log("appInfo for " + appId + " was not found.");
|
||||
}
|
||||
},
|
||||
|
||||
_addApp: function(appInfo) {
|
||||
let appId = appInfo.get_id();
|
||||
let appId = appInfo.id;
|
||||
this._allItems[appId] = appInfo;
|
||||
// [] is returned if we could not get the categories or the list of categories was empty
|
||||
let categories = Shell.get_categories_for_desktop_file(appId);
|
||||
this._appCategories[appId] = categories;
|
||||
},
|
||||
|
||||
//// Protected method overrides ////
|
||||
|
||||
// Gets information about all applications by calling Gio.app_info_get_all().
|
||||
_refreshCache : function() {
|
||||
let me = this;
|
||||
@@ -333,21 +325,16 @@ AppDisplay.prototype = {
|
||||
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, skipping empty menus
|
||||
let allMenus = this._appSystem.get_menus();
|
||||
this._menus = [];
|
||||
for (let i = 0; i < allMenus.length; i++) {
|
||||
let menu = allMenus[i];
|
||||
// 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);
|
||||
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);
|
||||
let appId = menuApps[j];
|
||||
this._addAppForId(appId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,16 +342,17 @@ AppDisplay.prototype = {
|
||||
// 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);
|
||||
let appId = settings[i];
|
||||
this._addAppForId(appId);
|
||||
}
|
||||
|
||||
this._appsStale = false;
|
||||
},
|
||||
|
||||
// Stub this out; the app display always has a category selected
|
||||
// Sets the list of the displayed items based on the most used apps.
|
||||
_setDefaultList : function() {
|
||||
this._matchedItems = [];
|
||||
let matchedInfos = AppInfo.getTopApps(MAX_ITEMS);
|
||||
this._matchedItems = matchedInfos.map(function(info) { return info.appId; });
|
||||
},
|
||||
|
||||
// Compares items associated with the item ids based on the alphabetical order
|
||||
@@ -373,17 +361,14 @@ AppDisplay.prototype = {
|
||||
_compareItems : function(itemIdA, itemIdB) {
|
||||
let appA = this._allItems[itemIdA];
|
||||
let appB = this._allItems[itemIdB];
|
||||
return appA.get_name().localeCompare(appB.get_name());
|
||||
return appA.name.localeCompare(appB.name);
|
||||
},
|
||||
|
||||
// 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.
|
||||
// Item info is expected to be Shell.AppInfo.
|
||||
// the name, description, execution command, and categories for the application.
|
||||
// Item info is expected to be GAppInfo.
|
||||
// Returns a boolean flag indicating if itemInfo is a match.
|
||||
_isInfoMatching : function(itemInfo, search) {
|
||||
// Don't show nodisplay items here
|
||||
if (itemInfo.get_is_nodisplay())
|
||||
return false;
|
||||
// Search takes precedence; not typically useful to search within a
|
||||
// menu
|
||||
if (this._activeMenu == null || search != "")
|
||||
@@ -393,10 +378,10 @@ AppDisplay.prototype = {
|
||||
},
|
||||
|
||||
_isInfoMatchingMenu : function(itemInfo, search) {
|
||||
let id = itemInfo.get_id();
|
||||
let id = itemInfo.id;
|
||||
for (let i = 0; i < this._activeMenuApps.length; i++) {
|
||||
let activeApp = this._activeMenuApps[i];
|
||||
if (activeApp.get_id() == id)
|
||||
let activeId = this._activeMenuApps[i];
|
||||
if (activeId == id)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -406,43 +391,39 @@ AppDisplay.prototype = {
|
||||
if (search == null || search == '')
|
||||
return true;
|
||||
|
||||
let fold = function(s) {
|
||||
if (!s)
|
||||
return s;
|
||||
return GLib.utf8_casefold(GLib.utf8_normalize(s, -1,
|
||||
GLib.NormalizeMode.ALL), -1);
|
||||
};
|
||||
let name = fold(itemInfo.get_name());
|
||||
let name = itemInfo.name.toLowerCase();
|
||||
if (name.indexOf(search) >= 0)
|
||||
return true;
|
||||
|
||||
let description = fold(itemInfo.get_description());
|
||||
let description = itemInfo.description;
|
||||
if (description) {
|
||||
description = description.toLowerCase();
|
||||
if (description.indexOf(search) >= 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
let exec = fold(itemInfo.get_executable());
|
||||
if (exec == null) {
|
||||
if (itemInfo.executable == null) {
|
||||
log("Missing an executable for " + itemInfo.name);
|
||||
} else {
|
||||
let exec = itemInfo.executable.toLowerCase();
|
||||
if (exec.indexOf(search) >= 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
let categories = itemInfo.get_categories();
|
||||
// we expect this._appCategories.hasOwnProperty(itemInfo.id) to always be true here
|
||||
let categories = this._appCategories[itemInfo.id];
|
||||
for (let i = 0; i < categories.length; i++) {
|
||||
let category = fold(categories[i]);
|
||||
let category = categories[i].toLowerCase();
|
||||
if (category.indexOf(search) >= 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
// Creates an AppDisplayItem based on itemInfo, which is expected be an Shell.AppInfo object.
|
||||
// Creates an AppDisplayItem based on itemInfo, which is expected be an AppInfo object.
|
||||
_createDisplayItem: function(itemInfo) {
|
||||
return new AppDisplayItem(itemInfo);
|
||||
return new AppDisplayItem(itemInfo, this._columnWidth);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -453,250 +434,142 @@ function WellDisplayItem(appInfo, isFavorite) {
|
||||
}
|
||||
|
||||
WellDisplayItem.prototype = {
|
||||
__proto__ : AppIcon.AppIcon.prototype,
|
||||
|
||||
_init : function(appInfo, isFavorite) {
|
||||
AppIcon.AppIcon.prototype._init.call(this, appInfo);
|
||||
this.appInfo = appInfo;
|
||||
|
||||
this.isFavorite = isFavorite;
|
||||
|
||||
this.actor = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
width: APP_ICON_SIZE,
|
||||
reactive: true });
|
||||
this.actor._delegate = this;
|
||||
this.actor.connect('button-release-event', Lang.bind(this, function (b, e) {
|
||||
this._handleActivate();
|
||||
this.launch();
|
||||
this.emit('activated');
|
||||
}));
|
||||
|
||||
let draggable = DND.makeDraggable(this.actor);
|
||||
},
|
||||
|
||||
_handleActivate: function () {
|
||||
if (this._windows.length == 0) {
|
||||
this.appInfo.launch();
|
||||
Main.overview.hide();
|
||||
this._icon = appInfo.createIcon(APP_ICON_SIZE);
|
||||
|
||||
this.actor.append(this._icon, Big.BoxPackFlags.NONE);
|
||||
|
||||
let count = Shell.AppMonitor.get_default().get_window_count(appInfo.appId);
|
||||
|
||||
this._name = new Clutter.Text({ color: GenericDisplay.ITEM_DISPLAY_NAME_COLOR,
|
||||
font_name: "Sans 12px",
|
||||
ellipsize: Pango.EllipsizeMode.END,
|
||||
text: appInfo.name });
|
||||
if (count > 0) {
|
||||
let runningBox = new Big.Box({ /* border_color: GenericDisplay.ITEM_DISPLAY_NAME_COLOR,
|
||||
border: 1,
|
||||
padding: 1 */ });
|
||||
runningBox.append(this._name, Big.BoxPackFlags.EXPAND);
|
||||
this.actor.append(runningBox, Big.BoxPackFlags.NONE);
|
||||
} 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.overview.activateWindow(first, Clutter.get_current_event_time());
|
||||
this.actor.append(this._name, Big.BoxPackFlags.NONE);
|
||||
}
|
||||
},
|
||||
|
||||
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.
|
||||
// Opens an application represented by this display item.
|
||||
launch : function() {
|
||||
this.appInfo.launch();
|
||||
},
|
||||
|
||||
// Draggable interface - FIXME deduplicate with GenericDisplay
|
||||
getDragActor: function(stageX, stageY) {
|
||||
return this.appInfo.create_icon_texture(this._icon.height);
|
||||
this.dragActor = this.appInfo.createIcon(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;
|
||||
},
|
||||
|
||||
// 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;
|
||||
},
|
||||
|
||||
setWidth: function(width) {
|
||||
this._nameBox.width = width + GLOW_PADDING * 2;
|
||||
}
|
||||
};
|
||||
|
||||
function WellGrid() {
|
||||
this._init();
|
||||
Signals.addSignalMethods(WellDisplayItem.prototype);
|
||||
|
||||
function WellArea(width, isFavorite) {
|
||||
this._init(width, isFavorite);
|
||||
}
|
||||
|
||||
WellGrid.prototype = {
|
||||
_init: function() {
|
||||
this.actor = new Shell.GenericContainer();
|
||||
WellArea.prototype = {
|
||||
_init : function(width, isFavorite) {
|
||||
this.isFavorite = isFavorite;
|
||||
|
||||
this._separator = new Big.Box({ height: 1 });
|
||||
this.actor.add_actor(this._separator);
|
||||
this._separatorIndex = 0;
|
||||
this._cachedSeparatorY = 0;
|
||||
|
||||
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
||||
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
||||
this.actor = new Tidy.Grid({ width: width });
|
||||
this.actor._delegate = this;
|
||||
},
|
||||
|
||||
_getPreferredWidth: function (grid, forHeight, alloc) {
|
||||
let [itemMin, itemNatural] = this._getItemPreferredWidth();
|
||||
let children = this._getItemChildren();
|
||||
let nColumns;
|
||||
if (children.length < WELL_DEFAULT_COLUMNS)
|
||||
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;
|
||||
redisplay: function (infos) {
|
||||
let children;
|
||||
|
||||
children = this.actor.get_children();
|
||||
children.forEach(Lang.bind(this, function (v) {
|
||||
v.destroy();
|
||||
}));
|
||||
|
||||
for (let i = 0; i < infos.length; i++) {
|
||||
let display = new WellDisplayItem(infos[i], this.isFavorite);
|
||||
display.connect('activated', Lang.bind(this, function (display) {
|
||||
this.emit('activated', display);
|
||||
}));
|
||||
this.actor.add_actor(display.actor);
|
||||
};
|
||||
},
|
||||
|
||||
_getPreferredHeight: function (grid, forWidth, alloc) {
|
||||
let [rows, columns, itemWidth, itemHeight] = this._computeLayout(forWidth);
|
||||
let totalVerticalSpacing = Math.max(rows - 1, 0) * WELL_ITEM_VSPACING;
|
||||
// Draggable target interface
|
||||
acceptDrop : function(source, actor, x, y, time) {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
let [separatorMin, separatorNatural] = this._separator.get_preferred_height(forWidth);
|
||||
alloc.min_size = alloc.natural_size = rows * itemHeight + totalVerticalSpacing + separatorNatural;
|
||||
},
|
||||
|
||||
_allocate: function (grid, box, flags) {
|
||||
let children = this._getItemChildren();
|
||||
let availWidth = box.x2 - box.x1;
|
||||
let availHeight = box.y2 - box.y1;
|
||||
|
||||
let [rows, columns, itemWidth, itemHeight] = this._computeLayout(availWidth);
|
||||
|
||||
let [separatorMin, separatorNatural] = this._separator.get_preferred_height(-1);
|
||||
|
||||
let x = box.x1;
|
||||
let y = box.y1;
|
||||
let columnIndex = 0;
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
let [childMinWidth, childNaturalWidth] = children[i].get_preferred_width(-1);
|
||||
|
||||
/* Center the item in its allocation horizontally */
|
||||
let width = Math.min(itemWidth, childNaturalWidth);
|
||||
let horizSpacing = (itemWidth - width) / 2;
|
||||
|
||||
let childBox = new Clutter.ActorBox();
|
||||
childBox.x1 = Math.floor(x + horizSpacing);
|
||||
childBox.y1 = y;
|
||||
childBox.x2 = childBox.x1 + width;
|
||||
childBox.y2 = childBox.y1 + itemHeight;
|
||||
children[i].allocate(childBox, flags);
|
||||
|
||||
let atSeparator = (i == this._separatorIndex - 1);
|
||||
|
||||
columnIndex++;
|
||||
if (columnIndex == columns || atSeparator) {
|
||||
columnIndex = 0;
|
||||
}
|
||||
|
||||
if (columnIndex == 0) {
|
||||
y += itemHeight + WELL_ITEM_VSPACING;
|
||||
x = box.x1;
|
||||
} else {
|
||||
x += itemWidth + WELL_ITEM_HSPACING;
|
||||
}
|
||||
|
||||
if (atSeparator) {
|
||||
y += separatorNatural + WELL_ITEM_VSPACING;
|
||||
}
|
||||
if (!(source instanceof WellDisplayItem)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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 () {
|
||||
let itemChildren = this._getItemChildren();
|
||||
for (let i = 0; i < itemChildren.length; i++) {
|
||||
itemChildren[i].destroy();
|
||||
}
|
||||
this._separatorIndex = 0;
|
||||
},
|
||||
|
||||
isBeforeSeparator: function(x, y) {
|
||||
return y < this._cachedSeparatorY;
|
||||
},
|
||||
|
||||
_getItemChildren: function () {
|
||||
let children = this.actor.get_children();
|
||||
children.shift();
|
||||
return children;
|
||||
},
|
||||
|
||||
_computeLayout: function (forWidth) {
|
||||
let [itemMinWidth, itemNaturalWidth] = this._getItemPreferredWidth();
|
||||
let columnsNatural;
|
||||
let i;
|
||||
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
|
||||
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 */
|
||||
}
|
||||
|
||||
let horizSpacingTotal = Math.max(nColumns - 1, 0) * WELL_ITEM_HSPACING;
|
||||
let minWidth = itemMinWidth * nColumns + horizSpacingTotal;
|
||||
|
||||
let lastColumnIndex = nColumns - 1;
|
||||
let separatorColumns = lastColumnIndex - ((lastColumnIndex + this._separatorIndex) % nColumns);
|
||||
let rows = Math.ceil((children.length + separatorColumns) / nColumns);
|
||||
|
||||
let itemWidth;
|
||||
if (forWidth < 0) {
|
||||
itemWidth = itemNaturalWidth;
|
||||
let appSystem = Shell.AppSystem.get_default();
|
||||
let id = source.appInfo.appId;
|
||||
if (source.isFavorite && (!this.isFavorite)) {
|
||||
Mainloop.idle_add(function () {
|
||||
appSystem.remove_favorite(id);
|
||||
});
|
||||
} else if ((!source.isFavorite) && this.isFavorite) {
|
||||
Mainloop.idle_add(function () {
|
||||
appSystem.add_favorite(id);
|
||||
});
|
||||
} else {
|
||||
itemWidth = Math.max(forWidth - horizSpacingTotal, 0) / nColumns;
|
||||
return false;
|
||||
}
|
||||
|
||||
let itemNaturalHeight = 0;
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
let [childMin, childNatural] = children[i].get_preferred_height(itemWidth);
|
||||
if (childNatural > itemNaturalHeight)
|
||||
itemNaturalHeight = childNatural;
|
||||
}
|
||||
|
||||
return [rows, WELL_DEFAULT_COLUMNS, itemWidth, itemNaturalHeight];
|
||||
},
|
||||
|
||||
_getItemPreferredWidth: function () {
|
||||
let children = this._getItemChildren();
|
||||
let minWidth = 0;
|
||||
let naturalWidth = 0;
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
let [childMin, childNatural] = children[i].get_preferred_width(-1);
|
||||
if (childMin > minWidth)
|
||||
minWidth = childMin;
|
||||
if (childNatural > naturalWidth)
|
||||
naturalWidth = childNatural;
|
||||
}
|
||||
return [minWidth, naturalWidth];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function AppWell() {
|
||||
this._init();
|
||||
Signals.addSignalMethods(WellArea.prototype);
|
||||
|
||||
function AppWell(width) {
|
||||
this._init(width);
|
||||
}
|
||||
|
||||
AppWell.prototype = {
|
||||
_init : function() {
|
||||
_init : function(width) {
|
||||
this._menus = [];
|
||||
this._menuDisplays = [];
|
||||
|
||||
this.actor = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
x_align: Big.BoxAlignment.CENTER });
|
||||
this.actor._delegate = this;
|
||||
|
||||
this._grid = new WellGrid();
|
||||
this.actor.append(this._grid.actor, Big.BoxPackFlags.EXPAND);
|
||||
width: width });
|
||||
|
||||
this._appSystem = Shell.AppSystem.get_default();
|
||||
this._appMonitor = Shell.AppMonitor.get_default();
|
||||
@@ -707,107 +580,44 @@ AppWell.prototype = {
|
||||
this._appSystem.connect('favorites-changed', Lang.bind(this, function(appSys) {
|
||||
this._redisplay();
|
||||
}));
|
||||
this._appMonitor.connect('window-added', Lang.bind(this, function(monitor) {
|
||||
this._appMonitor.connect('changed', Lang.bind(this, function(monitor) {
|
||||
this._redisplay();
|
||||
}));
|
||||
this._appMonitor.connect('window-removed', Lang.bind(this, function(monitor) {
|
||||
this._redisplay();
|
||||
|
||||
this._favoritesArea = new WellArea(width, true);
|
||||
this._favoritesArea.connect('activated', Lang.bind(this, function (a, display) {
|
||||
this.emit('activated');
|
||||
}));
|
||||
this.actor.append(this._favoritesArea.actor, Big.BoxPackFlags.NONE);
|
||||
|
||||
this._runningBox = new Big.Box({ border_color: GenericDisplay.ITEM_DISPLAY_NAME_COLOR,
|
||||
border: 1,
|
||||
corner_radius: 3,
|
||||
padding: GenericDisplay.PREVIEW_BOX_PADDING });
|
||||
this._runningArea = new WellArea(width, false);
|
||||
this._runningArea.connect('activated', Lang.bind(this, function (a, display) {
|
||||
this.emit('activated');
|
||||
}));
|
||||
this._runningBox.append(this._runningArea.actor, Big.BoxPackFlags.EXPAND);
|
||||
this.actor.append(this._runningBox, Big.BoxPackFlags.NONE);
|
||||
|
||||
this._redisplay();
|
||||
},
|
||||
|
||||
_lookupApps: function(appIds) {
|
||||
let result = [];
|
||||
for (let i = 0; i < appIds.length; i++) {
|
||||
let id = appIds[i];
|
||||
let app = this._appSystem.lookup_cached_app(id);
|
||||
if (!app)
|
||||
continue;
|
||||
result.push(app);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
_arrayValues: function(array) {
|
||||
return array.reduce(function (values, id, index) {
|
||||
values[id] = index; return values; }, {});
|
||||
},
|
||||
|
||||
_redisplay: function () {
|
||||
this._grid.removeAll();
|
||||
|
||||
let favoriteIds = this._appSystem.get_favorites();
|
||||
let favoriteIdsHash = this._arrayValues(favoriteIds);
|
||||
|
||||
/* hardcode here pending some design about how exactly desktop contexts behave */
|
||||
let contextId = "";
|
||||
|
||||
let running = this._appMonitor.get_running_apps(contextId).filter(function (e) {
|
||||
return !(e.get_id() in favoriteIdsHash);
|
||||
_redisplay: function() {
|
||||
let arrayToObject = function(a) {
|
||||
let o = {};
|
||||
for (let i = 0; i < a.length; i++)
|
||||
o[a[i]] = 1;
|
||||
return o;
|
||||
};
|
||||
let favorites = AppInfo.getFavorites();
|
||||
let favoriteIds = arrayToObject(favorites.map(function (e) { return e.appId; }));
|
||||
let running = AppInfo.getRunning().filter(function (e) {
|
||||
return !(e.appId in favoriteIds);
|
||||
});
|
||||
let favorites = this._lookupApps(favoriteIds);
|
||||
|
||||
let displays = []
|
||||
this._addApps(favorites, true);
|
||||
this._grid.setSeparatorIndex(favorites.length);
|
||||
this._addApps(running, false);
|
||||
this._displays = displays;
|
||||
},
|
||||
|
||||
_addApps: function(apps) {
|
||||
for (let i = 0; i < apps.length; i++) {
|
||||
let app = apps[i];
|
||||
let display = new WellDisplayItem(app, this.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 app = null;
|
||||
if (source instanceof WellDisplayItem) {
|
||||
app = source.appInfo;
|
||||
} else if (source instanceof AppDisplayItem) {
|
||||
app = appSystem.lookup_cached_app(source.getId());
|
||||
} else if (source instanceof Workspaces.WindowClone) {
|
||||
let appMonitor = Shell.AppMonitor.get_default();
|
||||
app = appMonitor.get_window_app(source.metaWindow);
|
||||
}
|
||||
|
||||
// Don't allow favoriting of transient apps
|
||||
if (app == null || app.is_transient()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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) {
|
||||
Mainloop.idle_add(function () {
|
||||
appSystem.add_favorite(id);
|
||||
return false;
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
this._favoritesArea.redisplay(favorites);
|
||||
this._runningArea.redisplay(running);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Big = imports.gi.Big;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Pango = imports.gi.Pango;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Lang = imports.lang;
|
||||
|
||||
const GenericDisplay = imports.ui.genericDisplay;
|
||||
const Main = imports.ui.main;
|
||||
|
||||
const GLOW_COLOR = new Clutter.Color();
|
||||
GLOW_COLOR.from_pixel(0x4f6ba4ff);
|
||||
const GLOW_PADDING = 5;
|
||||
|
||||
const APP_ICON_SIZE = 48;
|
||||
|
||||
function AppIcon(appInfo) {
|
||||
this._init(appInfo);
|
||||
}
|
||||
|
||||
AppIcon.prototype = {
|
||||
_init : function(appInfo) {
|
||||
this.appInfo = appInfo;
|
||||
|
||||
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;
|
||||
|
||||
let iconBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
x_align: Big.BoxAlignment.CENTER,
|
||||
y_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.EXPAND);
|
||||
|
||||
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_app_highlight(tex,
|
||||
this._windows.length,
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
};
|
||||
136
js/ui/button.js
136
js/ui/button.js
@@ -2,11 +2,6 @@
|
||||
|
||||
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();
|
||||
DEFAULT_BUTTON_COLOR.from_pixel(0xeeddcc66);
|
||||
@@ -14,20 +9,12 @@ DEFAULT_BUTTON_COLOR.from_pixel(0xeeddcc66);
|
||||
const DEFAULT_PRESSED_BUTTON_COLOR = new Clutter.Color();
|
||||
DEFAULT_PRESSED_BUTTON_COLOR.from_pixel(0xccbbaa66);
|
||||
|
||||
const DEFAULT_TEXT_COLOR = new Clutter.Color();
|
||||
DEFAULT_TEXT_COLOR.from_pixel(0x000000ff);
|
||||
|
||||
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, font) {
|
||||
this._init(widget, buttonColor, pressedButtonColor, textColor, staysPressed, font);
|
||||
function Button(widget, buttonColor, pressedButtonColor, staysPressed, minWidth, minHeight) {
|
||||
this._init(widget, buttonColor, pressedButtonColor, staysPressed, minWidth, minHeight);
|
||||
}
|
||||
|
||||
Button.prototype = {
|
||||
_init : function(widgetOrText, buttonColor, pressedButtonColor, textColor, staysPressed, font) {
|
||||
_init : function(widgetOrText, buttonColor, pressedButtonColor, staysPressed, minWidth, minHeight) {
|
||||
let me = this;
|
||||
|
||||
this._buttonColor = buttonColor
|
||||
@@ -38,17 +25,14 @@ Button.prototype = {
|
||||
if (pressedButtonColor == null)
|
||||
this._pressedButtonColor = DEFAULT_PRESSED_BUTTON_COLOR;
|
||||
|
||||
this._textColor = textColor;
|
||||
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
|
||||
@@ -58,14 +42,13 @@ Button.prototype = {
|
||||
|
||||
this.button = new Big.Box({ reactive: true,
|
||||
corner_radius: 5,
|
||||
padding_left: SIDE_PADDING,
|
||||
padding_right: SIDE_PADDING,
|
||||
padding_left: 4,
|
||||
padding_right: 4,
|
||||
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,
|
||||
this._widget = new Clutter.Text({ font_name: "Sans Bold 16px",
|
||||
text: widgetOrText });
|
||||
} else {
|
||||
this._widget = widgetOrText;
|
||||
@@ -73,6 +56,9 @@ Button.prototype = {
|
||||
|
||||
this.button.append(this._widget, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
this._minWidth = minWidth;
|
||||
this._minHeight = minHeight;
|
||||
|
||||
this.button.connect('button-press-event',
|
||||
function(o, event) {
|
||||
me._isBetweenPressAndRelease = true;
|
||||
@@ -95,7 +81,6 @@ Button.prototype = {
|
||||
if (!me._active) {
|
||||
me.button.backgroundColor = me._buttonColor;
|
||||
}
|
||||
me.emit('enter-event');
|
||||
return false;
|
||||
});
|
||||
this.button.connect('leave-event',
|
||||
@@ -105,7 +90,6 @@ Button.prototype = {
|
||||
if (!me._active) {
|
||||
me.button.backgroundColor = null;
|
||||
}
|
||||
me.emit('leave-event');
|
||||
return false;
|
||||
});
|
||||
},
|
||||
@@ -128,97 +112,3 @@ Button.prototype = {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Signals.addSignalMethods(Button.prototype);
|
||||
|
||||
/* Delay before the icon should appear, in seconds after the pointer has entered the parent */
|
||||
const ANIMATION_TIME = 0.25;
|
||||
|
||||
/* This is an icon button that fades in/out when mouse enters/leaves the parent.
|
||||
* A delay is used before the fading starts. You can force it to be shown if needed.
|
||||
*
|
||||
* parent -- used to show/hide the button depending on mouse entering/leaving it
|
||||
* 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) {
|
||||
this._init(parent, size, texture);
|
||||
}
|
||||
|
||||
iconButton.prototype = {
|
||||
_init : function(parent, size, texture) {
|
||||
this._size = size;
|
||||
if (texture)
|
||||
this.actor = texture;
|
||||
else
|
||||
this.actor = new Clutter.Texture({ width: this._size, height: this._size });
|
||||
this.actor.set_reactive(true);
|
||||
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)
|
||||
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)
|
||||
return;
|
||||
|
||||
// Remember that we should not be visible to hide the button if forceShow is unset
|
||||
if (this._forceShow) {
|
||||
this._shouldHide = true;
|
||||
return;
|
||||
}
|
||||
|
||||
this._fadeOut();
|
||||
}));
|
||||
},
|
||||
|
||||
/// Private methods ///
|
||||
|
||||
setIconFromName : function(iconName) {
|
||||
let iconTheme = Gtk.IconTheme.get_default();
|
||||
let iconInfo = iconTheme.lookup_icon(iconName, this._size, 0);
|
||||
if (!iconInfo)
|
||||
return;
|
||||
|
||||
let iconPath = iconInfo.get_filename();
|
||||
this.actor.set_from_file(iconPath);
|
||||
},
|
||||
|
||||
// Useful if we want to show the button immediately,
|
||||
// e.g. in case the mouse is already in the parent when the button is created
|
||||
show : function() {
|
||||
this.actor.set_opacity(255);
|
||||
},
|
||||
|
||||
// If show is true, prevents the button from fading out
|
||||
forceShow : function(show) {
|
||||
this._forceShow = show;
|
||||
// Hide the button if it should have been hidden under normal conditions
|
||||
if (!this._forceShow && this._shouldHide) {
|
||||
this._fadeOut();
|
||||
}
|
||||
},
|
||||
|
||||
/// Private methods ///
|
||||
|
||||
_fadeIn : function() {
|
||||
Tweener.removeTweens(this.actor);
|
||||
Tweener.addTween(this.actor, { opacity: 255,
|
||||
time: ANIMATION_TIME,
|
||||
transition :"easeInQuad" });
|
||||
},
|
||||
|
||||
_fadeOut : function() {
|
||||
Tweener.removeTweens(this.actor);
|
||||
Tweener.addTween(this.actor, { opacity: 0,
|
||||
time: ANIMATION_TIME,
|
||||
transition :"easeOutQuad" });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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 Overview), that surrounds the main
|
||||
// normal mode (ie, outside the overlay), that surrounds the main
|
||||
// workspace content.
|
||||
|
||||
function Chrome() {
|
||||
@@ -23,8 +23,8 @@ Chrome.prototype = {
|
||||
// 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.nonOverviewActor = new Clutter.Group();
|
||||
this.actor.add_actor(this.nonOverviewActor);
|
||||
this.nonOverlayActor = new Clutter.Group();
|
||||
this.actor.add_actor(this.nonOverlayActor);
|
||||
|
||||
this._obscuredByFullscreen = false;
|
||||
|
||||
@@ -37,10 +37,10 @@ Chrome.prototype = {
|
||||
global.screen.connect('notify::n-workspaces',
|
||||
Lang.bind(this, this._queueUpdateRegions));
|
||||
|
||||
Main.overview.connect('showing',
|
||||
Lang.bind(this, this._overviewShowing));
|
||||
Main.overview.connect('hidden',
|
||||
Lang.bind(this, this._overviewHidden));
|
||||
Main.overlay.connect('showing',
|
||||
Lang.bind(this, this._overlayShowing));
|
||||
Main.overlay.connect('hidden',
|
||||
Lang.bind(this, this._overlayHidden));
|
||||
|
||||
this._queueUpdateRegions();
|
||||
},
|
||||
@@ -78,27 +78,27 @@ Chrome.prototype = {
|
||||
else if (shapeActor && !this._verifyAncestry(shapeActor, actor))
|
||||
throw new Error('shapeActor is not a descendent of actor');
|
||||
|
||||
this.nonOverviewActor.add_actor(actor);
|
||||
this.nonOverlayActor.add_actor(actor);
|
||||
|
||||
if (shapeActor)
|
||||
this._trackActor(shapeActor, true, true);
|
||||
},
|
||||
|
||||
// setVisibleInOverview:
|
||||
// setVisibleInOverlay:
|
||||
// @actor: an actor in the chrome layer
|
||||
// @visible: Overview visibility
|
||||
// @visible: overlay visibility
|
||||
//
|
||||
// By default, actors in the chrome layer are automatically hidden
|
||||
// when the Overview is shown. This can be used to override that
|
||||
// when the overlay is shown. This can be used to override that
|
||||
// behavior
|
||||
setVisibleInOverview: function(actor, visible) {
|
||||
setVisibleInOverlay: 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.nonOverviewActor);
|
||||
actor.reparent(this.nonOverlayActor);
|
||||
},
|
||||
|
||||
// addInputRegionActor:
|
||||
@@ -126,11 +126,9 @@ Chrome.prototype = {
|
||||
//
|
||||
// Removes @actor from the chrome layer
|
||||
removeActor: function(actor) {
|
||||
if (actor.get_parent() == this.nonOverviewActor)
|
||||
this.nonOverviewActor.remove_actor(actor);
|
||||
else
|
||||
this.actor.remove_actor(actor);
|
||||
this._untrackActor(actor, true, true);
|
||||
this.actor.remove_actor(actor);
|
||||
// We don't have to do anything else; the parent-set handlers
|
||||
// will do the rest.
|
||||
},
|
||||
|
||||
_findActor: function(actor) {
|
||||
@@ -172,7 +170,7 @@ Chrome.prototype = {
|
||||
this._trackedActors.push(actorData);
|
||||
|
||||
actor = actor.get_parent();
|
||||
if (actor != this.actor && actor != this.nonOverviewActor)
|
||||
if (actor != this.actor)
|
||||
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.nonOverviewActor)
|
||||
if (actor && actor != this.actor)
|
||||
this._untrackActor(actor, false, false);
|
||||
}
|
||||
|
||||
@@ -211,30 +209,29 @@ Chrome.prototype = {
|
||||
_actorReparented: function(actor, oldParent) {
|
||||
if (this._verifyAncestry(actor, this.actor)) {
|
||||
let newParent = actor.get_parent();
|
||||
if (newParent != this.actor && newParent != this.nonOverviewActor)
|
||||
if (newParent != this.actor)
|
||||
this._trackActor(newParent, false, false);
|
||||
}
|
||||
if (oldParent != this.actor && oldParent != this.nonOverviewActor)
|
||||
if (oldParent != this.actor)
|
||||
this._untrackActor(oldParent, false, false);
|
||||
},
|
||||
|
||||
_overviewShowing: function() {
|
||||
_overlayShowing: function() {
|
||||
this.actor.show();
|
||||
this.nonOverviewActor.hide();
|
||||
this.nonOverlayActor.hide();
|
||||
this._queueUpdateRegions();
|
||||
},
|
||||
|
||||
_overviewHidden: function() {
|
||||
_overlayHidden: function() {
|
||||
if (this._obscuredByFullscreen)
|
||||
this.actor.hide();
|
||||
this.nonOverviewActor.show();
|
||||
this.nonOverlayActor.show();
|
||||
this._queueUpdateRegions();
|
||||
},
|
||||
|
||||
_queueUpdateRegions: function() {
|
||||
if (!this._updateRegionIdle)
|
||||
this._updateRegionIdle = Mainloop.idle_add(Lang.bind(this, this._updateRegions),
|
||||
Meta.PRIORITY_BEFORE_REDRAW);
|
||||
this._updateRegionIdle = Mainloop.idle_add(Lang.bind(this, this._updateRegions));
|
||||
},
|
||||
|
||||
_windowsRestacked: function() {
|
||||
@@ -272,7 +269,7 @@ Chrome.prototype = {
|
||||
break;
|
||||
}
|
||||
|
||||
let shouldBeVisible = !this._obscuredByFullscreen || Main.overview.visible;
|
||||
let shouldBeVisible = !this._obscuredByFullscreen || Main.overlay.visible;
|
||||
if (this.actor.visible != shouldBeVisible) {
|
||||
this.actor.visible = shouldBeVisible;
|
||||
this._queueUpdateRegions();
|
||||
|
||||
819
js/ui/dash.js
819
js/ui/dash.js
@@ -1,819 +0,0 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Big = imports.gi.Big;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Pango = imports.gi.Pango;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const Lang = imports.lang;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const AppDisplay = imports.ui.appDisplay;
|
||||
const DocDisplay = imports.ui.docDisplay;
|
||||
const Places = imports.ui.places;
|
||||
const GenericDisplay = imports.ui.genericDisplay;
|
||||
const Button = imports.ui.button;
|
||||
const Main = imports.ui.main;
|
||||
|
||||
const DEFAULT_PADDING = 4;
|
||||
const DEFAULT_SPACING = 4;
|
||||
const DASH_SECTION_PADDING = 6;
|
||||
const DASH_SECTION_SPACING = 40;
|
||||
const DASH_CORNER_RADIUS = 5;
|
||||
const DASH_PADDING_SIDE = 14;
|
||||
|
||||
const BACKGROUND_COLOR = new Clutter.Color();
|
||||
BACKGROUND_COLOR.from_pixel(0x000000c0);
|
||||
|
||||
const PRELIGHT_COLOR = new Clutter.Color();
|
||||
PRELIGHT_COLOR.from_pixel(0x4f6fadaa);
|
||||
|
||||
const TEXT_COLOR = new Clutter.Color();
|
||||
TEXT_COLOR.from_pixel(0x5f5f5fff);
|
||||
const BRIGHTER_TEXT_COLOR = new Clutter.Color();
|
||||
BRIGHTER_TEXT_COLOR.from_pixel(0xbbbbbbff);
|
||||
const BRIGHT_TEXT_COLOR = new Clutter.Color();
|
||||
BRIGHT_TEXT_COLOR.from_pixel(0xffffffff);
|
||||
const SEARCH_TEXT_COLOR = new Clutter.Color();
|
||||
SEARCH_TEXT_COLOR.from_pixel(0x333333ff);
|
||||
|
||||
const SEARCH_CURSOR_COLOR = BRIGHT_TEXT_COLOR;
|
||||
const HIGHLIGHTED_SEARCH_CURSOR_COLOR = SEARCH_TEXT_COLOR;
|
||||
|
||||
const HIGHLIGHTED_SEARCH_BACKGROUND_COLOR = new Clutter.Color();
|
||||
HIGHLIGHTED_SEARCH_BACKGROUND_COLOR.from_pixel(0xc4c4c4ff);
|
||||
|
||||
const SEARCH_BORDER_BOTTOM_COLOR = new Clutter.Color();
|
||||
SEARCH_BORDER_BOTTOM_COLOR.from_pixel(0x191919ff);
|
||||
|
||||
const SECTION_BORDER_COLOR = new Clutter.Color();
|
||||
SECTION_BORDER_COLOR.from_pixel(0x262626ff);
|
||||
const SECTION_BORDER = 1;
|
||||
const SECTION_INNER_BORDER_COLOR = new Clutter.Color();
|
||||
SECTION_INNER_BORDER_COLOR.from_pixel(0x000000ff);
|
||||
const SECTION_BACKGROUND_TOP_COLOR = new Clutter.Color();
|
||||
SECTION_BACKGROUND_TOP_COLOR.from_pixel(0x161616ff);
|
||||
const SECTION_BACKGROUND_BOTTOM_COLOR = new Clutter.Color();
|
||||
SECTION_BACKGROUND_BOTTOM_COLOR.from_pixel(0x000000ff);
|
||||
const SECTION_INNER_SPACING = 8;
|
||||
|
||||
const BROWSE_ACTIVATED_BG = new Clutter.Color();
|
||||
BROWSE_ACTIVATED_BG.from_pixel(0x303030f0);
|
||||
|
||||
const PANE_BORDER_COLOR = new Clutter.Color();
|
||||
PANE_BORDER_COLOR.from_pixel(0x101d3cfa);
|
||||
const PANE_BORDER_WIDTH = 2;
|
||||
|
||||
const PANE_BACKGROUND_COLOR = new Clutter.Color();
|
||||
PANE_BACKGROUND_COLOR.from_pixel(0x000000f4);
|
||||
|
||||
function Pane() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
Pane.prototype = {
|
||||
_init: function () {
|
||||
this._open = false;
|
||||
|
||||
this.actor = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
background_color: PANE_BACKGROUND_COLOR,
|
||||
border: PANE_BORDER_WIDTH,
|
||||
border_color: PANE_BORDER_COLOR,
|
||||
padding: DEFAULT_PADDING,
|
||||
reactive: true });
|
||||
this.actor.connect('button-press-event', Lang.bind(this, function (a, e) {
|
||||
// Eat button press events so they don't go through and close the pane
|
||||
return true;
|
||||
}));
|
||||
|
||||
let chromeTop = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
spacing: 6 });
|
||||
|
||||
let global = Shell.Global.get();
|
||||
let closeIconUri = "file://" + global.imagedir + "close.svg";
|
||||
let closeIcon = Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.FOREVER,
|
||||
closeIconUri,
|
||||
16,
|
||||
16);
|
||||
closeIcon.reactive = true;
|
||||
closeIcon.connect('button-press-event', Lang.bind(this, function (b, e) {
|
||||
this.close();
|
||||
return true;
|
||||
}));
|
||||
chromeTop.append(closeIcon, Big.BoxPackFlags.END);
|
||||
this.actor.append(chromeTop, Big.BoxPackFlags.NONE);
|
||||
|
||||
this.content = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
spacing: DEFAULT_PADDING });
|
||||
this.actor.append(this.content, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
// Hidden by default
|
||||
this.actor.hide();
|
||||
},
|
||||
|
||||
open: function () {
|
||||
if (this._open)
|
||||
return;
|
||||
this._open = true;
|
||||
this.actor.show();
|
||||
this.emit('open-state-changed', this._open);
|
||||
},
|
||||
|
||||
close: function () {
|
||||
if (!this._open)
|
||||
return;
|
||||
this._open = false;
|
||||
this.actor.hide();
|
||||
this.emit('open-state-changed', this._open);
|
||||
},
|
||||
|
||||
destroyContent: function() {
|
||||
let children = this.content.get_children();
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
children[i].destroy();
|
||||
}
|
||||
},
|
||||
|
||||
toggle: function () {
|
||||
if (this._open)
|
||||
this.close();
|
||||
else
|
||||
this.open();
|
||||
}
|
||||
}
|
||||
Signals.addSignalMethods(Pane.prototype);
|
||||
|
||||
function ResultArea(displayClass, enableNavigation) {
|
||||
this._init(displayClass, enableNavigation);
|
||||
}
|
||||
|
||||
ResultArea.prototype = {
|
||||
_init : function(displayClass, enableNavigation) {
|
||||
this.actor = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL });
|
||||
this.resultsContainer = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
spacing: DEFAULT_PADDING
|
||||
});
|
||||
this.actor.append(this.resultsContainer, Big.BoxPackFlags.EXPAND);
|
||||
this.navContainer = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL });
|
||||
this.resultsContainer.append(this.navContainer, Big.BoxPackFlags.NONE);
|
||||
|
||||
this.display = new displayClass();
|
||||
|
||||
this.navArea = this.display.getNavigationArea();
|
||||
if (enableNavigation && this.navArea)
|
||||
this.navContainer.append(this.navArea, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
this.resultsContainer.append(this.display.actor, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
this.controlBox = new Big.Box({ x_align: Big.BoxAlignment.CENTER });
|
||||
this.controlBox.append(this.display.displayControl, Big.BoxPackFlags.NONE);
|
||||
this.actor.append(this.controlBox, Big.BoxPackFlags.NONE);
|
||||
|
||||
this.display.load();
|
||||
}
|
||||
}
|
||||
|
||||
// Utility function shared between ResultPane and the DocDisplay in the main dash.
|
||||
// Connects to the detail signal of the display, and on-demand creates a new
|
||||
// pane.
|
||||
function createPaneForDetails(dash, display) {
|
||||
let detailPane = null;
|
||||
display.connect('show-details', Lang.bind(this, function(display, index) {
|
||||
if (detailPane == null) {
|
||||
detailPane = new Pane();
|
||||
detailPane.connect('open-state-changed', Lang.bind(this, function (pane, isOpen) {
|
||||
if (!isOpen) {
|
||||
/* Ensure we don't keep around large preview textures */
|
||||
detailPane.destroyContent();
|
||||
}
|
||||
}));
|
||||
dash._addPane(detailPane);
|
||||
}
|
||||
|
||||
if (index >= 0) {
|
||||
detailPane.destroyContent();
|
||||
let details = display.createDetailsForIndex(index);
|
||||
detailPane.content.append(details, Big.BoxPackFlags.EXPAND);
|
||||
detailPane.open();
|
||||
} else {
|
||||
detailPane.close();
|
||||
}
|
||||
}));
|
||||
return null;
|
||||
}
|
||||
|
||||
function ResultPane(dash) {
|
||||
this._init(dash);
|
||||
}
|
||||
|
||||
ResultPane.prototype = {
|
||||
__proto__: Pane.prototype,
|
||||
|
||||
_init: function(dash) {
|
||||
Pane.prototype._init.call(this);
|
||||
this._dash = dash;
|
||||
},
|
||||
|
||||
// Create an instance of displayClass and pack it into this pane's
|
||||
// content area. Return the displayClass instance.
|
||||
packResults: function(displayClass, enableNavigation) {
|
||||
let resultArea = new ResultArea(displayClass, enableNavigation);
|
||||
|
||||
createPaneForDetails(this._dash, resultArea.display);
|
||||
|
||||
this.content.append(resultArea.actor, Big.BoxPackFlags.EXPAND);
|
||||
this.connect('open-state-changed', Lang.bind(this, function(pane, isOpen) {
|
||||
resultArea.display.resetState();
|
||||
}));
|
||||
return resultArea.display;
|
||||
}
|
||||
}
|
||||
|
||||
function SearchEntry() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
SearchEntry.prototype = {
|
||||
_init : function() {
|
||||
this.actor = new Big.Box({ padding: DEFAULT_PADDING,
|
||||
border_bottom: SECTION_BORDER,
|
||||
border_color: SEARCH_BORDER_BOTTOM_COLOR,
|
||||
corner_radius: DASH_CORNER_RADIUS,
|
||||
reactive: true });
|
||||
let box = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
y_align: Big.BoxAlignment.CENTER });
|
||||
this.actor.append(box, Big.BoxPackFlags.EXPAND);
|
||||
this.actor.connect('button-press-event', Lang.bind(this, function () {
|
||||
this._resetTextState(true);
|
||||
return false;
|
||||
}));
|
||||
|
||||
this.pane = null;
|
||||
|
||||
this._defaultText = _("Find...");
|
||||
|
||||
let textProperties = { font_name: "Sans 16px" };
|
||||
let entryProperties = { editable: true,
|
||||
activatable: true,
|
||||
single_line_mode: true,
|
||||
color: SEARCH_TEXT_COLOR,
|
||||
cursor_color: SEARCH_CURSOR_COLOR };
|
||||
Lang.copyProperties(textProperties, entryProperties);
|
||||
this.entry = new Clutter.Text(entryProperties);
|
||||
|
||||
this.entry.connect('notify::text', Lang.bind(this, function () {
|
||||
this._resetTextState(false);
|
||||
}));
|
||||
box.append(this.entry, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
// Mark as editable just to get a cursor
|
||||
let defaultTextProperties = { ellipsize: Pango.EllipsizeMode.END,
|
||||
text: this._defaultText,
|
||||
editable: true,
|
||||
color: TEXT_COLOR,
|
||||
cursor_visible: false,
|
||||
single_line_mode: true };
|
||||
Lang.copyProperties(textProperties, defaultTextProperties);
|
||||
this._defaultText = new Clutter.Text(defaultTextProperties);
|
||||
box.add_actor(this._defaultText);
|
||||
this.entry.connect('notify::allocation', Lang.bind(this, function () {
|
||||
this._repositionDefaultText();
|
||||
}));
|
||||
|
||||
this._iconBox = new Big.Box({ x_align: Big.BoxAlignment.CENTER,
|
||||
y_align: Big.BoxAlignment.CENTER,
|
||||
padding_right: 4 });
|
||||
box.append(this._iconBox, Big.BoxPackFlags.END);
|
||||
|
||||
let global = Shell.Global.get();
|
||||
let magnifierUri = "file://" + global.imagedir + "magnifier.svg";
|
||||
this._magnifierIcon = Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.FOREVER,
|
||||
magnifierUri, 18, 18);
|
||||
let closeUri = "file://" + global.imagedir + "close-black.svg";
|
||||
this._closeIcon = Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.FOREVER,
|
||||
closeUri, 18, 18);
|
||||
this._closeIcon.reactive = true;
|
||||
this._closeIcon.connect('button-press-event', Lang.bind(this, function () {
|
||||
// Resetting this.entry.text will trigger notify::text signal which will
|
||||
// result in this._resetTextState() being called, but we should not rely
|
||||
// on that not short-circuiting if the text was already empty, so we call
|
||||
// this._resetTextState() explicitly in that case.
|
||||
if (this.entry.text == '')
|
||||
this._resetTextState(false);
|
||||
else
|
||||
this.entry.text = '';
|
||||
|
||||
// Return true to stop the signal emission, so that this.actor doesn't get
|
||||
// the button-press-event and re-highlight itself.
|
||||
return true;
|
||||
}));
|
||||
this._repositionDefaultText();
|
||||
this._resetTextState();
|
||||
},
|
||||
|
||||
setPane: function (pane) {
|
||||
this._pane = pane;
|
||||
},
|
||||
|
||||
reset: function () {
|
||||
this.entry.text = '';
|
||||
},
|
||||
|
||||
getText: function () {
|
||||
return this.entry.text;
|
||||
},
|
||||
|
||||
_resetTextState: function (searchEntryClicked) {
|
||||
let text = this.getText();
|
||||
this._iconBox.remove_all();
|
||||
// We highlight the search box if the user starts typing in it
|
||||
// or just clicks in it to indicate that the search is active.
|
||||
if (text != '' || searchEntryClicked) {
|
||||
if (!searchEntryClicked)
|
||||
this._defaultText.hide();
|
||||
this._iconBox.append(this._closeIcon, Big.BoxPackFlags.NONE);
|
||||
this.actor.background_color = HIGHLIGHTED_SEARCH_BACKGROUND_COLOR;
|
||||
this.entry.cursor_color = HIGHLIGHTED_SEARCH_CURSOR_COLOR;
|
||||
} else {
|
||||
this._defaultText.show();
|
||||
this._iconBox.append(this._magnifierIcon, Big.BoxPackFlags.NONE);
|
||||
this.actor.background_color = BACKGROUND_COLOR;
|
||||
this.entry.cursor_color = SEARCH_CURSOR_COLOR;
|
||||
}
|
||||
},
|
||||
|
||||
_repositionDefaultText: function () {
|
||||
// Offset a little to show the cursor
|
||||
this._defaultText.set_position(this.entry.x + 4, this.entry.y);
|
||||
this._defaultText.set_size(this.entry.width, this.entry.height);
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(SearchEntry.prototype);
|
||||
|
||||
function MoreLink() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
MoreLink.prototype = {
|
||||
_init : function () {
|
||||
this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
padding_right: DEFAULT_PADDING,
|
||||
padding_left: DEFAULT_PADDING,
|
||||
reactive: true,
|
||||
x_align: Big.BoxAlignment.CENTER,
|
||||
y_align: Big.BoxAlignment.CENTER,
|
||||
border_left: SECTION_BORDER,
|
||||
border_color: SECTION_BORDER_COLOR });
|
||||
this.pane = null;
|
||||
|
||||
let text = new Clutter.Text({ font_name: "Sans 12px",
|
||||
color: BRIGHT_TEXT_COLOR,
|
||||
text: _("Browse") });
|
||||
this.actor.append(text, Big.BoxPackFlags.NONE);
|
||||
|
||||
this.actor.connect('button-press-event', Lang.bind(this, function (b, e) {
|
||||
if (this.pane == null) {
|
||||
// Ensure the pane is created; the activated handler will call setPane
|
||||
this.emit('activated');
|
||||
}
|
||||
this._pane.toggle();
|
||||
return true;
|
||||
}));
|
||||
},
|
||||
|
||||
setPane: function (pane) {
|
||||
this._pane = pane;
|
||||
this._pane.connect('open-state-changed', Lang.bind(this, function(pane, isOpen) {
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
Signals.addSignalMethods(MoreLink.prototype);
|
||||
|
||||
function SectionHeader(title, suppressBrowse) {
|
||||
this._init(title, suppressBrowse);
|
||||
}
|
||||
|
||||
SectionHeader.prototype = {
|
||||
_init : function (title, suppressBrowse) {
|
||||
this.actor = new Big.Box({ border: SECTION_BORDER,
|
||||
border_color: SECTION_BORDER_COLOR });
|
||||
this._innerBox = new Big.Box({ border: SECTION_BORDER,
|
||||
border_color: SECTION_INNER_BORDER_COLOR,
|
||||
padding_left: DEFAULT_PADDING,
|
||||
padding_right: DEFAULT_PADDING,
|
||||
orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
spacing: DEFAULT_SPACING });
|
||||
this.actor.append(this._innerBox, Big.BoxPackFlags.EXPAND);
|
||||
let backgroundGradient = Shell.create_vertical_gradient(SECTION_BACKGROUND_TOP_COLOR,
|
||||
SECTION_BACKGROUND_BOTTOM_COLOR);
|
||||
this._innerBox.add_actor(backgroundGradient);
|
||||
this._innerBox.connect('notify::allocation', Lang.bind(this, function (actor) {
|
||||
let [width, height] = actor.get_size();
|
||||
backgroundGradient.set_size(width, height);
|
||||
}));
|
||||
|
||||
let textBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
padding_top: DEFAULT_PADDING,
|
||||
padding_bottom: DEFAULT_PADDING });
|
||||
this.text = new Clutter.Text({ color: TEXT_COLOR,
|
||||
font_name: "Sans Bold 12px",
|
||||
text: title });
|
||||
textBox.append(this.text, Big.BoxPackFlags.NONE);
|
||||
|
||||
this._innerBox.append(textBox, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
if (!suppressBrowse) {
|
||||
this.moreLink = new MoreLink();
|
||||
this._innerBox.append(this.moreLink.actor, Big.BoxPackFlags.END);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function SearchSectionHeader(title, onClick) {
|
||||
this._init(title, onClick);
|
||||
}
|
||||
|
||||
SearchSectionHeader.prototype = {
|
||||
_init : function(title, onClick) {
|
||||
let box = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
padding_top: DASH_SECTION_PADDING,
|
||||
padding_bottom: DASH_SECTION_PADDING,
|
||||
spacing: DEFAULT_SPACING });
|
||||
let titleText = new Clutter.Text({ color: BRIGHTER_TEXT_COLOR,
|
||||
font_name: 'Sans Bold 12px',
|
||||
text: title });
|
||||
this.tooltip = new Clutter.Text({ color: BRIGHTER_TEXT_COLOR,
|
||||
font_name: 'Sans 12px',
|
||||
text: _("(see all)") });
|
||||
this.countText = new Clutter.Text({ color: BRIGHTER_TEXT_COLOR,
|
||||
font_name: 'Sans Bold 14px' });
|
||||
|
||||
box.append(titleText, Big.BoxPackFlags.NONE);
|
||||
box.append(this.tooltip, Big.BoxPackFlags.NONE);
|
||||
box.append(this.countText, Big.BoxPackFlags.END);
|
||||
|
||||
this.tooltip.hide();
|
||||
this._showTooltip = true;
|
||||
|
||||
let button = new Button.Button(box, PRELIGHT_COLOR, BACKGROUND_COLOR,
|
||||
TEXT_COLOR, false, null);
|
||||
button.button.height = box.height;
|
||||
button.button.padding_left = DEFAULT_PADDING;
|
||||
button.button.padding_right = DEFAULT_PADDING;
|
||||
|
||||
button.button.connect('button-release-event', onClick);
|
||||
button.connect('enter-event', Lang.bind(this, this._onButtonEntered));
|
||||
button.connect('leave-event', Lang.bind(this, this._onButtonLeft));
|
||||
this.actor = button.button;
|
||||
},
|
||||
|
||||
_onButtonEntered : function() {
|
||||
if (this._showTooltip)
|
||||
this.tooltip.show();
|
||||
},
|
||||
|
||||
_onButtonLeft : function() {
|
||||
this.tooltip.hide();
|
||||
},
|
||||
|
||||
setShowTooltip : function(showTooltip) {
|
||||
this._showTooltip = showTooltip;
|
||||
// Because we only show tooltip on mouse-over,
|
||||
// we should not just show it here if showTooltip is
|
||||
// set to true, but in the future we could check if
|
||||
// the mouse happens to be over the header and show it
|
||||
// in that case.
|
||||
if (!this._showTooltip)
|
||||
this.tooltip.hide();
|
||||
}
|
||||
}
|
||||
|
||||
function Section(titleString, suppressBrowse) {
|
||||
this._init(titleString, suppressBrowse);
|
||||
}
|
||||
|
||||
Section.prototype = {
|
||||
_init: function(titleString, suppressBrowse) {
|
||||
this.actor = new Big.Box({ spacing: SECTION_INNER_SPACING });
|
||||
this.header = new SectionHeader(titleString, suppressBrowse);
|
||||
this.actor.append(this.header.actor, Big.BoxPackFlags.NONE);
|
||||
this.content = new Big.Box({spacing: SECTION_INNER_SPACING });
|
||||
this.actor.append(this.content, Big.BoxPackFlags.EXPAND);
|
||||
}
|
||||
}
|
||||
|
||||
function Dash() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
Dash.prototype = {
|
||||
_init : function() {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
// dash and the popup panes need to be reactive so that the clicks in unoccupied places on them
|
||||
// are not passed to the transparent background underneath them. This background is used for the workspaces area when
|
||||
// the additional dash panes are being shown and it handles clicks by closing the additional panes, so that the user
|
||||
// can interact with the workspaces. However, this behavior is not desirable when the click is actually over a pane.
|
||||
//
|
||||
// We have to make the individual panes reactive instead of making the whole dash actor reactive because the width
|
||||
// of the Group actor ends up including the width of its hidden children, so we were getting a reactive object as
|
||||
// wide as the details pane that was blocking the clicks to the workspaces underneath it even when the details pane
|
||||
// was actually hidden.
|
||||
this.actor = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
background_color: BACKGROUND_COLOR,
|
||||
corner_radius: DASH_CORNER_RADIUS,
|
||||
padding_left: DASH_PADDING_SIDE,
|
||||
padding_right: DASH_PADDING_SIDE,
|
||||
reactive: true });
|
||||
|
||||
// Size for this one explicitly set from overlay.js
|
||||
this.searchArea = new Big.Box({ y_align: Big.BoxAlignment.CENTER });
|
||||
|
||||
this.sectionArea = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
spacing: DASH_SECTION_SPACING });
|
||||
|
||||
this.actor.append(this.searchArea, Big.BoxPackFlags.NONE);
|
||||
this.actor.append(this.sectionArea, Big.BoxPackFlags.NONE);
|
||||
|
||||
// The currently active popup display
|
||||
this._activePane = null;
|
||||
|
||||
/***** Search *****/
|
||||
|
||||
this._searchActive = false;
|
||||
this._searchEntry = new SearchEntry();
|
||||
this.searchArea.append(this._searchEntry.actor, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
this._searchTimeoutId = 0;
|
||||
this._searchEntry.entry.connect('text-changed', Lang.bind(this, function (se, prop) {
|
||||
let text = this._searchEntry.getText();
|
||||
text = text.replace(/^\s+/g, "").replace(/\s+$/g, "")
|
||||
this._searchActive = text != '';
|
||||
this._updateDashActors();
|
||||
if (!this._searchActive) {
|
||||
if (this._searchTimeoutId > 0) {
|
||||
Mainloop.source_remove(this._searchTimeoutId);
|
||||
this._searchTimeoutId = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (this._searchTimeoutId > 0)
|
||||
return;
|
||||
this._searchTimeoutId = Mainloop.timeout_add(150, Lang.bind(this, function() {
|
||||
this._searchTimeoutId = 0;
|
||||
let text = this._searchEntry.getText();
|
||||
text = text.replace(/^\s+/g, "").replace(/\s+$/g, "");
|
||||
this._appSearchResultArea.display.setSearch(text);
|
||||
this._docSearchResultArea.display.setSearch(text);
|
||||
|
||||
this._appSearchHeader.countText.text = this._appSearchResultArea.display.getMatchedItemsCount() + "";
|
||||
this._docSearchHeader.countText.text = this._docSearchResultArea.display.getMatchedItemsCount() + "";
|
||||
|
||||
return false;
|
||||
}));
|
||||
}));
|
||||
this._searchEntry.entry.connect('activate', Lang.bind(this, function (se) {
|
||||
// only one of the displays will have an item selected, so it's ok to
|
||||
// call activateSelected() on all of them
|
||||
this._appSearchResultArea.display.activateSelected();
|
||||
this._docSearchResultArea.display.activateSelected();
|
||||
return true;
|
||||
}));
|
||||
this._searchEntry.entry.connect('key-press-event', Lang.bind(this, function (se, e) {
|
||||
let text = this._searchEntry.getText();
|
||||
let symbol = Shell.get_event_key_symbol(e);
|
||||
if (symbol == Clutter.Escape) {
|
||||
// Escape will keep clearing things back to the desktop.
|
||||
// If we are showing a particular section of search, go back to all sections.
|
||||
if (this._getOnlyAppSearchShown() || this._getOnlyDocSearchShown())
|
||||
this._showAllSearchSections();
|
||||
// If we have an active search, we remove it.
|
||||
else if (this._searchActive)
|
||||
this._searchEntry.reset();
|
||||
// Next, if we're in one of the "more" modes or showing the details pane, close them
|
||||
else if (this._activePane != null)
|
||||
this._activePane.close();
|
||||
// Finally, just close the Overview entirely
|
||||
else
|
||||
Main.overview.hide();
|
||||
return true;
|
||||
} else if (symbol == Clutter.Up) {
|
||||
if (!this._searchActive)
|
||||
return true;
|
||||
// selectUp and selectDown wrap around in their respective displays
|
||||
// too, but there doesn't seem to be any flickering if we first select
|
||||
// something in one display, but then unset the selection, and move
|
||||
// it to the other display, so it's ok to do that.
|
||||
if (this._docSearchResultArea.display.hasSelected())
|
||||
this._docSearchResultArea.display.selectUp();
|
||||
else if (this._appSearchResultArea.display.hasItems())
|
||||
this._appSearchResultArea.display.selectUp();
|
||||
else
|
||||
this._docSearchResultArea.display.selectUp();
|
||||
return true;
|
||||
} else if (symbol == Clutter.Down) {
|
||||
if (!this._searchActive)
|
||||
return true;
|
||||
if (this._docSearchResultArea.display.hasSelected())
|
||||
this._docSearchResultArea.display.selectDown();
|
||||
else if (this._appSearchResultArea.display.hasItems())
|
||||
this._appSearchResultArea.display.selectDown();
|
||||
else
|
||||
this._docSearchResultArea.display.selectDown();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
|
||||
/***** Applications *****/
|
||||
|
||||
this._appsSection = new Section(_("APPLICATIONS"));
|
||||
let appWell = new AppDisplay.AppWell();
|
||||
this._appsSection.content.append(appWell.actor, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
this._moreAppsPane = null;
|
||||
this._appsSection.header.moreLink.connect('activated', Lang.bind(this, function (link) {
|
||||
if (this._moreAppsPane == null) {
|
||||
this._moreAppsPane = new ResultPane(this);
|
||||
this._moreAppsPane.packResults(AppDisplay.AppDisplay, true);
|
||||
this._addPane(this._moreAppsPane);
|
||||
link.setPane(this._moreAppsPane);
|
||||
}
|
||||
}));
|
||||
|
||||
this.sectionArea.append(this._appsSection.actor, Big.BoxPackFlags.NONE);
|
||||
|
||||
/***** Places *****/
|
||||
|
||||
/* Translators: This is in the sense of locations for documents,
|
||||
network locations, etc. */
|
||||
this._placesSection = new Section(_("PLACES"), true);
|
||||
let placesDisplay = new Places.Places();
|
||||
this._placesSection.content.append(placesDisplay.actor, Big.BoxPackFlags.EXPAND);
|
||||
this.sectionArea.append(this._placesSection.actor, Big.BoxPackFlags.NONE);
|
||||
|
||||
/***** Documents *****/
|
||||
|
||||
this._docsSection = new Section(_("RECENT DOCUMENTS"));
|
||||
|
||||
let docDisplay = new DocDisplay.DashDocDisplay();
|
||||
this._docsSection.content.append(docDisplay.actor, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
this._moreDocsPane = null;
|
||||
this._docsSection.header.moreLink.connect('activated', Lang.bind(this, function (link) {
|
||||
if (this._moreDocsPane == null) {
|
||||
this._moreDocsPane = new ResultPane(this);
|
||||
this._moreDocsPane.packResults(DocDisplay.DocDisplay, true);
|
||||
this._addPane(this._moreDocsPane);
|
||||
link.setPane(this._moreDocsPane);
|
||||
}
|
||||
}));
|
||||
|
||||
this.sectionArea.append(this._docsSection.actor, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
/***** Search Results *****/
|
||||
|
||||
this._searchResultsSection = new Section(_("SEARCH RESULTS"), true);
|
||||
|
||||
this._appSearchHeader = new SearchSectionHeader(_("APPLICATIONS"),
|
||||
Lang.bind(this,
|
||||
function () {
|
||||
this._toggleOnlyAppSearchShown();
|
||||
return true;
|
||||
}));
|
||||
this._searchResultsSection.content.append(this._appSearchHeader.actor, Big.BoxPackFlags.NONE);
|
||||
this._appSearchResultArea = new ResultArea(AppDisplay.AppDisplay, false);
|
||||
this._appSearchResultArea.controlBox.hide();
|
||||
this._searchResultsSection.content.append(this._appSearchResultArea.actor, Big.BoxPackFlags.EXPAND);
|
||||
createPaneForDetails(this, this._appSearchResultArea.display);
|
||||
|
||||
this._docSearchHeader = new SearchSectionHeader(_("RECENT DOCUMENTS"),
|
||||
Lang.bind(this,
|
||||
function () {
|
||||
this._toggleOnlyDocSearchShown();
|
||||
return true;
|
||||
}));
|
||||
this._searchResultsSection.content.append(this._docSearchHeader.actor, Big.BoxPackFlags.NONE);
|
||||
this._docSearchResultArea = new ResultArea(DocDisplay.DocDisplay, false);
|
||||
this._docSearchResultArea.controlBox.hide();
|
||||
this._searchResultsSection.content.append(this._docSearchResultArea.actor, Big.BoxPackFlags.EXPAND);
|
||||
createPaneForDetails(this, this._docSearchResultArea.display);
|
||||
|
||||
this.sectionArea.append(this._searchResultsSection.actor, Big.BoxPackFlags.EXPAND);
|
||||
this._searchResultsSection.actor.hide();
|
||||
},
|
||||
|
||||
show: function() {
|
||||
let global = Shell.Global.get();
|
||||
global.stage.set_key_focus(this._searchEntry.entry);
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
this._firstSelectAfterOverlayShow = true;
|
||||
this._searchEntry.reset();
|
||||
if (this._activePane != null)
|
||||
this._activePane.close();
|
||||
},
|
||||
|
||||
closePanes: function () {
|
||||
if (this._activePane != null)
|
||||
this._activePane.close();
|
||||
},
|
||||
|
||||
_addPane: function(pane) {
|
||||
pane.connect('open-state-changed', Lang.bind(this, function (pane, isOpen) {
|
||||
if (isOpen) {
|
||||
if (pane != this._activePane && this._activePane != null) {
|
||||
this._activePane.close();
|
||||
}
|
||||
this._activePane = pane;
|
||||
} else if (pane == this._activePane) {
|
||||
this._activePane = null;
|
||||
}
|
||||
}));
|
||||
Main.overview.addPane(pane);
|
||||
},
|
||||
|
||||
_updateDashActors: function() {
|
||||
if (!this._searchActive && this._searchResultsSection.actor.visible) {
|
||||
this._showAllSearchSections();
|
||||
this._searchResultsSection.actor.hide();
|
||||
this._appsSection.actor.show();
|
||||
this._placesSection.actor.show();
|
||||
this._docsSection.actor.show();
|
||||
} else if (this._searchActive && !this._searchResultsSection.actor.visible) {
|
||||
this._searchResultsSection.actor.show();
|
||||
this._appsSection.actor.hide();
|
||||
this._placesSection.actor.hide();
|
||||
this._docsSection.actor.hide();
|
||||
}
|
||||
},
|
||||
|
||||
_toggleOnlyAppSearchShown: function() {
|
||||
if (this._getOnlyAppSearchShown()) {
|
||||
this._setDocSearchShown(true);
|
||||
} else {
|
||||
this._setDocSearchShown(false);
|
||||
}
|
||||
},
|
||||
|
||||
_toggleOnlyDocSearchShown: function() {
|
||||
if (this._getOnlyDocSearchShown()) {
|
||||
this._setAppSearchShown(true);
|
||||
} else {
|
||||
this._setAppSearchShown(false);
|
||||
}
|
||||
},
|
||||
|
||||
// TODO: the following two functions currently rely on us showing the
|
||||
// section header even if there are no results in that section. We'll need
|
||||
// to change the check if we update that behavior. We'll also need to change
|
||||
// the check if we add more sections to search results.
|
||||
_getOnlyAppSearchShown: function() {
|
||||
return this._searchActive && !this._docSearchHeader.actor.visible;
|
||||
},
|
||||
|
||||
_getOnlyDocSearchShown: function() {
|
||||
return this._searchActive && !this._appSearchHeader.actor.visible;
|
||||
},
|
||||
|
||||
_setAppSearchShown: function(show) {
|
||||
if (show) {
|
||||
this._appSearchHeader.actor.show();
|
||||
this._appSearchResultArea.actor.show();
|
||||
this._docSearchResultArea.display.displayPage(0);
|
||||
this._docSearchResultArea.controlBox.hide();
|
||||
this._docSearchHeader.setShowTooltip(true);
|
||||
} else {
|
||||
this._appSearchHeader.actor.hide();
|
||||
this._appSearchResultArea.actor.hide();
|
||||
this._docSearchResultArea.controlBox.show();
|
||||
this._docSearchHeader.setShowTooltip(false);
|
||||
}
|
||||
},
|
||||
|
||||
_setDocSearchShown: function(show) {
|
||||
if (show) {
|
||||
this._docSearchHeader.actor.show();
|
||||
this._docSearchResultArea.actor.show();
|
||||
this._appSearchResultArea.display.displayPage(0);
|
||||
this._appSearchResultArea.controlBox.hide();
|
||||
this._appSearchHeader.setShowTooltip(true);
|
||||
} else {
|
||||
this._docSearchHeader.actor.hide();
|
||||
this._docSearchResultArea.actor.hide();
|
||||
this._appSearchResultArea.controlBox.show();
|
||||
this._appSearchHeader.setShowTooltip(false);
|
||||
}
|
||||
},
|
||||
|
||||
_showAllSearchSections: function() {
|
||||
this._setAppSearchShown(true);
|
||||
this._setDocSearchShown(true);
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(Dash.prototype);
|
||||
34
js/ui/dnd.js
34
js/ui/dnd.js
@@ -82,21 +82,10 @@ _Draggable.prototype = {
|
||||
// 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) {
|
||||
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();
|
||||
if (stageX > sourceX && stageX <= sourceX + sourceWidth &&
|
||||
stageY > sourceY && stageY <= sourceY + sourceHeight)
|
||||
this._dragActor.set_position(sourceX, sourceY);
|
||||
else
|
||||
this._dragActor.set_position(stageX - this._dragActor.width / 2, stageY - this._dragActor.height / 2);
|
||||
} else {
|
||||
else
|
||||
this._dragActorSource = this.actor;
|
||||
}
|
||||
this._dragOrigParent = undefined;
|
||||
this._ungrabActor(actor);
|
||||
this._grabActor(this._dragActor);
|
||||
@@ -144,8 +133,8 @@ _Draggable.prototype = {
|
||||
// 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,
|
||||
(stageX + this._dragOffsetX - targX) / target.scale_x,
|
||||
(stageY + this._dragOffsetY - targY) / target.scale_y,
|
||||
(stageX + this._dragOffsetX + this._xOffset - targX) / target.scale_x,
|
||||
(stageY + this._dragOffsetY + this._yOffset - targY) / target.scale_y,
|
||||
event.get_time());
|
||||
}
|
||||
target = target.get_parent();
|
||||
@@ -164,6 +153,8 @@ _Draggable.prototype = {
|
||||
if (!dragging)
|
||||
return false;
|
||||
|
||||
this.emit('drag-end', event.get_time());
|
||||
|
||||
// Find a drop target
|
||||
actor.hide();
|
||||
let [dropX, dropY] = event.get_coords();
|
||||
@@ -174,15 +165,14 @@ _Draggable.prototype = {
|
||||
if (target._delegate && target._delegate.acceptDrop) {
|
||||
let [targX, targY] = target.get_transformed_position();
|
||||
if (target._delegate.acceptDrop(this.actor._delegate, actor,
|
||||
(dropX - targX) / target.scale_x,
|
||||
(dropY - targY) / target.scale_y,
|
||||
(dropX + this._xOffset - targX) / target.scale_x,
|
||||
(dropY + this._yOffset - 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();
|
||||
|
||||
this.emit('drag-end', event.get_time(), true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -206,20 +196,18 @@ _Draggable.prototype = {
|
||||
transition: "easeOutQuad",
|
||||
onComplete: this._onSnapBackComplete,
|
||||
onCompleteScope: this,
|
||||
onCompleteParams: [actor, event.get_time()]
|
||||
onCompleteParams: [actor]
|
||||
});
|
||||
return true;
|
||||
},
|
||||
|
||||
_onSnapBackComplete : function (dragActor, eventTime) {
|
||||
_onSnapBackComplete : function (dragActor) {
|
||||
if (this._dragOrigParent) {
|
||||
dragActor.reparent(this._dragOrigParent);
|
||||
dragActor.set_scale(this._dragOrigScale, this._dragOrigScale);
|
||||
dragActor.set_position(this._dragOrigX, this._dragOrigY);
|
||||
} else {
|
||||
} else
|
||||
dragActor.destroy();
|
||||
}
|
||||
this.emit('drag-end', eventTime, false);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,59 +1,37 @@
|
||||
/* -*- 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.
|
||||
*
|
||||
* docInfo - DocInfo object containing information about the document
|
||||
* currentSeconds - current number of seconds since the epoch
|
||||
* availableWidth - total width available for the item
|
||||
*/
|
||||
function DocDisplayItem(docInfo, currentSecs) {
|
||||
this._init(docInfo, currentSecs);
|
||||
function DocDisplayItem(docInfo, availableWidth) {
|
||||
this._init(docInfo, availableWidth);
|
||||
}
|
||||
|
||||
DocDisplayItem.prototype = {
|
||||
__proto__: GenericDisplay.GenericDisplayItem.prototype,
|
||||
|
||||
_init : function(docInfo, currentSecs) {
|
||||
GenericDisplay.GenericDisplayItem.prototype._init.call(this);
|
||||
_init : function(docInfo, availableWidth) {
|
||||
GenericDisplay.GenericDisplayItem.prototype._init.call(this, availableWidth);
|
||||
this._docInfo = docInfo;
|
||||
|
||||
|
||||
this._setItemInfo(docInfo.name, "");
|
||||
|
||||
this._timeoutTime = -1;
|
||||
this._resetTimeDisplay(currentSecs);
|
||||
},
|
||||
|
||||
//// Public methods ////
|
||||
|
||||
getUpdateTimeoutTime: function() {
|
||||
return this._timeoutTime;
|
||||
},
|
||||
|
||||
// Update any relative-time based displays for this item.
|
||||
redisplay: function(currentSecs) {
|
||||
this._resetTimeDisplay(currentSecs);
|
||||
},
|
||||
|
||||
//// Public method overrides ////
|
||||
|
||||
// Opens a document represented by this display item.
|
||||
@@ -68,92 +46,66 @@ DocDisplayItem.prototype = {
|
||||
return this._docInfo.createIcon(GenericDisplay.ITEM_DISPLAY_ICON_SIZE);
|
||||
},
|
||||
|
||||
// Returns a preview icon for the item.
|
||||
_createPreviewIcon : function() {
|
||||
return this._docInfo.createIcon(GenericDisplay.PREVIEW_ICON_SIZE);
|
||||
// Ensures the preview icon is created.
|
||||
_ensurePreviewIconCreated : function() {
|
||||
if (!this._previewIcon)
|
||||
this._previewIcon = this._docInfo.createIcon(GenericDisplay.PREVIEW_ICON_SIZE);
|
||||
},
|
||||
|
||||
// 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() {
|
||||
_createLargePreviewIcon : function(availableWidth, availableHeight) {
|
||||
if (this._docInfo.mimeType == null || this._docInfo.mimeType.indexOf("image/") != 0)
|
||||
return null;
|
||||
|
||||
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.
|
||||
_resetTimeDisplay: function(currentSecs) {
|
||||
let lastSecs = this._docInfo.timestamp;
|
||||
let timeDelta = currentSecs - lastSecs;
|
||||
let [text, nextUpdate] = Shell.Global.get().format_time_relative_pretty(timeDelta);
|
||||
this._timeoutTime = currentSecs + nextUpdate;
|
||||
this._setDescriptionText(text);
|
||||
return Shell.TextureCache.get_default().load_uri_sync(this._docInfo.uri, availableWidth, availableHeight);
|
||||
}
|
||||
};
|
||||
|
||||
/* This class represents a display containing a collection of document items.
|
||||
* The documents are sorted by how recently they were last visited.
|
||||
*
|
||||
* width - width available for the display
|
||||
* height - height available for the display
|
||||
*/
|
||||
function DocDisplay() {
|
||||
this._init();
|
||||
}
|
||||
function DocDisplay(width, height, numberOfColumns, columnGap) {
|
||||
this._init(width, height, numberOfColumns, columnGap);
|
||||
}
|
||||
|
||||
DocDisplay.prototype = {
|
||||
__proto__: GenericDisplay.GenericDisplay.prototype,
|
||||
|
||||
_init : function() {
|
||||
GenericDisplay.GenericDisplay.prototype._init.call(this);
|
||||
_init : function(width, height, numberOfColumns, columnGap) {
|
||||
GenericDisplay.GenericDisplay.prototype._init.call(this, width, height, numberOfColumns, columnGap);
|
||||
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
|
||||
// for individual items and item details depend on the item being
|
||||
// associated with one of the displays.
|
||||
this._updateTimeoutTargetTime = -1;
|
||||
this._updateTimeoutId = 0;
|
||||
|
||||
this._docManager = DocInfo.getDocManager();
|
||||
this._recentManager = Gtk.RecentManager.get_default();
|
||||
this._docsStale = true;
|
||||
this._docManager.connect('changed', function(mgr, userData) {
|
||||
this._recentManager.connect('changed', function(recentManager, userData) {
|
||||
me._docsStale = true;
|
||||
// Changes in local recent files should not happen when we are in the Overview mode,
|
||||
// Changes in local recent files should not happen when we are in the overlay 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);
|
||||
me._redisplay(false);
|
||||
});
|
||||
|
||||
this.connect('destroy', Lang.bind(this, function (o) {
|
||||
if (this._updateTimeoutId > 0)
|
||||
Mainloop.source_remove(this._updateTimeoutId);
|
||||
}));
|
||||
},
|
||||
|
||||
//// Protected method overrides ////
|
||||
|
||||
// Gets the list of recent items from the recent items manager.
|
||||
_refreshCache : function() {
|
||||
let me = this;
|
||||
if (!this._docsStale)
|
||||
return;
|
||||
this._allItems = this._docManager.getItems();
|
||||
this._allItems = {};
|
||||
let docs = this._recentManager.get_items();
|
||||
for (let i = 0; i < docs.length; i++) {
|
||||
let recentInfo = docs[i];
|
||||
let docInfo = new DocInfo.DocInfo(recentInfo);
|
||||
|
||||
// we use GtkRecentInfo URI as an item Id
|
||||
this._allItems[docInfo.uri] = docInfo;
|
||||
}
|
||||
this._docsStale = false;
|
||||
},
|
||||
|
||||
@@ -168,7 +120,7 @@ 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 Overview, so we are doing the sorting over the same items multiple times if the list
|
||||
// the overlay, 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
|
||||
@@ -197,7 +149,7 @@ DocDisplay.prototype = {
|
||||
let docA = this._allItems[itemIdA];
|
||||
let docB = this._allItems[itemIdB];
|
||||
|
||||
return docB.timestamp - docA.timestamp;
|
||||
return docB.lastVisited() - docA.lastVisited();
|
||||
},
|
||||
|
||||
// Checks if the item info can be a match for the search string by checking
|
||||
@@ -220,219 +172,8 @@ DocDisplay.prototype = {
|
||||
|
||||
// Creates a DocDisplayItem based on itemInfo, which is expected to be a DocInfo object.
|
||||
_createDisplayItem: function(itemInfo) {
|
||||
let currentSecs = new Date().getTime() / 1000;
|
||||
let docDisplayItem = new DocDisplayItem(itemInfo, currentSecs);
|
||||
this._updateTimeoutCallback(docDisplayItem, currentSecs);
|
||||
return docDisplayItem;
|
||||
},
|
||||
|
||||
//// Private Methods ////
|
||||
|
||||
// A callback function that redisplays the items, updating their descriptions,
|
||||
// and sets up a new timeout callback.
|
||||
_docTimeout: function () {
|
||||
let currentSecs = new Date().getTime() / 1000;
|
||||
this._updateTimeoutId = 0;
|
||||
this._updateTimeoutTargetTime = -1;
|
||||
for (let docId in this._displayedItems) {
|
||||
let docDisplayItem = this._displayedItems[docId];
|
||||
docDisplayItem.redisplay(currentSecs);
|
||||
this._updateTimeoutCallback(docDisplayItem, currentSecs);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
// Updates the timeout callback if the timeout time for the docDisplayItem
|
||||
// is earlier than the target time for the current timeout callback.
|
||||
_updateTimeoutCallback: function (docDisplayItem, currentSecs) {
|
||||
let timeoutTime = docDisplayItem.getUpdateTimeoutTime();
|
||||
if (this._updateTimeoutTargetTime < 0 || timeoutTime < this._updateTimeoutTargetTime) {
|
||||
if (this._updateTimeoutId > 0)
|
||||
Mainloop.source_remove(this._updateTimeoutId);
|
||||
this._updateTimeoutId = Mainloop.timeout_add_seconds(timeoutTime - currentSecs, Lang.bind(this, this._docTimeout));
|
||||
this._updateTimeoutTargetTime = timeoutTime;
|
||||
}
|
||||
}
|
||||
return new DocDisplayItem(itemInfo, this._columnWidth);
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,11 +10,10 @@ const Mainloop = imports.mainloop;
|
||||
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 ITEM_DISPLAY_NAME_COLOR = new Clutter.Color();
|
||||
ITEM_DISPLAY_NAME_COLOR.from_pixel(0xffffffff);
|
||||
@@ -29,18 +28,17 @@ DISPLAY_CONTROL_SELECTED_COLOR.from_pixel(0x112288ff);
|
||||
const PREVIEW_BOX_BACKGROUND_COLOR = new Clutter.Color();
|
||||
PREVIEW_BOX_BACKGROUND_COLOR.from_pixel(0xADADADf0);
|
||||
|
||||
const DEFAULT_PADDING = 4;
|
||||
|
||||
const ITEM_DISPLAY_HEIGHT = 50;
|
||||
const ITEM_DISPLAY_ICON_SIZE = 48;
|
||||
const ITEM_DISPLAY_PADDING = 1;
|
||||
const ITEM_DISPLAY_PADDING_TOP = 1;
|
||||
const ITEM_DISPLAY_PADDING_RIGHT = 2;
|
||||
const DEFAULT_COLUMN_GAP = 6;
|
||||
const LABEL_HEIGHT = 16;
|
||||
|
||||
const PREVIEW_ICON_SIZE = 96;
|
||||
const PREVIEW_BOX_PADDING = 6;
|
||||
const PREVIEW_BOX_SPACING = DEFAULT_PADDING;
|
||||
const PREVIEW_BOX_CORNER_RADIUS = 10;
|
||||
const PREVIEW_BOX_SPACING = 4;
|
||||
const PREVIEW_BOX_CORNER_RADIUS = 10;
|
||||
// how far relative to the full item width the preview box should be placed
|
||||
const PREVIEW_PLACING = 3/4;
|
||||
const PREVIEW_DETAILS_MIN_WIDTH = PREVIEW_ICON_SIZE * 2;
|
||||
@@ -48,25 +46,25 @@ const PREVIEW_DETAILS_MIN_WIDTH = PREVIEW_ICON_SIZE * 2;
|
||||
const INFORMATION_BUTTON_SIZE = 16;
|
||||
|
||||
/* This is a virtual class that represents a single display item containing
|
||||
* a name, a description, and an icon. It allows selecting an item and represents
|
||||
* a name, a description, and an icon. It allows selecting an item and represents
|
||||
* it by highlighting it with a different background color than the default.
|
||||
*
|
||||
* availableWidth - total width available for the item
|
||||
*/
|
||||
function GenericDisplayItem() {
|
||||
this._init();
|
||||
function GenericDisplayItem(availableWidth) {
|
||||
this._init(availableWidth);
|
||||
}
|
||||
|
||||
GenericDisplayItem.prototype = {
|
||||
_init: function() {
|
||||
this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
spacing: ITEM_DISPLAY_PADDING,
|
||||
reactive: true,
|
||||
background_color: ITEM_DISPLAY_BACKGROUND_COLOR,
|
||||
corner_radius: 4,
|
||||
height: ITEM_DISPLAY_HEIGHT });
|
||||
_init: function(availableWidth) {
|
||||
this._availableWidth = availableWidth;
|
||||
|
||||
this.actor = new Clutter.Group({ reactive: true,
|
||||
width: availableWidth,
|
||||
height: ITEM_DISPLAY_HEIGHT });
|
||||
this.actor._delegate = this;
|
||||
this.actor.connect('button-release-event',
|
||||
Lang.bind(this,
|
||||
this.actor.connect('button-release-event',
|
||||
Lang.bind(this,
|
||||
function() {
|
||||
// Activates the item by launching it
|
||||
this.emit('activate');
|
||||
@@ -76,55 +74,51 @@ GenericDisplayItem.prototype = {
|
||||
let draggable = DND.makeDraggable(this.actor);
|
||||
draggable.connect('drag-begin', Lang.bind(this, this._onDragBegin));
|
||||
|
||||
this._infoContent = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
spacing: DEFAULT_PADDING });
|
||||
this.actor.append(this._infoContent, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
this._iconBox = new Big.Box();
|
||||
this._infoContent.append(this._iconBox, Big.BoxPackFlags.NONE);
|
||||
|
||||
this._infoText = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
spacing: DEFAULT_PADDING });
|
||||
this._infoContent.append(this._infoText, Big.BoxPackFlags.EXPAND);
|
||||
this._bg = new Big.Box({ background_color: ITEM_DISPLAY_BACKGROUND_COLOR,
|
||||
corner_radius: 4,
|
||||
x: 0, y: 0,
|
||||
width: availableWidth, height: ITEM_DISPLAY_HEIGHT });
|
||||
this.actor.add_actor(this._bg);
|
||||
|
||||
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);
|
||||
let buttonBox = new Big.Box({ width: INFORMATION_BUTTON_SIZE + 2 * DEFAULT_PADDING,
|
||||
height: INFORMATION_BUTTON_SIZE,
|
||||
padding_left: DEFAULT_PADDING, padding_right: DEFAULT_PADDING,
|
||||
y_align: Big.BoxAlignment.CENTER });
|
||||
buttonBox.append(this._informationButton.actor, Big.BoxPackFlags.NONE);
|
||||
this.actor.append(buttonBox, Big.BoxPackFlags.END);
|
||||
|
||||
// Connecting to the button-press-event for the information button ensures that the actor,
|
||||
this._informationButton = Shell.TextureCache.get_default().load_uri_sync(infoIconUri,
|
||||
INFORMATION_BUTTON_SIZE,
|
||||
INFORMATION_BUTTON_SIZE);
|
||||
|
||||
this._informationButton.x = availableWidth - ITEM_DISPLAY_PADDING_RIGHT - INFORMATION_BUTTON_SIZE;
|
||||
this._informationButton.y = ITEM_DISPLAY_HEIGHT / 2 - INFORMATION_BUTTON_SIZE / 2;
|
||||
this._informationButton.reactive = true;
|
||||
|
||||
// Connecting to the button-press-event for the information button ensures that the actor,
|
||||
// which is a draggable actor, does not get the button-press-event and doesn't initiate
|
||||
// the dragging, which then prevents us from getting the button-release-event for the button.
|
||||
this._informationButton.actor.connect('button-press-event',
|
||||
Lang.bind(this,
|
||||
function() {
|
||||
return true;
|
||||
}));
|
||||
this._informationButton.actor.connect('button-release-event',
|
||||
Lang.bind(this,
|
||||
function() {
|
||||
// Selects the item by highlighting it and displaying its details
|
||||
this.emit('show-details');
|
||||
return true;
|
||||
}));
|
||||
this._informationButton.connect('button-press-event',
|
||||
Lang.bind(this,
|
||||
function() {
|
||||
return true;
|
||||
}));
|
||||
this._informationButton.connect('button-release-event',
|
||||
Lang.bind(this,
|
||||
function() {
|
||||
// Selects the item by highlighting it and displaying its details
|
||||
this.emit('select');
|
||||
return true;
|
||||
}));
|
||||
this._informationButton.hide();
|
||||
this.actor.add_actor(this._informationButton);
|
||||
this._informationButton.lower_bottom();
|
||||
|
||||
this._name = null;
|
||||
this._description = null;
|
||||
this._icon = null;
|
||||
this._previewIcon = null;
|
||||
|
||||
// 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;
|
||||
|
||||
this.actor.connect('enter-event', Lang.bind(this, this._onEnter));
|
||||
this.actor.connect('leave-event', Lang.bind(this, this._onLeave));
|
||||
},
|
||||
|
||||
//// Draggable object interface ////
|
||||
@@ -132,9 +126,21 @@ GenericDisplayItem.prototype = {
|
||||
// Returns a cloned texture of the item's icon to represent the item as it
|
||||
// is being dragged.
|
||||
getDragActor: function(stageX, stageY) {
|
||||
return this._createIcon();
|
||||
},
|
||||
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;
|
||||
},
|
||||
|
||||
// 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
|
||||
@@ -147,35 +153,36 @@ GenericDisplayItem.prototype = {
|
||||
|
||||
// Shows the information button when the item was drawn under the mouse pointer.
|
||||
onDrawnUnderPointer: function() {
|
||||
this._informationButton.show();
|
||||
this._informationButton.show();
|
||||
},
|
||||
|
||||
// Highlights the item by setting a different background color than the default
|
||||
// if isSelected is true, removes the highlighting otherwise.
|
||||
markSelected: function(isSelected) {
|
||||
let color;
|
||||
if (isSelected) {
|
||||
if (isSelected)
|
||||
color = ITEM_DISPLAY_SELECTED_BACKGROUND_COLOR;
|
||||
this._informationButton.forceShow(true);
|
||||
}
|
||||
else {
|
||||
else
|
||||
color = ITEM_DISPLAY_BACKGROUND_COLOR;
|
||||
this._informationButton.forceShow(false);
|
||||
}
|
||||
this.actor.background_color = color;
|
||||
this._bg.background_color = color;
|
||||
},
|
||||
|
||||
/*
|
||||
* Returns an actor containing item details. In the future details can have more information than what
|
||||
* 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.
|
||||
*/
|
||||
createDetailsActor: function() {
|
||||
|
||||
*
|
||||
* availableWidth - width available for displaying details
|
||||
* availableHeight - height available for displaying details
|
||||
*/
|
||||
createDetailsActor: function(availableWidth, availableHeight) {
|
||||
|
||||
let details = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
spacing: PREVIEW_BOX_SPACING });
|
||||
spacing: PREVIEW_BOX_SPACING,
|
||||
width: availableWidth });
|
||||
|
||||
let mainDetails = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
spacing: PREVIEW_BOX_SPACING });
|
||||
spacing: PREVIEW_BOX_SPACING,
|
||||
width: availableWidth });
|
||||
|
||||
// Inner box with name and description
|
||||
let textDetails = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
@@ -183,7 +190,7 @@ GenericDisplayItem.prototype = {
|
||||
let detailsName = new Clutter.Text({ color: ITEM_DISPLAY_NAME_COLOR,
|
||||
font_name: "Sans bold 14px",
|
||||
line_wrap: true,
|
||||
text: this._name.text });
|
||||
text: this._name.text});
|
||||
textDetails.append(detailsName, Big.BoxPackFlags.NONE);
|
||||
|
||||
let detailsDescription = new Clutter.Text({ color: ITEM_DISPLAY_NAME_COLOR,
|
||||
@@ -192,15 +199,14 @@ GenericDisplayItem.prototype = {
|
||||
text: this._description.text });
|
||||
textDetails.append(detailsDescription, Big.BoxPackFlags.NONE);
|
||||
|
||||
this._detailsDescriptions.push(detailsDescription);
|
||||
|
||||
mainDetails.append(textDetails, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
let previewIcon = this._createPreviewIcon();
|
||||
let largePreviewIcon = this._createLargePreviewIcon();
|
||||
this._ensurePreviewIconCreated();
|
||||
let largePreviewIcon = this._createLargePreviewIcon(availableWidth, Math.max(0, availableHeight - mainDetails.height - PREVIEW_BOX_SPACING));
|
||||
|
||||
if (previewIcon != null && largePreviewIcon == null) {
|
||||
mainDetails.prepend(previewIcon, Big.BoxPackFlags.NONE);
|
||||
if (this._previewIcon != null && largePreviewIcon == null) {
|
||||
let previewIconClone = new Clutter.Clone({ source: this._previewIcon });
|
||||
mainDetails.prepend(previewIconClone, Big.BoxPackFlags.NONE);
|
||||
}
|
||||
|
||||
details.append(mainDetails, Big.BoxPackFlags.NONE);
|
||||
@@ -214,13 +220,13 @@ GenericDisplayItem.prototype = {
|
||||
return details;
|
||||
},
|
||||
|
||||
// Destroys the item.
|
||||
// Destoys the item.
|
||||
destroy: function() {
|
||||
this.actor.destroy();
|
||||
},
|
||||
|
||||
|
||||
//// Pure virtual public methods ////
|
||||
|
||||
|
||||
// Performes an action associated with launching this item, such as opening a file or an application.
|
||||
launch: function() {
|
||||
throw new Error("Not implemented");
|
||||
@@ -250,41 +256,39 @@ GenericDisplayItem.prototype = {
|
||||
// and therefore should be responsible for distroying it
|
||||
this._icon.destroy();
|
||||
this._icon = null;
|
||||
}
|
||||
// This ensures we'll create a new previewIcon next time we need it
|
||||
if (this._previewIcon != null) {
|
||||
this._previewIcon.destroy();
|
||||
this._previewIcon = null;
|
||||
}
|
||||
|
||||
this._icon = this._createIcon();
|
||||
this._iconBox.append(this._icon, Big.BoxPackFlags.NONE);
|
||||
this.actor.add_actor(this._icon);
|
||||
|
||||
let textWidth = this._availableWidth - (ITEM_DISPLAY_ICON_SIZE + 4) - INFORMATION_BUTTON_SIZE - ITEM_DISPLAY_PADDING_RIGHT;
|
||||
this._name = new Clutter.Text({ color: ITEM_DISPLAY_NAME_COLOR,
|
||||
font_name: "Sans 14px",
|
||||
width: textWidth,
|
||||
ellipsize: Pango.EllipsizeMode.END,
|
||||
text: nameText });
|
||||
this._infoText.append(this._name, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
text: nameText,
|
||||
x: ITEM_DISPLAY_ICON_SIZE + 4,
|
||||
y: ITEM_DISPLAY_PADDING_TOP });
|
||||
this.actor.add_actor(this._name);
|
||||
this._description = new Clutter.Text({ color: ITEM_DISPLAY_DESCRIPTION_COLOR,
|
||||
font_name: "Sans 12px",
|
||||
width: textWidth,
|
||||
ellipsize: Pango.EllipsizeMode.END,
|
||||
text: descriptionText ? descriptionText : ""
|
||||
});
|
||||
this._infoText.append(this._description, Big.BoxPackFlags.EXPAND);
|
||||
},
|
||||
|
||||
// Sets the description text for the item, including the description text
|
||||
// in the details actors that have been created for the item.
|
||||
_setDescriptionText: function(text) {
|
||||
this._description.text = text;
|
||||
for (let i = 0; i < this._detailsDescriptions.length; i++) {
|
||||
let detailsDescription = this._detailsDescriptions[i];
|
||||
if (detailsDescription != null) {
|
||||
detailsDescription.text = text;
|
||||
}
|
||||
}
|
||||
text: descriptionText ? descriptionText : "",
|
||||
x: this._name.x,
|
||||
y: this._name.height + 4 });
|
||||
this.actor.add_actor(this._description);
|
||||
},
|
||||
|
||||
//// Virtual protected methods ////
|
||||
|
||||
// Creates and returns a large preview icon, but only if we have a detailed image.
|
||||
_createLargePreviewIcon : function() {
|
||||
_createLargePreviewIcon : function(availableWidth, availableHeight) {
|
||||
return null;
|
||||
},
|
||||
|
||||
@@ -295,18 +299,28 @@ GenericDisplayItem.prototype = {
|
||||
throw new Error("Not implemented");
|
||||
},
|
||||
|
||||
// Returns a preview icon for the item.
|
||||
_createPreviewIcon: function() {
|
||||
// Ensures the preview icon is created.
|
||||
_ensurePreviewIconCreated: function() {
|
||||
throw new Error("Not implemented");
|
||||
},
|
||||
|
||||
//// Private methods ////
|
||||
|
||||
// Performs actions on mouse enter event for the item. Currently, shows the information button for the item.
|
||||
_onEnter: function(actor, event) {
|
||||
this._informationButton.show();
|
||||
},
|
||||
|
||||
// Performs actions on mouse leave event for the item. Currently, hides the information button for the item.
|
||||
_onLeave: function(actor, event) {
|
||||
this._informationButton.hide();
|
||||
},
|
||||
|
||||
// Hides the information button once the item starts being dragged.
|
||||
_onDragBegin : function (draggable, time) {
|
||||
// For some reason, we are not getting leave-event signal when we are dragging an item,
|
||||
// so we should remove the link manually.
|
||||
this._informationButton.actor.hide();
|
||||
this._informationButton.hide();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -314,60 +328,82 @@ Signals.addSignalMethods(GenericDisplayItem.prototype);
|
||||
|
||||
/* This is a virtual class that represents a display containing a collection of items
|
||||
* that can be filtered with a search string.
|
||||
*
|
||||
* width - width available for the display
|
||||
* height - height available for the display
|
||||
*/
|
||||
function GenericDisplay() {
|
||||
this._init();
|
||||
function GenericDisplay(width, height, numberOfColumns, columnGap) {
|
||||
this._init(width, height, numberOfColumns, columnGap);
|
||||
}
|
||||
|
||||
GenericDisplay.prototype = {
|
||||
_init : function() {
|
||||
_init : function(width, height, numberOfColumns, columnGap) {
|
||||
this._search = '';
|
||||
this._expanded = false;
|
||||
this._width = null;
|
||||
this._height = null;
|
||||
this._columnWidth = null;
|
||||
|
||||
this._numberOfColumns = numberOfColumns;
|
||||
this._columnGap = columnGap;
|
||||
if (this._columnGap == null)
|
||||
this._columnGap = DEFAULT_COLUMN_GAP;
|
||||
|
||||
this._maxItemsPerPage = null;
|
||||
this._list = new Shell.OverflowList({ spacing: 6.0,
|
||||
item_height: ITEM_DISPLAY_HEIGHT });
|
||||
this._grid = new Tidy.Grid({width: this._width, height: this._height});
|
||||
|
||||
this._list.connect('notify::n-pages', Lang.bind(this, function () {
|
||||
this._updateDisplayControl(true);
|
||||
}));
|
||||
this._list.connect('notify::page', Lang.bind(this, function () {
|
||||
this._updateDisplayControl(false);
|
||||
}));
|
||||
this._setDimensionsAndMaxItems(width, 0, height);
|
||||
|
||||
this._grid.column_major = true;
|
||||
this._grid.column_gap = this._columnGap;
|
||||
// map<itemId, Object> where Object represents the item info
|
||||
this._allItems = {};
|
||||
// an array of itemIds of items that match the current request
|
||||
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 = [];
|
||||
// map<itemId, GenericDisplayItem>
|
||||
this._displayedItems = {};
|
||||
this._openDetailIndex = -1;
|
||||
this._displayedItems = {};
|
||||
this._displayedItemsCount = 0;
|
||||
this._pageDisplayed = 0;
|
||||
this._selectedIndex = -1;
|
||||
// These two are public - .actor is the normal "actor subclass" property,
|
||||
// but we also expose a .displayControl actor which is separate.
|
||||
// See also getNavigationArea.
|
||||
this.actor = this._list;
|
||||
// See also getSideArea.
|
||||
this.actor = this._grid;
|
||||
this.displayControl = new Big.Box({ background_color: ITEM_DISPLAY_BACKGROUND_COLOR,
|
||||
spacing: 12,
|
||||
orientation: Big.BoxOrientation.HORIZONTAL});
|
||||
|
||||
this._availableWidthForItemDetails = this._columnWidth;
|
||||
this._availableHeightForItemDetails = this._height;
|
||||
this.selectedItemDetails = new Big.Box({});
|
||||
},
|
||||
|
||||
//// Public methods ////
|
||||
|
||||
// Sets dimensions available for the item details display.
|
||||
setAvailableDimensionsForItemDetails: function(availableWidth, availableHeight) {
|
||||
this._availableWidthForItemDetails = availableWidth;
|
||||
this._availableHeightForItemDetails = availableHeight;
|
||||
},
|
||||
|
||||
// Returns dimensions available for the item details display.
|
||||
getAvailableDimensionsForItemDetails: function() {
|
||||
return [this._availableWidthForItemDetails, this._availableHeightForItemDetails];
|
||||
},
|
||||
|
||||
// Sets the search string and displays the matching items.
|
||||
setSearch: function(text) {
|
||||
this._search = text.toLowerCase();
|
||||
this._redisplay(true);
|
||||
},
|
||||
|
||||
// Launches the item that is currently selected, closing the Overview
|
||||
// Launches the item that is currently selected and emits 'activated' signal.
|
||||
activateSelected: function() {
|
||||
if (this._selectedIndex != -1) {
|
||||
let selected = this._findDisplayedByIndex(this._selectedIndex);
|
||||
selected.launch();
|
||||
this.unsetSelected();
|
||||
Main.overview.hide();
|
||||
selected.launch()
|
||||
this.emit('activated');
|
||||
}
|
||||
},
|
||||
|
||||
@@ -375,11 +411,10 @@ GenericDisplay.prototype = {
|
||||
// to the bottom one. Returns true if the selection actually moved up, false if it wrapped
|
||||
// around to the bottom.
|
||||
selectUp: function() {
|
||||
let count = this._list.displayedCount;
|
||||
let selectedUp = true;
|
||||
let prev = this._selectedIndex - 1;
|
||||
if (this._selectedIndex <= 0) {
|
||||
prev = count - 1;
|
||||
prev = this._displayedItemsCount - 1;
|
||||
selectedUp = false;
|
||||
}
|
||||
this._selectIndex(prev);
|
||||
@@ -390,10 +425,9 @@ GenericDisplay.prototype = {
|
||||
// to the top one. Returns true if the selection actually moved down, false if it wrapped
|
||||
// around to the top.
|
||||
selectDown: function() {
|
||||
let count = this._list.displayedCount;
|
||||
let selectedDown = true;
|
||||
let next = this._selectedIndex + 1;
|
||||
if (this._selectedIndex == count - 1) {
|
||||
if (this._selectedIndex == this._displayedItemsCount - 1) {
|
||||
next = 0;
|
||||
selectedDown = false;
|
||||
}
|
||||
@@ -409,9 +443,8 @@ GenericDisplay.prototype = {
|
||||
|
||||
// Selects the last item among the displayed items.
|
||||
selectLastItem: function() {
|
||||
let count = this._list.displayedCount;
|
||||
if (this.hasItems())
|
||||
this._selectIndex(count - 1);
|
||||
this._selectIndex(this._displayedItemsCount - 1);
|
||||
},
|
||||
|
||||
// Returns true if the display has some item selected.
|
||||
@@ -426,40 +459,48 @@ GenericDisplay.prototype = {
|
||||
|
||||
// Returns true if the display has any displayed items.
|
||||
hasItems: function() {
|
||||
return this._list.displayedCount > 0;
|
||||
return this._displayedItemsCount > 0;
|
||||
},
|
||||
|
||||
getMatchedItemsCount: function() {
|
||||
return this._matchedItems.length;
|
||||
// Readjusts display layout and the items displayed based on the new dimensions.
|
||||
setExpanded: function(expanded, baseWidth, expandWidth, height, numberOfColumns) {
|
||||
this._expanded = expanded;
|
||||
this._numberOfColumns = numberOfColumns;
|
||||
this._setDimensionsAndMaxItems(baseWidth, expandWidth, height);
|
||||
this._grid.width = this._width;
|
||||
this._grid.height = this._height;
|
||||
this._pageDisplayed = 0;
|
||||
this._displayMatchedItems(true);
|
||||
let gridWidth = this._width;
|
||||
let sideArea = this.getSideArea();
|
||||
if (sideArea) {
|
||||
if (expanded)
|
||||
sideArea.show();
|
||||
else
|
||||
sideArea.hide();
|
||||
}
|
||||
this.emit('expanded');
|
||||
},
|
||||
|
||||
// Load the initial state
|
||||
load: function() {
|
||||
// Updates the displayed items and makes the display actor visible.
|
||||
show: function() {
|
||||
this._grid.show();
|
||||
this._redisplay(true);
|
||||
},
|
||||
|
||||
// Should be called when the display is closed
|
||||
resetState: function() {
|
||||
// Hides the display actor.
|
||||
hide: function() {
|
||||
this._grid.hide();
|
||||
this._filterReset();
|
||||
this._openDetailIndex = -1;
|
||||
this._removeAllDisplayItems();
|
||||
},
|
||||
|
||||
// Returns an actor which acts as a sidebar; this is used for
|
||||
// the applications category view
|
||||
getNavigationArea: function () {
|
||||
getSideArea: function () {
|
||||
return null;
|
||||
},
|
||||
|
||||
createDetailsForIndex: function(index) {
|
||||
let item = this._findDisplayedByIndex(index);
|
||||
return item.createDetailsActor();
|
||||
},
|
||||
|
||||
// Displays the page specified by the pageNumber argument.
|
||||
displayPage: function(pageNumber) {
|
||||
this._list.page = pageNumber;
|
||||
},
|
||||
|
||||
//// Protected methods ////
|
||||
|
||||
/*
|
||||
@@ -478,7 +519,9 @@ GenericDisplay.prototype = {
|
||||
let hadSelected = this.hasSelected();
|
||||
|
||||
this._removeAllDisplayItems();
|
||||
for (let i = 0; i < this._matchedItems.length; i++) {
|
||||
|
||||
for (let i = this._maxItemsPerPage * this._pageDisplayed; i < this._matchedItems.length && i < this._maxItemsPerPage * (this._pageDisplayed + 1); i++) {
|
||||
|
||||
this._addDisplayItem(this._matchedItems[i]);
|
||||
}
|
||||
|
||||
@@ -487,9 +530,11 @@ GenericDisplay.prototype = {
|
||||
this.selectFirstItem();
|
||||
}
|
||||
|
||||
this._updateDisplayControl(resetDisplayControl);
|
||||
|
||||
// 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,
|
||||
// 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.
|
||||
@@ -518,46 +563,40 @@ GenericDisplay.prototype = {
|
||||
let itemInfo = this._allItems[itemId];
|
||||
let displayItem = this._createDisplayItem(itemInfo);
|
||||
|
||||
displayItem.connect('activate',
|
||||
displayItem.connect('activate',
|
||||
Lang.bind(this,
|
||||
function() {
|
||||
// update the selection
|
||||
this._selectIndex(this._list.get_actor_index(displayItem.actor));
|
||||
this._selectIndex(this._getIndexOfDisplayedActor(displayItem.actor));
|
||||
this.activateSelected();
|
||||
}));
|
||||
|
||||
displayItem.connect('show-details',
|
||||
displayItem.connect('select',
|
||||
Lang.bind(this,
|
||||
function() {
|
||||
let index = this._list.get_actor_index(displayItem.actor);
|
||||
/* Close the details pane if already open */
|
||||
if (index == this._openDetailIndex) {
|
||||
this._openDetailIndex = -1;
|
||||
this.emit('show-details', -1);
|
||||
} else {
|
||||
this._openDetailIndex = index;
|
||||
this.emit('show-details', index);
|
||||
}
|
||||
// update the selection
|
||||
this._selectIndex(this._getIndexOfDisplayedActor(displayItem.actor));
|
||||
}));
|
||||
this._list.add_actor(displayItem.actor);
|
||||
this._grid.add_actor(displayItem.actor);
|
||||
this._displayedItems[itemId] = displayItem;
|
||||
this._displayedItemsCount++;
|
||||
},
|
||||
|
||||
// Removes an item identifed by the itemId from the displayed items.
|
||||
_removeDisplayItem: function(itemId) {
|
||||
let count = this._list.displayedCount;
|
||||
let displayItem = this._displayedItems[itemId];
|
||||
let displayItemIndex = this._list.get_actor_index(displayItem.actor);
|
||||
let displayItemIndex = this._getIndexOfDisplayedActor(displayItem.actor);
|
||||
|
||||
if (this.hasSelected() && count == 1) {
|
||||
if (this.hasSelected() && (this._displayedItemsCount == 1 || !this._grid.visible)) {
|
||||
this.unsetSelected();
|
||||
} else if (this.hasSelected() && displayItemIndex < this._selectedIndex) {
|
||||
this.selectUp();
|
||||
}
|
||||
}
|
||||
|
||||
displayItem.destroy();
|
||||
|
||||
delete this._displayedItems[itemId];
|
||||
this._displayedItemsCount--;
|
||||
},
|
||||
|
||||
// Removes all displayed items.
|
||||
@@ -588,6 +627,9 @@ GenericDisplay.prototype = {
|
||||
* their own while the user was browsing through the result pages.
|
||||
*/
|
||||
_redisplay: function(resetPage) {
|
||||
if (!this._grid.visible)
|
||||
return;
|
||||
|
||||
this._refreshCache();
|
||||
if (!this._filterActive())
|
||||
this._setDefaultList();
|
||||
@@ -595,7 +637,7 @@ GenericDisplay.prototype = {
|
||||
this._doSearchFilter();
|
||||
|
||||
if (resetPage)
|
||||
this._list.page = 0;
|
||||
this._pageDisplayed = 0;
|
||||
|
||||
this._displayMatchedItems(true);
|
||||
|
||||
@@ -636,6 +678,27 @@ GenericDisplay.prototype = {
|
||||
|
||||
//// Private methods ////
|
||||
|
||||
// Sets this._width, this._height, this._columnWidth, and this._maxItemsPerPage based on the
|
||||
// space available for the display, number of columns, and the number of items it can fit.
|
||||
_setDimensionsAndMaxItems: function(baseWidth, expandWidth, height) {
|
||||
this._width = baseWidth + expandWidth;
|
||||
let gridWidth;
|
||||
let sideArea = this.getSideArea();
|
||||
if (this._expanded && sideArea) {
|
||||
gridWidth = expandWidth;
|
||||
sideArea.width = baseWidth;
|
||||
sideArea.height = this._height;
|
||||
} else {
|
||||
gridWidth = this._width;
|
||||
}
|
||||
this._columnWidth = (gridWidth - this._columnGap * (this._numberOfColumns - 1)) / this._numberOfColumns;
|
||||
let maxItemsInColumn = Math.floor(height / ITEM_DISPLAY_HEIGHT);
|
||||
this._maxItemsPerPage = maxItemsInColumn * this._numberOfColumns;
|
||||
this._height = maxItemsInColumn * ITEM_DISPLAY_HEIGHT;
|
||||
this._grid.width = gridWidth;
|
||||
this._grid.height = this._height;
|
||||
},
|
||||
|
||||
_getSearchMatchedItems: function() {
|
||||
let matchedItemsForSearch = {};
|
||||
// Break the search up into terms, and search for each
|
||||
@@ -685,7 +748,13 @@ GenericDisplay.prototype = {
|
||||
return 1;
|
||||
else
|
||||
return this._compareItems(a, b);
|
||||
}));
|
||||
}));
|
||||
},
|
||||
|
||||
// Displays the page specified by the pageNumber argument. The pageNumber is 0-based.
|
||||
_displayPage: function(pageNumber) {
|
||||
this._pageDisplayed = pageNumber;
|
||||
this._displayMatchedItems(false);
|
||||
},
|
||||
|
||||
/*
|
||||
@@ -698,30 +767,30 @@ GenericDisplay.prototype = {
|
||||
*/
|
||||
_updateDisplayControl: function(resetDisplayControl) {
|
||||
if (resetDisplayControl) {
|
||||
this._selectedIndex = -1;
|
||||
this.displayControl.remove_all();
|
||||
let nPages = this._list.n_pages;
|
||||
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,
|
||||
let pageNumber = 0;
|
||||
for (let i = 0; i < this._matchedItems.length; i = i + this._maxItemsPerPage) {
|
||||
let pageControl = new Link.Link({ color: (pageNumber == this._pageDisplayed) ? DISPLAY_CONTROL_SELECTED_COLOR : ITEM_DISPLAY_DESCRIPTION_COLOR,
|
||||
font_name: "Sans Bold 16px",
|
||||
text: (i+1) + "",
|
||||
reactive: (i == pageNumber) ? false : true});
|
||||
text: (pageNumber + 1) + "",
|
||||
height: LABEL_HEIGHT,
|
||||
reactive: (pageNumber == this._pageDisplayed) ? false : true});
|
||||
this.displayControl.append(pageControl.actor, Big.BoxPackFlags.NONE);
|
||||
|
||||
// we use pageNumberLocalScope to get the page number right in the callback function
|
||||
let pageNumberLocalScope = i;
|
||||
let pageNumberLocalScope = pageNumber;
|
||||
pageControl.connect('clicked',
|
||||
Lang.bind(this,
|
||||
function(o, event) {
|
||||
this.displayPage(pageNumberLocalScope);
|
||||
this._displayPage(pageNumberLocalScope);
|
||||
}));
|
||||
pageNumber ++;
|
||||
}
|
||||
} else {
|
||||
let pageControlActors = this.displayControl.get_children();
|
||||
for (let i = 0; i < pageControlActors.length; i++) {
|
||||
for (let i = 0; i < pageControlActors.length; i++) {
|
||||
let pageControlActor = pageControlActors[i];
|
||||
if (i == this._list.page) {
|
||||
if (i == this._pageDisplayed) {
|
||||
pageControlActor.color = DISPLAY_CONTROL_SELECTED_COLOR;
|
||||
pageControlActor.reactive = false;
|
||||
} else {
|
||||
@@ -732,10 +801,11 @@ GenericDisplay.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
// Returns a display item based on its index in the ordering of the
|
||||
// Returns a display item based on its index in the ordering of the
|
||||
// display children.
|
||||
_findDisplayedByIndex: function(index) {
|
||||
let actor = this._list.get_displayed_actor(index);
|
||||
let displayedActors = this._grid.get_children();
|
||||
let actor = displayedActors[index];
|
||||
return this._findDisplayedByActor(actor);
|
||||
},
|
||||
|
||||
@@ -751,31 +821,39 @@ GenericDisplay.prototype = {
|
||||
return null;
|
||||
},
|
||||
|
||||
// Returns and index that the actor has in the ordering of the display's
|
||||
// children.
|
||||
_getIndexOfDisplayedActor: function(actor) {
|
||||
let children = this._grid.get_children();
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
if (children[i] == actor)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
},
|
||||
|
||||
// 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;
|
||||
if (this._selectedIndex != -1) {
|
||||
let prev = this._findDisplayedByIndex(this._selectedIndex);
|
||||
prev.markSelected(false);
|
||||
// Calling destroy() gets large image previews released as quickly as
|
||||
// possible, if we just removed them, they might hang around for a while
|
||||
// until the actor was garbage collected.
|
||||
let children = this.selectedItemDetails.get_children();
|
||||
for (let i = 0; i < children.length; i++)
|
||||
children[i].destroy();
|
||||
|
||||
this.selectedItemDetails.remove_all();
|
||||
}
|
||||
|
||||
// Cleanup from the previous item
|
||||
if (this._selectedIndex >= 0) {
|
||||
this._findDisplayedByIndex(this._selectedIndex).markSelected(false);
|
||||
}
|
||||
|
||||
this._selectedIndex = index;
|
||||
if (index < 0)
|
||||
return
|
||||
|
||||
// Mark the new item as selected and create its details pane
|
||||
let item = this._findDisplayedByIndex(index);
|
||||
item.markSelected(true);
|
||||
this.emit('selected');
|
||||
if (index != -1 && index < this._displayedItemsCount) {
|
||||
let item = this._findDisplayedByIndex(index);
|
||||
item.markSelected(true);
|
||||
this.selectedItemDetails.append(item.createDetailsActor(this._availableWidthForItemDetails, this._availableHeightForItemDetails), Big.BoxPackFlags.NONE);
|
||||
this.emit('selected');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,589 +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 Pango = imports.gi.Pango;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const Lang = imports.lang;
|
||||
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 */
|
||||
var commandHeader = "const Clutter = imports.gi.Clutter; " +
|
||||
"const GLib = imports.gi.GLib; " +
|
||||
"const Gtk = imports.gi.Gtk; " +
|
||||
"const Mainloop = imports.mainloop; " +
|
||||
"const Meta = imports.gi.Meta; " +
|
||||
"const Shell = imports.gi.Shell; " +
|
||||
"const Main = imports.ui.main; " +
|
||||
"const Lang = imports.lang; " +
|
||||
"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 */
|
||||
"const it = Main.lookingGlass.getIt(); " +
|
||||
"const r = Lang.bind(Main.lookingGlass, Main.lookingGlass.getResult); ";
|
||||
|
||||
function Notebook() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
Notebook.prototype = {
|
||||
_init: function() {
|
||||
this.actor = new Big.Box();
|
||||
|
||||
this.tabControls = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
spacing: 4, padding: 2 });
|
||||
|
||||
this._selectedIndex = -1;
|
||||
this._tabs = [];
|
||||
},
|
||||
|
||||
appendPage: function(name, child) {
|
||||
let labelOuterBox = new Big.Box({ padding: 2 });
|
||||
let labelBox = new Big.Box({ padding: 2, border_color: MATRIX_GREEN,
|
||||
reactive: true });
|
||||
labelOuterBox.append(labelBox, Big.BoxPackFlags.NONE);
|
||||
let label = new Clutter.Text({ color: MATRIX_GREEN,
|
||||
font_name: MATRIX_FONT,
|
||||
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);
|
||||
this.tabControls.append(labelOuterBox, Big.BoxPackFlags.NONE);
|
||||
if (this._selectedIndex == -1)
|
||||
this.selectIndex(0);
|
||||
},
|
||||
|
||||
_unselect: function() {
|
||||
if (this._selectedIndex < 0)
|
||||
return;
|
||||
let [child, labelBox] = this._tabs[this._selectedIndex];
|
||||
labelBox.padding = 2;
|
||||
labelBox.border = 0;
|
||||
child.hide();
|
||||
this._selectedIndex = -1;
|
||||
},
|
||||
|
||||
selectIndex: function(index) {
|
||||
if (index == this._selectedIndex)
|
||||
return;
|
||||
this._unselect();
|
||||
if (index < 0) {
|
||||
this.emit('selection', null);
|
||||
return;
|
||||
}
|
||||
let [child, labelBox] = this._tabs[index];
|
||||
labelBox.padding = 1;
|
||||
labelBox.border = 1;
|
||||
child.show();
|
||||
this._selectedIndex = index;
|
||||
this.emit('selection', child);
|
||||
},
|
||||
|
||||
selectChild: function(child) {
|
||||
if (child == null)
|
||||
this.selectIndex(-1);
|
||||
else {
|
||||
for (let i = 0; i < this._tabs.length; i++) {
|
||||
let [tabChild, labelBox] = this._tabs[i];
|
||||
if (tabChild == child) {
|
||||
this.selectIndex(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Signals.addSignalMethods(Notebook.prototype);
|
||||
|
||||
function Result(command, o, index) {
|
||||
this._init(command, o, index);
|
||||
}
|
||||
|
||||
Result.prototype = {
|
||||
_init : function(command, o, index) {
|
||||
this.index = index;
|
||||
this.o = o;
|
||||
|
||||
this.actor = new Big.Box();
|
||||
|
||||
let cmdTxt = new Clutter.Text({ color: MATRIX_GREEN,
|
||||
font_name: MATRIX_FONT,
|
||||
ellipsize: Pango.EllipsizeMode.END,
|
||||
text: command });
|
||||
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 });
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
function ActorHierarchy() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
ActorHierarchy.prototype = {
|
||||
_init : function () {
|
||||
this._previousTarget = null;
|
||||
this._target = null;
|
||||
|
||||
this._parentList = [];
|
||||
|
||||
this.actor = new Big.Box({ spacing: 4,
|
||||
border: 1,
|
||||
padding: 4,
|
||||
border_color: GREY });
|
||||
},
|
||||
|
||||
setTarget: function(actor) {
|
||||
this._previousTarget = this._target;
|
||||
this.target = actor;
|
||||
|
||||
this.actor.remove_all();
|
||||
|
||||
if (!(actor instanceof Clutter.Actor))
|
||||
return;
|
||||
|
||||
if (this.target == null)
|
||||
return;
|
||||
|
||||
this._parentList = [];
|
||||
let parent = actor;
|
||||
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 parentTarget = parent;
|
||||
link.connect('button-press-event', Lang.bind(this, function () {
|
||||
this._selectByActor(parentTarget);
|
||||
return true;
|
||||
}));
|
||||
}
|
||||
this.emit('selection', actor);
|
||||
},
|
||||
|
||||
_selectByActor: function(actor) {
|
||||
let idx = this._parentList.indexOf(actor);
|
||||
let children = this.actor.get_children();
|
||||
let link = children[idx];
|
||||
this.emit('selection', actor);
|
||||
}
|
||||
}
|
||||
Signals.addSignalMethods(ActorHierarchy.prototype);
|
||||
|
||||
function PropertyInspector() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
PropertyInspector.prototype = {
|
||||
_init : function () {
|
||||
this._target = null;
|
||||
|
||||
this._parentList = [];
|
||||
|
||||
this.actor = new Big.Box({ spacing: 4,
|
||||
border: 1,
|
||||
padding: 4,
|
||||
border_color: GREY });
|
||||
},
|
||||
|
||||
setTarget: function(actor) {
|
||||
this.target = actor;
|
||||
|
||||
this.actor.remove_all();
|
||||
|
||||
for (let propName in actor) {
|
||||
let valueStr;
|
||||
try {
|
||||
valueStr = "" + actor[propName];
|
||||
} catch (e) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Inspector() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
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
|
||||
});
|
||||
eventHandler.connect('notify::allocation', Lang.bind(this, function () {
|
||||
eventHandler.x = Math.floor((global.stage.width)/2 - (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 borderPaintTarget = null;
|
||||
let borderPaintId = null;
|
||||
eventHandler.connect('destroy', Lang.bind(this, function() {
|
||||
if (borderPaintTarget != null)
|
||||
borderPaintTarget.disconnect(borderPaintId);
|
||||
}));
|
||||
|
||||
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();
|
||||
let target = global.stage.get_actor_at_pos(Clutter.PickMode.ALL,
|
||||
stageX,
|
||||
stageY);
|
||||
this.emit('target', target, stageX, stageY);
|
||||
eventHandler.destroy();
|
||||
this.emit('closed');
|
||||
return true;
|
||||
}));
|
||||
|
||||
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,
|
||||
stageY);
|
||||
displayText.text = '<inspect x: ' + stageX + ' y: ' + stageY + '> ' + target;
|
||||
if (borderPaintTarget != null)
|
||||
borderPaintTarget.disconnect(borderPaintId);
|
||||
borderPaintTarget = target;
|
||||
borderPaintId = Shell.add_hook_paint_red_border(target);
|
||||
return true;
|
||||
}));
|
||||
Clutter.grab_pointer(eventHandler);
|
||||
}
|
||||
}
|
||||
|
||||
Signals.addSignalMethods(Inspector.prototype);
|
||||
|
||||
function LookingGlass() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
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);
|
||||
this._savedText = null;
|
||||
this._historyNavIndex = -1;
|
||||
this._history = [];
|
||||
this._readHistory();
|
||||
|
||||
this._open = false;
|
||||
|
||||
this._offset = 0;
|
||||
this._results = [];
|
||||
|
||||
// TODO replace with scrolling or something better
|
||||
this._maxItems = 10;
|
||||
|
||||
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 inspectIcon = Shell.TextureCache.get_default().load_gicon(new Gio.ThemedIcon({ name: 'gtk-color-picker' }),
|
||||
24);
|
||||
toolbar.append(inspectIcon, Big.BoxPackFlags.NONE);
|
||||
inspectIcon.reactive = true;
|
||||
inspectIcon.connect('button-press-event', Lang.bind(this, function () {
|
||||
let inspector = new Inspector();
|
||||
inspector.connect('target', Lang.bind(this, function(i, target, stageX, stageY) {
|
||||
this._pushResult('<inspect x:' + stageX + ' y:' + stageY + '>',
|
||||
target);
|
||||
this._hierarchy.setTarget(target);
|
||||
}));
|
||||
inspector.connect('closed', Lang.bind(this, function() {
|
||||
this.actor.show();
|
||||
global.stage.set_key_focus(this._entry);
|
||||
}));
|
||||
this.actor.hide();
|
||||
return true;
|
||||
}));
|
||||
|
||||
let notebook = new Notebook();
|
||||
this.actor.append(notebook.actor, Big.BoxPackFlags.EXPAND);
|
||||
toolbar.append(notebook.tabControls, Big.BoxPackFlags.END);
|
||||
|
||||
this._evalBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
spacing: 4 });
|
||||
notebook.appendPage('Evaluator', this._evalBox);
|
||||
|
||||
this._resultsArea = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
spacing: 4 });
|
||||
this._evalBox.append(this._resultsArea, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
let entryArea = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL });
|
||||
this._evalBox.append(entryArea, Big.BoxPackFlags.NONE);
|
||||
|
||||
let label = new Clutter.Text({ color: MATRIX_GREEN,
|
||||
font_name: MATRIX_FONT,
|
||||
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 */
|
||||
notebook.connect('selection', Lang.bind(this, function (nb, child) {
|
||||
if (child == this._evalBox)
|
||||
global.stage.set_key_focus(this._entry);
|
||||
}));
|
||||
entryArea.append(this._entry, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
this._hierarchy = new ActorHierarchy();
|
||||
notebook.appendPage('Hierarchy', this._hierarchy.actor);
|
||||
|
||||
this._propInspector = new PropertyInspector();
|
||||
notebook.appendPage('Properties', this._propInspector.actor);
|
||||
this._hierarchy.connect('selection', Lang.bind(this, function (h, actor) {
|
||||
this._pushResult('<parent selection>', actor);
|
||||
notebook.selectIndex(0);
|
||||
}));
|
||||
|
||||
this._entry.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.
|
||||
text.replace('\n', ' ');
|
||||
// Strip leading and trailing whitespace
|
||||
text = text.replace(/^\s+/g, "").replace(/\s+$/g, "");
|
||||
if (text == '')
|
||||
return true;
|
||||
this._evaluate(text);
|
||||
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);
|
||||
if (symbol == Clutter.Escape) {
|
||||
this.close();
|
||||
return true;
|
||||
} else if (symbol == Clutter.Up) {
|
||||
if (this._historyNavIndex >= this._history.length - 1)
|
||||
return true;
|
||||
this._historyNavIndex++;
|
||||
if (this._historyNavIndex == 0)
|
||||
this._savedText = this._entry.text;
|
||||
this._entry.text = this._history[this._history.length - this._historyNavIndex - 1];
|
||||
return true;
|
||||
} else if (symbol == Clutter.Down) {
|
||||
if (this._historyNavIndex <= 0)
|
||||
return true;
|
||||
this._historyNavIndex--;
|
||||
if (this._historyNavIndex < 0)
|
||||
this._entry.text = this._savedText;
|
||||
else
|
||||
this._entry.text = this._history[this._history.length - this._historyNavIndex - 1];
|
||||
return true;
|
||||
} else {
|
||||
this._historyNavIndex = -1;
|
||||
this._savedText = null;
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
},
|
||||
|
||||
_readHistory: function () {
|
||||
if (!this._historyFile.query_exists(null))
|
||||
return;
|
||||
let [result, contents, length, etag] = this._historyFile.load_contents(null);
|
||||
this._history = contents.split('\n').filter(function (e) { return e != ''; });
|
||||
},
|
||||
|
||||
_queueHistorySave: function() {
|
||||
if (this._idleHistorySaveId > 0)
|
||||
return;
|
||||
this._idleHistorySaveId = Mainloop.timeout_add_seconds(5, Lang.bind(this, this._doSaveHistory));
|
||||
},
|
||||
|
||||
_doSaveHistory: function () {
|
||||
this._idleHistorySaveId = false;
|
||||
let output = this._historyFile.replace(null, true, Gio.FileCreateFlags.NONE, null);
|
||||
let dataOut = new Gio.DataOutputStream({ base_stream: output });
|
||||
dataOut.put_string(this._history.join('\n'), null);
|
||||
dataOut.put_string('\n', null);
|
||||
dataOut.close(null);
|
||||
return false;
|
||||
},
|
||||
|
||||
_pushResult: function(command, obj) {
|
||||
let index = this._results.length + this._offset;
|
||||
let result = new Result('>>> ' + command, obj, index);
|
||||
this._results.push(result);
|
||||
this._resultsArea.append(result.actor, Big.BoxPackFlags.NONE);
|
||||
this._propInspector.setTarget(obj);
|
||||
let children = this._resultsArea.get_children();
|
||||
if (children.length > this._maxItems) {
|
||||
this._results.shift();
|
||||
children[0].destroy();
|
||||
this._offset++;
|
||||
}
|
||||
this._it = obj;
|
||||
},
|
||||
|
||||
_evaluate : function(command) {
|
||||
this._history.push(command);
|
||||
this._queueHistorySave();
|
||||
|
||||
let fullCmd = commandHeader + command;
|
||||
|
||||
let resultObj;
|
||||
try {
|
||||
resultObj = eval(fullCmd);
|
||||
} catch (e) {
|
||||
resultObj = "<exception " + e + ">";
|
||||
}
|
||||
|
||||
this._pushResult(command, resultObj);
|
||||
this._hierarchy.setTarget(null);
|
||||
this._entry.text = '';
|
||||
},
|
||||
|
||||
getIt: function () {
|
||||
return this._it;
|
||||
},
|
||||
|
||||
getResult: function(idx) {
|
||||
return this._results[idx - this._offset].o;
|
||||
},
|
||||
|
||||
toggle: function() {
|
||||
if (this._open)
|
||||
this.close();
|
||||
else
|
||||
this.open();
|
||||
},
|
||||
|
||||
_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 [srcX, srcY] = actor.get_transformed_position();
|
||||
this.actor.x = srcX + (stage.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;
|
||||
this.actor.width = myWidth;
|
||||
this.actor.height = myHeight;
|
||||
},
|
||||
|
||||
slaveTo: function(actor) {
|
||||
this._slaveTo = actor;
|
||||
actor.connect('notify::allocation', Lang.bind(this, function () {
|
||||
this._resizeTo(actor);
|
||||
}));
|
||||
this._resizeTo(actor);
|
||||
},
|
||||
|
||||
open : function() {
|
||||
if (this._open)
|
||||
return;
|
||||
|
||||
this.actor.show();
|
||||
this.actor.lower(Main.chrome.actor);
|
||||
this._open = true;
|
||||
|
||||
Tweener.removeTweens(this.actor);
|
||||
|
||||
if (!Main.beginModal())
|
||||
return;
|
||||
|
||||
let global = Shell.Global.get();
|
||||
global.stage.set_key_focus(this._entry);
|
||||
|
||||
Tweener.addTween(this.actor, { time: 0.5,
|
||||
transition: "easeOutQuad",
|
||||
y: this._targetY
|
||||
});
|
||||
},
|
||||
|
||||
close : function() {
|
||||
if (!this._open)
|
||||
return;
|
||||
|
||||
this._historyNavIndex = -1;
|
||||
this._open = false;
|
||||
Tweener.removeTweens(this.actor);
|
||||
|
||||
Main.endModal();
|
||||
|
||||
Tweener.addTween(this.actor, { time: 0.5,
|
||||
transition: "easeOutQuad",
|
||||
y: this._hiddenY,
|
||||
onComplete: Lang.bind(this, function () {
|
||||
this.actor.hide();
|
||||
})
|
||||
});
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(LookingGlass.prototype);
|
||||
120
js/ui/main.js
120
js/ui/main.js
@@ -3,7 +3,6 @@
|
||||
const Clutter = imports.gi.Clutter;
|
||||
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;
|
||||
@@ -11,10 +10,9 @@ const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const Chrome = imports.ui.chrome;
|
||||
const Overview = imports.ui.overview;
|
||||
const Overlay = imports.ui.overlay;
|
||||
const Panel = imports.ui.panel;
|
||||
const RunDialog = imports.ui.runDialog;
|
||||
const LookingGlass = imports.ui.lookingGlass;
|
||||
const Sidebar = imports.ui.sidebar;
|
||||
const Tweener = imports.ui.tweener;
|
||||
const WindowManager = imports.ui.windowManager;
|
||||
@@ -25,9 +23,8 @@ DEFAULT_BACKGROUND_COLOR.from_pixel(0x2266bbff);
|
||||
let chrome = null;
|
||||
let panel = null;
|
||||
let sidebar = null;
|
||||
let overview = null;
|
||||
let overlay = null;
|
||||
let runDialog = null;
|
||||
let lookingGlass = null;
|
||||
let wm = null;
|
||||
let recorder = null;
|
||||
let inModal = false;
|
||||
@@ -38,46 +35,49 @@ function start() {
|
||||
Gio.DesktopAppInfo.set_desktop_env("GNOME");
|
||||
|
||||
global.grab_dbus_service();
|
||||
global.start_task_panel();
|
||||
|
||||
Tweener.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
|
||||
// when we are running inside Xephyr.
|
||||
global.stage.color = DEFAULT_BACKGROUND_COLOR;
|
||||
|
||||
// Mutter currently hardcodes putting "Yessir. The compositor is running""
|
||||
// in the Overview. Clear that out.
|
||||
// in the overlay. Clear that out.
|
||||
let children = global.overlay_group.get_children();
|
||||
for (let i = 0; i < children.length; i++)
|
||||
children[i].destroy();
|
||||
|
||||
global.connect('panel-run-dialog', function(panel) {
|
||||
// Make sure not more than one run dialog is shown.
|
||||
if (runDialog == null) {
|
||||
if (!runDialog) {
|
||||
runDialog = new RunDialog.RunDialog();
|
||||
let endHandler = function() {
|
||||
runDialog.destroy();
|
||||
runDialog = null;
|
||||
};
|
||||
runDialog.connect('run', endHandler);
|
||||
runDialog.connect('cancel', endHandler);
|
||||
if (!runDialog.show())
|
||||
endHandler();
|
||||
}
|
||||
runDialog.open();
|
||||
});
|
||||
|
||||
overview = new Overview.Overview();
|
||||
overlay = new Overlay.Overlay();
|
||||
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) {
|
||||
// We have to initialize GStreamer first. This isn't done
|
||||
// inside ShellRecorder to make it usable inside projects
|
||||
// with other usage of GStreamer.
|
||||
let Gst = imports.gi.Gst;
|
||||
Gst.init(null, null);
|
||||
recorder = new Shell.Recorder({ stage: global.stage });
|
||||
}
|
||||
|
||||
@@ -88,25 +88,13 @@ function start() {
|
||||
}
|
||||
});
|
||||
|
||||
_relayout();
|
||||
|
||||
panel.startupAnimation();
|
||||
|
||||
let display = global.screen.get_display();
|
||||
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);
|
||||
|
||||
display.connect('overlay-key', Lang.bind(overlay, overlay.toggle));
|
||||
global.connect('panel-main-menu', Lang.bind(overlay, overlay.toggle));
|
||||
|
||||
Mainloop.idle_add(_removeUnusedWorkspaces);
|
||||
}
|
||||
|
||||
function _relayout() {
|
||||
let global = Shell.Global.get();
|
||||
panel.actor.set_size(global.screen_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
|
||||
@@ -137,60 +125,13 @@ function _removeUnusedWorkspaces() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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 (!inModal)
|
||||
return false;
|
||||
|
||||
let type = event.type();
|
||||
|
||||
if (type == Clutter.EventType.KEY_PRESS) {
|
||||
let symbol = Shell.get_event_key_symbol (event);
|
||||
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 = Shell.get_event_key_symbol (event);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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 beginModal() {
|
||||
function startModal() {
|
||||
let global = Shell.Global.get();
|
||||
let timestamp = global.screen.get_display().get_current_time();
|
||||
|
||||
if (!global.begin_modal(timestamp))
|
||||
if (!global.grab_keyboard())
|
||||
return false;
|
||||
global.set_stage_input_mode(Shell.StageInputMode.FULLSCREEN);
|
||||
|
||||
@@ -201,21 +142,12 @@ function beginModal() {
|
||||
|
||||
function endModal() {
|
||||
let global = Shell.Global.get();
|
||||
let timestamp = global.screen.get_display().get_current_time();
|
||||
|
||||
global.end_modal(timestamp);
|
||||
global.ungrab_keyboard();
|
||||
global.set_stage_input_mode(Shell.StageInputMode.NORMAL);
|
||||
inModal = false;
|
||||
}
|
||||
|
||||
function createLookingGlass() {
|
||||
if (lookingGlass == null) {
|
||||
lookingGlass = new LookingGlass.LookingGlass();
|
||||
lookingGlass.slaveTo(panel.actor);
|
||||
}
|
||||
return lookingGlass;
|
||||
}
|
||||
|
||||
function createAppLaunchContext() {
|
||||
let global = Shell.Global.get();
|
||||
let screen = global.screen;
|
||||
|
||||
954
js/ui/overlay.js
Normal file
954
js/ui/overlay.js
Normal file
@@ -0,0 +1,954 @@
|
||||
/* -*- 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 Tweener = imports.ui.tweener;
|
||||
const Workspaces = imports.ui.workspaces;
|
||||
|
||||
const ROOT_OVERLAY_COLOR = new Clutter.Color();
|
||||
ROOT_OVERLAY_COLOR.from_pixel(0x000000bb);
|
||||
|
||||
// The factor to scale the overlay wallpaper with. This should not be less
|
||||
// than 3/2, because the rule of thirds is used for positioning (see below).
|
||||
const BACKGROUND_SCALE = 2;
|
||||
|
||||
const LABEL_HEIGHT = 16;
|
||||
const DASH_MIN_WIDTH = 250;
|
||||
const DASH_SECTION_PADDING = 6;
|
||||
const DASH_SECTION_SPACING = 6;
|
||||
const DASH_COLUMNS = 1;
|
||||
const DASH_CORNER_RADIUS = 5;
|
||||
// This is the height of section components other than the item display.
|
||||
const DASH_SECTION_MISC_HEIGHT = (LABEL_HEIGHT + DASH_SECTION_SPACING) * 2 + DASH_SECTION_PADDING;
|
||||
const DASH_SEARCH_BG_COLOR = new Clutter.Color();
|
||||
DASH_SEARCH_BG_COLOR.from_pixel(0xffffffff);
|
||||
const DASH_TEXT_COLOR = new Clutter.Color();
|
||||
DASH_TEXT_COLOR.from_pixel(0xffffffff);
|
||||
|
||||
// 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;
|
||||
|
||||
// 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;
|
||||
|
||||
// The dash has a slightly transparent blue background with a gradient.
|
||||
const DASH_LEFT_COLOR = new Clutter.Color();
|
||||
DASH_LEFT_COLOR.from_pixel(0x324c6fbb);
|
||||
const DASH_MIDDLE_COLOR = new Clutter.Color();
|
||||
DASH_MIDDLE_COLOR.from_pixel(0x324c6faa);
|
||||
const DASH_RIGHT_COLOR = new Clutter.Color();
|
||||
DASH_RIGHT_COLOR.from_pixel(0x324c6fcc);
|
||||
|
||||
const DASH_BORDER_COLOR = new Clutter.Color();
|
||||
DASH_BORDER_COLOR.from_pixel(0x213b5dff);
|
||||
|
||||
const DASH_BORDER_WIDTH = 2;
|
||||
|
||||
// The results and details panes have a somewhat transparent blue background with a gradient.
|
||||
const PANE_LEFT_COLOR = new Clutter.Color();
|
||||
PANE_LEFT_COLOR.from_pixel(0x324c6ff4);
|
||||
const PANE_MIDDLE_COLOR = new Clutter.Color();
|
||||
PANE_MIDDLE_COLOR.from_pixel(0x324c6ffa);
|
||||
const PANE_RIGHT_COLOR = new Clutter.Color();
|
||||
PANE_RIGHT_COLOR.from_pixel(0x324c6ff4);
|
||||
|
||||
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 SearchEntry(width) {
|
||||
this._init(width);
|
||||
}
|
||||
|
||||
SearchEntry.prototype = {
|
||||
_init : function(width) {
|
||||
this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
y_align: Big.BoxAlignment.CENTER,
|
||||
background_color: DASH_SEARCH_BG_COLOR,
|
||||
corner_radius: 4,
|
||||
spacing: 4,
|
||||
padding_left: 4,
|
||||
padding_right: 4,
|
||||
width: width,
|
||||
height: 24
|
||||
});
|
||||
|
||||
let icontheme = Gtk.IconTheme.get_default();
|
||||
let searchIconTexture = new Clutter.Texture({});
|
||||
let searchIconPath = icontheme.lookup_icon('gtk-find', 16, 0).get_filename();
|
||||
searchIconTexture.set_from_file(searchIconPath);
|
||||
this.actor.append(searchIconTexture, 0);
|
||||
|
||||
// We need to initialize the text for the entry to have the cursor displayed
|
||||
// in it. See http://bugzilla.openedhand.com/show_bug.cgi?id=1365
|
||||
this.entry = new Clutter.Text({ font_name: "Sans 14px",
|
||||
editable: true,
|
||||
activatable: true,
|
||||
singleLineMode: true,
|
||||
text: ""
|
||||
});
|
||||
this.entry.connect('text-changed', Lang.bind(this, function (e) {
|
||||
let text = this.entry.text;
|
||||
}));
|
||||
this.actor.append(this.entry, Big.BoxPackFlags.EXPAND);
|
||||
}
|
||||
};
|
||||
|
||||
function ItemResults(resultsWidth, resultsHeight, displayClass, labelText) {
|
||||
this._init(resultsWidth, resultsHeight, displayClass, labelText);
|
||||
}
|
||||
|
||||
ItemResults.prototype = {
|
||||
_init: function(resultsWidth, resultsHeight, displayClass, labelText) {
|
||||
this._resultsWidth = resultsWidth;
|
||||
this._resultsHeight = resultsHeight;
|
||||
|
||||
this.actor = new Big.Box({ height: resultsHeight,
|
||||
padding: DASH_SECTION_PADDING + DASH_BORDER_WIDTH,
|
||||
spacing: DASH_SECTION_SPACING });
|
||||
|
||||
this._resultsText = new Clutter.Text({ color: DASH_TEXT_COLOR,
|
||||
font_name: "Sans Bold 14px",
|
||||
text: labelText });
|
||||
this.actor.append(this._resultsText, Big.BoxPackFlags.NONE);
|
||||
|
||||
// LABEL_HEIGHT is the height of this._resultsText and GenericDisplay.LABEL_HEIGHT is the height
|
||||
// of the display controls.
|
||||
this._displayHeight = resultsHeight - LABEL_HEIGHT - GenericDisplay.LABEL_HEIGHT - DASH_SECTION_SPACING * 2;
|
||||
this.display = new displayClass(resultsWidth, this._displayHeight, DASH_COLUMNS, DASH_SECTION_SPACING);
|
||||
|
||||
this.actor.append(this.display.actor, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
this.controlBox = new Big.Box({ x_align: Big.BoxAlignment.CENTER });
|
||||
this.controlBox.append(this.display.displayControl, Big.BoxPackFlags.NONE);
|
||||
|
||||
this.actor.append(this.controlBox, Big.BoxPackFlags.END);
|
||||
},
|
||||
|
||||
_setSearchMode: function() {
|
||||
this.actor.height = this._resultsHeight / NUMBER_OF_SECTIONS_IN_SEARCH;
|
||||
let displayHeight = this._displayHeight - this._resultsHeight * (NUMBER_OF_SECTIONS_IN_SEARCH - 1) / NUMBER_OF_SECTIONS_IN_SEARCH;
|
||||
this.display.setExpanded(false, this._resultsWidth, 0, displayHeight, DASH_COLUMNS);
|
||||
this.actor.remove_all();
|
||||
this.actor.append(this._resultsText, Big.BoxPackFlags.NONE);
|
||||
this.actor.append(this.display.actor, Big.BoxPackFlags.EXPAND);
|
||||
this.actor.append(this.controlBox, Big.BoxPackFlags.END);
|
||||
},
|
||||
|
||||
_unsetSearchMode: function() {
|
||||
this.actor.height = this._resultsHeight;
|
||||
this.display.setExpanded(false, this._resultsWidth, 0, this._displayHeight, DASH_COLUMNS);
|
||||
this.actor.remove_all();
|
||||
this.actor.append(this._resultsText, Big.BoxPackFlags.NONE);
|
||||
this.actor.append(this.display.actor, Big.BoxPackFlags.EXPAND);
|
||||
this.actor.append(this.controlBox, Big.BoxPackFlags.END);
|
||||
}
|
||||
}
|
||||
|
||||
function Dash() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
Dash.prototype = {
|
||||
_init : function() {
|
||||
let me = this;
|
||||
|
||||
this._moreAppsMode = false;
|
||||
this._moreDocsMode = false;
|
||||
|
||||
this._width = displayGridColumnWidth;
|
||||
|
||||
this._displayWidth = displayGridColumnWidth - DASH_SECTION_PADDING * 2;
|
||||
this._resultsWidth = displayGridColumnWidth;
|
||||
this._detailsWidth = displayGridColumnWidth * 2;
|
||||
|
||||
let bottomHeight = DASH_SECTION_PADDING;
|
||||
|
||||
let global = Shell.Global.get();
|
||||
|
||||
let resultsHeight = global.screen_height - Panel.PANEL_HEIGHT - DASH_SECTION_PADDING - bottomHeight;
|
||||
let detailsHeight = global.screen_height - Panel.PANEL_HEIGHT - DASH_SECTION_PADDING - bottomHeight;
|
||||
|
||||
// The whole dash group needs to be reactive so that the clicks are not passed to the transparent background underneath it.
|
||||
// This background is used in the workspaces area when the additional dash panes are being shown. It handles clicks in the
|
||||
// workspaces area by closing these additional dash panes and revealing all workspaces.
|
||||
this.actor = new Clutter.Group({reactive: true});
|
||||
this.actor.height = global.screen_height;
|
||||
|
||||
let dashPane = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
x: 0,
|
||||
y: Panel.PANEL_HEIGHT + DASH_SECTION_PADDING,
|
||||
width: this._width + SHADOW_WIDTH,
|
||||
height: global.screen_height - Panel.PANEL_HEIGHT - DASH_SECTION_PADDING - bottomHeight});
|
||||
|
||||
let dashBackground = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
width: this._width,
|
||||
height: global.screen_height - Panel.PANEL_HEIGHT - DASH_SECTION_PADDING - bottomHeight,
|
||||
corner_radius: DASH_CORNER_RADIUS,
|
||||
border: DASH_BORDER_WIDTH,
|
||||
border_color: DASH_BORDER_COLOR });
|
||||
|
||||
dashPane.append(dashBackground, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
let dashLeft = global.create_horizontal_gradient(DASH_LEFT_COLOR,
|
||||
DASH_MIDDLE_COLOR);
|
||||
let dashRight = global.create_horizontal_gradient(DASH_MIDDLE_COLOR,
|
||||
DASH_RIGHT_COLOR);
|
||||
let dashShadow = global.create_horizontal_gradient(SHADOW_COLOR,
|
||||
TRANSPARENT_COLOR);
|
||||
dashShadow.set_width(SHADOW_WIDTH);
|
||||
|
||||
dashBackground.append(dashLeft, Big.BoxPackFlags.EXPAND);
|
||||
dashBackground.append(dashRight, Big.BoxPackFlags.EXPAND);
|
||||
dashPane.append(dashShadow, Big.BoxPackFlags.NONE);
|
||||
|
||||
this.actor.add_actor(dashPane);
|
||||
|
||||
this._searchEntry = new SearchEntry(this._width - DASH_SECTION_PADDING * 2 - DASH_BORDER_WIDTH * 2);
|
||||
this.actor.add_actor(this._searchEntry.actor);
|
||||
this._searchEntry.actor.set_position(DASH_SECTION_PADDING + DASH_BORDER_WIDTH, dashPane.y + DASH_SECTION_PADDING + DASH_BORDER_WIDTH);
|
||||
|
||||
this._searchQueued = false;
|
||||
this._searchEntry.entry.connect('text-changed', function (se, prop) {
|
||||
if (me._searchQueued)
|
||||
return;
|
||||
me._searchQueued = true;
|
||||
Mainloop.timeout_add(250, function() {
|
||||
// Strip leading and trailing whitespace
|
||||
let text = me._searchEntry.entry.text.replace(/^\s+/g, "").replace(/\s+$/g, "");
|
||||
me._searchQueued = false;
|
||||
me._resultsAppsSection.display.setSearch(text);
|
||||
me._resultsDocsSection.display.setSearch(text);
|
||||
if (text == '')
|
||||
me._unsetSearchMode();
|
||||
else
|
||||
me._setSearchMode();
|
||||
|
||||
return false;
|
||||
});
|
||||
});
|
||||
this._searchEntry.entry.connect('activate', function (se) {
|
||||
// only one of the displays will have an item selected, so it's ok to
|
||||
// call activateSelected() on all of them
|
||||
me._docDisplay.activateSelected();
|
||||
me._resultsAppsSection.display.activateSelected();
|
||||
me._resultsDocsSection.display.activateSelected();
|
||||
return true;
|
||||
});
|
||||
this._searchEntry.entry.connect('key-press-event', function (se, e) {
|
||||
let symbol = Shell.get_event_key_symbol(e);
|
||||
if (symbol == Clutter.Escape) {
|
||||
// Escape will keep clearing things back to the desktop. First, if
|
||||
// we have active text, we remove it.
|
||||
if (me._searchEntry.entry.text != '')
|
||||
me._searchEntry.entry.text = '';
|
||||
// Next, if we're in one of the "more" modes or showing the details pane, close them
|
||||
else if (me._moreAppsMode || me._moreDocsMode || me._detailsShowing())
|
||||
me.unsetMoreMode();
|
||||
// Finally, just close the overlay entirely
|
||||
else
|
||||
me.emit('activated');
|
||||
return true;
|
||||
} else if (symbol == Clutter.Up) {
|
||||
// selectUp and selectDown wrap around in their respective displays
|
||||
// too, but there doesn't seem to be any flickering if we first select
|
||||
// something in one display, but then unset the selection, and move
|
||||
// it to the other display, so it's ok to do that.
|
||||
// TODO: add the right logic
|
||||
} else if (symbol == Clutter.Down) {
|
||||
// TODO: add the right logic
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
this._appsText = new Clutter.Text({ color: DASH_TEXT_COLOR,
|
||||
font_name: "Sans Bold 14px",
|
||||
text: "Applications",
|
||||
height: LABEL_HEIGHT});
|
||||
this._appsSection = new Big.Box({ x: DASH_SECTION_PADDING,
|
||||
y: this._searchEntry.actor.y + this._searchEntry.actor.height + DASH_SECTION_PADDING,
|
||||
padding_top: DASH_SECTION_PADDING,
|
||||
spacing: DASH_SECTION_SPACING});
|
||||
this._appsSection.append(this._appsText, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
this._itemDisplayHeight = global.screen_height - this._appsSection.y - DASH_SECTION_MISC_HEIGHT * 2 - bottomHeight;
|
||||
|
||||
this._appsContent = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL });
|
||||
this._appsSection.append(this._appsContent, Big.BoxPackFlags.EXPAND);
|
||||
this._appWell = new AppDisplay.AppWell(this._displayWidth);
|
||||
this._appWell.actor.show();
|
||||
this._appsContent.append(this._appWell.actor, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
let moreAppsBox = new Big.Box({x_align: Big.BoxAlignment.END});
|
||||
this._moreAppsLink = new Link.Link({ color: DASH_TEXT_COLOR,
|
||||
font_name: "Sans Bold 14px",
|
||||
text: "More...",
|
||||
height: LABEL_HEIGHT });
|
||||
moreAppsBox.append(this._moreAppsLink.actor, Big.BoxPackFlags.EXPAND);
|
||||
this._appsSection.append(moreAppsBox, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
this.actor.add_actor(this._appsSection);
|
||||
|
||||
this._appsSectionDefaultHeight = this._appsSection.height;
|
||||
|
||||
this._docsSection = new Big.Box({ x: DASH_SECTION_PADDING,
|
||||
y: this._appsSection.y + this._appsSection.height,
|
||||
padding_top: DASH_SECTION_PADDING,
|
||||
spacing: DASH_SECTION_SPACING});
|
||||
|
||||
this._docsText = new Clutter.Text({ color: DASH_TEXT_COLOR,
|
||||
font_name: "Sans Bold 14px",
|
||||
text: "Recent Documents",
|
||||
height: LABEL_HEIGHT});
|
||||
this._docsSection.append(this._docsText, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
this._docDisplay = new DocDisplay.DocDisplay(this._displayWidth, this._itemDisplayHeight - this._appsContent.height, DASH_COLUMNS, DASH_SECTION_PADDING);
|
||||
this._docsSection.append(this._docDisplay.actor, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
let moreDocsBox = new Big.Box({x_align: Big.BoxAlignment.END});
|
||||
this._moreDocsLink = new Link.Link({ color: DASH_TEXT_COLOR,
|
||||
font_name: "Sans Bold 14px",
|
||||
text: "More...",
|
||||
height: LABEL_HEIGHT });
|
||||
moreDocsBox.append(this._moreDocsLink.actor, Big.BoxPackFlags.EXPAND);
|
||||
this._docsSection.append(moreDocsBox, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
this.actor.add_actor(this._docsSection);
|
||||
|
||||
this._docsSectionDefaultHeight = this._docsSection.height;
|
||||
|
||||
// The "More" or search results area
|
||||
this._resultsAppsSection = new ItemResults(this._displayWidth, resultsHeight, AppDisplay.AppDisplay, "Applications");
|
||||
this._resultsDocsSection = new ItemResults(this._displayWidth, resultsHeight, DocDisplay.DocDisplay, "Documents");
|
||||
|
||||
this._resultsPane = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
x: this._width,
|
||||
y: Panel.PANEL_HEIGHT + DASH_SECTION_PADDING,
|
||||
width: this._resultsWidth + SHADOW_WIDTH,
|
||||
height: resultsHeight });
|
||||
|
||||
let resultsBackground = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
width: this._resultsWidth,
|
||||
height: resultsHeight,
|
||||
corner_radius: DASH_CORNER_RADIUS,
|
||||
border: DASH_BORDER_WIDTH,
|
||||
border_color: DASH_BORDER_COLOR });
|
||||
|
||||
this._resultsPane.append(resultsBackground, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
let resultsLeft = global.create_horizontal_gradient(PANE_LEFT_COLOR,
|
||||
PANE_MIDDLE_COLOR);
|
||||
let resultsRight = global.create_horizontal_gradient(PANE_MIDDLE_COLOR,
|
||||
PANE_RIGHT_COLOR);
|
||||
let resultsShadow = global.create_horizontal_gradient(SHADOW_COLOR,
|
||||
TRANSPARENT_COLOR);
|
||||
resultsShadow.set_width(SHADOW_WIDTH);
|
||||
|
||||
resultsBackground.append(resultsLeft, Big.BoxPackFlags.EXPAND);
|
||||
resultsBackground.append(resultsRight, Big.BoxPackFlags.EXPAND);
|
||||
this._resultsPane.append(resultsShadow, Big.BoxPackFlags.NONE);
|
||||
|
||||
this.actor.add_actor(this._resultsPane);
|
||||
this._resultsPane.hide();
|
||||
|
||||
this._detailsPane = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
x: this._width,
|
||||
y: Panel.PANEL_HEIGHT + DASH_SECTION_PADDING,
|
||||
width: this._detailsWidth + SHADOW_WIDTH,
|
||||
height: detailsHeight });
|
||||
this._firstSelectAfterOverlayShow = true;
|
||||
|
||||
let detailsBackground = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
width: this._detailsWidth,
|
||||
height: detailsHeight,
|
||||
corner_radius: DASH_CORNER_RADIUS,
|
||||
border: DASH_BORDER_WIDTH,
|
||||
border_color: DASH_BORDER_COLOR });
|
||||
|
||||
this._detailsPane.append(detailsBackground, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
let detailsLeft = global.create_horizontal_gradient(PANE_LEFT_COLOR,
|
||||
PANE_MIDDLE_COLOR);
|
||||
let detailsRight = global.create_horizontal_gradient(PANE_MIDDLE_COLOR,
|
||||
PANE_RIGHT_COLOR);
|
||||
let detailsShadow = global.create_horizontal_gradient(SHADOW_COLOR,
|
||||
TRANSPARENT_COLOR);
|
||||
detailsShadow.set_width(SHADOW_WIDTH);
|
||||
|
||||
detailsBackground.append(detailsLeft, Big.BoxPackFlags.EXPAND);
|
||||
detailsBackground.append(detailsRight, Big.BoxPackFlags.EXPAND);
|
||||
this._detailsPane.append(detailsShadow, Big.BoxPackFlags.NONE);
|
||||
|
||||
this._detailsContent = new Big.Box({ padding: DASH_SECTION_PADDING + DASH_BORDER_WIDTH });
|
||||
this._detailsPane.add_actor(this._detailsContent);
|
||||
|
||||
this.actor.add_actor(this._detailsPane);
|
||||
this._detailsPane.hide();
|
||||
|
||||
let itemDetailsAvailableWidth = this._detailsWidth - DASH_SECTION_PADDING * 2 - DASH_BORDER_WIDTH * 2;
|
||||
let itemDetailsAvailableHeight = detailsHeight - DASH_SECTION_PADDING * 2 - DASH_BORDER_WIDTH * 2;
|
||||
|
||||
this._docDisplay.setAvailableDimensionsForItemDetails(itemDetailsAvailableWidth, itemDetailsAvailableHeight);
|
||||
this._resultsAppsSection.display.setAvailableDimensionsForItemDetails(itemDetailsAvailableWidth, itemDetailsAvailableHeight);
|
||||
this._resultsDocsSection.display.setAvailableDimensionsForItemDetails(itemDetailsAvailableWidth, itemDetailsAvailableHeight);
|
||||
|
||||
/* Proxy the activated signals */
|
||||
this._appWell.connect('activated', function(well) {
|
||||
me.emit('activated');
|
||||
});
|
||||
this._docDisplay.connect('activated', function(docDisplay) {
|
||||
me.emit('activated');
|
||||
});
|
||||
this._resultsAppsSection.display.connect('activated', function(resultsAppsDisplay) {
|
||||
me.emit('activated');
|
||||
});
|
||||
this._resultsDocsSection.display.connect('activated', function(resultsDocsDisplay) {
|
||||
me.emit('activated');
|
||||
});
|
||||
this._docDisplay.connect('selected', function(docDisplay) {
|
||||
me._resultsDocsSection.display.unsetSelected();
|
||||
me._resultsAppsSection.display.unsetSelected();
|
||||
if (!me._detailsShowing()) {
|
||||
me._detailsPane.show();
|
||||
me.emit('panes-displayed');
|
||||
}
|
||||
me._detailsContent.remove_all();
|
||||
me._detailsContent.append(me._docDisplay.selectedItemDetails, Big.BoxPackFlags.NONE);
|
||||
});
|
||||
this._resultsDocsSection.display.connect('selected', function(resultsDocDisplay) {
|
||||
me._docDisplay.unsetSelected();
|
||||
me._resultsAppsSection.display.unsetSelected();
|
||||
if (!me._detailsShowing()) {
|
||||
me._detailsPane.show();
|
||||
me.emit('panes-displayed');
|
||||
}
|
||||
me._detailsContent.remove_all();
|
||||
me._detailsContent.append(me._resultsDocsSection.display.selectedItemDetails, Big.BoxPackFlags.NONE);
|
||||
});
|
||||
this._resultsAppsSection.display.connect('selected', function(resultsAppDisplay) {
|
||||
me._docDisplay.unsetSelected();
|
||||
me._resultsDocsSection.display.unsetSelected();
|
||||
if (!me._detailsShowing()) {
|
||||
me._detailsPane.show();
|
||||
me.emit('panes-displayed');
|
||||
}
|
||||
me._detailsContent.remove_all();
|
||||
me._detailsContent.append(me._resultsAppsSection.display.selectedItemDetails, Big.BoxPackFlags.NONE);
|
||||
});
|
||||
|
||||
this._moreAppsLink.connect('clicked',
|
||||
function(o, event) {
|
||||
if (me._moreAppsMode) {
|
||||
me._unsetMoreAppsMode();
|
||||
} else {
|
||||
me._setMoreAppsMode();
|
||||
}
|
||||
});
|
||||
|
||||
this._moreDocsLink.connect('clicked',
|
||||
function(o, event) {
|
||||
if (me._moreDocsMode) {
|
||||
me._unsetMoreDocsMode();
|
||||
} else {
|
||||
me._setMoreDocsMode();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
show: function() {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
this._appsContent.show();
|
||||
this._docDisplay.show();
|
||||
global.stage.set_key_focus(this._searchEntry.entry);
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
this._firstSelectAfterOverlayShow = true;
|
||||
this._appsContent.hide();
|
||||
this._docDisplay.hide();
|
||||
this._searchEntry.entry.text = '';
|
||||
this.unsetMoreMode();
|
||||
},
|
||||
|
||||
unsetMoreMode: function() {
|
||||
this._unsetMoreAppsMode();
|
||||
this._unsetMoreDocsMode();
|
||||
if (this._detailsShowing()) {
|
||||
this._detailsPane.hide();
|
||||
this.emit('panes-removed');
|
||||
}
|
||||
this._unsetSearchMode();
|
||||
},
|
||||
|
||||
// Sets the 'More' mode for browsing applications.
|
||||
_setMoreAppsMode: function() {
|
||||
if (this._moreAppsMode)
|
||||
return;
|
||||
|
||||
this._unsetMoreDocsMode();
|
||||
this._unsetSearchMode();
|
||||
this._moreAppsMode = true;
|
||||
|
||||
this._resultsAppsSection.display.show();
|
||||
this._resultsPane.add_actor(this._resultsAppsSection.actor);
|
||||
this._resultsPane.show();
|
||||
|
||||
this._moreAppsLink.setText("Less...");
|
||||
|
||||
this._detailsPane.x = this._width + this._resultsWidth;
|
||||
this.emit('panes-displayed');
|
||||
},
|
||||
|
||||
// Unsets the 'More' mode for browsing applications.
|
||||
_unsetMoreAppsMode: function() {
|
||||
if (!this._moreAppsMode)
|
||||
return;
|
||||
|
||||
this._moreAppsMode = false;
|
||||
|
||||
this._resultsPane.remove_actor(this._resultsAppsSection.actor);
|
||||
this._resultsAppsSection.display.hide();
|
||||
this._resultsPane.hide();
|
||||
|
||||
this._moreAppsLink.setText("More...");
|
||||
|
||||
this._detailsPane.x = this._width;
|
||||
|
||||
if (!this._detailsShowing()) {
|
||||
this.emit('panes-removed');
|
||||
}
|
||||
},
|
||||
|
||||
// Sets the 'More' mode for browsing documents.
|
||||
_setMoreDocsMode: function() {
|
||||
if (this._moreDocsMode)
|
||||
return;
|
||||
|
||||
this._unsetMoreAppsMode();
|
||||
this._unsetSearchMode();
|
||||
this._moreDocsMode = true;
|
||||
|
||||
this._resultsDocsSection.display.show();
|
||||
this._resultsPane.add_actor(this._resultsDocsSection.actor);
|
||||
this._resultsPane.show();
|
||||
|
||||
this._moreDocsLink.setText("Less...");
|
||||
|
||||
this._detailsPane.x = this._width + this._resultsWidth;
|
||||
this.emit('panes-displayed');
|
||||
},
|
||||
|
||||
// Unsets the 'More' mode for browsing documents.
|
||||
_unsetMoreDocsMode: function() {
|
||||
if (!this._moreDocsMode)
|
||||
return;
|
||||
|
||||
this._moreDocsMode = false;
|
||||
|
||||
this._resultsPane.hide();
|
||||
this._resultsPane.remove_actor(this._resultsDocsSection.actor);
|
||||
this._resultsDocsSection.display.hide();
|
||||
|
||||
this._moreDocsLink.setText("More...");
|
||||
|
||||
this._detailsPane.x = this._width;
|
||||
|
||||
if (!this._detailsShowing()) {
|
||||
this.emit('panes-removed');
|
||||
}
|
||||
},
|
||||
|
||||
_setSearchMode: function() {
|
||||
if (this._resultsShowing())
|
||||
return;
|
||||
|
||||
this._resultsAppsSection._setSearchMode();
|
||||
this._resultsAppsSection.display.show();
|
||||
this._resultsPane.add_actor(this._resultsAppsSection.actor);
|
||||
|
||||
this._resultsDocsSection._setSearchMode();
|
||||
this._resultsDocsSection.display.show();
|
||||
this._resultsPane.add_actor(this._resultsDocsSection.actor);
|
||||
this._resultsDocsSection.actor.set_y(this._resultsAppsSection.actor.height);
|
||||
|
||||
this._resultsPane.show();
|
||||
|
||||
this._detailsPane.x = this._width + this._resultsWidth;
|
||||
this.emit('panes-displayed');
|
||||
},
|
||||
|
||||
_unsetSearchMode: function() {
|
||||
if (this._moreDocsMode || this._moreAppsMode || !this._resultsShowing())
|
||||
return;
|
||||
|
||||
this._resultsPane.hide();
|
||||
|
||||
this._resultsPane.remove_actor(this._resultsAppsSection.actor);
|
||||
this._resultsAppsSection.display.hide();
|
||||
this._resultsAppsSection._unsetSearchMode();
|
||||
|
||||
this._resultsPane.remove_actor(this._resultsDocsSection.actor);
|
||||
this._resultsDocsSection.display.hide();
|
||||
this._resultsDocsSection._unsetSearchMode();
|
||||
this._resultsDocsSection.actor.set_y(0);
|
||||
|
||||
this._detailsPane.x = this._width;
|
||||
|
||||
if (!this._detailsShowing()) {
|
||||
this.emit('panes-removed');
|
||||
}
|
||||
},
|
||||
|
||||
_detailsShowing: function() {
|
||||
return this._detailsPane.visible;
|
||||
},
|
||||
|
||||
_resultsShowing: function() {
|
||||
return this._resultsPane.visible;
|
||||
}
|
||||
};
|
||||
|
||||
Signals.addSignalMethods(Dash.prototype);
|
||||
|
||||
function Overlay() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
Overlay.prototype = {
|
||||
_init : function() {
|
||||
let me = this;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
this._group = new Clutter.Group();
|
||||
this._group._delegate = this;
|
||||
|
||||
this.visible = false;
|
||||
this._hideInProgress = false;
|
||||
|
||||
// A scaled root pixmap actor is used as a background. It is zoomed in
|
||||
// to the lower right intersection of the lines that divide the image
|
||||
// evenly in a 3x3 grid. This is based on the rule of thirds, a
|
||||
// compositional rule of thumb in visual arts. The choice for the
|
||||
// lower right point is based on a quick survey of GNOME wallpapers.
|
||||
let background = global.create_root_pixmap_actor();
|
||||
background.width = global.screen_width * BACKGROUND_SCALE;
|
||||
background.height = global.screen_height * BACKGROUND_SCALE;
|
||||
background.x = -global.screen_width * (4 * BACKGROUND_SCALE - 3) / 6;
|
||||
background.y = -global.screen_height * (4 * BACKGROUND_SCALE - 3) / 6;
|
||||
this._group.add_actor(background);
|
||||
|
||||
// Transparent background is used to catch clicks outside of the dash panes when the panes
|
||||
// are being displayed and the workspaces area should not be reactive. Catching such a
|
||||
// click results in the panes being closed and the workspaces area becoming reactive again.
|
||||
this._transparentBackground = new Clutter.Rectangle({ opacity: 0,
|
||||
width: global.screen_width,
|
||||
height: global.screen_height - Panel.PANEL_HEIGHT,
|
||||
y: Panel.PANEL_HEIGHT,
|
||||
reactive: true });
|
||||
this._group.add_actor(this._transparentBackground);
|
||||
|
||||
// Draw a semitransparent rectangle over the background for readability.
|
||||
let backOver = new Clutter.Rectangle({ color: ROOT_OVERLAY_COLOR,
|
||||
width: global.screen_width,
|
||||
height: global.screen_height - Panel.PANEL_HEIGHT,
|
||||
y: Panel.PANEL_HEIGHT });
|
||||
this._group.add_actor(backOver);
|
||||
|
||||
this._group.hide();
|
||||
global.overlay_group.add_actor(this._group);
|
||||
|
||||
// TODO - recalculate everything when desktop size changes
|
||||
this._dash = new Dash();
|
||||
this._group.add_actor(this._dash.actor);
|
||||
this._workspaces = null;
|
||||
this._buttonEventHandlerId = null;
|
||||
this._dash.connect('activated', function(dash) {
|
||||
// TODO - have some sort of animation/effect while
|
||||
// transitioning to the new app. We definitely need
|
||||
// startup-notification integration at least.
|
||||
me.hide();
|
||||
});
|
||||
this._dash.connect('panes-displayed', function(dash) {
|
||||
if (me._buttonEventHandlerId == null) {
|
||||
me._transparentBackground.raise_top();
|
||||
me._dash.actor.raise_top();
|
||||
me._buttonEventHandlerId = me._transparentBackground.connect('button-release-event', function(background) {
|
||||
me._dash.unsetMoreMode();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
});
|
||||
this._dash.connect('panes-removed', function(dash) {
|
||||
if (me._buttonEventHandlerId != null) {
|
||||
me._transparentBackground.lower_bottom();
|
||||
me._transparentBackground.disconnect(me._buttonEventHandlerId);
|
||||
me._buttonEventHandlerId = null;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
//// Draggable target interface ////
|
||||
|
||||
// Unsets the expanded display mode if a GenericDisplayItem is being
|
||||
// dragged over the overlay, i.e. as soon as it starts being dragged.
|
||||
// This closes the additional panes and allows the user to place
|
||||
// the item on any workspace.
|
||||
handleDragOver : function(source, actor, x, y, time) {
|
||||
if (source instanceof GenericDisplay.GenericDisplayItem) {
|
||||
this._dash.unsetMoreMode();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
//// Public methods ////
|
||||
|
||||
show : function() {
|
||||
if (this.visible)
|
||||
return;
|
||||
if (!Main.startModal())
|
||||
return;
|
||||
|
||||
this.visible = 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._hideInProgress = true;
|
||||
// lower the Dash, so that workspaces display is on top and covers the Dash while it is 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();
|
||||
},
|
||||
|
||||
//// 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.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._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);
|
||||
}
|
||||
@@ -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_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;
|
||||
|
||||
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 Overview() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
Overview.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 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._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;
|
||||
}
|
||||
},
|
||||
|
||||
relayout: function () {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
let screenHeight = global.screen_height;
|
||||
let screenWidth = global.screen_width;
|
||||
|
||||
let contentHeight = screenHeight - Panel.PANEL_HEIGHT;
|
||||
|
||||
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 (screenHeight / screenWidth)
|
||||
// so that the workspace preserves its aspect ratio.
|
||||
this._workspacesHeight = displayGridRowHeight * workspaceRowsUsed
|
||||
- WORKSPACE_GRID_PADDING * (screenHeight / screenWidth) * 2;
|
||||
|
||||
this._workspacesX = displayGridColumnWidth + WORKSPACE_GRID_PADDING;
|
||||
this._workspacesY = displayGridRowHeight + WORKSPACE_GRID_PADDING * (screenHeight / screenWidth);
|
||||
|
||||
let dashY = Panel.PANEL_HEIGHT;
|
||||
this._dash.actor.set_position(0, dashY);
|
||||
this._dash.actor.set_size(displayGridColumnWidth, screenHeight - dashY);
|
||||
this._dash.searchArea.height = this._workspacesY - dashY;
|
||||
this._dash.sectionArea.height = this._workspacesHeight;
|
||||
|
||||
// place the 'Add Workspace' button in the bottom row of the grid
|
||||
this._addButtonSize = Math.floor(displayGridRowHeight * 3/5);
|
||||
this._addButtonX = this._workspacesX + this._workspacesWidth - this._addButtonSize;
|
||||
this._addButtonY = screenHeight - Math.floor(displayGridRowHeight * 4/5);
|
||||
|
||||
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);
|
||||
|
||||
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.WellDisplayItem) {
|
||||
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.beginModal())
|
||||
return;
|
||||
|
||||
this.visible = true;
|
||||
this.animationInProgress = true;
|
||||
|
||||
let global = Shell.Global.get();
|
||||
|
||||
this._dash.show();
|
||||
|
||||
/* TODO: make this stuff dynamic */
|
||||
this._workspaces = new Workspaces.Workspaces(this._workspacesWidth, this._workspacesHeight,
|
||||
this._workspacesX, this._workspacesY,
|
||||
this._addButtonSize, this._addButtonX, this._addButtonY);
|
||||
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);
|
||||
|
||||
// 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();
|
||||
Tweener.addTween(this._group,
|
||||
{ x: 0,
|
||||
y: 0,
|
||||
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.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();
|
||||
this._workspaces.hide();
|
||||
|
||||
// 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.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 Overview is currently active;
|
||||
* outside of that, use the relevant methods on MetaDisplay.
|
||||
*/
|
||||
activateWindow: function (metaWindow, time) {
|
||||
this._workspaces.activateWindowFromOverview(metaWindow, time);
|
||||
this.hide();
|
||||
},
|
||||
|
||||
//// Private methods ////
|
||||
|
||||
_showDone: function() {
|
||||
if (this._hideInProgress)
|
||||
return;
|
||||
|
||||
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.hide();
|
||||
this._group.hide();
|
||||
|
||||
this.visible = false;
|
||||
this.animationInProgress = false;
|
||||
this._hideInProgress = false;
|
||||
|
||||
Main.endModal();
|
||||
this.emit('hidden');
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(Overview.prototype);
|
||||
467
js/ui/panel.js
467
js/ui/panel.js
@@ -7,48 +7,35 @@ const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Shell = imports.gi.Shell;
|
||||
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 Main = imports.ui.main;
|
||||
|
||||
const PANEL_HEIGHT = 26;
|
||||
const PANEL_HEIGHT = 32;
|
||||
const TRAY_HEIGHT = PANEL_HEIGHT - 1;
|
||||
const SHADOW_HEIGHT = 6;
|
||||
|
||||
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);
|
||||
// The panel has a transparent white background with a gradient.
|
||||
const PANEL_TOP_COLOR = new Clutter.Color();
|
||||
PANEL_TOP_COLOR.from_pixel(0xffffff99);
|
||||
const PANEL_MIDDLE_COLOR = new Clutter.Color();
|
||||
PANEL_MIDDLE_COLOR.from_pixel(0xffffff88);
|
||||
const PANEL_BOTTOM_COLOR = new Clutter.Color();
|
||||
PANEL_BOTTOM_COLOR.from_pixel(0xffffffaa);
|
||||
|
||||
const SHADOW_COLOR = new Clutter.Color();
|
||||
SHADOW_COLOR.from_pixel(0x00000033);
|
||||
const TRANSPARENT_COLOR = new Clutter.Color();
|
||||
TRANSPARENT_COLOR.from_pixel(0x00000000);
|
||||
|
||||
// Don't make the mouse hover effect visible to the user for a menu feel.
|
||||
// Darken (pressed) buttons; lightening has no effect on white backgrounds.
|
||||
const PANEL_BUTTON_COLOR = new Clutter.Color();
|
||||
PANEL_BUTTON_COLOR.from_pixel(0x00000000);
|
||||
|
||||
// Lighten pressed buttons; darkening has no effect on a black background.
|
||||
PANEL_BUTTON_COLOR.from_pixel(0x00000015);
|
||||
const PRESSED_BUTTON_BACKGROUND_COLOR = new Clutter.Color();
|
||||
PRESSED_BUTTON_BACKGROUND_COLOR.from_pixel(0x324c6ffa);
|
||||
|
||||
const DEFAULT_FONT = 'Sans 16px';
|
||||
PRESSED_BUTTON_BACKGROUND_COLOR.from_pixel(0x00000030);
|
||||
|
||||
const TRAY_PADDING = 0;
|
||||
// See comments around _recomputeTraySize
|
||||
const TRAY_SPACING = 14;
|
||||
const TRAY_SPACING_MIN = 8;
|
||||
const TRAY_SPACING = 2;
|
||||
|
||||
// Used for the tray icon container with gtk pre-2.16, which doesn't
|
||||
// fully support tray icon transparency
|
||||
@@ -59,109 +46,6 @@ TRAY_BORDER_COLOR.from_pixel(0x00000033);
|
||||
const TRAY_CORNER_RADIUS = 5;
|
||||
const TRAY_BORDER_WIDTH = 0;
|
||||
|
||||
|
||||
function AppPanelMenu() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
AppPanelMenu.prototype = {
|
||||
_init: function() {
|
||||
this._metaDisplay = Shell.Global.get().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();
|
||||
}
|
||||
@@ -170,168 +54,76 @@ 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);
|
||||
// Create backBox, which contains two boxes, backUpper and backLower,
|
||||
// for the background gradients and one for the shadow. The shadow at
|
||||
// the bottom has a fixed height (packing flag NONE), and the rest of
|
||||
// the height above is divided evenly between backUpper and backLower
|
||||
// (with packing flag EXPAND).
|
||||
let backBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: global.screen_width,
|
||||
height: PANEL_HEIGHT + SHADOW_HEIGHT });
|
||||
let backUpper = global.create_vertical_gradient(PANEL_TOP_COLOR,
|
||||
PANEL_MIDDLE_COLOR);
|
||||
let backLower = global.create_vertical_gradient(PANEL_MIDDLE_COLOR,
|
||||
PANEL_BOTTOM_COLOR);
|
||||
let shadow = global.create_vertical_gradient(SHADOW_COLOR,
|
||||
TRANSPARENT_COLOR);
|
||||
shadow.set_height(SHADOW_HEIGHT + 1);
|
||||
backBox.append(backUpper, Big.BoxPackFlags.EXPAND);
|
||||
backBox.append(backLower, Big.BoxPackFlags.EXPAND);
|
||||
backBox.append(shadow, Big.BoxPackFlags.NONE);
|
||||
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, true, null, PANEL_HEIGHT);
|
||||
|
||||
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 statusbox = new Big.Box();
|
||||
let statusmenu = this._statusmenu = new Shell.StatusMenu();
|
||||
statusbox.append(this._statusmenu, Big.BoxPackFlags.NONE);
|
||||
let statusbutton = new Button.Button(statusbox, PANEL_BUTTON_COLOR, PRESSED_BUTTON_BACKGROUND_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();
|
||||
});
|
||||
|
||||
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, true, DEFAULT_FONT);
|
||||
this.button.button.height = PANEL_HEIGHT;
|
||||
|
||||
this._leftBox.append(this.button.button, 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._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.
|
||||
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));
|
||||
|
||||
this._leftBox.append(this._hotCornerEnvirons, Big.BoxPackFlags.FIXED);
|
||||
this._leftBox.append(this._hotCorner, Big.BoxPackFlags.FIXED);
|
||||
|
||||
let appMenu = new AppPanelMenu();
|
||||
this._leftBox.append(appMenu.actor, Big.BoxPackFlags.NONE);
|
||||
|
||||
/* center */
|
||||
|
||||
this._clock = new Clutter.Text({ font_name: DEFAULT_FONT,
|
||||
color: PANEL_FOREGROUND_COLOR,
|
||||
this._clock = new Clutter.Text({ font_name: "Sans Bold 16px",
|
||||
text: "" });
|
||||
this._centerBox.append(this._clock, Big.BoxPackFlags.NONE);
|
||||
|
||||
/* right */
|
||||
let pad = (PANEL_HEIGHT - this._clock.height) / 2;
|
||||
let clockbox = new Big.Box({ padding_top: pad,
|
||||
padding_bottom: pad,
|
||||
padding_left: 4,
|
||||
padding_right: 4 });
|
||||
clockbox.append(this._clock, Big.BoxPackFlags.NONE);
|
||||
box.append(clockbox, Big.BoxPackFlags.END);
|
||||
|
||||
// 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 });
|
||||
this._rightBox.append(trayContainer, Big.BoxPackFlags.NONE);
|
||||
box.append(trayContainer, Big.BoxPackFlags.END);
|
||||
let trayBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
height: TRAY_HEIGHT,
|
||||
padding: TRAY_PADDING,
|
||||
spacing: TRAY_SPACING });
|
||||
this._trayBox = trayBox;
|
||||
|
||||
// gtk+ < 2.16 doesn't have fully-working icon transparency,
|
||||
// so we want trayBox to be opaque in that case (the icons
|
||||
@@ -348,97 +140,42 @@ Panel.prototype = {
|
||||
|
||||
this._traymanager = new Shell.TrayManager({ bg_color: TRAY_BACKGROUND_COLOR });
|
||||
this._traymanager.connect('tray-icon-added',
|
||||
Lang.bind(this, function(o, icon) {
|
||||
function(o, icon) {
|
||||
trayBox.append(icon, Big.BoxPackFlags.NONE);
|
||||
|
||||
// Make sure the trayBox is shown.
|
||||
trayBox.show();
|
||||
this._recomputeTraySize();
|
||||
}));
|
||||
});
|
||||
this._traymanager.connect('tray-icon-removed',
|
||||
Lang.bind(this, function(o, icon) {
|
||||
function(o, icon) {
|
||||
trayBox.remove_actor(icon);
|
||||
|
||||
if (trayBox.get_children().length == 0)
|
||||
trayBox.hide();
|
||||
this._recomputeTraySize();
|
||||
}));
|
||||
});
|
||||
this._traymanager.manage_stage(global.stage);
|
||||
|
||||
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);
|
||||
statusbutton.button.height = PANEL_HEIGHT;
|
||||
statusbutton.button.connect('button-press-event', function (b, e) {
|
||||
statusmenu.toggle(e);
|
||||
return false;
|
||||
});
|
||||
// If popping up the menu failed (because there was already a grab in
|
||||
// effect from Mutter or another app), then we'll never get a ::deactivated
|
||||
// signal because the menu was never activated, so we need to unhighlight
|
||||
// separately when the user releases the mouse button.
|
||||
//
|
||||
// We depend on connection ordering; this needs to be called after Button's
|
||||
// ::button-release-event handler; that will set the active flag for this
|
||||
// stays-pressed button, then we unset the active flag by calling release().
|
||||
statusbutton.button.connect('button-release-event', function (b, e) {
|
||||
if (!statusmenu.is_active())
|
||||
statusbutton.release();
|
||||
return false;
|
||||
});
|
||||
this._rightBox.append(statusbutton.button, Big.BoxPackFlags.NONE);
|
||||
// We get a deactivated event when the popup disappears
|
||||
this._statusmenu.connect('deactivated', function (sm) {
|
||||
statusbutton.release();
|
||||
});
|
||||
|
||||
// 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
|
||||
// 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
|
||||
// to switch to.
|
||||
this.button.button.connect('button-press-event',
|
||||
Lang.bind(Main.overview, Main.overview.toggle));
|
||||
// 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
|
||||
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
|
||||
// and to be released when it is exited regardless of how it was triggered.
|
||||
Main.overview.connect('showing', Lang.bind(this.button, this.button.pressIn));
|
||||
Main.overview.connect('hiding', Lang.bind(this.button, this.button.release));
|
||||
Main.overlay.connect('showing', Lang.bind(this.button, this.button.pressIn));
|
||||
Main.overlay.connect('hiding', Lang.bind(this.button, this.button.release));
|
||||
|
||||
Main.chrome.addActor(this.actor);
|
||||
Main.chrome.setVisibleInOverview(this.actor, true);
|
||||
this.actor.add_actor(box);
|
||||
|
||||
Main.chrome.addActor(this.actor, box);
|
||||
Main.chrome.setVisibleInOverlay(this.actor, true);
|
||||
|
||||
// Start the clock
|
||||
this._updateClock();
|
||||
},
|
||||
|
||||
startupAnimation: function() {
|
||||
this.actor.y = -this.actor.height;
|
||||
Tweener.addTween(this.actor,
|
||||
{ y: 0,
|
||||
time: 0.2,
|
||||
transition: "easeOutQuad"
|
||||
});
|
||||
},
|
||||
|
||||
// By default, tray icons have a spacing of TRAY_SPACING. However this
|
||||
// starts to fail if we have too many as can sadly happen; just jump down
|
||||
// to a spacing of 8 if we're over 6.
|
||||
// http://bugzilla.gnome.org/show_bug.cgi?id=590495
|
||||
_recomputeTraySize: function () {
|
||||
if (this._trayBox.get_children().length > 6)
|
||||
this._trayBox.spacing = TRAY_SPACING_MIN;
|
||||
else
|
||||
this._trayBox.spacing = TRAY_SPACING;
|
||||
},
|
||||
|
||||
_updateClock: function() {
|
||||
let displayDate = new Date();
|
||||
let msecRemaining = 60000 - (1000 * displayDate.getSeconds() +
|
||||
@@ -447,40 +184,8 @@ Panel.prototype = {
|
||||
displayDate.setMinutes(displayDate.getMinutes() + 1);
|
||||
msecRemaining += 60000;
|
||||
}
|
||||
/* Translators: This is a time format. */
|
||||
this._clock.set_text(displayDate.toLocaleFormat(_("%a %l:%M %p")));
|
||||
this._clock.set_text(displayDate.toLocaleFormat("%a %b %e, %l:%M %p"));
|
||||
Mainloop.timeout_add(msecRemaining, Lang.bind(this, this._updateClock));
|
||||
return false;
|
||||
},
|
||||
|
||||
_onHotCornerEntered : function() {
|
||||
if (!this._hotCornerEntered) {
|
||||
this._hotCornerEntered = true;
|
||||
if (!Main.overview.animationInProgress) {
|
||||
Main.overview.toggle();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_onHotCornerClicked : function() {
|
||||
if (!Main.overview.animationInProgress) {
|
||||
Main.overview.toggle();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_onHotCornerLeft : function(actor, event) {
|
||||
if (Shell.get_event_related(event) != this._hotCornerEnvirons) {
|
||||
this._hotCornerEntered = false;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_onHotCornerEnvironsLeft : function(actor, event) {
|
||||
if (Shell.get_event_related(event) != this._hotCorner) {
|
||||
this._hotCornerEntered = false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
199
js/ui/places.js
199
js/ui/places.js
@@ -1,199 +0,0 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Big = imports.gi.Big;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Pango = imports.gi.Pango;
|
||||
const GLib = imports.gi.GLib;
|
||||
const Gio = imports.gi.Gio;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const DND = imports.ui.dnd;
|
||||
const Main = imports.ui.main;
|
||||
const GenericDisplay = imports.ui.genericDisplay;
|
||||
|
||||
const PLACES_VSPACING = 8;
|
||||
const PLACES_ICON_SIZE = 16;
|
||||
|
||||
/**
|
||||
* 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, iconFactory, onActivate) {
|
||||
this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
reactive: true,
|
||||
spacing: 4 });
|
||||
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 });
|
||||
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);
|
||||
|
||||
function Places() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
Places.prototype = {
|
||||
_init : function() {
|
||||
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._dirsBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
spacing: PLACES_VSPACING });
|
||||
this.actor.append(this._dirsBox, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
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 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);
|
||||
|
||||
let networkApp = null;
|
||||
try {
|
||||
networkApp = Shell.AppSystem.get_default().load_from_desktop_file('gnome-network-scheme.desktop');
|
||||
} catch(e) {
|
||||
try {
|
||||
networkApp = Shell.AppSystem.get_default().load_from_desktop_file('network-scheme.desktop');
|
||||
} catch(e) {
|
||||
log("Cannot create \"Network\" item, .desktop file not found or corrupt.");
|
||||
}
|
||||
}
|
||||
|
||||
if (networkApp != null) {
|
||||
let network = new PlaceDisplay(networkApp.get_name(),
|
||||
function() {
|
||||
return networkApp.create_icon_texture(PLACES_ICON_SIZE);
|
||||
},
|
||||
function () {
|
||||
networkApp.launch();
|
||||
});
|
||||
this._menuBox.append(network.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._menuBox.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);
|
||||
this._bookmarkTimeoutId = 0;
|
||||
monitor.connect('changed', Lang.bind(this, function () {
|
||||
if (this._bookmarkTimeoutId > 0)
|
||||
return;
|
||||
/* Defensive event compression */
|
||||
this._bookmarkTimeoutId = Mainloop.timeout_add(100, Lang.bind(this, function () {
|
||||
this._bookmarkTimeoutId = 0;
|
||||
this._reloadBookmarks();
|
||||
return false;
|
||||
}));
|
||||
}));
|
||||
|
||||
this._reloadBookmarks();
|
||||
},
|
||||
|
||||
_reloadBookmarks: function() {
|
||||
|
||||
this._dirsBox.remove_all();
|
||||
|
||||
let [success, bookmarksContent, len] = GLib.file_get_contents(this._bookmarksPath);
|
||||
|
||||
if (!success)
|
||||
return;
|
||||
|
||||
let bookmarks = bookmarksContent.split('\n');
|
||||
|
||||
let bookmarksToLabel = {};
|
||||
let bookmarksOrder = [];
|
||||
for (let i = 0; i < bookmarks.length; i++) {
|
||||
let bookmarkLine = bookmarks[i];
|
||||
let components = bookmarkLine.split(' ');
|
||||
let bookmark = components[0];
|
||||
if (bookmark in bookmarksToLabel)
|
||||
continue;
|
||||
let label = null;
|
||||
if (components.length > 1)
|
||||
label = components.slice(1).join(' ');
|
||||
bookmarksToLabel[bookmark] = label;
|
||||
bookmarksOrder.push(bookmark);
|
||||
}
|
||||
|
||||
for (let i = 0; i < bookmarksOrder.length; i++) {
|
||||
let bookmark = bookmarksOrder[i];
|
||||
let label = bookmarksToLabel[bookmark];
|
||||
let file = Gio.file_new_for_uri(bookmark);
|
||||
if (!file.query_exists(null))
|
||||
continue;
|
||||
if (label == null)
|
||||
label = Shell.util_get_label_for_uri(bookmark);
|
||||
if (label == null)
|
||||
continue;
|
||||
let icon = Shell.util_get_icon_for_uri(bookmark);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(Places.prototype);
|
||||
@@ -1,14 +1,8 @@
|
||||
/* -*- 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 Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
|
||||
@@ -32,26 +26,6 @@ RunDialog.prototype = {
|
||||
_init : function() {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
this._isOpen = false;
|
||||
|
||||
this._internalCommands = { 'lg':
|
||||
Lang.bind(this, function() {
|
||||
// Run in an idle to avoid recursive key grab problems
|
||||
Mainloop.idle_add(function() { Main.createLookingGlass().open(); });
|
||||
}),
|
||||
|
||||
'r': Lang.bind(this, function() {
|
||||
let global = Shell.Global.get();
|
||||
global.reexec_self();
|
||||
}),
|
||||
|
||||
// Developer brain backwards compatibility
|
||||
'restart': Lang.bind(this, function() {
|
||||
let global = Shell.Global.get();
|
||||
global.reexec_self();
|
||||
})
|
||||
};
|
||||
|
||||
// All actors are inside _group. We create it initially
|
||||
// hidden then show it in show()
|
||||
this._group = new Clutter.Group({ visible: false });
|
||||
@@ -69,17 +43,16 @@ RunDialog.prototype = {
|
||||
(global.screen_height - BOX_HEIGHT) / 2);
|
||||
this._group.add_actor(boxGroup);
|
||||
|
||||
let box = new Big.Box({ background_color: BOX_BACKGROUND_COLOR,
|
||||
corner_radius: 4,
|
||||
reactive: false,
|
||||
width: BOX_WIDTH,
|
||||
height: BOX_HEIGHT
|
||||
});
|
||||
let box = new Clutter.Rectangle({ color: BOX_BACKGROUND_COLOR,
|
||||
reactive: false,
|
||||
width: BOX_WIDTH,
|
||||
height: BOX_HEIGHT,
|
||||
border_width: 0 });
|
||||
boxGroup.add_actor(box);
|
||||
|
||||
let label = new Clutter.Text({ color: BOX_TEXT_COLOR,
|
||||
font_name: '18px Sans',
|
||||
text: _("Please enter a command:") });
|
||||
text: 'Please enter a command:' });
|
||||
label.set_position(6, 6);
|
||||
boxGroup.add_actor(label);
|
||||
|
||||
@@ -95,62 +68,70 @@ RunDialog.prototype = {
|
||||
this._entry.set_position(6, 30);
|
||||
boxGroup.add_actor(this._entry);
|
||||
|
||||
this._entry.connect('activate', Lang.bind(this, function (o, e) {
|
||||
this._run(o.get_text());
|
||||
this.close();
|
||||
let me = this;
|
||||
|
||||
this._entry.connect('activate', function (o, e) {
|
||||
me.hide();
|
||||
me._run(o.get_text());
|
||||
return false;
|
||||
}));
|
||||
|
||||
this._entry.connect('key-press-event', Lang.bind(this, function(o, e) {
|
||||
let symbol = Shell.get_event_key_symbol(e);
|
||||
if (symbol == Clutter.Escape) {
|
||||
this.close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}));
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
_run : function(command) {
|
||||
let f = this._internalCommands[command];
|
||||
if (f) {
|
||||
f();
|
||||
if (command == 'restart') {
|
||||
let global = Shell.Global.get();
|
||||
global.reexec_self();
|
||||
} 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 + ': ' + e);
|
||||
log('Could not run command ' + command + '.');
|
||||
}
|
||||
}
|
||||
|
||||
this.emit('run');
|
||||
},
|
||||
|
||||
open : function() {
|
||||
if (this._isOpen) // Already shown
|
||||
return;
|
||||
show : function() {
|
||||
let me = this;
|
||||
|
||||
if (!Main.beginModal())
|
||||
return;
|
||||
|
||||
this._isOpen = true;
|
||||
this._group.show();
|
||||
if (this._group.visible) // Already shown
|
||||
return false;
|
||||
|
||||
if (!Main.startModal())
|
||||
return false;
|
||||
|
||||
this._group.show_all();
|
||||
|
||||
this._entry.connect('key-press-event', function(o, e) {
|
||||
if (Shell.get_event_key_symbol(e) == Clutter.Escape) {
|
||||
me.hide();
|
||||
me.emit('cancel');
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
});
|
||||
|
||||
let global = Shell.Global.get();
|
||||
global.stage.set_key_focus(this._entry);
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
close : function() {
|
||||
if (!this._isOpen)
|
||||
hide : function() {
|
||||
if (!this._group.visible)
|
||||
return;
|
||||
|
||||
this._isOpen = false;
|
||||
|
||||
this._group.hide();
|
||||
this._entry.text = '';
|
||||
|
||||
Main.endModal();
|
||||
},
|
||||
|
||||
destroy : function(){
|
||||
this.hide();
|
||||
this._group.destroy();
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(RunDialog.prototype);
|
||||
|
||||
@@ -14,12 +14,10 @@ const WidgetBox = imports.ui.widgetBox;
|
||||
const SIDEBAR_SPACING = 4;
|
||||
const SIDEBAR_PADDING = 4;
|
||||
|
||||
// The total sidebar width is the widget width plus the widget padding
|
||||
// (counted twice for the widget box, and once again for the
|
||||
// out-of-screen padding), plus the empty space between the border of
|
||||
// the bar and of the windows
|
||||
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 total sidebar width is the widget width plus the widget
|
||||
// padding, plus the sidebar padding
|
||||
const SIDEBAR_COLLAPSED_WIDTH = Widget.COLLAPSED_WIDTH + 2 * WidgetBox.WIDGETBOX_PADDING + 2 * SIDEBAR_PADDING;
|
||||
const SIDEBAR_EXPANDED_WIDTH = Widget.EXPANDED_WIDTH + 2 * WidgetBox.WIDGETBOX_PADDING + 2 * 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
|
||||
@@ -28,6 +26,13 @@ const SIDEBAR_EXPANDED_WIDTH = Widget.EXPANDED_WIDTH + 3 * WidgetBox.WIDGETBOX_P
|
||||
const HARDCODED_TASKBAR_HEIGHT = 24;
|
||||
const MAXIMUM_SIDEBAR_HEIGHT = Shell.Global.get().screen_height - Panel.PANEL_HEIGHT - HARDCODED_TASKBAR_HEIGHT;
|
||||
|
||||
// FIXME, needs to be configurable, obviously
|
||||
const default_widgets = [
|
||||
"imports.ui.widget.ClockWidget",
|
||||
"imports.ui.widget.AppsWidget",
|
||||
"imports.ui.widget.DocsWidget"
|
||||
];
|
||||
|
||||
function Sidebar() {
|
||||
this._init();
|
||||
}
|
||||
@@ -43,6 +48,7 @@ Sidebar.prototype = {
|
||||
this.actor = new Clutter.Group({ x: -WidgetBox.WIDGETBOX_PADDING,
|
||||
y: Panel.PANEL_HEIGHT,
|
||||
width: SIDEBAR_EXPANDED_WIDTH });
|
||||
Main.chrome.addActor(this.actor);
|
||||
|
||||
// The actual widgets go into a Big.Box inside this.actor. The
|
||||
// box's width will vary during the expand/collapse animations,
|
||||
@@ -52,38 +58,23 @@ Sidebar.prototype = {
|
||||
// during the animation.
|
||||
this.box = new Big.Box ({ padding_top: SIDEBAR_PADDING,
|
||||
padding_bottom: SIDEBAR_PADDING,
|
||||
padding_right: 0,
|
||||
padding_right: SIDEBAR_PADDING,
|
||||
padding_left: 0,
|
||||
spacing: SIDEBAR_SPACING });
|
||||
this.actor.add_actor(this.box);
|
||||
|
||||
this._gconf = Shell.GConf.get_default();
|
||||
|
||||
this._expanded = this._gconf.get_boolean ("sidebar/expanded");
|
||||
if (!this._expanded)
|
||||
this.actor.width = SIDEBAR_COLLAPSED_WIDTH;
|
||||
|
||||
this._visible = this._gconf.get_boolean ("sidebar/visible");
|
||||
if (this._visible)
|
||||
Main.chrome.addActor(this.actor);
|
||||
this._visible = this.expanded = true;
|
||||
|
||||
this._widgets = [];
|
||||
this.addWidget(new ToggleWidget());
|
||||
|
||||
let default_widgets = this._gconf.get_string_list("sidebar/widgets");
|
||||
this.addWidget(new ToggleWidget(this));
|
||||
for (let i = 0; i < default_widgets.length; i++)
|
||||
this.addWidget(default_widgets[i]);
|
||||
|
||||
this._gconf.connect('changed::sidebar/expanded',
|
||||
Lang.bind(this, this._expandedChanged));
|
||||
this._gconf.connect('changed::sidebar/visible',
|
||||
Lang.bind(this, this._visibleChanged));
|
||||
},
|
||||
|
||||
addWidget: function(widget) {
|
||||
let widgetBox;
|
||||
try {
|
||||
widgetBox = new WidgetBox.WidgetBox(widget, this._expanded);
|
||||
widgetBox = new WidgetBox.WidgetBox(widget);
|
||||
} catch(e) {
|
||||
logError(e, "Failed to add widget '" + widget + "'");
|
||||
return;
|
||||
@@ -93,32 +84,18 @@ Sidebar.prototype = {
|
||||
this._widgets.push(widgetBox);
|
||||
},
|
||||
|
||||
_visibleChanged: function() {
|
||||
let visible = this._gconf.get_boolean("sidebar/visible");
|
||||
if (visible == this._visible)
|
||||
return;
|
||||
|
||||
this._visible = visible;
|
||||
if (visible)
|
||||
Main.chrome.addActor(this.actor);
|
||||
else
|
||||
Main.chrome.removeActor(this.actor);
|
||||
show: function() {
|
||||
this._visible = true;
|
||||
this.actor.show();
|
||||
},
|
||||
|
||||
_expandedChanged: function() {
|
||||
let expanded = this._gconf.get_boolean("sidebar/expanded");
|
||||
if (expanded == this._expanded)
|
||||
return;
|
||||
|
||||
this._expanded = expanded;
|
||||
if (expanded)
|
||||
this._expand();
|
||||
else
|
||||
this._collapse();
|
||||
hide: function() {
|
||||
this._visible = false;
|
||||
this.actor.hide();
|
||||
},
|
||||
|
||||
_expand: function() {
|
||||
this._expanded = true;
|
||||
expand: function() {
|
||||
this.expanded = true;
|
||||
for (let i = 0; i < this._widgets.length; i++)
|
||||
this._widgets[i].expand();
|
||||
|
||||
@@ -129,8 +106,8 @@ Sidebar.prototype = {
|
||||
} });
|
||||
},
|
||||
|
||||
_collapse: function() {
|
||||
this._expanded = false;
|
||||
collapse: function() {
|
||||
this.expanded = false;
|
||||
for (let i = 0; i < this._widgets.length; i++)
|
||||
this._widgets[i].collapse();
|
||||
|
||||
@@ -153,33 +130,24 @@ Sidebar.prototype = {
|
||||
const LEFT_DOUBLE_ARROW = "\u00AB";
|
||||
const RIGHT_DOUBLE_ARROW = "\u00BB";
|
||||
|
||||
function ToggleWidget() {
|
||||
this._init();
|
||||
function ToggleWidget(sidebar) {
|
||||
this._init(sidebar);
|
||||
}
|
||||
|
||||
ToggleWidget.prototype = {
|
||||
__proto__ : Widget.Widget.prototype,
|
||||
|
||||
_init : function() {
|
||||
this._gconf = Shell.GConf.get_default();
|
||||
|
||||
_init : function(sidebar) {
|
||||
this._sidebar = sidebar;
|
||||
this.actor = new Clutter.Text({ font_name: "Sans Bold 16px",
|
||||
text: LEFT_DOUBLE_ARROW,
|
||||
reactive: true });
|
||||
this.actor.connect('button-release-event',
|
||||
Lang.bind(this, this._collapse));
|
||||
Lang.bind(this._sidebar, this._sidebar.collapse));
|
||||
this.collapsedActor = new Clutter.Text({ font_name: "Sans Bold 16px",
|
||||
text: RIGHT_DOUBLE_ARROW,
|
||||
reactive: true });
|
||||
this.collapsedActor.connect('button-release-event',
|
||||
Lang.bind(this, this._expand));
|
||||
},
|
||||
|
||||
_collapse : function () {
|
||||
this._gconf.set_boolean ("sidebar/expanded", false);
|
||||
},
|
||||
|
||||
_expand : function () {
|
||||
this._gconf.set_boolean ("sidebar/expanded", true);
|
||||
Lang.bind(this._sidebar, this._sidebar.expand));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -9,9 +9,9 @@ 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 AppInfo = imports.misc.appInfo;
|
||||
const DocDisplay = imports.ui.docDisplay;
|
||||
const DocInfo = imports.misc.docInfo;
|
||||
|
||||
const COLLAPSED_WIDTH = 24;
|
||||
@@ -31,22 +31,12 @@ function Widget() {
|
||||
Widget.prototype = {
|
||||
// _init():
|
||||
//
|
||||
// Your widget constructor. Your constructor function should look
|
||||
// like:
|
||||
//
|
||||
// function MyWidgetType() {
|
||||
// this._init.apply(this, arguments);
|
||||
// }
|
||||
//
|
||||
// and your _init method should start by doing:
|
||||
//
|
||||
// Widget.Widget.prototype._init.apply(this, arguments);
|
||||
//
|
||||
// The _init method must define a field named "actor" containing
|
||||
// the Clutter.Actor to show in expanded mode. This actor will be
|
||||
// clipped to Widget.EXPANDED_WIDTH. Most widgets will also define
|
||||
// a field named "title" containing the title string to show above
|
||||
// the widget in the sidebar.
|
||||
// Your widget constructor. Receives no arguments. Must define a
|
||||
// field named "actor" containing the Clutter.Actor to show in
|
||||
// expanded mode. This actor will be clipped to
|
||||
// Widget.EXPANDED_WIDTH. Most widgets will also define a field
|
||||
// named "title" containing the title string to show above the
|
||||
// widget in the sidebar.
|
||||
//
|
||||
// If you want to have a separate collapsed view, you can define a
|
||||
// field "collapsedActor" containing the Clutter.Actor to show in
|
||||
@@ -61,9 +51,6 @@ Widget.prototype = {
|
||||
// the sidebar is collapsed, the widget's expanded view will pop
|
||||
// out of the sidebar until either the cursor moves out of it,
|
||||
// or else the widget calls this.activated() on itself.
|
||||
_init: function (initialState) {
|
||||
this.state = initialState;
|
||||
},
|
||||
|
||||
// destroy():
|
||||
//
|
||||
@@ -94,22 +81,23 @@ Widget.prototype = {
|
||||
// state:
|
||||
//
|
||||
// A field set on your widget by the sidebar. Will contain one of
|
||||
// the Widget.STATE_* values. (Eg, Widget.STATE_EXPANDED).
|
||||
// the Widget.STATE_* values. (Eg, Widget.STATE_EXPANDED). Note
|
||||
// that this will not be set until *after* _init() is called, so
|
||||
// you cannot rely on it being set at that point. The widget will
|
||||
// always initially be in STATE_EXPANDED.
|
||||
};
|
||||
|
||||
Signals.addSignalMethods(Widget.prototype);
|
||||
|
||||
|
||||
function ClockWidget() {
|
||||
this._init.apply(this, arguments);
|
||||
this._init();
|
||||
}
|
||||
|
||||
ClockWidget.prototype = {
|
||||
__proto__ : Widget.prototype,
|
||||
|
||||
_init: function() {
|
||||
Widget.prototype._init.apply(this, arguments);
|
||||
|
||||
this.actor = new Clutter.Text({ font_name: "Sans Bold 16px",
|
||||
text: "",
|
||||
// Give an explicit height to ensure
|
||||
@@ -158,15 +146,14 @@ ClockWidget.prototype = {
|
||||
},
|
||||
|
||||
_updateText: function(time) {
|
||||
// Translators: This is a time format.
|
||||
this.actor.set_text(time.toLocaleFormat(_("%H:%M")));
|
||||
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());
|
||||
global.clutter_cairo_texture_draw_clock(this.collapsedActor,
|
||||
time.getHours() % 12,
|
||||
time.getMinutes());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -181,7 +168,7 @@ const ITEM_NAME_COLOR = new Clutter.Color();
|
||||
ITEM_NAME_COLOR.from_pixel(0x000000ff);
|
||||
|
||||
function LauncherWidget() {
|
||||
this._init.apply(this, arguments);
|
||||
this._init();
|
||||
}
|
||||
|
||||
LauncherWidget.prototype = {
|
||||
@@ -285,61 +272,33 @@ LauncherWidget.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
function AppsWidgetInfo(appInfo) {
|
||||
this._init(appInfo);
|
||||
}
|
||||
|
||||
AppsWidgetInfo.prototype = {
|
||||
_init : function(appInfo) {
|
||||
this._info = appInfo;
|
||||
this.name = appInfo.get_name();
|
||||
},
|
||||
|
||||
createIcon : function(size) {
|
||||
return this._info.create_icon_texture(size);
|
||||
},
|
||||
|
||||
launch : function() {
|
||||
this._info.launch();
|
||||
}
|
||||
}
|
||||
|
||||
function AppsWidget() {
|
||||
this._init.apply(this, arguments);
|
||||
this._init();
|
||||
}
|
||||
|
||||
AppsWidget.prototype = {
|
||||
__proto__ : LauncherWidget.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});
|
||||
|
||||
let appSystem = Shell.AppSystem.get_default();
|
||||
let apps = appSystem.get_favorites();
|
||||
for (let i = 0; i < apps.length; i++) {
|
||||
let app = appSystem.lookup_cached_app(apps[i]);
|
||||
if (!app)
|
||||
continue;
|
||||
this.addItem(new AppsWidgetInfo(app));
|
||||
}
|
||||
let apps = AppInfo.getTopApps(5);
|
||||
for (let i = 0; i < apps.length; i++)
|
||||
this.addItem(apps[i]);
|
||||
}
|
||||
};
|
||||
|
||||
function RecentDocsWidget() {
|
||||
this._init.apply(this, arguments);
|
||||
function DocsWidget() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
RecentDocsWidget.prototype = {
|
||||
DocsWidget.prototype = {
|
||||
__proto__ : LauncherWidget.prototype,
|
||||
|
||||
_init : function() {
|
||||
Widget.prototype._init.apply(this, arguments);
|
||||
|
||||
this.title = _("Recent Documents");
|
||||
this.title = "Recent Docs";
|
||||
this.actor = new Big.Box({ spacing: 2 });
|
||||
|
||||
this._recentManager = Gtk.RecentManager.get_default();
|
||||
@@ -361,7 +320,7 @@ RecentDocsWidget.prototype = {
|
||||
items.push(docInfo);
|
||||
}
|
||||
|
||||
items.sort(function (a,b) { return b.timestamp - a.timestamp; });
|
||||
items.sort(function (a,b) { return b.lastVisited() - a.lastVisited(); });
|
||||
for (i = 0; i < Math.min(items.length, 5); i++)
|
||||
this.addItem(items[i]);
|
||||
}
|
||||
|
||||
@@ -15,24 +15,21 @@ WIDGETBOX_BG_COLOR.from_pixel(0xf0f0f0ff);
|
||||
const BLACK = new Clutter.Color();
|
||||
BLACK.from_pixel(0x000000ff);
|
||||
|
||||
const WIDGETBOX_PADDING = 2;
|
||||
const WIDGETBOX_PADDING = 4;
|
||||
const ANIMATION_TIME = 0.5;
|
||||
const POP_IN_LAG = 250; /* milliseconds */
|
||||
|
||||
function WidgetBox(widget, expanded) {
|
||||
this._init(widget, expanded);
|
||||
function WidgetBox(widget) {
|
||||
this._init(widget);
|
||||
}
|
||||
|
||||
WidgetBox.prototype = {
|
||||
_init: function(widget, expanded) {
|
||||
this.state = expanded ? Widget.STATE_EXPANDED : Widget.STATE_COLLAPSED;
|
||||
|
||||
if (widget instanceof Widget.Widget) {
|
||||
_init: function(widget) {
|
||||
if (widget instanceof Widget.Widget)
|
||||
this._widget = widget;
|
||||
this._widget.state = this.state;
|
||||
} else {
|
||||
else {
|
||||
let ctor = this._ctorFromName(widget);
|
||||
this._widget = new ctor(this.state);
|
||||
this._widget = new ctor();
|
||||
}
|
||||
|
||||
if (!this._widget.actor)
|
||||
@@ -40,7 +37,7 @@ WidgetBox.prototype = {
|
||||
else if (!this._widget.title && !this._widget.collapsedActor)
|
||||
throw new Error("widget has neither title nor collapsedActor");
|
||||
|
||||
this.state = expanded ? Widget.STATE_EXPANDED : Widget.STATE_COLLAPSED;
|
||||
this.state = this._widget.state = Widget.STATE_EXPANDED;
|
||||
|
||||
// The structure of a WidgetBox:
|
||||
//
|
||||
@@ -80,15 +77,9 @@ WidgetBox.prototype = {
|
||||
|
||||
this.actor = new Clutter.Group();
|
||||
this._hbox = new Big.Box({ background_color: WIDGETBOX_BG_COLOR,
|
||||
padding_top: WIDGETBOX_PADDING,
|
||||
padding_bottom: WIDGETBOX_PADDING,
|
||||
padding_right: WIDGETBOX_PADDING,
|
||||
// Left padding is here to make up for
|
||||
// the X offset used for the sidebar
|
||||
// to hide its rounded corners
|
||||
padding_left: 2 * WIDGETBOX_PADDING,
|
||||
padding: WIDGETBOX_PADDING,
|
||||
spacing: WIDGETBOX_PADDING,
|
||||
corner_radius: WIDGETBOX_PADDING,
|
||||
corner_radius: WIDGETBOX_PADDING / 2,
|
||||
orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
reactive: true });
|
||||
this.actor.add_actor(this._hbox);
|
||||
@@ -131,6 +122,7 @@ WidgetBox.prototype = {
|
||||
this._activationHandler = this._widget.connect('activated',
|
||||
Lang.bind(this, this._activationHandler));
|
||||
}
|
||||
this._cgroup.hide();
|
||||
|
||||
this._egroup = new Clutter.Group({ clip_to_allocation: true });
|
||||
this._hbox.append(this._egroup, Big.BoxPackFlags.NONE);
|
||||
@@ -150,11 +142,6 @@ WidgetBox.prototype = {
|
||||
}
|
||||
|
||||
this._ebox.append(this._widget.actor, Big.BoxPackFlags.NONE);
|
||||
|
||||
if (expanded)
|
||||
this._setWidgetExpanded();
|
||||
else
|
||||
this._setWidgetCollapsed();
|
||||
},
|
||||
|
||||
// Given a name like "imports.ui.widget.ClockWidget", turn that
|
||||
@@ -191,25 +178,16 @@ WidgetBox.prototype = {
|
||||
this.state = this._widget.state = Widget.STATE_EXPANDING;
|
||||
},
|
||||
|
||||
_setWidgetExpanded: function() {
|
||||
_expandPart1Complete: function() {
|
||||
this._cgroup.hide();
|
||||
this._egroup.show();
|
||||
this._cbox.x = 0;
|
||||
|
||||
if (this._singleActor) {
|
||||
log(this._widget.actor);
|
||||
this._widget.actor.unparent();
|
||||
this._ebox.append(this._widget.actor, Big.BoxPackFlags.NONE);
|
||||
}
|
||||
|
||||
if (this._htitle) {
|
||||
this._htitle.show();
|
||||
this._hline.show();
|
||||
}
|
||||
},
|
||||
|
||||
_expandPart1Complete: function() {
|
||||
this._cbox.x = 0;
|
||||
this._setWidgetExpanded();
|
||||
|
||||
if (this._widget.expand) {
|
||||
try {
|
||||
this._widget.expand();
|
||||
@@ -218,6 +196,11 @@ WidgetBox.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
this._egroup.show();
|
||||
if (this._htitle) {
|
||||
this._htitle.show();
|
||||
this._hline.show();
|
||||
}
|
||||
this._ebox.x = -Widget.EXPANDED_WIDTH;
|
||||
Tweener.addTween(this._ebox, { x: 0,
|
||||
time: ANIMATION_TIME / 2,
|
||||
@@ -239,27 +222,19 @@ WidgetBox.prototype = {
|
||||
this.state = this._widget.state = Widget.STATE_COLLAPSING;
|
||||
},
|
||||
|
||||
_setWidgetCollapsed: function() {
|
||||
_collapsePart1Complete: function() {
|
||||
this._egroup.hide();
|
||||
this._cgroup.show();
|
||||
|
||||
if (this._singleActor) {
|
||||
this._widget.actor.unparent();
|
||||
this._cbox.append(this._widget.actor, Big.BoxPackFlags.NONE);
|
||||
}
|
||||
|
||||
this._ebox.x = 0;
|
||||
if (this._htitle) {
|
||||
this._htitle.hide();
|
||||
this._hline.hide();
|
||||
}
|
||||
|
||||
if (this._vtitle)
|
||||
this._cbox.height = this._ebox.height;
|
||||
},
|
||||
|
||||
_collapsePart1Complete: function() {
|
||||
this._ebox.x = 0;
|
||||
this._setWidgetCollapsed();
|
||||
if (this._singleActor) {
|
||||
log(this._widget.actor);
|
||||
this._widget.actor.unparent();
|
||||
this._cbox.append(this._widget.actor, Big.BoxPackFlags.NONE);
|
||||
}
|
||||
|
||||
if (this._widget.collapse) {
|
||||
try {
|
||||
@@ -269,7 +244,10 @@ WidgetBox.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
this._cgroup.show();
|
||||
this._cbox.x = -Widget.COLLAPSED_WIDTH;
|
||||
if (this._vtitle)
|
||||
this._cbox.height = this._ebox.height;
|
||||
Tweener.addTween(this._cbox, { x: 0,
|
||||
time: ANIMATION_TIME / 2,
|
||||
transition: "easeOutQuad",
|
||||
|
||||
@@ -85,7 +85,7 @@ WindowManager.prototype = {
|
||||
},
|
||||
|
||||
_shouldAnimate : function(actor) {
|
||||
if (Main.overview.visible)
|
||||
if (Main.overlay.visible)
|
||||
return false;
|
||||
if (actor && (actor.get_window_type() != Meta.CompWindowType.NORMAL))
|
||||
return false;
|
||||
@@ -145,13 +145,50 @@ WindowManager.prototype = {
|
||||
},
|
||||
|
||||
_maximizeWindow : function(actor, targetX, targetY, targetWidth, targetHeight) {
|
||||
this._shellwm.completed_maximize(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) {
|
||||
|
||||
@@ -11,9 +11,11 @@ const Pango = imports.gi.Pango;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const AppDisplay = imports.ui.appDisplay;
|
||||
const DND = imports.ui.dnd;
|
||||
const GenericDisplay = imports.ui.genericDisplay;
|
||||
const Main = imports.ui.main;
|
||||
const Overview = imports.ui.overview;
|
||||
const Overlay = imports.ui.overlay;
|
||||
const Panel = imports.ui.panel;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
@@ -33,11 +35,11 @@ FRAME_COLOR.from_pixel(0xffffffff);
|
||||
// Each triplet is [xCenter, yCenter, scale] where the scale
|
||||
// is relative to the width of the workspace.
|
||||
const POSITIONS = {
|
||||
1: [[0.5, 0.5, 0.95]],
|
||||
2: [[0.25, 0.5, 0.48], [0.75, 0.5, 0.48]],
|
||||
3: [[0.25, 0.25, 0.48], [0.75, 0.25, 0.48], [0.5, 0.75, 0.48]],
|
||||
4: [[0.25, 0.25, 0.47], [0.75, 0.25, 0.47], [0.75, 0.75, 0.47], [0.25, 0.75, 0.47]],
|
||||
5: [[0.165, 0.25, 0.32], [0.495, 0.25, 0.32], [0.825, 0.25, 0.32], [0.25, 0.75, 0.32], [0.75, 0.75, 0.32]]
|
||||
1: [[0.5, 0.5, 0.8]],
|
||||
2: [[0.25, 0.5, 0.4], [0.75, 0.5, 0.4]],
|
||||
3: [[0.25, 0.25, 0.33], [0.75, 0.25, 0.33], [0.5, 0.75, 0.33]],
|
||||
4: [[0.25, 0.25, 0.33], [0.75, 0.25, 0.33], [0.75, 0.75, 0.33], [0.25, 0.75, 0.33]],
|
||||
5: [[0.165, 0.25, 0.28], [0.495, 0.25, 0.28], [0.825, 0.25, 0.28], [0.25, 0.75, 0.4], [0.75, 0.75, 0.4]]
|
||||
};
|
||||
|
||||
// Spacing between workspaces. At the moment, the same spacing is used
|
||||
@@ -119,10 +121,9 @@ WindowClone.prototype = {
|
||||
_onDragBegin : function (draggable, time) {
|
||||
this._inDrag = true;
|
||||
this._updateTitle();
|
||||
this.emit('drag-begin');
|
||||
},
|
||||
|
||||
_onDragEnd : function (draggable, time, snapback) {
|
||||
_onDragEnd : function (draggable, time) {
|
||||
this._inDrag = false;
|
||||
|
||||
// Most likely, the clone is going to move away from the
|
||||
@@ -132,8 +133,6 @@ WindowClone.prototype = {
|
||||
// better to have the label mysteriously missing than
|
||||
// mysteriously present
|
||||
this._havePointer = false;
|
||||
|
||||
this.emit('drag-end');
|
||||
},
|
||||
|
||||
// Called by Tweener
|
||||
@@ -156,7 +155,16 @@ WindowClone.prototype = {
|
||||
padding: 4,
|
||||
spacing: 4,
|
||||
orientation: Big.BoxOrientation.HORIZONTAL });
|
||||
|
||||
|
||||
let icon = this.metaWindow.mini_icon;
|
||||
let iconTexture = new Clutter.Texture({ x: this.actor.x,
|
||||
y: this.actor.y + this.actor.height - 16,
|
||||
width: 16,
|
||||
height: 16,
|
||||
keep_aspect_ratio: true });
|
||||
Shell.clutter_texture_set_from_pixbuf(iconTexture, icon);
|
||||
box.append(iconTexture, Big.BoxPackFlags.NONE);
|
||||
|
||||
let title = new Clutter.Text({ color: WINDOWCLONE_TITLE_COLOR,
|
||||
font_name: "Sans 12",
|
||||
text: this.metaWindow.title,
|
||||
@@ -250,34 +258,20 @@ DesktopClone.prototype = {
|
||||
Signals.addSignalMethods(DesktopClone.prototype);
|
||||
|
||||
|
||||
/**
|
||||
* @workspaceNum: Workspace index
|
||||
* @parentActor: The actor which will be the parent of this workspace;
|
||||
* we need this in order to add chrome such as the icons
|
||||
* on top of the windows without having them be scaled.
|
||||
*/
|
||||
function Workspace(workspaceNum, parentActor) {
|
||||
this._init(workspaceNum, parentActor);
|
||||
function Workspace(workspaceNum) {
|
||||
this._init(workspaceNum);
|
||||
}
|
||||
|
||||
Workspace.prototype = {
|
||||
_init : function(workspaceNum, parentActor) {
|
||||
_init : function(workspaceNum) {
|
||||
let me = this;
|
||||
let global = Shell.Global.get();
|
||||
|
||||
this.workspaceNum = workspaceNum;
|
||||
this._metaWorkspace = global.screen.get_workspace_by_index(workspaceNum);
|
||||
|
||||
this.parentActor = parentActor;
|
||||
|
||||
this.actor = new Clutter.Group();
|
||||
this.actor._delegate = this;
|
||||
// Auto-sizing is unreliable in the presence of ClutterClone, so rather than
|
||||
// implicitly counting on the workspace actor to be sized to the size of the
|
||||
// included desktop actor clone, set the size explicitly to the screen size.
|
||||
// See http://bugzilla.openedhand.com/show_bug.cgi?id=1755
|
||||
this.actor.width = global.screen_width;
|
||||
this.actor.height = global.screen_height;
|
||||
this.scale = 1.0;
|
||||
|
||||
let windows = global.get_windows().filter(this._isMyWindow, this);
|
||||
@@ -297,16 +291,15 @@ Workspace.prototype = {
|
||||
Lang.bind(this,
|
||||
function(clone, time) {
|
||||
this._metaWorkspace.activate(time);
|
||||
Main.overview.hide();
|
||||
Main.overlay.hide();
|
||||
}));
|
||||
this.actor.add_actor(this._desktop.actor);
|
||||
|
||||
// Create clones for remaining windows that should be
|
||||
// visible in the Overview
|
||||
// visible in the overlay
|
||||
this._windows = [this._desktop];
|
||||
this._windowIcons = [ null ];
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
if (this._isOverviewWindow(windows[i])) {
|
||||
if (this._isOverlayWindow(windows[i])) {
|
||||
this._addWindowClone(windows[i]);
|
||||
}
|
||||
}
|
||||
@@ -322,13 +315,12 @@ Workspace.prototype = {
|
||||
|
||||
this._frame = null;
|
||||
|
||||
this.leavingOverview = false;
|
||||
this.leavingOverlay = false;
|
||||
},
|
||||
|
||||
updateRemovable : function() {
|
||||
let global = Shell.Global.get();
|
||||
let removable = (this._windows.length == 1 /* just desktop */ &&
|
||||
this.workspaceNum != 0 &&
|
||||
this.workspaceNum == global.screen.n_workspaces - 1);
|
||||
|
||||
if (removable) {
|
||||
@@ -350,7 +342,7 @@ Workspace.prototype = {
|
||||
this._removeButton.set_opacity(0);
|
||||
Tweener.addTween(this._removeButton,
|
||||
{ opacity: 255,
|
||||
time: Overview.ANIMATION_TIME,
|
||||
time: Overlay.ANIMATION_TIME,
|
||||
transition: "easeOutQuad"
|
||||
});
|
||||
}
|
||||
@@ -361,7 +353,7 @@ Workspace.prototype = {
|
||||
if (this._visible) {
|
||||
Tweener.addTween(this._removeButton,
|
||||
{ opacity: 0,
|
||||
time: Overview.ANIMATION_TIME,
|
||||
time: Overlay.ANIMATION_TIME,
|
||||
transition: "easeOutQuad",
|
||||
onComplete: this._removeRemoveButton,
|
||||
onCompleteScope: this
|
||||
@@ -371,21 +363,6 @@ Workspace.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_lookupIndex: function (metaWindow) {
|
||||
let index, clone;
|
||||
for (let i = 0; i < this._windows.length; i++) {
|
||||
if (this._windows[i].metaWindow == metaWindow) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
},
|
||||
|
||||
lookupCloneForMetaWindow: function (metaWindow) {
|
||||
let index = this._lookupIndex (metaWindow);
|
||||
return index < 0 ? null : this._windows[index];
|
||||
},
|
||||
|
||||
_adjustRemoveButton : function() {
|
||||
this._removeButton.set_scale(1.0 / this.actor.scale_x,
|
||||
1.0 / this.actor.scale_y);
|
||||
@@ -402,9 +379,7 @@ Workspace.prototype = {
|
||||
|
||||
// Mark the workspace selected/not-selected
|
||||
setSelected : function(selected) {
|
||||
let global = Shell.Global.get();
|
||||
// Don't draw a frame if we only have one workspace
|
||||
if (selected && global.screen.n_workspaces > 1) {
|
||||
if (selected) {
|
||||
if (this._frame)
|
||||
return;
|
||||
|
||||
@@ -417,11 +392,13 @@ Workspace.prototype = {
|
||||
this._desktop.actor.height + 2 * FRAME_SIZE / this.actor.scale_y);
|
||||
this._frame.lower_bottom();
|
||||
|
||||
this._framePosHandler = this.actor.connect('notify::scale-x', Lang.bind(this, this._updateFramePosition));
|
||||
this._framePosHandler = this.actor.connect('notify::x', Lang.bind(this, this._updateFramePosition));
|
||||
this._frameSizeHandler = this.actor.connect('notify::scale-x', Lang.bind(this, this._updateFrameSize));
|
||||
} else {
|
||||
if (!this._frame)
|
||||
return;
|
||||
this.actor.disconnect(this._framePosHandler);
|
||||
this.actor.disconnect(this._frameSizeHandler);
|
||||
this._frame.destroy();
|
||||
this._frame = null;
|
||||
}
|
||||
@@ -430,135 +407,85 @@ Workspace.prototype = {
|
||||
_updateFramePosition : function() {
|
||||
this._frame.set_position(this._desktop.actor.x - FRAME_SIZE / this.actor.scale_x,
|
||||
this._desktop.actor.y - FRAME_SIZE / this.actor.scale_y);
|
||||
},
|
||||
|
||||
_updateFrameSize : function() {
|
||||
this._frame.set_size(this._desktop.actor.width + 2 * FRAME_SIZE / this.actor.scale_x,
|
||||
this._desktop.actor.height + 2 * FRAME_SIZE / this.actor.scale_y);
|
||||
},
|
||||
|
||||
// Reposition all windows in their zoomed-to-Overview position. if workspaceZooming
|
||||
// Reposition all windows in their zoomed-to-overlay position. if workspaceZooming
|
||||
// is true, then the workspace is moving at the same time and we need to take
|
||||
// that into account
|
||||
positionWindows : function(workspaceZooming) {
|
||||
_positionWindows : function(workspaceZooming) {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
for (let i = 1; i < this._windows.length; i++) {
|
||||
let clone = this._windows[i];
|
||||
let icon = this._windowIcons[i];
|
||||
clone.stackAbove = this._windows[i - 1].actor;
|
||||
|
||||
let [xCenter, yCenter, fraction] = this._computeWindowPosition(i);
|
||||
xCenter = xCenter * global.screen_width;
|
||||
yCenter = yCenter * global.screen_height;
|
||||
|
||||
// clone.actor.width/height aren't reliably set at this point for
|
||||
// a new window - they're only set when the window contents are
|
||||
// initially updated prior to painting.
|
||||
let cloneRect = new Meta.Rectangle();
|
||||
clone.realWindow.meta_window.get_outer_rect(cloneRect);
|
||||
let size = Math.max(clone.actor.width, clone.actor.height);
|
||||
let desiredSize = global.screen_width * fraction;
|
||||
let scale = Math.min(desiredSize / size, 1.0 / this.scale);
|
||||
|
||||
let desiredWidth = global.screen_width * fraction;
|
||||
let desiredHeight = global.screen_height * fraction;
|
||||
let scale = Math.min(desiredWidth / cloneRect.width, desiredHeight / cloneRect.height, 1.0 / this.scale);
|
||||
|
||||
icon.hide();
|
||||
Tweener.addTween(clone.actor,
|
||||
{ x: xCenter - 0.5 * scale * cloneRect.width,
|
||||
y: yCenter - 0.5 * scale * cloneRect.height,
|
||||
{ x: xCenter - 0.5 * scale * clone.actor.width,
|
||||
y: yCenter - 0.5 * scale * clone.actor.height,
|
||||
scale_x: scale,
|
||||
scale_y: scale,
|
||||
workspace_relative: workspaceZooming ? this : null,
|
||||
time: Overview.ANIMATION_TIME,
|
||||
transition: "easeOutQuad",
|
||||
onComplete: Lang.bind(this, function() {
|
||||
this._fadeInWindowIcon(clone, icon);
|
||||
})
|
||||
time: Overlay.ANIMATION_TIME,
|
||||
transition: "easeOutQuad"
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
_fadeInWindowIcon: function (clone, icon) {
|
||||
icon.opacity = 0;
|
||||
icon.show();
|
||||
// This is a little messy and complicated because when we
|
||||
// start the fade-in we may not have done the final positioning
|
||||
// of the workspaces. (Tweener doesn't necessarily finish
|
||||
// all animations before calling onComplete callbacks.)
|
||||
// So we need to manually compute where the window will
|
||||
// be after the workspace animation finishes.
|
||||
let [parentX, parentY] = icon.get_parent().get_position();
|
||||
let [cloneX, cloneY] = clone.actor.get_position();
|
||||
let [cloneWidth, cloneHeight] = clone.actor.get_size();
|
||||
cloneX = this.gridX + this.scale * cloneX;
|
||||
cloneY = this.gridY + this.scale * cloneY;
|
||||
cloneWidth = this.scale * clone.actor.scale_x * cloneWidth;
|
||||
cloneHeight = this.scale * clone.actor.scale_y * cloneHeight;
|
||||
// Note we only round the first part, because we're still going to be
|
||||
// positioned relative to the parent. By subtracting a possibly
|
||||
// non-integral parent X/Y we cancel it out.
|
||||
let x = Math.round(cloneX + cloneWidth - icon.width) - parentX;
|
||||
let y = Math.round(cloneY + cloneHeight - icon.height) - parentY;
|
||||
icon.set_position(x, y);
|
||||
icon.raise(this.actor);
|
||||
Tweener.addTween(icon,
|
||||
{ opacity: 255,
|
||||
time: Overview.ANIMATION_TIME,
|
||||
transition: "easeOutQuad" });
|
||||
},
|
||||
|
||||
_fadeInAllIcons: function () {
|
||||
for (let i = 1; i < this._windows.length; i++) {
|
||||
let clone = this._windows[i];
|
||||
let icon = this._windowIcons[i];
|
||||
this._fadeInWindowIcon(clone, icon);
|
||||
}
|
||||
},
|
||||
|
||||
_hideAllIcons: function () {
|
||||
for (let i = 1; i < this._windows.length; i++) {
|
||||
let icon = this._windowIcons[i];
|
||||
icon.hide();
|
||||
}
|
||||
},
|
||||
|
||||
_windowRemoved : function(metaWorkspace, metaWin) {
|
||||
let global = Shell.Global.get();
|
||||
let win = metaWin.get_compositor_private();
|
||||
|
||||
// find the position of the window in our list
|
||||
let index = this._lookupIndex (metaWin);
|
||||
let index = - 1, clone;
|
||||
for (let i = 0; i < this._windows.length; i++) {
|
||||
if (this._windows[i].metaWindow == metaWin) {
|
||||
index = i;
|
||||
clone = this._windows[index];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index == -1)
|
||||
return;
|
||||
|
||||
let clone = this._windows[index];
|
||||
let icon = this._windowIcons[index];
|
||||
|
||||
this._windows.splice(index, 1);
|
||||
this._windowIcons.splice(index, 1);
|
||||
|
||||
// If metaWin.get_compositor_private() returned non-NULL, that
|
||||
// means the window still exists (and is just being moved to
|
||||
// another workspace or something), so set its overviewHint
|
||||
// another workspace or something), so set its overlayHint
|
||||
// accordingly. (If it returned NULL, then the window is being
|
||||
// destroyed; we'd like to animate this, but it's too late at
|
||||
// this point.)
|
||||
if (win) {
|
||||
let [stageX, stageY] = clone.actor.get_transformed_position();
|
||||
let [stageWidth, stageHeight] = clone.actor.get_transformed_size();
|
||||
win._overviewHint = {
|
||||
win._overlayHint = {
|
||||
x: stageX,
|
||||
y: stageY,
|
||||
scale: stageWidth / clone.actor.width
|
||||
};
|
||||
}
|
||||
clone.destroy();
|
||||
icon.destroy();
|
||||
|
||||
this.positionWindows(false);
|
||||
this._positionWindows(false);
|
||||
this.updateRemovable();
|
||||
},
|
||||
|
||||
_windowAdded : function(metaWorkspace, metaWin) {
|
||||
if (this.leavingOverview)
|
||||
if (this.leavingOverlay)
|
||||
return;
|
||||
|
||||
let win = metaWin.get_compositor_private();
|
||||
@@ -575,69 +502,65 @@ Workspace.prototype = {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this._isOverviewWindow(win))
|
||||
if (!this._isOverlayWindow(win))
|
||||
return;
|
||||
|
||||
let clone = this._addWindowClone(win);
|
||||
|
||||
if (win._overviewHint) {
|
||||
let x = (win._overviewHint.x - this.actor.x) / this.scale;
|
||||
let y = (win._overviewHint.y - this.actor.y) / this.scale;
|
||||
let scale = win._overviewHint.scale / this.scale;
|
||||
delete win._overviewHint;
|
||||
if (win._overlayHint) {
|
||||
let x = (win._overlayHint.x - this.actor.x) / this.scale;
|
||||
let y = (win._overlayHint.y - this.actor.y) / this.scale;
|
||||
let scale = win._overlayHint.scale / this.scale;
|
||||
delete win._overlayHint;
|
||||
|
||||
clone.actor.set_position (x, y);
|
||||
clone.actor.set_scale (scale, scale);
|
||||
}
|
||||
|
||||
this.positionWindows(false);
|
||||
this._positionWindows(false);
|
||||
this.updateRemovable();
|
||||
},
|
||||
|
||||
// Animate the full-screen to Overview transition.
|
||||
zoomToOverview : function() {
|
||||
this.actor.set_position(this.gridX, this.gridY);
|
||||
this.actor.set_scale(this.scale, this.scale);
|
||||
|
||||
// Position and scale the windows.
|
||||
this.positionWindows(true);
|
||||
|
||||
// Fade in the remove button if available, so that it doesn't appear
|
||||
// too abrubtly and doesn't start at a too big size.
|
||||
if (this._removeButton) {
|
||||
Tweener.removeTweens(this._removeButton);
|
||||
this._removeButton.opacity = 0;
|
||||
Tweener.addTween(this._removeButton,
|
||||
{ opacity: 255,
|
||||
time: Overview.ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
}
|
||||
// Animate the full-screen to overlay transition.
|
||||
zoomToOverlay : function() {
|
||||
// Move the workspace into size/position
|
||||
this.actor.set_position(this.fullSizeX, this.fullSizeY);
|
||||
|
||||
this.updateInOverlay();
|
||||
|
||||
this._visible = true;
|
||||
},
|
||||
|
||||
// Animates the return from Overview mode
|
||||
zoomFromOverview : function() {
|
||||
this.leavingOverview = true;
|
||||
// Animates the display of a workspace and its windows to have the current dimensions and position.
|
||||
updateInOverlay : function() {
|
||||
Tweener.addTween(this.actor,
|
||||
{ x: this.gridX,
|
||||
y: this.gridY,
|
||||
scale_x: this.scale,
|
||||
scale_y: this.scale,
|
||||
time: Overlay.ANIMATION_TIME,
|
||||
transition: "easeOutQuad"
|
||||
});
|
||||
|
||||
this._hideAllIcons();
|
||||
// Likewise for each of the windows in the workspace.
|
||||
this._positionWindows(true);
|
||||
},
|
||||
|
||||
Main.overview.connect('hidden', Lang.bind(this,
|
||||
this._doneLeavingOverview));
|
||||
// Animates the return from overlay mode
|
||||
zoomFromOverlay : function() {
|
||||
this.leavingOverlay = true;
|
||||
|
||||
Tweener.addTween(this.actor,
|
||||
{ x: this.fullSizeX,
|
||||
y: this.fullSizeY,
|
||||
scale_x: 1.0,
|
||||
scale_y: 1.0,
|
||||
time: Overlay.ANIMATION_TIME,
|
||||
transition: "easeOutQuad",
|
||||
onComplete: this._doneLeavingOverlay,
|
||||
onCompleteScope: this
|
||||
});
|
||||
|
||||
// Fade out the remove button if available, so that it doesn't
|
||||
// disappear too abrubtly and doesn't become too big.
|
||||
if (this._removeButton) {
|
||||
Tweener.removeTweens(this._removeButton);
|
||||
Tweener.addTween(this._removeButton,
|
||||
{ opacity: 0,
|
||||
time: Overview.ANIMATION_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
});
|
||||
}
|
||||
|
||||
// Position and scale the windows.
|
||||
for (let i = 1; i < this._windows.length; i++) {
|
||||
let clone = this._windows[i];
|
||||
Tweener.addTween(clone.actor,
|
||||
@@ -646,7 +569,7 @@ Workspace.prototype = {
|
||||
scale_x: 1.0,
|
||||
scale_y: 1.0,
|
||||
workspace_relative: this,
|
||||
time: Overview.ANIMATION_TIME,
|
||||
time: Overlay.ANIMATION_TIME,
|
||||
opacity: 255,
|
||||
transition: "easeOutQuad"
|
||||
});
|
||||
@@ -658,18 +581,16 @@ Workspace.prototype = {
|
||||
// Animates grid shrinking/expanding when a row or column
|
||||
// of workspaces is added or removed
|
||||
resizeToGrid : function (oldScale) {
|
||||
this._hideAllIcons();
|
||||
Tweener.addTween(this.actor,
|
||||
{ x: this.gridX,
|
||||
y: this.gridY,
|
||||
scale_x: this.scale,
|
||||
scale_y: this.scale,
|
||||
time: Overview.ANIMATION_TIME,
|
||||
transition: "easeOutQuad",
|
||||
onComplete: Lang.bind(this, this._fadeInAllIcons)
|
||||
time: Overlay.ANIMATION_TIME,
|
||||
transition: "easeOutQuad"
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
// Animates the addition of a new (empty) workspace
|
||||
slideIn : function(oldScale) {
|
||||
let global = Shell.Global.get();
|
||||
@@ -686,7 +607,7 @@ Workspace.prototype = {
|
||||
y: this.gridY,
|
||||
scale_x: this.scale,
|
||||
scale_y: this.scale,
|
||||
time: Overview.ANIMATION_TIME,
|
||||
time: Overlay.ANIMATION_TIME,
|
||||
transition: "easeOutQuad"
|
||||
});
|
||||
|
||||
@@ -698,8 +619,6 @@ Workspace.prototype = {
|
||||
let global = Shell.Global.get();
|
||||
let destX = this.actor.x, destY = this.actor.y;
|
||||
|
||||
this._hideAllIcons();
|
||||
|
||||
if (this.gridCol > this.gridRow)
|
||||
destX = global.screen_width;
|
||||
else
|
||||
@@ -709,7 +628,7 @@ Workspace.prototype = {
|
||||
y: destY,
|
||||
scale_x: this.scale,
|
||||
scale_y: this.scale,
|
||||
time: Overview.ANIMATION_TIME,
|
||||
time: Overlay.ANIMATION_TIME,
|
||||
transition: "easeOutQuad",
|
||||
onComplete: onComplete
|
||||
});
|
||||
@@ -732,9 +651,9 @@ Workspace.prototype = {
|
||||
this._metaWorkspace.disconnect(this._windowRemovedId);
|
||||
},
|
||||
|
||||
// Sets this.leavingOverview flag to false.
|
||||
_doneLeavingOverview : function() {
|
||||
this.leavingOverview = false;
|
||||
// Sets this.leavingOverlay flag to false.
|
||||
_doneLeavingOverlay : function() {
|
||||
this.leavingOverlay = false;
|
||||
},
|
||||
|
||||
// Tests if @win belongs to this workspaces
|
||||
@@ -743,8 +662,8 @@ Workspace.prototype = {
|
||||
(win.get_meta_window() && win.get_meta_window().is_on_all_workspaces());
|
||||
},
|
||||
|
||||
// Tests if @win should be shown in the Overview
|
||||
_isOverviewWindow : function (win) {
|
||||
// Tests if @win should be shown in the overlay
|
||||
_isOverlayWindow : function (win) {
|
||||
let wintype = win.get_window_type();
|
||||
if (wintype == Meta.WindowType.DESKTOP ||
|
||||
wintype == Meta.WindowType.DOCK)
|
||||
@@ -752,47 +671,16 @@ Workspace.prototype = {
|
||||
return !win.is_override_redirect();
|
||||
},
|
||||
|
||||
_createWindowIcon: function(window) {
|
||||
let appSys = Shell.AppSystem.get_default();
|
||||
let appMon = Shell.AppMonitor.get_default()
|
||||
let appInfo = appMon.get_window_app(window.metaWindow);
|
||||
let iconTexture = null;
|
||||
// The design is application based, so prefer the application
|
||||
// icon here if we have it. FIXME - should move this fallback code
|
||||
// into ShellAppMonitor.
|
||||
if (appInfo) {
|
||||
iconTexture = appInfo.create_icon_texture(48);
|
||||
} else {
|
||||
let icon = window.metaWindow.icon;
|
||||
iconTexture = new Clutter.Texture({ width: 48,
|
||||
height: 48,
|
||||
keep_aspect_ratio: true });
|
||||
Shell.clutter_texture_set_from_pixbuf(iconTexture, icon);
|
||||
}
|
||||
return iconTexture;
|
||||
},
|
||||
|
||||
// Create a clone of a (non-desktop) window and add it to the window list
|
||||
_addWindowClone : function(win) {
|
||||
let icon = this._createWindowIcon(win);
|
||||
this.parentActor.add_actor(icon);
|
||||
|
||||
let clone = new WindowClone(win);
|
||||
clone.connect('selected',
|
||||
Lang.bind(this, this._onCloneSelected));
|
||||
clone.connect('drag-begin',
|
||||
Lang.bind(this, function() {
|
||||
icon.hide();
|
||||
}));
|
||||
clone.connect('drag-end',
|
||||
Lang.bind(this, function() {
|
||||
icon.show();
|
||||
}));
|
||||
clone.connect('dragged',
|
||||
Lang.bind(this, this._onCloneDragged));
|
||||
|
||||
this.actor.add_actor(clone.actor);
|
||||
|
||||
this._windows.push(clone);
|
||||
this._windowIcons.push(icon);
|
||||
|
||||
return clone;
|
||||
},
|
||||
@@ -810,7 +698,7 @@ Workspace.prototype = {
|
||||
let gridWidth = Math.ceil(Math.sqrt(numberOfWindows));
|
||||
let gridHeight = Math.ceil(numberOfWindows / gridWidth);
|
||||
|
||||
let fraction = 0.95 * (1. / gridWidth);
|
||||
let fraction = Math.sqrt(.5/(gridWidth * gridHeight));
|
||||
|
||||
let xCenter = (.5 / gridWidth) + ((windowIndex) % gridWidth) / gridWidth;
|
||||
let yCenter = (.5 / gridHeight) + Math.floor((windowIndex / gridWidth)) / gridHeight;
|
||||
@@ -818,8 +706,20 @@ Workspace.prototype = {
|
||||
return [xCenter, yCenter, fraction];
|
||||
},
|
||||
|
||||
_onCloneDragged : function (clone, stageX, stageY, time) {
|
||||
this.emit('window-dragged', clone, stageX, stageY, time);
|
||||
},
|
||||
|
||||
_onCloneSelected : function (clone, time) {
|
||||
Main.overview.activateWindow(clone.metaWindow, time);
|
||||
let global = Shell.Global.get();
|
||||
let activeWorkspace = global.screen.get_active_workspace_index();
|
||||
|
||||
if (this.workspaceNum != activeWorkspace) {
|
||||
let workspace = global.screen.get_workspace_by_index(this.workspaceNum);
|
||||
workspace.activate_with_focus(clone.metaWindow, time);
|
||||
} else
|
||||
clone.metaWindow.activate(time);
|
||||
Main.overlay.hide();
|
||||
},
|
||||
|
||||
_removeSelf : function(actor, event) {
|
||||
@@ -842,7 +742,7 @@ Workspace.prototype = {
|
||||
|
||||
// Set a hint on the Mutter.Window so its initial position
|
||||
// in the new workspace will be correct
|
||||
win._overviewHint = {
|
||||
win._overlayHint = {
|
||||
x: actor.x,
|
||||
y: actor.y,
|
||||
scale: actor.scale_x
|
||||
@@ -853,9 +753,9 @@ Workspace.prototype = {
|
||||
false, // don't create workspace
|
||||
time);
|
||||
return true;
|
||||
} else if (source.shellWorkspaceLaunch) {
|
||||
} else if (source instanceof GenericDisplay.GenericDisplayItem || source instanceof AppDisplay.WellDisplayItem) {
|
||||
this._metaWorkspace.activate(time);
|
||||
source.shellWorkspaceLaunch();
|
||||
source.launch();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -898,28 +798,25 @@ Workspaces.prototype = {
|
||||
activeWorkspace.actor.raise_top();
|
||||
this._positionWorkspaces(global, activeWorkspace);
|
||||
|
||||
// Save the button size as a global variable so we can us it to create
|
||||
// matching button sizes for workspace remove buttons.
|
||||
buttonSize = addButtonSize;
|
||||
|
||||
// Create (+) button
|
||||
this.addButton = new AddWorkspaceButton(addButtonSize, addButtonX, addButtonY, Lang.bind(this, this._addWorkspaceAcceptDrop));
|
||||
this.addButton.actor.connect('button-release-event', Lang.bind(this, this._appendNewWorkspace));
|
||||
this.actor.add_actor(this.addButton.actor);
|
||||
this.addButton.actor.lower_bottom();
|
||||
buttonSize = addButtonSize;
|
||||
this.addButton = new Clutter.Texture({ x: addButtonX,
|
||||
y: addButtonY,
|
||||
width: buttonSize,
|
||||
height: buttonSize,
|
||||
reactive: true
|
||||
});
|
||||
this.addButton.set_from_file(global.imagedir + "add-workspace.svg");
|
||||
this.addButton.connect('button-release-event', this._appendNewWorkspace);
|
||||
this.actor.add_actor(this.addButton);
|
||||
this.addButton.lower_bottom();
|
||||
|
||||
let lastWorkspace = this._workspaces[this._workspaces.length - 1];
|
||||
lastWorkspace.updateRemovable(true);
|
||||
|
||||
// Position/scale the desktop windows and their children after the
|
||||
// workspaces have been created. This cannot be done first because
|
||||
// window movement depends on the Workspaces object being accessible
|
||||
// as an Overview member.
|
||||
Main.overview.connect('showing',
|
||||
Lang.bind(this, function() {
|
||||
for (let w = 0; w < this._workspaces.length; w++)
|
||||
this._workspaces[w].zoomToOverview();
|
||||
}));
|
||||
// Position/scale the desktop windows and their children
|
||||
for (let w = 0; w < this._workspaces.length; w++)
|
||||
this._workspaces[w].zoomToOverlay();
|
||||
|
||||
// Track changes to the number of workspaces
|
||||
this._nWorkspacesNotifyId =
|
||||
@@ -930,30 +827,15 @@ Workspaces.prototype = {
|
||||
Lang.bind(this, this._activeWorkspaceChanged));
|
||||
},
|
||||
|
||||
_lookupCloneForMetaWindow: function (metaWindow) {
|
||||
for (let i = 0; i < this._workspaces.length; i++) {
|
||||
let clone = this._workspaces[i].lookupCloneForMetaWindow(metaWindow);
|
||||
if (clone)
|
||||
return clone;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
// Updates position of the workspaces display based on the new coordinates.
|
||||
// Preserves the old value for the coordinate, if the passed value is null.
|
||||
updatePosition : function(x, y) {
|
||||
if (x != null)
|
||||
this._x = x;
|
||||
if (y != null)
|
||||
this._y = y;
|
||||
|
||||
// Should only be called from active Overview context
|
||||
activateWindowFromOverview: function (metaWindow, time) {
|
||||
let global = Shell.Global.get();
|
||||
let activeWorkspaceNum = global.screen.get_active_workspace_index();
|
||||
let windowWorkspaceNum = metaWindow.get_workspace().index();
|
||||
|
||||
let clone = this._lookupCloneForMetaWindow (metaWindow);
|
||||
clone.actor.raise_top();
|
||||
|
||||
if (windowWorkspaceNum != activeWorkspaceNum) {
|
||||
let workspace = global.screen.get_workspace_by_index(windowWorkspaceNum);
|
||||
workspace.activate_with_focus(metaWindow, time);
|
||||
} else {
|
||||
metaWindow.activate(time);
|
||||
}
|
||||
this._updateInOverlay();
|
||||
},
|
||||
|
||||
hide : function() {
|
||||
@@ -965,7 +847,7 @@ Workspaces.prototype = {
|
||||
activeWorkspace.actor.raise_top();
|
||||
|
||||
for (let w = 0; w < this._workspaces.length; w++)
|
||||
this._workspaces[w].zoomFromOverview();
|
||||
this._workspaces[w].zoomFromOverlay();
|
||||
},
|
||||
|
||||
destroy : function() {
|
||||
@@ -982,17 +864,35 @@ Workspaces.prototype = {
|
||||
global.window_manager.disconnect(this._switchWorkspaceNotifyId);
|
||||
},
|
||||
|
||||
getScale : function() {
|
||||
return this._workspaces[0].scale;
|
||||
getFullSizeX : function() {
|
||||
return this._workspaces[0].fullSizeX;
|
||||
},
|
||||
|
||||
// Get the grid position of the active workspace.
|
||||
getActiveWorkspacePosition : function() {
|
||||
// If j-th workspace in the i-th row is active, returns the full width
|
||||
// of j workspaces including empty space if i = 1, or the width of one
|
||||
// workspace.
|
||||
// Used in overlay.js to determine when it is ok to remove the sideshow
|
||||
// during animations for entering and leaving the overlay.
|
||||
getWidthToTopActiveWorkspace : function() {
|
||||
let global = Shell.Global.get();
|
||||
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
|
||||
let activeWorkspace = this._workspaces[activeWorkspaceIndex];
|
||||
|
||||
return [activeWorkspace.gridX, activeWorkspace.gridY];
|
||||
if (activeWorkspace.gridRow == 0)
|
||||
return (activeWorkspace.gridCol + 1) * global.screen_width + activeWorkspace.gridCol * GRID_SPACING;
|
||||
else
|
||||
return global.screen_width;
|
||||
},
|
||||
|
||||
// Updates the workspaces display based on the current dimensions and position.
|
||||
_updateInOverlay : function() {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
this._positionWorkspaces(global);
|
||||
|
||||
// Position/scale the desktop windows and their children
|
||||
for (let w = 0; w < this._workspaces.length; w++)
|
||||
this._workspaces[w].updateInOverlay();
|
||||
},
|
||||
|
||||
// Assign grid positions to workspaces. We can't just do a simple
|
||||
@@ -1045,6 +945,14 @@ Workspaces.prototype = {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now figure out their full-size coordinates
|
||||
for (let w = 0; w < this._workspaces.length; w++) {
|
||||
let workspace = this._workspaces[w];
|
||||
|
||||
workspace.fullSizeX = (workspace.gridCol - activeWorkspace.gridCol) * (global.screen_width + GRID_SPACING);
|
||||
workspace.fullSizeY = (workspace.gridRow - activeWorkspace.gridRow) * (global.screen_height + GRID_SPACING);
|
||||
}
|
||||
},
|
||||
|
||||
_workspacesChanged : function() {
|
||||
@@ -1094,14 +1002,6 @@ Workspaces.prototype = {
|
||||
this._workspaces[w].resizeToGrid(oldScale);
|
||||
}
|
||||
|
||||
if (newScale != oldScale) {
|
||||
// The workspace scale affects window size/positioning because we clamp
|
||||
// window size to a 1:1 ratio and never scale them up
|
||||
let existingWorkspaces = Math.min(oldNumWorkspaces, newNumWorkspaces);
|
||||
for (let w = 0; w < existingWorkspaces; w++)
|
||||
this._workspaces[w].positionWindows(false);
|
||||
}
|
||||
|
||||
if (newNumWorkspaces > oldNumWorkspaces) {
|
||||
// Slide new workspaces in from offscreen
|
||||
for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++)
|
||||
@@ -1115,11 +1015,6 @@ Workspaces.prototype = {
|
||||
|
||||
// FIXME: deal with windows on the lost workspaces
|
||||
}
|
||||
|
||||
// Reset the selection state; if we went from > 1 workspace to 1,
|
||||
// this has the side effect of removing the frame border
|
||||
let activeIndex = global.screen.get_active_workspace_index();
|
||||
this._workspaces[activeIndex].setSelected(true);
|
||||
},
|
||||
|
||||
_activeWorkspaceChanged : function(wm, from, to, direction) {
|
||||
@@ -1128,44 +1023,15 @@ Workspaces.prototype = {
|
||||
},
|
||||
|
||||
_addWorkspaceActor : function(workspaceNum) {
|
||||
let workspace = new Workspace(workspaceNum, this.actor);
|
||||
let workspace = new Workspace(workspaceNum);
|
||||
this._workspaces[workspaceNum] = workspace;
|
||||
this.actor.add_actor(workspace.actor);
|
||||
},
|
||||
|
||||
_appendNewWorkspace : function() {
|
||||
_appendNewWorkspace : function(actor, event) {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
global.screen.append_new_workspace(false, global.screen.get_display().get_current_time());
|
||||
},
|
||||
|
||||
// Creates a new workspace and drops the dropActor there
|
||||
_addWorkspaceAcceptDrop : function(source, dropActor, x, y, time) {
|
||||
this._appendNewWorkspace();
|
||||
return this._workspaces[this._workspaces.length - 1].acceptDrop(source, dropActor, x, y, time);
|
||||
}
|
||||
};
|
||||
|
||||
function AddWorkspaceButton(buttonSize, buttonX, buttonY, acceptDropCallback) {
|
||||
this._init(buttonSize, buttonX, buttonY, acceptDropCallback);
|
||||
}
|
||||
|
||||
AddWorkspaceButton.prototype = {
|
||||
_init : function(buttonSize, buttonX, buttonY, acceptDropCallback) {
|
||||
this.actor = new Clutter.Texture({ x: buttonX,
|
||||
y: buttonY,
|
||||
width: buttonSize,
|
||||
height: buttonSize,
|
||||
reactive: true });
|
||||
this._acceptDropCallback = acceptDropCallback;
|
||||
let global = Shell.Global.get();
|
||||
this.actor._delegate = this;
|
||||
this.actor.set_from_file(global.imagedir + 'add-workspace.svg');
|
||||
},
|
||||
|
||||
// Draggable target interface
|
||||
acceptDrop : function(source, actor, x, y, time) {
|
||||
return this._acceptDropCallback(source, actor, x, y, time);
|
||||
global.screen.append_new_workspace(false, event.get_time());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1175,49 +1041,28 @@ AddWorkspaceButton.prototype = {
|
||||
Tweener.registerSpecialPropertyModifier("workspace_relative", _workspaceRelativeModifier, _workspaceRelativeGet);
|
||||
|
||||
function _workspaceRelativeModifier(workspace) {
|
||||
let [startX, startY] = Main.overview.getPosition();
|
||||
let overviewPosX, overviewPosY, overviewScale;
|
||||
let endX, endY;
|
||||
|
||||
if (!workspace)
|
||||
return [];
|
||||
|
||||
if (workspace.leavingOverview) {
|
||||
let [zoomedInX, zoomedInY] = Main.overview.getZoomedInPosition();
|
||||
overviewPosX = { begin: startX, end: zoomedInX };
|
||||
overviewPosY = { begin: startY, end: zoomedInY };
|
||||
overviewScale = { begin: Main.overview.getScale(),
|
||||
end: Main.overview.getZoomedInScale() };
|
||||
if (workspace.leavingOverlay) {
|
||||
endX = workspace.fullSizeX;
|
||||
endY = workspace.fullSizeY;
|
||||
} else {
|
||||
overviewPosX = { begin: startX, end: 0 };
|
||||
overviewPosY = { begin: startY, end: 0 };
|
||||
overviewScale = { begin: Main.overview.getScale(), end: 1 };
|
||||
endX = workspace.gridX;
|
||||
endY = workspace.gridY;
|
||||
}
|
||||
|
||||
return [ { name: "x",
|
||||
parameters: { workspacePos: workspace.gridX,
|
||||
overviewPos: overviewPosX,
|
||||
overviewScale: overviewScale } },
|
||||
parameters: { begin: workspace.actor.x, end: endX,
|
||||
cur: function() { return workspace.actor.x; } } },
|
||||
{ name: "y",
|
||||
parameters: { workspacePos: workspace.gridY,
|
||||
overviewPos: overviewPosY,
|
||||
overviewScale: overviewScale } }
|
||||
parameters: { begin: workspace.actor.y, end: endY,
|
||||
cur: function() { return workspace.actor.y; } } }
|
||||
];
|
||||
}
|
||||
|
||||
function _workspaceRelativeGet(begin, end, time, params) {
|
||||
let curOverviewPos = (1 - time) * params.overviewPos.begin +
|
||||
time * params.overviewPos.end;
|
||||
let curOverviewScale = (1 - time) * params.overviewScale.begin +
|
||||
time * params.overviewScale.end;
|
||||
|
||||
// Calculate the screen position of the window.
|
||||
let screen = (1 - time) *
|
||||
((begin + params.workspacePos) * params.overviewScale.begin +
|
||||
params.overviewPos.begin) +
|
||||
time *
|
||||
((end + params.workspacePos) * params.overviewScale.end +
|
||||
params.overviewPos.end);
|
||||
|
||||
// Return the workspace coordinates.
|
||||
return (screen - curOverviewPos) / curOverviewScale - params.workspacePos;
|
||||
return (begin + params.begin) + time * (end + params.end - (begin + params.begin)) - params.cur();
|
||||
}
|
||||
|
||||
16
po/LINGUAS
16
po/LINGUAS
@@ -1,16 +0,0 @@
|
||||
ca
|
||||
cs
|
||||
de
|
||||
es
|
||||
fr
|
||||
ga
|
||||
gl
|
||||
hu
|
||||
it
|
||||
ko
|
||||
nb
|
||||
nl
|
||||
pl
|
||||
pt_BR
|
||||
sv
|
||||
tr
|
||||
@@ -1,9 +0,0 @@
|
||||
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 +0,0 @@
|
||||
data/gnome-shell.desktop.in
|
||||
147
po/ca.po
147
po/ca.po
@@ -1,147 +0,0 @@
|
||||
# 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-08-14 20:38+0200\n"
|
||||
"PO-Revision-Date: 2009-08-14 23:59+0100\n"
|
||||
"Last-Translator: Siegfried-Angel Gevatter Pujals <rainct@ubuntu.com>\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"
|
||||
"Language-Team: \n"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:266
|
||||
msgid "Activities"
|
||||
msgstr "Activitats"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:412
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %H:%M"
|
||||
|
||||
#: ../js/ui/dash.js:235
|
||||
msgid "Find apps or documents"
|
||||
msgstr "Cerca aplicacions o documents"
|
||||
|
||||
#: ../js/ui/dash.js:336
|
||||
msgid "Browse"
|
||||
msgstr "Navega"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:472
|
||||
#: ../js/ui/dash.js:545
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "APLICACIONS"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:477
|
||||
#: ../js/ui/dash.js:570
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "DOCUMENTS RECENTS"
|
||||
|
||||
#. **** Places ****
|
||||
#: ../js/ui/dash.js:563
|
||||
msgid "PLACES"
|
||||
msgstr "LLOCS"
|
||||
|
||||
#: ../js/ui/runDialog.js:74
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Introduïu una ordre:"
|
||||
|
||||
#: ../src/gdmuser/gdm-user.c:242
|
||||
msgid "Manager"
|
||||
msgstr "Gestor"
|
||||
|
||||
#: ../src/gdmuser/gdm-user.c:243
|
||||
msgid "The user manager object this user is controlled by."
|
||||
msgstr "L'objecte gestor d'usuaris que controla a aquest usuari."
|
||||
|
||||
#: ../src/shell-global.c:841
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Fa menys d'un minut"
|
||||
|
||||
#: ../src/shell-global.c:844
|
||||
#, 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:847
|
||||
#, 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:850
|
||||
#, 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:853
|
||||
#, 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'estalviador de pantalles 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..."
|
||||
|
||||
184
po/cs.po
184
po/cs.po
@@ -1,184 +0,0 @@
|
||||
# Czech 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.
|
||||
# Andre Klapper <ak-47@gmx.net>, 2009.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell master\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2009-08-15 15:25+0200\n"
|
||||
"PO-Revision-Date: 2009-08-15 13:23+0000\n"
|
||||
"Last-Translator: Andre Klapper <ak-47@gmx.net>\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 ""
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:2
|
||||
#, fuzzy
|
||||
msgid "Window management and application launching"
|
||||
msgstr "Správa oken"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:266
|
||||
msgid "Activities"
|
||||
msgstr ""
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:412
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr ""
|
||||
|
||||
#: ../js/ui/dash.js:235
|
||||
msgid "Find apps or documents"
|
||||
msgstr ""
|
||||
|
||||
#: ../js/ui/dash.js:336
|
||||
#, fuzzy
|
||||
msgid "Browse"
|
||||
msgstr "Procházet"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:472 ../js/ui/dash.js:545
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "APLIKACE"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:477 ../js/ui/dash.js:570
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "NEDÁVNÉ DOKUMENTY"
|
||||
|
||||
#. **** Places ****
|
||||
#: ../js/ui/dash.js:563
|
||||
msgid "PLACES"
|
||||
msgstr "MÍSTA"
|
||||
|
||||
#: ../js/ui/runDialog.js:74
|
||||
msgid "Please enter a command:"
|
||||
msgstr ""
|
||||
|
||||
#: ../src/gdmuser/gdm-user.c:242
|
||||
msgid "Manager"
|
||||
msgstr "Správce"
|
||||
|
||||
#: ../src/gdmuser/gdm-user.c:243
|
||||
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."
|
||||
|
||||
#: ../src/shell-global.c:841
|
||||
#, fuzzy
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Dříve než před minutou"
|
||||
|
||||
#: ../src/shell-global.c:844
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "%d minuta nazpět"
|
||||
msgstr[1] "%d minuty nazpět"
|
||||
msgstr[2] "%d minut nazpět"
|
||||
|
||||
#: ../src/shell-global.c:847
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "%d hodina nazpět"
|
||||
msgstr[1] "%d hodiny nazpět"
|
||||
msgstr[2] "%d hodin nazpět"
|
||||
|
||||
#: ../src/shell-global.c:850
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "%d den nazpět"
|
||||
msgstr[1] "%d dny nazpět"
|
||||
msgstr[2] "%d dnů nazpět"
|
||||
|
||||
#: ../src/shell-global.c:853
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
msgstr[0] "%d týden nazpět"
|
||||
msgstr[1] "%d týdny nazpět"
|
||||
msgstr[2] "%d týdnů nazpět"
|
||||
|
||||
#: ../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
|
||||
#, fuzzy
|
||||
msgid "Sidebar"
|
||||
msgstr "Boční panel"
|
||||
|
||||
#: ../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
|
||||
#, fuzzy, c-format
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
||||
182
po/de.po
182
po/de.po
@@ -1,182 +0,0 @@
|
||||
# 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.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: HEAD\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2009-08-20 16:47+0200\n"
|
||||
"PO-Revision-Date: 2009-08-20 16:49+0200\n"
|
||||
"Last-Translator: Hendrik Richter <hendrikr@gnome.org>\n"
|
||||
"Language-Team: Deutsch <gnome-de@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 "Fenster verwalten und Anwendungen starten"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:266
|
||||
msgid "Activities"
|
||||
msgstr "Aktivitäten"
|
||||
|
||||
#. 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 "Anwendungen oder Dokumente suchen"
|
||||
|
||||
#: ../js/ui/dash.js:369
|
||||
msgid "Browse"
|
||||
msgstr "Durchsuchen"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:505 ../js/ui/dash.js:578
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "ANWENDUNGEN"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:510 ../js/ui/dash.js:605
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "ZULETZT GEÖFFNETE DOKUMENTE"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:598
|
||||
msgid "PLACES"
|
||||
msgstr "ORTE"
|
||||
|
||||
#: ../js/ui/runDialog.js:75
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Bitte geben Sie einen Befehl ein:"
|
||||
|
||||
#: ../src/gdmuser/gdm-user.c:243
|
||||
msgid "Manager"
|
||||
msgstr "Verwaltung"
|
||||
|
||||
#: ../src/gdmuser/gdm-user.c:244
|
||||
msgid "The user manager object this user is controlled by."
|
||||
msgstr "Das Benutzerverwaltungsobjekt welches diesen Benutzer überwacht."
|
||||
|
||||
#: ../src/shell-global.c:841
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Vor weniger als einer Minute"
|
||||
|
||||
#: ../src/shell-global.c:844
|
||||
#, 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:847
|
||||
#, 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:850
|
||||
#, 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:853
|
||||
#, 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"
|
||||
189
po/es.po
189
po/es.po
@@ -1,189 +0,0 @@
|
||||
# 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-08-21 22:23+0000\n"
|
||||
"PO-Revision-Date: 2009-08-22 12:21+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: 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ón de ventanas e inicio de aplicaciones"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:266
|
||||
msgid "Activities"
|
||||
msgstr "Actividades"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:433
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %H:%M"
|
||||
|
||||
#: ../js/ui/dash.js:250
|
||||
msgid "Find apps or documents"
|
||||
msgstr "Encuentre aplicaciones o documentos"
|
||||
|
||||
#: ../js/ui/dash.js:368
|
||||
msgid "Browse"
|
||||
msgstr "Examine"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:556 ../js/ui/dash.js:606
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "APLICACIONES"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:576
|
||||
msgid "PLACES"
|
||||
msgstr "LUGARES"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:583
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "DOCUMENTOS RECIENTES"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:602
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "RESULTADOS DE LA BÚSQUEDA"
|
||||
|
||||
#: ../js/ui/dash.js:615
|
||||
#| msgid "RECENT DOCUMENTS"
|
||||
msgid "DOCUMENTS"
|
||||
msgstr "DOCUMENTOS"
|
||||
|
||||
#: ../js/ui/runDialog.js:75
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Introduzca un comando:"
|
||||
|
||||
#: ../src/shell-global.c:841
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Hace menos de un minuto"
|
||||
|
||||
#: ../src/shell-global.c:844
|
||||
#, 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:847
|
||||
#, 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:850
|
||||
#, 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:853
|
||||
#, 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 "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."
|
||||
21
po/fr.po
21
po/fr.po
@@ -1,21 +0,0 @@
|
||||
# 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.
|
||||
# Colin Walters <walters@verbum.org>, 2009.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell 0.0.1\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2009-07-27 15:09-0400\n"
|
||||
"PO-Revision-Date: 2009-07-27 15:23-0400\n"
|
||||
"Last-Translator: Colin Walters <walters@verbum.org>\n"
|
||||
"Language-Team: French\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"
|
||||
|
||||
#: ../js/ui/panel.js:74
|
||||
msgid "Activities"
|
||||
msgstr "Activités"
|
||||
181
po/ga.po
181
po/ga.po
@@ -1,181 +0,0 @@
|
||||
# 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"
|
||||
184
po/gl.po
184
po/gl.po
@@ -1,184 +0,0 @@
|
||||
# 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-08-22 16:39+0200\n"
|
||||
"PO-Revision-Date: 2009-08-18 21:20+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:266
|
||||
msgid "Activities"
|
||||
msgstr "Actividades"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:433
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %l:%M %p"
|
||||
|
||||
#: ../js/ui/dash.js:250
|
||||
msgid "Find apps or documents"
|
||||
msgstr "Atopar aplicativos ou documentos"
|
||||
|
||||
#: ../js/ui/dash.js:368
|
||||
msgid "Browse"
|
||||
msgstr "Explorar"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:556 ../js/ui/dash.js:606
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "APLICATIVOS"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:576
|
||||
msgid "PLACES"
|
||||
msgstr "LUGARES"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:583
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "DOCUMENTOS RECENTES"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:602
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr ""
|
||||
|
||||
#: ../js/ui/dash.js:615
|
||||
#, fuzzy
|
||||
msgid "DOCUMENTS"
|
||||
msgstr "DOCUMENTOS RECENTES"
|
||||
|
||||
#: ../js/ui/runDialog.js:75
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Insira unha orde:"
|
||||
|
||||
#: ../src/shell-global.c:841
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Menos de un minuto"
|
||||
|
||||
#: ../src/shell-global.c:844
|
||||
#, 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:847
|
||||
#, 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:850
|
||||
#, 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:853
|
||||
#, 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 "Manager"
|
||||
#~ msgstr "Xestor"
|
||||
180
po/hu.po
180
po/hu.po
@@ -1,180 +0,0 @@
|
||||
# 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-08-15 11:35+0200\n"
|
||||
"PO-Revision-Date: 2009-08-15 11:35+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"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:266
|
||||
msgid "Activities"
|
||||
msgstr "Tevékenységek"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:412
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a., %k.%M"
|
||||
|
||||
#: ../js/ui/dash.js:235
|
||||
msgid "Find apps or documents"
|
||||
msgstr "Alkalmazások vagy dokumentumok keresése"
|
||||
|
||||
#: ../js/ui/dash.js:336
|
||||
msgid "Browse"
|
||||
msgstr "Tallózás"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:472 ../js/ui/dash.js:545
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "ALKALMAZÁSOK"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:477 ../js/ui/dash.js:570
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "LEGUTÓBBI DOKUMENTUMOK"
|
||||
|
||||
#. **** Places ****
|
||||
#: ../js/ui/dash.js:563
|
||||
msgid "PLACES"
|
||||
msgstr "HELYEK"
|
||||
|
||||
#: ../js/ui/runDialog.js:74
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Adjon meg egy parancsot:"
|
||||
|
||||
#: ../src/gdmuser/gdm-user.c:242
|
||||
msgid "Manager"
|
||||
msgstr "Kezelő"
|
||||
|
||||
#: ../src/gdmuser/gdm-user.c:243
|
||||
msgid "The user manager object this user is controlled by."
|
||||
msgstr "A felhasználót kezelő felhasználókezelő objektum."
|
||||
|
||||
#: ../src/shell-global.c:841
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Kevesebb, mint egy perce"
|
||||
|
||||
#: ../src/shell-global.c:844
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "%d perce"
|
||||
msgstr[1] "%d perce"
|
||||
|
||||
#: ../src/shell-global.c:847
|
||||
#, 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:850
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "%d napja"
|
||||
msgstr[1] "%d napja"
|
||||
|
||||
#: ../src/shell-global.c:853
|
||||
#, 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…"
|
||||
|
||||
#: ../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"
|
||||
|
||||
#: ../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"
|
||||
|
||||
184
po/it.po
184
po/it.po
@@ -1,184 +0,0 @@
|
||||
# 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: \n"
|
||||
"POT-Creation-Date: 2009-08-20 23:25+0200\n"
|
||||
"PO-Revision-Date: 2009-08-20 23:26+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:266
|
||||
msgid "Activities"
|
||||
msgstr "Attività"
|
||||
|
||||
# (ndt) proviamo col k, se non funge, sappiamo il perché...
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:433
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %k.%M"
|
||||
|
||||
# (ndt) è da valutare se è troppo lunga, è in una casella di ricerca
|
||||
#: ../js/ui/dash.js:251
|
||||
msgid "Find apps or documents"
|
||||
msgstr "Trova programmi e documenti"
|
||||
|
||||
#: ../js/ui/dash.js:369
|
||||
msgid "Browse"
|
||||
msgstr "Esplora"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:505 ../js/ui/dash.js:578
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "Applicazioni"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:510 ../js/ui/dash.js:605
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "Documenti recenti"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:598
|
||||
msgid "PLACES"
|
||||
msgstr "Risorse"
|
||||
|
||||
#: ../js/ui/runDialog.js:75
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Inserire un comando:"
|
||||
|
||||
#: ../src/shell-global.c:841
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Meno di un minuto fa"
|
||||
|
||||
#: ../src/shell-global.c:844
|
||||
#, 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:847
|
||||
#, 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:850
|
||||
#, 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:853
|
||||
#, 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) 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
166
po/ko.po
@@ -1,166 +0,0 @@
|
||||
# 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"
|
||||
170
po/nb.po
170
po/nb.po
@@ -1,170 +0,0 @@
|
||||
# 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-08-21 12:36+0200\n"
|
||||
"PO-Revision-Date: 2009-08-21 12:44+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:266
|
||||
msgid "Activities"
|
||||
msgstr "Aktiviteter"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:433
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %l:%M"
|
||||
|
||||
#: ../js/ui/dash.js:250
|
||||
msgid "Find apps or documents"
|
||||
msgstr "Finn programmer eller dokumenter"
|
||||
|
||||
#: ../js/ui/dash.js:368
|
||||
msgid "Browse"
|
||||
msgstr "Bla gjennom"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:504 ../js/ui/dash.js:577
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "PROGRAMMER"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:509 ../js/ui/dash.js:604
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "SISTE DOKUMENTER"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:597
|
||||
msgid "PLACES"
|
||||
msgstr "STEDER"
|
||||
|
||||
#: ../js/ui/runDialog.js:75
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Oppgi en kommando:"
|
||||
|
||||
#: ../src/shell-global.c:841
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Mindre enn ett minutt siden"
|
||||
|
||||
#: ../src/shell-global.c:844
|
||||
#, 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:847
|
||||
#, 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:850
|
||||
#, 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:853
|
||||
#, 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
179
po/nl.po
@@ -1,179 +0,0 @@
|
||||
# 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-24 22:30+0200\n"
|
||||
"PO-Revision-Date: 2009-08-24 22:38+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:266
|
||||
msgid "Activities"
|
||||
msgstr "Activiteiten"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:433
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %k:%M"
|
||||
|
||||
#: ../js/ui/dash.js:250
|
||||
msgid "Find apps or documents"
|
||||
msgstr "Zoeken"
|
||||
|
||||
#: ../js/ui/dash.js:368
|
||||
msgid "Browse"
|
||||
msgstr "Bladeren"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:556 ../js/ui/dash.js:606
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "TOEPASSINGEN"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:576
|
||||
msgid "PLACES"
|
||||
msgstr "LOCATIES"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:583
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "RECENTE DOCUMENTEN"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:602
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "ZOEKRESULTATEN"
|
||||
|
||||
#: ../js/ui/dash.js:615
|
||||
msgid "DOCUMENTS"
|
||||
msgstr "DOCUMENTEN"
|
||||
|
||||
#: ../js/ui/runDialog.js:75
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Voer een opdracht in:"
|
||||
|
||||
#: ../src/shell-global.c:841
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Korter dan een minuut geleden"
|
||||
|
||||
#: ../src/shell-global.c:844
|
||||
#, 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:847
|
||||
#, 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:850
|
||||
#, 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:853
|
||||
#, 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"
|
||||
187
po/pl.po
187
po/pl.po
@@ -1,187 +0,0 @@
|
||||
# -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||
# 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-08-18 23:25+0200\n"
|
||||
"PO-Revision-Date: 2009-08-18 23:23+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:266
|
||||
msgid "Activities"
|
||||
msgstr "Czynności"
|
||||
|
||||
#. 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 "Wyszukuje programy lub dokumenty"
|
||||
|
||||
#: ../js/ui/dash.js:369
|
||||
msgid "Browse"
|
||||
msgstr "Przeglądaj"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:505 ../js/ui/dash.js:578
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "Programy"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:510 ../js/ui/dash.js:605
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "Ostatnie dokumenty"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:598
|
||||
msgid "PLACES"
|
||||
msgstr "Miejsca"
|
||||
|
||||
#: ../js/ui/runDialog.js:74
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Proszę wprowadzić polecenie:"
|
||||
|
||||
#: ../src/gdmuser/gdm-user.c:243
|
||||
msgid "Manager"
|
||||
msgstr "Menedżer"
|
||||
|
||||
#: ../src/gdmuser/gdm-user.c:244
|
||||
msgid "The user manager object this user is controlled by."
|
||||
msgstr "Obiekt menedżera użytkowników, który steruje tym użytkownikiem."
|
||||
|
||||
#: ../src/shell-global.c:841
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Mniej niż minutę temu"
|
||||
|
||||
#: ../src/shell-global.c:844
|
||||
#, 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:847
|
||||
#, 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:850
|
||||
#, 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:853
|
||||
#, 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"
|
||||
144
po/pt_BR.po
144
po/pt_BR.po
@@ -1,144 +0,0 @@
|
||||
# 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.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2009-08-14 17:53-0400\n"
|
||||
"PO-Revision-Date: 2009-08-14 17:53-0400\n"
|
||||
"Last-Translator: Og Maciel <ogmaciel@gnome.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"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:266
|
||||
msgid "Activities"
|
||||
msgstr "Atividades"
|
||||
|
||||
#. 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 "Localizar aplicativos ou documentos"
|
||||
|
||||
#: ../js/ui/dash.js:336
|
||||
msgid "Browse"
|
||||
msgstr "Navegar"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:472 ../js/ui/dash.js:545
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "APLICATIVOS"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:477 ../js/ui/dash.js:570
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "DOCUMENTOS RECENTES"
|
||||
|
||||
#. **** Places ****
|
||||
#: ../js/ui/dash.js:563
|
||||
msgid "PLACES"
|
||||
msgstr "LOCAIS"
|
||||
|
||||
#: ../js/ui/runDialog.js:74
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Por favor digite um comando:"
|
||||
|
||||
#: ../src/gdmuser/gdm-user.c:242
|
||||
msgid "Manager"
|
||||
msgstr "Gerenciador"
|
||||
|
||||
#: ../src/gdmuser/gdm-user.c:243
|
||||
msgid "The user manager object this user is controlled by."
|
||||
msgstr "O objeto gerenciador de usuários que controla este usuário."
|
||||
|
||||
#: ../src/shell-global.c:841
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Menos de um minuto atrás"
|
||||
|
||||
#: ../src/shell-global.c:844
|
||||
#, 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:847
|
||||
#, 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:850
|
||||
#, 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:853
|
||||
#, 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..."
|
||||
186
po/sv.po
186
po/sv.po
@@ -1,186 +0,0 @@
|
||||
# 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-08-25 07:48+0200\n"
|
||||
"PO-Revision-Date: 2009-08-25 07:48+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:266
|
||||
msgid "Activities"
|
||||
msgstr "Aktiviteter"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:433
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %H.%M"
|
||||
|
||||
#: ../js/ui/dash.js:250
|
||||
msgid "Find apps or documents"
|
||||
msgstr "Hitta program eller dokument"
|
||||
|
||||
#: ../js/ui/dash.js:368
|
||||
msgid "Browse"
|
||||
msgstr "Bläddra"
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:556
|
||||
#: ../js/ui/dash.js:606
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "PROGRAM"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:576
|
||||
msgid "PLACES"
|
||||
msgstr "PLATSER"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:583
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "SENASTE DOKUMENT"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:602
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "SÖKRESULTAT"
|
||||
|
||||
#: ../js/ui/dash.js:615
|
||||
msgid "DOCUMENTS"
|
||||
msgstr "DOKUMENT"
|
||||
|
||||
#: ../js/ui/runDialog.js:75
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Ange ett kommando:"
|
||||
|
||||
#: ../src/shell-global.c:841
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Mindre än en minut sedan"
|
||||
|
||||
#: ../src/shell-global.c:844
|
||||
#, 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:847
|
||||
#, 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:850
|
||||
#, 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:853
|
||||
#, 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 "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
166
po/tr.po
@@ -1,166 +0,0 @@
|
||||
# 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"
|
||||
@@ -33,21 +33,21 @@ big_source_c = \
|
||||
big-enum-types.h: stamp-big-enum-types.h Makefile
|
||||
@true
|
||||
stamp-big-enum-types.h: $(big_source_h) big/big-enum-types.h.in
|
||||
$(AM_V_GEN) ( cd $(srcdir) && \
|
||||
( cd $(srcdir) && \
|
||||
$(GLIB_MKENUMS) \
|
||||
--template $(srcdir)/big/big-enum-types.h.in \
|
||||
$(big_source_h) ) >> xgen-beth && \
|
||||
(cmp -s xgen-beth big-enum-types.h || cp xgen-beth big-enum-types.h) && \
|
||||
rm -f xgen-beth && \
|
||||
$(big_source_h) ) >> xgen-teth && \
|
||||
(cmp xgen-teth big-enum-types.h || cp xgen-teth big-enum-types.h) && \
|
||||
rm -f xgen-teth && \
|
||||
echo timestamp > $(@F)
|
||||
|
||||
big-enum-types.c: stamp-big-enum-types.h big/big-enum-types.c.in
|
||||
$(AM_V_GEN) ( cd $(srcdir) && \
|
||||
( cd $(srcdir) && \
|
||||
$(GLIB_MKENUMS) \
|
||||
--template $(srcdir)/big/big-enum-types.c.in \
|
||||
$(big_source_h) ) >> xgen-betc && \
|
||||
cp xgen-betc big-enum-types.c && \
|
||||
rm -f xgen-betc
|
||||
$(big_source_h) ) >> xgen-tetc && \
|
||||
cp xgen-tetc big-enum-types.c && \
|
||||
rm -f xgen-tetc
|
||||
|
||||
noinst_LTLIBRARIES += libbig-1.0.la
|
||||
|
||||
|
||||
17
src/Makefile-taskpanel.am
Normal file
17
src/Makefile-taskpanel.am
Normal file
@@ -0,0 +1,17 @@
|
||||
gnomeshell_taskpanel_CPPFLAGS = \
|
||||
-I$(top_srcdir)/src \
|
||||
-DG_DISABLE_DEPRECATED \
|
||||
-DWNCK_I_KNOW_THIS_IS_UNSTABLE \
|
||||
-DG_LOG_DOMAIN=\"gnomeshell-taskpanel\" \
|
||||
$(TASKPANEL_CFLAGS) \
|
||||
$(NULL)
|
||||
|
||||
gnomeshell_taskpanel_SOURCES = \
|
||||
gnomeshell-taskpanel.c \
|
||||
shell-panel-window.c \
|
||||
shell-panel-window.h \
|
||||
$(NULL)
|
||||
|
||||
gnomeshell_taskpanel_LDADD = $(TASKPANEL_LIBS)
|
||||
|
||||
libexec_PROGRAMS += gnomeshell-taskpanel
|
||||
89
src/Makefile-tidy.am
Normal file
89
src/Makefile-tidy.am
Normal file
@@ -0,0 +1,89 @@
|
||||
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
|
||||
$(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
|
||||
(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
|
||||
( cd $(srcdir) && \
|
||||
$(GLIB_MKENUMS) \
|
||||
--template $(srcdir)/tidy/tidy-enum-types.h.in \
|
||||
$(tidy_source_h) ) >> xgen-teth && \
|
||||
(cmp 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
|
||||
( 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
|
||||
@@ -24,7 +24,7 @@ tray_source = \
|
||||
na-marshal.h: stamp-na-marshal.h
|
||||
@true
|
||||
stamp-na-marshal.h: Makefile tray/na-marshal.list
|
||||
$(AM_V_GEN) $(GLIB_GENMARSHAL) \
|
||||
$(GLIB_GENMARSHAL) \
|
||||
--prefix=_na_marshal \
|
||||
--header \
|
||||
$(srcdir)/tray/na-marshal.list > xgen-tmh && \
|
||||
@@ -33,7 +33,7 @@ stamp-na-marshal.h: Makefile tray/na-marshal.list
|
||||
echo timestamp > $(@F)
|
||||
|
||||
na-marshal.c: Makefile tray/na-marshal.list
|
||||
$(AM_V_GEN) (echo "#include \"na-marshal.h\"" ; \
|
||||
(echo "#include \"na-marshal.h\"" ; \
|
||||
$(GLIB_GENMARSHAL) \
|
||||
--prefix=_na_marshal \
|
||||
--body \
|
||||
|
||||
@@ -8,27 +8,27 @@ noinst_LTLIBRARIES =
|
||||
bin_SCRIPTS = gnome-shell
|
||||
|
||||
gnome-shell: gnome-shell.in
|
||||
$(AM_V_GEN) sed -e "s|@MUTTER_BIN_DIR[@]|$(MUTTER_BIN_DIR)|" \
|
||||
sed -e "s|@MUTTER_BIN_DIR[@]|$(MUTTER_BIN_DIR)|" \
|
||||
-e "s|@GJS_JS_DIR[@]|$(GJS_JS_DIR)|" \
|
||||
-e "s|@GJS_JS_NATIVE_DIR[@]|$(GJS_JS_NATIVE_DIR)|" \
|
||||
-e "s|@libexecdir[@]|$(libexecdir)|" \
|
||||
-e "s|@libdir[@]|$(libdir)|" \
|
||||
-e "s|@pkgdatadir[@]|$(pkgdatadir)|" \
|
||||
-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-tray.am
|
||||
include Makefile-taskpanel.am
|
||||
|
||||
gnome_shell_cflags = \
|
||||
$(MUTTER_PLUGIN_CFLAGS) \
|
||||
$(LIBGNOMEUI_CFLAGS) \
|
||||
-I$(srcdir)/tray \
|
||||
-DGETTEXT_PACKAGE=\"gnome-shell\" \
|
||||
-DLOCALEDIR=\"$(datadir)/locale\" \
|
||||
-DGETTEXT_PACKAGE=gnome-shell \
|
||||
-DGNOME_SHELL_DATADIR=\"$(pkgdatadir)\" \
|
||||
-DGNOME_SHELL_PKGLIBDIR=\"$(pkglibdir)\" \
|
||||
-DJSDIR=\"$(pkgdatadir)/js\"
|
||||
@@ -57,37 +57,21 @@ libgnome_shell_la_SOURCES = \
|
||||
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 \
|
||||
shell-drawing-area.h \
|
||||
shell-embedded-window.c \
|
||||
shell-embedded-window.h \
|
||||
shell-embedded-window-private.h \
|
||||
shell-gconf.c \
|
||||
shell-gconf.h \
|
||||
shell-generic-container.c \
|
||||
shell-generic-container.h \
|
||||
shell-gtk-embed.c \
|
||||
shell-gtk-embed.h \
|
||||
shell-overflow-list.c \
|
||||
shell-overflow-list.h \
|
||||
shell-process.c \
|
||||
shell-process.h \
|
||||
shell-global.c \
|
||||
shell-global.h \
|
||||
shell-status-menu.c \
|
||||
shell-status-menu.h \
|
||||
shell-stack.c \
|
||||
shell-stack.h \
|
||||
shell-tray-manager.c \
|
||||
shell-tray-manager.h \
|
||||
shell-texture-cache.c \
|
||||
shell-texture-cache.h \
|
||||
shell-uri-util.c \
|
||||
shell-uri-util.h \
|
||||
shell-wm.c \
|
||||
shell-wm.h
|
||||
|
||||
@@ -125,22 +109,22 @@ libgnome_shell_la_gir_sources = \
|
||||
shell-marshal.h: stamp-shell-marshal.h
|
||||
@true
|
||||
stamp-shell-marshal.h: Makefile shell-marshal.list
|
||||
$(AM_V_GEN) $(GLIB_GENMARSHAL) \
|
||||
$(GLIB_GENMARSHAL) \
|
||||
--prefix=_shell_marshal \
|
||||
--header \
|
||||
$(srcdir)/shell-marshal.list > xgen-smh && \
|
||||
(cmp -s xgen-smh shell-marshal.h || cp -f xgen-smh shell-marshal.h) && \
|
||||
rm -f xgen-smh && \
|
||||
$(srcdir)/shell-marshal.list > xgen-tmh && \
|
||||
(cmp -s xgen-tmh shell-marshal.h || cp -f xgen-tmh shell-marshal.h) && \
|
||||
rm -f xgen-tmh && \
|
||||
echo timestamp > $(@F)
|
||||
|
||||
shell-marshal.c: Makefile shell-marshal.list
|
||||
$(AM_V_GEN) (echo "#include \"shell-marshal.h\"" ; \
|
||||
(echo "#include \"shell-marshal.h\"" ; \
|
||||
$(GLIB_GENMARSHAL) \
|
||||
--prefix=_shell_marshal \
|
||||
--body \
|
||||
$(srcdir)/shell-marshal.list ) > xgen-smc && \
|
||||
cp -f xgen-smc shell-marshal.c && \
|
||||
rm -f xgen-smc
|
||||
$(srcdir)/shell-marshal.list ) > xgen-tmc && \
|
||||
cp -f xgen-tmc shell-marshal.c && \
|
||||
rm -f xgen-tmc
|
||||
|
||||
libgnome_shell_la_LDFLAGS = -avoid-version -module
|
||||
libgnome_shell_la_LIBADD = \
|
||||
@@ -148,18 +132,19 @@ libgnome_shell_la_LIBADD = \
|
||||
$(LIBGNOMEUI_LIBS) \
|
||||
libbig-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 Big-1.0.typelib
|
||||
typelib_DATA = Shell-0.1.typelib Tidy-1.0.typelib Big-1.0.typelib
|
||||
|
||||
Shell-0.1.gir: $(mutter) $(G_IR_SCANNER) Big-1.0.gir libgnome-shell.la Makefile
|
||||
$(AM_V_GEN) $(G_IR_SCANNER) \
|
||||
$(G_IR_SCANNER) \
|
||||
--namespace=Shell \
|
||||
--nsversion=0.1 \
|
||||
--add-include-path=$(MUTTER_LIB_DIR)/mutter/ \
|
||||
--include=Clutter-1.0 \
|
||||
--include=Clutter-0.9 \
|
||||
--include=Meta-2.27 \
|
||||
--add-include-path=$(builddir) \
|
||||
--include=Big-1.0 \
|
||||
@@ -173,18 +158,32 @@ 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
|
||||
$(AM_V_GEN) LD_LIBRARY_PATH=.$${LD_LIBRARY_PATH:+:$$LD_LIBRARY_PATH} \
|
||||
$(G_IR_COMPILER) \
|
||||
--includedir=. \
|
||||
--includedir=$(MUTTER_LIB_DIR)/mutter/ \
|
||||
Shell-0.1.gir -o $@
|
||||
LD_LIBRARY_PATH=$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}. g-ir-compiler --includedir=$(builddir) --includedir=$(MUTTER_LIB_DIR)/mutter/ Shell-0.1.gir -o $@
|
||||
CLEANFILES += Shell-0.1.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 \
|
||||
Tidy-1.0.gir: $(mutter) $(G_IR_SCANNER) libgnome-shell.la libtidy-1.0.la Makefile
|
||||
$(G_IR_SCANNER) \
|
||||
--namespace=Tidy \
|
||||
--nsversion=1.0 \
|
||||
--include=Clutter-1.0 \
|
||||
--include=Clutter-0.9 \
|
||||
--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
|
||||
$(G_IR_SCANNER) \
|
||||
--namespace=Big \
|
||||
--nsversion=1.0 \
|
||||
--include=Clutter-0.9 \
|
||||
--include=GdkPixbuf-2.0 \
|
||||
--program=mutter \
|
||||
--program-arg=--mutter-plugins=$$(pwd)/libgnome-shell.la \
|
||||
@@ -196,6 +195,5 @@ 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
|
||||
$(AM_V_GEN) LD_LIBRARY_PATH=.$${LD_LIBRARY_PATH:+:$$LD_LIBRARY_PATH} \
|
||||
$(G_IR_COMPILER) Big-1.0.gir -o $@
|
||||
LD_LIBRARY_PATH=$${LD_LIBRARY_PATH:+$$LD_LIBRARY_PATH:}. g-ir-compiler Big-1.0.gir -o $@
|
||||
CLEANFILES += Big-1.0.typelib
|
||||
|
||||
208
src/gdmuser/gdm-user-chooser-dialog.c
Normal file
208
src/gdmuser/gdm-user-chooser-dialog.c
Normal file
@@ -0,0 +1,208 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
|
||||
*
|
||||
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <glib-object.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "gdm-user-chooser-widget.h"
|
||||
#include "gdm-user-chooser-dialog.h"
|
||||
|
||||
#define GDM_USER_CHOOSER_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_USER_CHOOSER_DIALOG, GdmUserChooserDialogPrivate))
|
||||
|
||||
struct GdmUserChooserDialogPrivate
|
||||
{
|
||||
GtkWidget *chooser_widget;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
};
|
||||
|
||||
static void gdm_user_chooser_dialog_class_init (GdmUserChooserDialogClass *klass);
|
||||
static void gdm_user_chooser_dialog_init (GdmUserChooserDialog *user_chooser_dialog);
|
||||
static void gdm_user_chooser_dialog_finalize (GObject *object);
|
||||
|
||||
G_DEFINE_TYPE (GdmUserChooserDialog, gdm_user_chooser_dialog, GTK_TYPE_DIALOG)
|
||||
|
||||
char *
|
||||
gdm_user_chooser_dialog_get_chosen_user_name (GdmUserChooserDialog *dialog)
|
||||
{
|
||||
char *user_name;
|
||||
|
||||
g_return_val_if_fail (GDM_IS_USER_CHOOSER_DIALOG (dialog), NULL);
|
||||
|
||||
user_name = gdm_user_chooser_widget_get_chosen_user_name (GDM_USER_CHOOSER_WIDGET (dialog->priv->chooser_widget));
|
||||
|
||||
return user_name;
|
||||
}
|
||||
|
||||
void
|
||||
gdm_user_chooser_dialog_set_show_user_other (GdmUserChooserDialog *dialog,
|
||||
gboolean show_user)
|
||||
{
|
||||
g_return_if_fail (GDM_IS_USER_CHOOSER_DIALOG (dialog));
|
||||
|
||||
gdm_user_chooser_widget_set_show_user_other (GDM_USER_CHOOSER_WIDGET (dialog->priv->chooser_widget), show_user);
|
||||
}
|
||||
|
||||
void
|
||||
gdm_user_chooser_dialog_set_show_user_guest (GdmUserChooserDialog *dialog,
|
||||
gboolean show_user)
|
||||
{
|
||||
g_return_if_fail (GDM_IS_USER_CHOOSER_DIALOG (dialog));
|
||||
|
||||
gdm_user_chooser_widget_set_show_user_guest (GDM_USER_CHOOSER_WIDGET (dialog->priv->chooser_widget), show_user);
|
||||
}
|
||||
|
||||
void
|
||||
gdm_user_chooser_dialog_set_show_user_auto (GdmUserChooserDialog *dialog,
|
||||
gboolean show_user)
|
||||
{
|
||||
g_return_if_fail (GDM_IS_USER_CHOOSER_DIALOG (dialog));
|
||||
|
||||
gdm_user_chooser_widget_set_show_user_auto (GDM_USER_CHOOSER_WIDGET (dialog->priv->chooser_widget), show_user);
|
||||
}
|
||||
|
||||
static void
|
||||
gdm_user_chooser_dialog_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
switch (prop_id) {
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdm_user_chooser_dialog_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
switch (prop_id) {
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static GObject *
|
||||
gdm_user_chooser_dialog_constructor (GType type,
|
||||
guint n_construct_properties,
|
||||
GObjectConstructParam *construct_properties)
|
||||
{
|
||||
GdmUserChooserDialog *user_chooser_dialog;
|
||||
|
||||
user_chooser_dialog = GDM_USER_CHOOSER_DIALOG (G_OBJECT_CLASS (gdm_user_chooser_dialog_parent_class)->constructor (type,
|
||||
n_construct_properties,
|
||||
construct_properties));
|
||||
|
||||
return G_OBJECT (user_chooser_dialog);
|
||||
}
|
||||
|
||||
static void
|
||||
gdm_user_chooser_dialog_dispose (GObject *object)
|
||||
{
|
||||
G_OBJECT_CLASS (gdm_user_chooser_dialog_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
gdm_user_chooser_dialog_class_init (GdmUserChooserDialogClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->get_property = gdm_user_chooser_dialog_get_property;
|
||||
object_class->set_property = gdm_user_chooser_dialog_set_property;
|
||||
object_class->constructor = gdm_user_chooser_dialog_constructor;
|
||||
object_class->dispose = gdm_user_chooser_dialog_dispose;
|
||||
object_class->finalize = gdm_user_chooser_dialog_finalize;
|
||||
|
||||
g_type_class_add_private (klass, sizeof (GdmUserChooserDialogPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
on_response (GdmUserChooserDialog *dialog,
|
||||
gint response_id)
|
||||
{
|
||||
switch (response_id) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdm_user_chooser_dialog_init (GdmUserChooserDialog *dialog)
|
||||
{
|
||||
|
||||
dialog->priv = GDM_USER_CHOOSER_DIALOG_GET_PRIVATE (dialog);
|
||||
|
||||
dialog->priv->chooser_widget = gdm_user_chooser_widget_new ();
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), dialog->priv->chooser_widget);
|
||||
|
||||
gtk_dialog_add_buttons (GTK_DIALOG (dialog),
|
||||
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
||||
GTK_STOCK_OK, GTK_RESPONSE_OK,
|
||||
NULL);
|
||||
g_signal_connect (dialog,
|
||||
"response",
|
||||
G_CALLBACK (on_response),
|
||||
dialog);
|
||||
|
||||
gtk_widget_show_all (GTK_WIDGET (dialog));
|
||||
}
|
||||
|
||||
static void
|
||||
gdm_user_chooser_dialog_finalize (GObject *object)
|
||||
{
|
||||
GdmUserChooserDialog *user_chooser_dialog;
|
||||
|
||||
g_return_if_fail (object != NULL);
|
||||
g_return_if_fail (GDM_IS_USER_CHOOSER_DIALOG (object));
|
||||
|
||||
user_chooser_dialog = GDM_USER_CHOOSER_DIALOG (object);
|
||||
|
||||
g_return_if_fail (user_chooser_dialog->priv != NULL);
|
||||
|
||||
G_OBJECT_CLASS (gdm_user_chooser_dialog_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gdm_user_chooser_dialog_new (void)
|
||||
{
|
||||
GObject *object;
|
||||
|
||||
object = g_object_new (GDM_TYPE_USER_CHOOSER_DIALOG,
|
||||
NULL);
|
||||
|
||||
return GTK_WIDGET (object);
|
||||
}
|
||||
62
src/gdmuser/gdm-user-chooser-dialog.h
Normal file
62
src/gdmuser/gdm-user-chooser-dialog.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
|
||||
*
|
||||
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __GDM_USER_CHOOSER_DIALOG_H
|
||||
#define __GDM_USER_CHOOSER_DIALOG_H
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <gtk/gtkdialog.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GDM_TYPE_USER_CHOOSER_DIALOG (gdm_user_chooser_dialog_get_type ())
|
||||
#define GDM_USER_CHOOSER_DIALOG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_USER_CHOOSER_DIALOG, GdmUserChooserDialog))
|
||||
#define GDM_USER_CHOOSER_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_USER_CHOOSER_DIALOG, GdmUserChooserDialogClass))
|
||||
#define GDM_IS_USER_CHOOSER_DIALOG(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_USER_CHOOSER_DIALOG))
|
||||
#define GDM_IS_USER_CHOOSER_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_USER_CHOOSER_DIALOG))
|
||||
#define GDM_USER_CHOOSER_DIALOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_USER_CHOOSER_DIALOG, GdmUserChooserDialogClass))
|
||||
|
||||
typedef struct GdmUserChooserDialogPrivate GdmUserChooserDialogPrivate;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GtkDialog parent;
|
||||
GdmUserChooserDialogPrivate *priv;
|
||||
} GdmUserChooserDialog;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GtkDialogClass parent_class;
|
||||
} GdmUserChooserDialogClass;
|
||||
|
||||
GType gdm_user_chooser_dialog_get_type (void);
|
||||
|
||||
GtkWidget * gdm_user_chooser_dialog_new (void);
|
||||
|
||||
char * gdm_user_chooser_dialog_get_chosen_user_name (GdmUserChooserDialog *dialog);
|
||||
void gdm_user_chooser_dialog_set_show_other_user (GdmUserChooserDialog *dialog,
|
||||
gboolean show);
|
||||
void gdm_user_chooser_dialog_set_show_user_guest (GdmUserChooserDialog *dialog,
|
||||
gboolean show);
|
||||
void gdm_user_chooser_dialog_set_show_user_auto (GdmUserChooserDialog *dialog,
|
||||
gboolean show);
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDM_USER_CHOOSER_DIALOG_H */
|
||||
723
src/gdmuser/gdm-user-chooser-widget.c
Normal file
723
src/gdmuser/gdm-user-chooser-widget.c
Normal file
@@ -0,0 +1,723 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
|
||||
*
|
||||
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
|
||||
* Copyright (C) 2007 Ray Strode <rstrode@redhat.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <dirent.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include <gconf/gconf-client.h>
|
||||
|
||||
#include "gdm-user-manager.h"
|
||||
#include "gdm-user-chooser-widget.h"
|
||||
|
||||
|
||||
#define KEY_DISABLE_USER_LIST "/apps/gdm/simple-greeter/disable_user_list"
|
||||
|
||||
enum {
|
||||
USER_NO_DISPLAY = 1 << 0,
|
||||
USER_ACCOUNT_DISABLED = 1 << 1,
|
||||
};
|
||||
|
||||
#define DEFAULT_USER_ICON "stock_person"
|
||||
|
||||
#define GDM_USER_CHOOSER_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_USER_CHOOSER_WIDGET, GdmUserChooserWidgetPrivate))
|
||||
|
||||
#define MAX_ICON_SIZE 128
|
||||
|
||||
struct GdmUserChooserWidgetPrivate
|
||||
{
|
||||
GdmUserManager *manager;
|
||||
GtkIconTheme *icon_theme;
|
||||
|
||||
GdkPixbuf *logged_in_pixbuf;
|
||||
GdkPixbuf *stock_person_pixbuf;
|
||||
|
||||
guint loaded : 1;
|
||||
guint show_user_other : 1;
|
||||
guint show_user_guest : 1;
|
||||
guint show_user_auto : 1;
|
||||
guint show_normal_users : 1;
|
||||
|
||||
guint load_idle_id;
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_SHOW_USER_GUEST,
|
||||
PROP_SHOW_USER_AUTO,
|
||||
PROP_SHOW_USER_OTHER,
|
||||
};
|
||||
|
||||
static void gdm_user_chooser_widget_class_init (GdmUserChooserWidgetClass *klass);
|
||||
static void gdm_user_chooser_widget_init (GdmUserChooserWidget *user_chooser_widget);
|
||||
static void gdm_user_chooser_widget_finalize (GObject *object);
|
||||
|
||||
G_DEFINE_TYPE (GdmUserChooserWidget, gdm_user_chooser_widget, GDM_TYPE_CHOOSER_WIDGET)
|
||||
|
||||
static int
|
||||
get_font_height_for_widget (GtkWidget *widget)
|
||||
{
|
||||
PangoFontMetrics *metrics;
|
||||
PangoContext *context;
|
||||
int ascent;
|
||||
int descent;
|
||||
int height;
|
||||
|
||||
gtk_widget_ensure_style (widget);
|
||||
context = gtk_widget_get_pango_context (widget);
|
||||
metrics = pango_context_get_metrics (context,
|
||||
widget->style->font_desc,
|
||||
pango_context_get_language (context));
|
||||
|
||||
ascent = pango_font_metrics_get_ascent (metrics);
|
||||
descent = pango_font_metrics_get_descent (metrics);
|
||||
height = PANGO_PIXELS (ascent + descent);
|
||||
pango_font_metrics_unref (metrics);
|
||||
return height;
|
||||
}
|
||||
|
||||
static int
|
||||
get_icon_height_for_widget (GtkWidget *widget)
|
||||
{
|
||||
int font_height;
|
||||
int height;
|
||||
|
||||
font_height = get_font_height_for_widget (widget);
|
||||
height = 3 * font_height;
|
||||
if (height > MAX_ICON_SIZE) {
|
||||
height = MAX_ICON_SIZE;
|
||||
}
|
||||
|
||||
g_debug ("GdmUserChooserWidget: font height %d; using icon size %d", font_height, height);
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
static void
|
||||
add_user_other (GdmUserChooserWidget *widget)
|
||||
{
|
||||
gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (widget),
|
||||
GDM_USER_CHOOSER_USER_OTHER,
|
||||
NULL,
|
||||
_("Other..."),
|
||||
_("Choose a different account"),
|
||||
0,
|
||||
FALSE,
|
||||
TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
add_user_guest (GdmUserChooserWidget *widget)
|
||||
{
|
||||
gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (widget),
|
||||
GDM_USER_CHOOSER_USER_GUEST,
|
||||
widget->priv->stock_person_pixbuf,
|
||||
_("Guest"),
|
||||
_("Login as a temporary guest"),
|
||||
0,
|
||||
FALSE,
|
||||
TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
add_user_auto (GdmUserChooserWidget *widget)
|
||||
{
|
||||
gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (widget),
|
||||
GDM_USER_CHOOSER_USER_AUTO,
|
||||
NULL,
|
||||
_("Automatic Login"),
|
||||
_("Automatically login to the system after selecting options"),
|
||||
0,
|
||||
FALSE,
|
||||
TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
remove_user_other (GdmUserChooserWidget *widget)
|
||||
{
|
||||
gdm_chooser_widget_remove_item (GDM_CHOOSER_WIDGET (widget),
|
||||
GDM_USER_CHOOSER_USER_OTHER);
|
||||
}
|
||||
|
||||
static void
|
||||
remove_user_guest (GdmUserChooserWidget *widget)
|
||||
{
|
||||
gdm_chooser_widget_remove_item (GDM_CHOOSER_WIDGET (widget),
|
||||
GDM_USER_CHOOSER_USER_GUEST);
|
||||
}
|
||||
|
||||
static void
|
||||
remove_user_auto (GdmUserChooserWidget *widget)
|
||||
{
|
||||
gdm_chooser_widget_remove_item (GDM_CHOOSER_WIDGET (widget),
|
||||
GDM_USER_CHOOSER_USER_AUTO);
|
||||
}
|
||||
|
||||
void
|
||||
gdm_user_chooser_widget_set_show_user_other (GdmUserChooserWidget *widget,
|
||||
gboolean show_user)
|
||||
{
|
||||
g_return_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget));
|
||||
|
||||
if (widget->priv->show_user_other != show_user) {
|
||||
widget->priv->show_user_other = show_user;
|
||||
if (show_user) {
|
||||
add_user_other (widget);
|
||||
} else {
|
||||
remove_user_other (widget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gdm_user_chooser_widget_set_show_user_guest (GdmUserChooserWidget *widget,
|
||||
gboolean show_user)
|
||||
{
|
||||
g_return_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget));
|
||||
|
||||
if (widget->priv->show_user_guest != show_user) {
|
||||
widget->priv->show_user_guest = show_user;
|
||||
if (show_user) {
|
||||
add_user_guest (widget);
|
||||
} else {
|
||||
remove_user_guest (widget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gdm_user_chooser_widget_set_show_user_auto (GdmUserChooserWidget *widget,
|
||||
gboolean show_user)
|
||||
{
|
||||
g_return_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget));
|
||||
|
||||
if (widget->priv->show_user_auto != show_user) {
|
||||
widget->priv->show_user_auto = show_user;
|
||||
if (show_user) {
|
||||
add_user_auto (widget);
|
||||
} else {
|
||||
remove_user_auto (widget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char *
|
||||
gdm_user_chooser_widget_get_chosen_user_name (GdmUserChooserWidget *widget)
|
||||
{
|
||||
g_return_val_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget), NULL);
|
||||
|
||||
return gdm_chooser_widget_get_active_item (GDM_CHOOSER_WIDGET (widget));
|
||||
}
|
||||
|
||||
void
|
||||
gdm_user_chooser_widget_set_chosen_user_name (GdmUserChooserWidget *widget,
|
||||
const char *name)
|
||||
{
|
||||
g_return_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget));
|
||||
|
||||
gdm_chooser_widget_set_active_item (GDM_CHOOSER_WIDGET (widget), name);
|
||||
}
|
||||
|
||||
void
|
||||
gdm_user_chooser_widget_set_show_only_chosen (GdmUserChooserWidget *widget,
|
||||
gboolean show_only) {
|
||||
g_return_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget));
|
||||
|
||||
gdm_chooser_widget_set_hide_inactive_items (GDM_CHOOSER_WIDGET (widget),
|
||||
show_only);
|
||||
|
||||
}
|
||||
static void
|
||||
gdm_user_chooser_widget_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GdmUserChooserWidget *self;
|
||||
|
||||
self = GDM_USER_CHOOSER_WIDGET (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_SHOW_USER_AUTO:
|
||||
gdm_user_chooser_widget_set_show_user_auto (self, g_value_get_boolean (value));
|
||||
break;
|
||||
case PROP_SHOW_USER_GUEST:
|
||||
gdm_user_chooser_widget_set_show_user_guest (self, g_value_get_boolean (value));
|
||||
break;
|
||||
case PROP_SHOW_USER_OTHER:
|
||||
gdm_user_chooser_widget_set_show_user_other (self, g_value_get_boolean (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdm_user_chooser_widget_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GdmUserChooserWidget *self;
|
||||
|
||||
self = GDM_USER_CHOOSER_WIDGET (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_SHOW_USER_AUTO:
|
||||
g_value_set_boolean (value, self->priv->show_user_auto);
|
||||
break;
|
||||
case PROP_SHOW_USER_GUEST:
|
||||
g_value_set_boolean (value, self->priv->show_user_guest);
|
||||
break;
|
||||
case PROP_SHOW_USER_OTHER:
|
||||
g_value_set_boolean (value, self->priv->show_user_other);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
is_user_list_disabled (GdmUserChooserWidget *widget)
|
||||
{
|
||||
GConfClient *client;
|
||||
GError *error;
|
||||
gboolean result;
|
||||
|
||||
client = gconf_client_get_default ();
|
||||
error = NULL;
|
||||
result = gconf_client_get_bool (client, KEY_DISABLE_USER_LIST, &error);
|
||||
if (error != NULL) {
|
||||
g_debug ("GdmUserChooserWidget: unable to get disable-user-list configuration: %s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
g_object_unref (client);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
add_user (GdmUserChooserWidget *widget,
|
||||
GdmUser *user)
|
||||
{
|
||||
GdkPixbuf *pixbuf;
|
||||
char *tooltip;
|
||||
gboolean is_logged_in;
|
||||
int size;
|
||||
|
||||
if (!widget->priv->show_normal_users) {
|
||||
return;
|
||||
}
|
||||
|
||||
size = get_icon_height_for_widget (widget);
|
||||
pixbuf = gdm_user_render_icon (user, size);
|
||||
if (pixbuf == NULL && widget->priv->stock_person_pixbuf != NULL) {
|
||||
pixbuf = g_object_ref (widget->priv->stock_person_pixbuf);
|
||||
}
|
||||
|
||||
tooltip = g_strdup_printf (_("Log in as %s"),
|
||||
gdm_user_get_user_name (user));
|
||||
|
||||
is_logged_in = gdm_user_get_num_sessions (user) > 0;
|
||||
|
||||
g_debug ("GdmUserChooserWidget: User added name:%s logged-in:%d pixbuf:%p",
|
||||
gdm_user_get_user_name (user),
|
||||
is_logged_in,
|
||||
pixbuf);
|
||||
|
||||
gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (widget),
|
||||
gdm_user_get_user_name (user),
|
||||
pixbuf,
|
||||
gdm_user_get_real_name (user),
|
||||
tooltip,
|
||||
gdm_user_get_login_frequency (user),
|
||||
is_logged_in,
|
||||
FALSE);
|
||||
g_free (tooltip);
|
||||
|
||||
if (pixbuf != NULL) {
|
||||
g_object_unref (pixbuf);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_user_added (GdmUserManager *manager,
|
||||
GdmUser *user,
|
||||
GdmUserChooserWidget *widget)
|
||||
{
|
||||
/* wait for all users to be loaded */
|
||||
if (! widget->priv->loaded) {
|
||||
return;
|
||||
}
|
||||
add_user (widget, user);
|
||||
}
|
||||
|
||||
static void
|
||||
on_user_removed (GdmUserManager *manager,
|
||||
GdmUser *user,
|
||||
GdmUserChooserWidget *widget)
|
||||
{
|
||||
const char *user_name;
|
||||
|
||||
g_debug ("GdmUserChooserWidget: User removed: %s", gdm_user_get_user_name (user));
|
||||
/* wait for all users to be loaded */
|
||||
if (! widget->priv->loaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
user_name = gdm_user_get_user_name (user);
|
||||
|
||||
gdm_chooser_widget_remove_item (GDM_CHOOSER_WIDGET (widget),
|
||||
user_name);
|
||||
}
|
||||
|
||||
static void
|
||||
on_user_is_logged_in_changed (GdmUserManager *manager,
|
||||
GdmUser *user,
|
||||
GdmUserChooserWidget *widget)
|
||||
{
|
||||
const char *user_name;
|
||||
gboolean is_logged_in;
|
||||
|
||||
g_debug ("GdmUserChooserWidget: User logged in changed: %s", gdm_user_get_user_name (user));
|
||||
|
||||
user_name = gdm_user_get_user_name (user);
|
||||
is_logged_in = gdm_user_get_num_sessions (user) > 0;
|
||||
|
||||
gdm_chooser_widget_set_item_in_use (GDM_CHOOSER_WIDGET (widget),
|
||||
user_name,
|
||||
is_logged_in);
|
||||
}
|
||||
|
||||
static void
|
||||
on_user_login_frequency_changed (GdmUserManager *manager,
|
||||
GdmUser *user,
|
||||
GdmUserChooserWidget *widget)
|
||||
{
|
||||
const char *user_name;
|
||||
gulong freq;
|
||||
|
||||
g_debug ("GdmUserChooserWidget: User login frequency changed: %s", gdm_user_get_user_name (user));
|
||||
|
||||
user_name = gdm_user_get_user_name (user);
|
||||
freq = gdm_user_get_login_frequency (user);
|
||||
|
||||
gdm_chooser_widget_set_item_priority (GDM_CHOOSER_WIDGET (widget),
|
||||
user_name,
|
||||
freq);
|
||||
}
|
||||
|
||||
static void
|
||||
on_users_loaded (GdmUserManager *manager,
|
||||
GdmUserChooserWidget *widget)
|
||||
{
|
||||
GSList *users;
|
||||
|
||||
widget->priv->loaded = TRUE;
|
||||
|
||||
g_debug ("GdmUserChooserWidget: Users loaded");
|
||||
|
||||
users = gdm_user_manager_list_users (manager);
|
||||
while (users != NULL) {
|
||||
add_user (widget, users->data);
|
||||
users = g_slist_delete_link (users, users);
|
||||
}
|
||||
|
||||
gtk_widget_grab_focus (GTK_WIDGET (widget));
|
||||
|
||||
gdm_chooser_widget_loaded (GDM_CHOOSER_WIDGET (widget));
|
||||
}
|
||||
|
||||
static gboolean
|
||||
load_users (GdmUserChooserWidget *widget)
|
||||
{
|
||||
|
||||
if (widget->priv->show_normal_users) {
|
||||
widget->priv->manager = gdm_user_manager_ref_default ();
|
||||
g_signal_connect (widget->priv->manager,
|
||||
"user-added",
|
||||
G_CALLBACK (on_user_added),
|
||||
widget);
|
||||
g_signal_connect (widget->priv->manager,
|
||||
"user-removed",
|
||||
G_CALLBACK (on_user_removed),
|
||||
widget);
|
||||
g_signal_connect (widget->priv->manager,
|
||||
"users-loaded",
|
||||
G_CALLBACK (on_users_loaded),
|
||||
widget);
|
||||
g_signal_connect (widget->priv->manager,
|
||||
"user-is-logged-in-changed",
|
||||
G_CALLBACK (on_user_is_logged_in_changed),
|
||||
widget);
|
||||
g_signal_connect (widget->priv->manager,
|
||||
"user-login-frequency-changed",
|
||||
G_CALLBACK (on_user_login_frequency_changed),
|
||||
widget);
|
||||
} else {
|
||||
gdm_chooser_widget_loaded (GDM_CHOOSER_WIDGET (widget));
|
||||
}
|
||||
|
||||
widget->priv->load_idle_id = 0;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static GObject *
|
||||
gdm_user_chooser_widget_constructor (GType type,
|
||||
guint n_construct_properties,
|
||||
GObjectConstructParam *construct_properties)
|
||||
{
|
||||
GdmUserChooserWidget *widget;
|
||||
|
||||
widget = GDM_USER_CHOOSER_WIDGET (G_OBJECT_CLASS (gdm_user_chooser_widget_parent_class)->constructor (type,
|
||||
n_construct_properties,
|
||||
construct_properties));
|
||||
|
||||
widget->priv->show_normal_users = !is_user_list_disabled (widget);
|
||||
|
||||
widget->priv->load_idle_id = g_idle_add ((GSourceFunc)load_users, widget);
|
||||
|
||||
return G_OBJECT (widget);
|
||||
}
|
||||
|
||||
static void
|
||||
gdm_user_chooser_widget_dispose (GObject *object)
|
||||
{
|
||||
GdmUserChooserWidget *widget;
|
||||
|
||||
widget = GDM_USER_CHOOSER_WIDGET (object);
|
||||
|
||||
G_OBJECT_CLASS (gdm_user_chooser_widget_parent_class)->dispose (object);
|
||||
|
||||
if (widget->priv->load_idle_id > 0) {
|
||||
g_source_remove (widget->priv->load_idle_id);
|
||||
widget->priv->load_idle_id = 0;
|
||||
}
|
||||
|
||||
if (widget->priv->logged_in_pixbuf != NULL) {
|
||||
g_object_unref (widget->priv->logged_in_pixbuf);
|
||||
widget->priv->logged_in_pixbuf = NULL;
|
||||
}
|
||||
|
||||
if (widget->priv->stock_person_pixbuf != NULL) {
|
||||
g_object_unref (widget->priv->stock_person_pixbuf);
|
||||
widget->priv->stock_person_pixbuf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gdm_user_chooser_widget_class_init (GdmUserChooserWidgetClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->get_property = gdm_user_chooser_widget_get_property;
|
||||
object_class->set_property = gdm_user_chooser_widget_set_property;
|
||||
object_class->constructor = gdm_user_chooser_widget_constructor;
|
||||
object_class->dispose = gdm_user_chooser_widget_dispose;
|
||||
object_class->finalize = gdm_user_chooser_widget_finalize;
|
||||
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_SHOW_USER_AUTO,
|
||||
g_param_spec_boolean ("show-user-auto",
|
||||
"show user auto",
|
||||
"show user auto",
|
||||
FALSE,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_SHOW_USER_GUEST,
|
||||
g_param_spec_boolean ("show-user-guest",
|
||||
"show user guest",
|
||||
"show user guest",
|
||||
FALSE,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_SHOW_USER_OTHER,
|
||||
g_param_spec_boolean ("show-user-other",
|
||||
"show user other",
|
||||
"show user other",
|
||||
TRUE,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||
|
||||
g_type_class_add_private (klass, sizeof (GdmUserChooserWidgetPrivate));
|
||||
}
|
||||
|
||||
static GdkPixbuf *
|
||||
get_stock_person_pixbuf (GdmUserChooserWidget *widget)
|
||||
{
|
||||
GdkPixbuf *pixbuf;
|
||||
int size;
|
||||
|
||||
size = get_icon_height_for_widget (widget);
|
||||
|
||||
pixbuf = gtk_icon_theme_load_icon (widget->priv->icon_theme,
|
||||
DEFAULT_USER_ICON,
|
||||
size,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
return pixbuf;
|
||||
}
|
||||
|
||||
static GdkPixbuf *
|
||||
get_logged_in_pixbuf (GdmUserChooserWidget *widget)
|
||||
{
|
||||
GdkPixbuf *pixbuf;
|
||||
int size;
|
||||
|
||||
size = get_icon_height_for_widget (widget);
|
||||
|
||||
pixbuf = gtk_icon_theme_load_icon (widget->priv->icon_theme,
|
||||
"emblem-default",
|
||||
size / 3,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
return pixbuf;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
GdkPixbuf *old_icon;
|
||||
GdkPixbuf *new_icon;
|
||||
} IconUpdateData;
|
||||
|
||||
static gboolean
|
||||
update_icons (GdmChooserWidget *widget,
|
||||
const char *id,
|
||||
GdkPixbuf **image,
|
||||
char **name,
|
||||
char **comment,
|
||||
gulong *priority,
|
||||
gboolean *is_in_use,
|
||||
gboolean *is_separate,
|
||||
IconUpdateData *data)
|
||||
{
|
||||
if (data->old_icon == *image) {
|
||||
*image = data->new_icon;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
load_icons (GdmUserChooserWidget *widget)
|
||||
{
|
||||
GdkPixbuf *old_pixbuf;
|
||||
IconUpdateData data;
|
||||
|
||||
if (widget->priv->logged_in_pixbuf != NULL) {
|
||||
g_object_unref (widget->priv->logged_in_pixbuf);
|
||||
}
|
||||
widget->priv->logged_in_pixbuf = get_logged_in_pixbuf (widget);
|
||||
|
||||
old_pixbuf = widget->priv->stock_person_pixbuf;
|
||||
widget->priv->stock_person_pixbuf = get_stock_person_pixbuf (widget);
|
||||
/* update the icons in the model */
|
||||
data.old_icon = old_pixbuf;
|
||||
data.new_icon = widget->priv->stock_person_pixbuf;
|
||||
gdm_chooser_widget_update_foreach_item (GDM_CHOOSER_WIDGET (widget),
|
||||
(GdmChooserUpdateForeachFunc)update_icons,
|
||||
&data);
|
||||
if (old_pixbuf != NULL) {
|
||||
g_object_unref (old_pixbuf);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
on_icon_theme_changed (GtkIconTheme *icon_theme,
|
||||
GdmUserChooserWidget *widget)
|
||||
{
|
||||
g_debug ("GdmUserChooserWidget: icon theme changed");
|
||||
load_icons (widget);
|
||||
}
|
||||
|
||||
static void
|
||||
setup_icons (GdmUserChooserWidget *widget)
|
||||
{
|
||||
if (gtk_widget_has_screen (GTK_WIDGET (widget))) {
|
||||
widget->priv->icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (widget)));
|
||||
} else {
|
||||
widget->priv->icon_theme = gtk_icon_theme_get_default ();
|
||||
}
|
||||
|
||||
if (widget->priv->icon_theme != NULL) {
|
||||
g_signal_connect (widget->priv->icon_theme,
|
||||
"changed",
|
||||
G_CALLBACK (on_icon_theme_changed),
|
||||
widget);
|
||||
}
|
||||
|
||||
load_icons (widget);
|
||||
}
|
||||
|
||||
static void
|
||||
gdm_user_chooser_widget_init (GdmUserChooserWidget *widget)
|
||||
{
|
||||
widget->priv = GDM_USER_CHOOSER_WIDGET_GET_PRIVATE (widget);
|
||||
|
||||
gdm_chooser_widget_set_separator_position (GDM_CHOOSER_WIDGET (widget),
|
||||
GDM_CHOOSER_WIDGET_POSITION_BOTTOM);
|
||||
gdm_chooser_widget_set_in_use_message (GDM_CHOOSER_WIDGET (widget),
|
||||
_("Currently logged in"));
|
||||
|
||||
setup_icons (widget);
|
||||
}
|
||||
|
||||
static void
|
||||
gdm_user_chooser_widget_finalize (GObject *object)
|
||||
{
|
||||
GdmUserChooserWidget *widget;
|
||||
|
||||
g_return_if_fail (object != NULL);
|
||||
g_return_if_fail (GDM_IS_USER_CHOOSER_WIDGET (object));
|
||||
|
||||
widget = GDM_USER_CHOOSER_WIDGET (object);
|
||||
|
||||
g_return_if_fail (widget->priv != NULL);
|
||||
|
||||
G_OBJECT_CLASS (gdm_user_chooser_widget_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gdm_user_chooser_widget_new (void)
|
||||
{
|
||||
GObject *object;
|
||||
|
||||
object = g_object_new (GDM_TYPE_USER_CHOOSER_WIDGET,
|
||||
NULL);
|
||||
|
||||
return GTK_WIDGET (object);
|
||||
}
|
||||
70
src/gdmuser/gdm-user-chooser-widget.h
Normal file
70
src/gdmuser/gdm-user-chooser-widget.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
|
||||
*
|
||||
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __GDM_USER_CHOOSER_WIDGET_H
|
||||
#define __GDM_USER_CHOOSER_WIDGET_H
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
#include "gdm-chooser-widget.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GDM_TYPE_USER_CHOOSER_WIDGET (gdm_user_chooser_widget_get_type ())
|
||||
#define GDM_USER_CHOOSER_WIDGET(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_USER_CHOOSER_WIDGET, GdmUserChooserWidget))
|
||||
#define GDM_USER_CHOOSER_WIDGET_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_USER_CHOOSER_WIDGET, GdmUserChooserWidgetClass))
|
||||
#define GDM_IS_USER_CHOOSER_WIDGET(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_USER_CHOOSER_WIDGET))
|
||||
#define GDM_IS_USER_CHOOSER_WIDGET_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_USER_CHOOSER_WIDGET))
|
||||
#define GDM_USER_CHOOSER_WIDGET_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_USER_CHOOSER_WIDGET, GdmUserChooserWidgetClass))
|
||||
|
||||
typedef struct GdmUserChooserWidgetPrivate GdmUserChooserWidgetPrivate;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GdmChooserWidget parent;
|
||||
GdmUserChooserWidgetPrivate *priv;
|
||||
} GdmUserChooserWidget;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GdmChooserWidgetClass parent_class;
|
||||
} GdmUserChooserWidgetClass;
|
||||
|
||||
#define GDM_USER_CHOOSER_USER_OTHER "__other"
|
||||
#define GDM_USER_CHOOSER_USER_GUEST "__guest"
|
||||
#define GDM_USER_CHOOSER_USER_AUTO "__auto"
|
||||
|
||||
GType gdm_user_chooser_widget_get_type (void);
|
||||
GtkWidget * gdm_user_chooser_widget_new (void);
|
||||
|
||||
char * gdm_user_chooser_widget_get_chosen_user_name (GdmUserChooserWidget *widget);
|
||||
void gdm_user_chooser_widget_set_chosen_user_name (GdmUserChooserWidget *widget,
|
||||
const char *user_name);
|
||||
void gdm_user_chooser_widget_set_show_only_chosen (GdmUserChooserWidget *widget,
|
||||
gboolean show_only);
|
||||
void gdm_user_chooser_widget_set_show_user_other (GdmUserChooserWidget *widget,
|
||||
gboolean show);
|
||||
void gdm_user_chooser_widget_set_show_user_guest (GdmUserChooserWidget *widget,
|
||||
gboolean show);
|
||||
void gdm_user_chooser_widget_set_show_user_auto (GdmUserChooserWidget *widget,
|
||||
gboolean show);
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GDM_USER_CHOOSER_WIDGET_H */
|
||||
@@ -35,8 +35,7 @@
|
||||
#endif /* HAVE_PATHS_H */
|
||||
|
||||
#include <glib.h>
|
||||
/* Note on sync with gdm; need to use -lib here */
|
||||
#include <glib/gi18n-lib.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include <glib-object.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
@@ -20,14 +20,12 @@
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <float.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* Note on sync with gdm; need to use -lib here */
|
||||
#include <glib/gi18n-lib.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <gio/gio.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
@@ -240,8 +238,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)));
|
||||
@@ -413,16 +411,13 @@ _gdm_user_update (GdmUser *user,
|
||||
/* Display Name */
|
||||
if (pwent->pw_gecos && pwent->pw_gecos[0] != '\0') {
|
||||
gchar *first_comma;
|
||||
gchar *real_name_utf8;
|
||||
|
||||
real_name_utf8 = g_locale_to_utf8 (pwent->pw_gecos, -1, NULL, NULL, NULL);
|
||||
|
||||
first_comma = strchr (real_name_utf8, ',');
|
||||
first_comma = strchr (pwent->pw_gecos, ',');
|
||||
if (first_comma) {
|
||||
real_name = g_strndup (real_name_utf8, first_comma - real_name_utf8);
|
||||
g_free (real_name_utf8);
|
||||
real_name = g_strndup (pwent->pw_gecos,
|
||||
(first_comma - pwent->pw_gecos));
|
||||
} else {
|
||||
real_name = real_name_utf8;
|
||||
real_name = g_strdup (pwent->pw_gecos);
|
||||
}
|
||||
|
||||
if (real_name[0] == '\0') {
|
||||
@@ -886,7 +881,7 @@ curved_rectangle (cairo_t *cr,
|
||||
x1 = x0 + width;
|
||||
y1 = y0 + height;
|
||||
|
||||
if (width < FLT_EPSILON || height < FLT_EPSILON) {
|
||||
if (!width || !height) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1161,8 +1156,8 @@ gdm_user_render_icon (GdmUser *user,
|
||||
} else {
|
||||
pixbuf = NULL;
|
||||
}
|
||||
g_free (path);
|
||||
out:
|
||||
g_free (path);
|
||||
|
||||
if (pixbuf != NULL) {
|
||||
framed = frame_pixbuf (pixbuf);
|
||||
|
||||
@@ -153,9 +153,6 @@ 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
|
||||
|
||||
156
src/gnome-shell.in
Normal file → Executable file
156
src/gnome-shell.in
Normal file → Executable file
@@ -14,6 +14,43 @@ import termios
|
||||
import time
|
||||
import errno
|
||||
|
||||
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.")
|
||||
atexit.register(shutil.rmtree, tmpdir)
|
||||
@@ -85,27 +122,25 @@ def start_shell():
|
||||
top_dir = os.path.dirname(bin_dir)
|
||||
plugin = os.path.join(top_dir, 'src', 'libgnome-shell.la')
|
||||
typelib_dir = os.path.join(top_dir, "src")
|
||||
taskpanel_dir = os.path.join(top_dir, "src")
|
||||
js_dir = os.path.join(top_dir, "js")
|
||||
data_dir = os.path.join(top_dir, "data")
|
||||
else:
|
||||
running_from_source_tree = False
|
||||
plugin = 'libgnome-shell'
|
||||
js_dir = os.path.join('@pkgdatadir@', 'js')
|
||||
taskpanel_dir = '@libexecdir@'
|
||||
|
||||
# Set up environment
|
||||
env = dict(os.environ)
|
||||
env.update({'GNOME_SHELL_JS' : '@GJS_JS_DIR@:@GJS_JS_NATIVE_DIR@:' + js_dir,
|
||||
'PATH' : '@MUTTER_BIN_DIR@:' + os.environ.get('PATH', ''),
|
||||
'PATH' : '@MUTTER_BIN_DIR@:' + os.environ.get('PATH', '') + ':' + taskpanel_dir,
|
||||
'GNOME_DISABLE_CRASH_DIALOG' : '1'})
|
||||
|
||||
if running_from_source_tree:
|
||||
env.update({'GNOME_SHELL_DATADIR' : data_dir,
|
||||
'GI_TYPELIB_PATH' : typelib_dir})
|
||||
|
||||
jhbuild_gconf_source = os.path.join('@sysconfdir@', 'gconf/2/path.jhbuild')
|
||||
if os.path.exists(jhbuild_gconf_source):
|
||||
env['GCONF_DEFAULT_SOURCE_PATH'] = jhbuild_gconf_source
|
||||
|
||||
# Work around Ubuntu xulrunner bug,
|
||||
# http://bugzilla.gnome.org/show_bug.cgi?id=573413
|
||||
pkgconfig = subprocess.Popen(['pkg-config', '--variable=sdkdir', 'mozilla-js'],
|
||||
@@ -152,47 +187,11 @@ def start_shell():
|
||||
else:
|
||||
args = []
|
||||
|
||||
args.extend(['mutter', '--mutter-plugins=' + plugin])
|
||||
if options.replace:
|
||||
args.append('--replace')
|
||||
args.extend(['mutter', '--mutter-plugins=' + plugin, '--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
|
||||
|
||||
@@ -205,8 +204,6 @@ 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,6 +224,18 @@ elif options.debug:
|
||||
if options.wide:
|
||||
options.geometry = "1280x800"
|
||||
|
||||
metacity_pid = pidof("metacity")
|
||||
compiz_pid = pidof("compiz.real") or pidof("compiz")
|
||||
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.
|
||||
@@ -237,7 +246,7 @@ if 'GNOME_SHELL_DISABLE_TFP' in os.environ and \
|
||||
use_tfp = False
|
||||
else:
|
||||
# tfp does not work correctly in Xephyr
|
||||
use_tfp = not options.xephyr
|
||||
use_tfp = not run_in_xephyr
|
||||
|
||||
if options.verbose:
|
||||
print "Starting shell"
|
||||
@@ -247,25 +256,21 @@ 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 options.xephyr:
|
||||
xephyr = start_xephyr()
|
||||
# This makes us not grab the org.gnome.Panel name
|
||||
os.environ['GNOME_SHELL_NO_REPLACE_PANEL'] = '1'
|
||||
shell = start_shell()
|
||||
if run_in_xephyr:
|
||||
shell = start_xephyr()
|
||||
start_shell()
|
||||
else:
|
||||
xephyr = None
|
||||
if gnome_panel_pid is not None:
|
||||
kill_gnome_panel(gnome_panel_pid)
|
||||
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:
|
||||
@@ -273,29 +278,24 @@ 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.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 options.xephyr and options.replace and not normal_exit:
|
||||
restore_gnome()
|
||||
if not run_in_xephyr:
|
||||
# Restart gnome-panel and window manager
|
||||
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_pid:
|
||||
if options.verbose:
|
||||
print "Restarting gnome-panel"
|
||||
subprocess.Popen(["/usr/bin/gnome-panel"])
|
||||
|
||||
90
src/gnomeshell-taskpanel.c
Normal file
90
src/gnomeshell-taskpanel.c
Normal file
@@ -0,0 +1,90 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include "shell-panel-window.h"
|
||||
#include <libwnck/libwnck.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <dbus/dbus-glib.h>
|
||||
|
||||
static void
|
||||
on_name_owner_changed (DBusGProxy *proxy,
|
||||
const char *name,
|
||||
const char *prev_owner,
|
||||
const char *new_owner,
|
||||
gpointer user_data)
|
||||
{
|
||||
if (strcmp (name, "org.gnome.Shell") == 0 && new_owner[0] == '\0')
|
||||
exit (0);
|
||||
}
|
||||
|
||||
static void
|
||||
monitor_main_shell (const char *shell_name)
|
||||
{
|
||||
DBusGConnection *session;
|
||||
DBusGProxy *driver;
|
||||
GError *error = NULL;
|
||||
gboolean have_shell;
|
||||
|
||||
session = dbus_g_bus_get (DBUS_BUS_SESSION, NULL);
|
||||
|
||||
driver = dbus_g_proxy_new_for_name (session,
|
||||
DBUS_SERVICE_DBUS,
|
||||
DBUS_PATH_DBUS,
|
||||
DBUS_INTERFACE_DBUS);
|
||||
|
||||
if (!dbus_g_proxy_call (driver, "NameHasOwner", &error, G_TYPE_STRING,
|
||||
shell_name, G_TYPE_INVALID, G_TYPE_BOOLEAN,
|
||||
&have_shell, G_TYPE_INVALID))
|
||||
{
|
||||
/* Shouldn't happen */
|
||||
exit (1);
|
||||
}
|
||||
if (!have_shell)
|
||||
{
|
||||
/* Shell doesn't exist; either crashed or was restarted. Just abort. */
|
||||
exit (0);
|
||||
}
|
||||
|
||||
dbus_g_proxy_add_signal (driver,
|
||||
"NameOwnerChanged",
|
||||
G_TYPE_STRING,
|
||||
G_TYPE_STRING,
|
||||
G_TYPE_STRING,
|
||||
G_TYPE_INVALID);
|
||||
|
||||
dbus_g_proxy_connect_signal (driver,
|
||||
"NameOwnerChanged",
|
||||
G_CALLBACK (on_name_owner_changed),
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
ShellPanelWindow *panel;
|
||||
WnckScreen *screen;
|
||||
WnckTasklist *tasks;
|
||||
|
||||
gtk_init (&argc, &argv);
|
||||
|
||||
if (argc != 2) {
|
||||
g_printerr ("Usage: gnomeshell-taskpanel [PARENT_DBUS_SERVICE]\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
monitor_main_shell (argv[1]);
|
||||
|
||||
panel = shell_panel_window_new ();
|
||||
|
||||
screen = wnck_screen_get_default();
|
||||
tasks = WNCK_TASKLIST (wnck_tasklist_new (screen));
|
||||
|
||||
gtk_container_add (GTK_CONTAINER (panel), GTK_WIDGET (tasks));
|
||||
|
||||
gtk_widget_show_all (GTK_WIDGET (panel));
|
||||
|
||||
gtk_main ();
|
||||
|
||||
exit (0);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -5,9 +5,6 @@
|
||||
#include <glib-object.h>
|
||||
#include <glib.h>
|
||||
|
||||
#include "window.h"
|
||||
#include "shell-app-system.h"
|
||||
|
||||
/*
|
||||
* This object provides monitoring of system application directories (.desktop files)
|
||||
* and activity-based statistics about applications usage
|
||||
@@ -30,34 +27,23 @@ struct _ShellAppMonitorClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (*apps_changed)(ShellAppMonitor *menuwrapper,
|
||||
gpointer data);
|
||||
};
|
||||
|
||||
GType shell_app_monitor_get_type (void) G_GNUC_CONST;
|
||||
|
||||
ShellAppMonitor* shell_app_monitor_get_default(void);
|
||||
|
||||
ShellAppInfo *shell_app_monitor_get_window_app (ShellAppMonitor *monitor, MetaWindow *metawin);
|
||||
/* Get the most popular applications for a given activity */
|
||||
GSList *shell_app_monitor_get_most_used_apps (ShellAppMonitor *monitor,
|
||||
int activity,
|
||||
gint number);
|
||||
|
||||
GList *shell_app_monitor_get_most_used_apps (ShellAppMonitor *monitor,
|
||||
const char *context,
|
||||
gint number);
|
||||
|
||||
GSList *shell_app_monitor_get_windows_for_app (ShellAppMonitor *monitor, const char *appid);
|
||||
guint shell_app_monitor_get_window_count (ShellAppMonitor *monitor, const char *appid);
|
||||
|
||||
/* Get whatever's running right now */
|
||||
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);
|
||||
GList *shell_app_monitor_get_running_app_ids (ShellAppMonitor *monitor);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
@@ -4,28 +4,14 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gio/gdesktopappinfo.h>
|
||||
#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"
|
||||
#include "display.h"
|
||||
|
||||
#define GMENU_I_KNOW_THIS_IS_UNSTABLE
|
||||
#include <gmenu-tree.h>
|
||||
|
||||
#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,
|
||||
|
||||
@@ -43,13 +29,11 @@ struct _ShellAppSystemPrivate {
|
||||
GMenuTree *apps_tree;
|
||||
GMenuTree *settings_tree;
|
||||
|
||||
GHashTable *app_id_to_app;
|
||||
|
||||
GSList *cached_app_menus; /* ShellAppMenuEntry */
|
||||
|
||||
GSList *cached_settings; /* ShellAppInfo */
|
||||
GSList *cached_setting_ids; /* utf8 */
|
||||
|
||||
GList *cached_favorites; /* utf8 */
|
||||
GHashTable *cached_favorites; /* <utf8,integer> */
|
||||
|
||||
gint app_monitor_id;
|
||||
};
|
||||
@@ -62,107 +46,6 @@ static void reread_favorite_apps (ShellAppSystem *system);
|
||||
|
||||
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_WINDOW
|
||||
} ShellAppInfoType;
|
||||
|
||||
struct _ShellAppInfo {
|
||||
ShellAppInfoType type;
|
||||
|
||||
/* We need this for two reasons. First, GKeyFile doesn't have a refcount.
|
||||
* http://bugzilla.gnome.org/show_bug.cgi?id=590808
|
||||
*
|
||||
* But more generally we'll always need it so we know when to free this
|
||||
* structure (short of weak references on each item).
|
||||
*/
|
||||
guint refcount;
|
||||
|
||||
GMenuTreeItem *entry;
|
||||
|
||||
GKeyFile *keyfile;
|
||||
char *keyfile_path;
|
||||
|
||||
MetaWindow *window;
|
||||
char *window_id;
|
||||
};
|
||||
|
||||
ShellAppInfo*
|
||||
shell_app_info_ref (ShellAppInfo *info)
|
||||
{
|
||||
info->refcount++;
|
||||
return info;
|
||||
}
|
||||
|
||||
void
|
||||
shell_app_info_unref (ShellAppInfo *info)
|
||||
{
|
||||
if (--info->refcount > 0)
|
||||
return;
|
||||
switch (info->type)
|
||||
{
|
||||
case SHELL_APP_INFO_TYPE_ENTRY:
|
||||
gmenu_tree_item_unref (info->entry);
|
||||
break;
|
||||
case SHELL_APP_INFO_TYPE_DESKTOP_FILE:
|
||||
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);
|
||||
}
|
||||
|
||||
static ShellAppInfo *
|
||||
shell_app_info_new_from_tree_item (GMenuTreeItem *item)
|
||||
{
|
||||
ShellAppInfo *info;
|
||||
|
||||
if (!item)
|
||||
return NULL;
|
||||
|
||||
info = g_slice_alloc (sizeof (ShellAppInfo));
|
||||
info->type = SHELL_APP_INFO_TYPE_ENTRY;
|
||||
info->refcount = 1;
|
||||
info->entry = gmenu_tree_item_ref (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)
|
||||
{
|
||||
ShellAppInfo *info;
|
||||
|
||||
info = g_slice_alloc (sizeof (ShellAppInfo));
|
||||
info->type = SHELL_APP_INFO_TYPE_DESKTOP_FILE;
|
||||
info->refcount = 1;
|
||||
info->keyfile = keyfile;
|
||||
info->keyfile_path = g_strdup (path);
|
||||
return info;
|
||||
}
|
||||
|
||||
static gpointer
|
||||
shell_app_menu_entry_copy (gpointer entryp)
|
||||
{
|
||||
@@ -222,15 +105,11 @@ shell_app_system_init (ShellAppSystem *self)
|
||||
SHELL_TYPE_APP_SYSTEM,
|
||||
ShellAppSystemPrivate);
|
||||
|
||||
/* The key is owned by the value */
|
||||
priv->app_id_to_app = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
NULL, (GDestroyNotify) shell_app_info_unref);
|
||||
priv->cached_favorites = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
(GDestroyNotify)g_free,
|
||||
NULL);
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
priv->apps_tree = gmenu_tree_lookup ("applications.menu", GMENU_TREE_FLAGS_INCLUDE_NODISPLAY);
|
||||
priv->apps_tree = gmenu_tree_lookup ("applications.menu", GMENU_TREE_FLAGS_NONE);
|
||||
priv->settings_tree = gmenu_tree_lookup ("settings.menu", GMENU_TREE_FLAGS_NONE);
|
||||
|
||||
gmenu_tree_add_monitor (priv->apps_tree, on_tree_changed, self);
|
||||
@@ -257,17 +136,15 @@ shell_app_system_finalize (GObject *object)
|
||||
gmenu_tree_unref (priv->apps_tree);
|
||||
gmenu_tree_unref (priv->settings_tree);
|
||||
|
||||
g_hash_table_destroy (priv->app_id_to_app);
|
||||
|
||||
g_slist_foreach (priv->cached_app_menus, (GFunc)shell_app_menu_entry_free, NULL);
|
||||
g_slist_free (priv->cached_app_menus);
|
||||
priv->cached_app_menus = NULL;
|
||||
|
||||
g_slist_foreach (priv->cached_settings, (GFunc)shell_app_info_unref, NULL);
|
||||
g_slist_free (priv->cached_settings);
|
||||
priv->cached_settings = NULL;
|
||||
g_slist_foreach (priv->cached_setting_ids, (GFunc)g_free, NULL);
|
||||
g_slist_free (priv->cached_setting_ids);
|
||||
priv->cached_setting_ids = NULL;
|
||||
|
||||
g_list_free (priv->cached_favorites);
|
||||
g_hash_table_destroy (priv->cached_favorites);
|
||||
|
||||
gconf_client_notify_remove (gconf_client_get_default (), priv->app_monitor_id);
|
||||
|
||||
@@ -319,7 +196,7 @@ reread_directories (ShellAppSystem *self, GSList **cache, GMenuTree *tree)
|
||||
|
||||
static GSList *
|
||||
gather_entries_recurse (ShellAppSystem *monitor,
|
||||
GSList *apps,
|
||||
GSList *ids,
|
||||
GMenuTreeDirectory *root)
|
||||
{
|
||||
GSList *contents;
|
||||
@@ -334,14 +211,15 @@ gather_entries_recurse (ShellAppSystem *monitor,
|
||||
{
|
||||
case GMENU_TREE_ITEM_ENTRY:
|
||||
{
|
||||
ShellAppInfo *app = shell_app_info_new_from_tree_item (item);
|
||||
apps = g_slist_prepend (apps, app);
|
||||
GMenuTreeEntry *entry = (GMenuTreeEntry *)item;
|
||||
const char *id = gmenu_tree_entry_get_desktop_file_id (entry);
|
||||
ids = g_slist_prepend (ids, g_strdup (id));
|
||||
}
|
||||
break;
|
||||
case GMENU_TREE_ITEM_DIRECTORY:
|
||||
{
|
||||
GMenuTreeDirectory *dir = (GMenuTreeDirectory*)item;
|
||||
apps = gather_entries_recurse (monitor, apps, dir);
|
||||
ids = gather_entries_recurse (monitor, ids, dir);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@@ -352,7 +230,7 @@ gather_entries_recurse (ShellAppSystem *monitor,
|
||||
|
||||
g_slist_free (contents);
|
||||
|
||||
return apps;
|
||||
return ids;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -364,7 +242,7 @@ reread_entries (ShellAppSystem *self,
|
||||
|
||||
trunk = gmenu_tree_get_root_directory (tree);
|
||||
|
||||
g_slist_foreach (*cache, (GFunc)shell_app_info_unref, NULL);
|
||||
g_slist_foreach (*cache, (GFunc)g_free, NULL);
|
||||
g_slist_free (*cache);
|
||||
*cache = NULL;
|
||||
|
||||
@@ -373,41 +251,11 @@ reread_entries (ShellAppSystem *self,
|
||||
gmenu_tree_item_unref (trunk);
|
||||
}
|
||||
|
||||
static void
|
||||
cache_by_id (ShellAppSystem *self, GSList *apps, gboolean ref)
|
||||
{
|
||||
GSList *iter;
|
||||
|
||||
for (iter = apps; iter; iter = iter->next)
|
||||
{
|
||||
ShellAppInfo *info = iter->data;
|
||||
if (ref)
|
||||
shell_app_info_ref (info);
|
||||
/* the name is owned by the info itself */
|
||||
g_hash_table_insert (self->priv->app_id_to_app, (char*)shell_app_info_get_id (info),
|
||||
info);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
reread_menus (ShellAppSystem *self)
|
||||
{
|
||||
GSList *apps;
|
||||
GMenuTreeDirectory *trunk;
|
||||
|
||||
reread_directories (self, &(self->priv->cached_app_menus), self->priv->apps_tree);
|
||||
|
||||
reread_entries (self, &(self->priv->cached_settings), self->priv->settings_tree);
|
||||
|
||||
/* Now loop over applications.menu and settings.menu, inserting each by desktop file
|
||||
* ID into a hash */
|
||||
g_hash_table_remove_all (self->priv->app_id_to_app);
|
||||
trunk = gmenu_tree_get_root_directory (self->priv->apps_tree);
|
||||
apps = gather_entries_recurse (self, NULL, trunk);
|
||||
gmenu_tree_item_unref (trunk);
|
||||
cache_by_id (self, apps, FALSE);
|
||||
g_slist_free (apps);
|
||||
cache_by_id (self, self->priv->cached_settings, TRUE);
|
||||
reread_entries (self, &(self->priv->cached_setting_ids), self->priv->settings_tree);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -420,13 +268,12 @@ on_tree_changed (GMenuTree *monitor, gpointer user_data)
|
||||
reread_menus (self);
|
||||
}
|
||||
|
||||
static GList *
|
||||
convert_gconf_value_string_list_to_list_uniquify (GConfValue *value )
|
||||
static void
|
||||
copy_gconf_value_string_list_to_hashset (GConfValue *value,
|
||||
GHashTable *dest)
|
||||
{
|
||||
GSList *list;
|
||||
GSList *tmp;
|
||||
GList *result = NULL;
|
||||
GHashTable *tmp_table = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
|
||||
list = gconf_value_get_list (value);
|
||||
|
||||
@@ -436,16 +283,8 @@ convert_gconf_value_string_list_to_list_uniquify (GConfValue *value )
|
||||
char *str = g_strdup (gconf_value_get_string (value));
|
||||
if (!str)
|
||||
continue;
|
||||
if (g_hash_table_lookup (tmp_table, str))
|
||||
{
|
||||
g_free (str);
|
||||
continue;
|
||||
}
|
||||
g_hash_table_insert (tmp_table, str, GUINT_TO_POINTER(1));
|
||||
result = g_list_prepend (result, str);
|
||||
g_hash_table_insert (dest, str, GUINT_TO_POINTER(1));
|
||||
}
|
||||
g_hash_table_destroy (tmp_table);
|
||||
return g_list_reverse (result);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -459,9 +298,8 @@ reread_favorite_apps (ShellAppSystem *system)
|
||||
if (!(val && val->type == GCONF_VALUE_LIST && gconf_value_get_list_type (val) == GCONF_VALUE_STRING))
|
||||
return;
|
||||
|
||||
g_list_foreach (system->priv->cached_favorites, (GFunc) g_free, NULL);
|
||||
g_list_free (system->priv->cached_favorites);
|
||||
system->priv->cached_favorites = convert_gconf_value_string_list_to_list_uniquify (val);
|
||||
g_hash_table_remove_all (system->priv->cached_favorites);
|
||||
copy_gconf_value_string_list_to_hashset (val, system->priv->cached_favorites);
|
||||
|
||||
gconf_value_free (val);
|
||||
}
|
||||
@@ -477,19 +315,6 @@ on_favorite_apps_changed (GConfClient *client,
|
||||
g_signal_emit (G_OBJECT (system), signals[FAVORITES_CHANGED], 0);
|
||||
}
|
||||
|
||||
GType
|
||||
shell_app_info_get_type (void)
|
||||
{
|
||||
static GType gtype = G_TYPE_INVALID;
|
||||
if (gtype == G_TYPE_INVALID)
|
||||
{
|
||||
gtype = g_boxed_type_register_static ("ShellAppInfo",
|
||||
(GBoxedCopyFunc)shell_app_info_ref,
|
||||
(GBoxedFreeFunc)shell_app_info_unref);
|
||||
}
|
||||
return gtype;
|
||||
}
|
||||
|
||||
GType
|
||||
shell_app_menu_entry_get_type (void)
|
||||
{
|
||||
@@ -509,7 +334,7 @@ shell_app_menu_entry_get_type (void)
|
||||
* Traverses a toplevel menu, and returns all items under it. Nested items
|
||||
* are flattened.
|
||||
*
|
||||
* Return value: (transfer container) (element-type ShellAppInfo): List of applications
|
||||
* Return value: (transfer full) (element-type utf8): List of desktop file ids
|
||||
*/
|
||||
GSList *
|
||||
shell_app_system_get_applications_for_menu (ShellAppSystem *monitor,
|
||||
@@ -534,7 +359,7 @@ shell_app_system_get_applications_for_menu (ShellAppSystem *monitor,
|
||||
/**
|
||||
* shell_app_system_get_menus:
|
||||
*
|
||||
* Returns a list of toplevel #ShellAppMenuEntry items
|
||||
* Returns a list of toplevel menu names, like "Accessories", "Programming", etc.
|
||||
*
|
||||
* Return value: (transfer none) (element-type AppMenuEntry): List of toplevel menus
|
||||
*/
|
||||
@@ -547,14 +372,14 @@ shell_app_system_get_menus (ShellAppSystem *monitor)
|
||||
/**
|
||||
* shell_app_system_get_all_settings:
|
||||
*
|
||||
* Returns a list of application items under "settings.menu".
|
||||
* Returns a list of all desktop file ids under "settings.menu".
|
||||
*
|
||||
* Return value: (transfer none) (element-type ShellAppInfo): List of applications
|
||||
* Return value: (transfer none) (element-type utf8): List of desktop file ids
|
||||
*/
|
||||
GSList *
|
||||
shell_app_system_get_all_settings (ShellAppSystem *monitor)
|
||||
{
|
||||
return monitor->priv->cached_settings;
|
||||
return monitor->priv->cached_setting_ids;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -579,12 +404,12 @@ shell_app_system_get_default ()
|
||||
* Return the list of applications which have been explicitly added to the
|
||||
* favorites.
|
||||
*
|
||||
* Return value: (transfer none) (element-type utf8): List of favorite application ids
|
||||
* Return value: (transfer container) (element-type utf8): List of favorite application ids
|
||||
*/
|
||||
GList *
|
||||
shell_app_system_get_favorites (ShellAppSystem *system)
|
||||
{
|
||||
return system->priv->cached_favorites;
|
||||
return g_hash_table_get_keys (system->priv->cached_favorites);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -611,18 +436,17 @@ shell_app_system_add_favorite (ShellAppSystem *system, const char *id)
|
||||
{
|
||||
GConfClient *client = gconf_client_get_default ();
|
||||
GConfValue *val;
|
||||
GList *iter;
|
||||
|
||||
iter = g_list_find_custom (system->priv->cached_favorites, id, (GCompareFunc)strcmp);
|
||||
if (iter)
|
||||
return;
|
||||
GList *favorites;
|
||||
|
||||
val = gconf_value_new (GCONF_VALUE_LIST);
|
||||
gconf_value_set_list_type (val, GCONF_VALUE_STRING);
|
||||
|
||||
system->priv->cached_favorites = g_list_append (system->priv->cached_favorites, g_strdup (id));
|
||||
g_hash_table_insert (system->priv->cached_favorites, g_strdup (id), GUINT_TO_POINTER (1));
|
||||
|
||||
favorites = g_hash_table_get_keys (system->priv->cached_favorites);
|
||||
set_gconf_value_string_list (val, favorites);
|
||||
g_list_free (favorites);
|
||||
|
||||
set_gconf_value_string_list (val, system->priv->cached_favorites);
|
||||
gconf_client_set (client, SHELL_APP_FAVORITES_KEY, val, NULL);
|
||||
}
|
||||
|
||||
@@ -631,416 +455,102 @@ shell_app_system_remove_favorite (ShellAppSystem *system, const char *id)
|
||||
{
|
||||
GConfClient *client = gconf_client_get_default ();
|
||||
GConfValue *val;
|
||||
GList *iter;
|
||||
GList *favorites;
|
||||
|
||||
iter = g_list_find_custom (system->priv->cached_favorites, id, (GCompareFunc)strcmp);
|
||||
if (!iter)
|
||||
if (!g_hash_table_remove (system->priv->cached_favorites, id))
|
||||
return;
|
||||
g_free (iter->data);
|
||||
system->priv->cached_favorites = g_list_delete_link (system->priv->cached_favorites, iter);
|
||||
|
||||
val = gconf_value_new (GCONF_VALUE_LIST);
|
||||
gconf_value_set_list_type (val, GCONF_VALUE_STRING);
|
||||
|
||||
set_gconf_value_string_list (val, system->priv->cached_favorites);
|
||||
favorites = g_hash_table_get_keys (system->priv->cached_favorites);
|
||||
set_gconf_value_string_list (val, favorites);
|
||||
g_list_free (favorites);
|
||||
|
||||
gconf_client_set (client, SHELL_APP_FAVORITES_KEY, val, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_app_system_lookup_app:
|
||||
*
|
||||
* Return value: (transfer full): The #ShellAppInfo for id, or %NULL if none
|
||||
*/
|
||||
ShellAppInfo *
|
||||
shell_app_system_lookup_cached_app (ShellAppSystem *self, const char *id)
|
||||
static gboolean
|
||||
desktop_id_exists (ShellAppSystem *system,
|
||||
const char *target_id,
|
||||
GMenuTreeDirectory *root)
|
||||
{
|
||||
ShellAppInfo *info;
|
||||
gboolean found = FALSE;
|
||||
GSList *contents, *iter;
|
||||
|
||||
info = g_hash_table_lookup (self->priv->app_id_to_app, id);
|
||||
if (info)
|
||||
shell_app_info_ref (info);
|
||||
return info;
|
||||
}
|
||||
contents = gmenu_tree_directory_get_contents (root);
|
||||
|
||||
ShellAppInfo *
|
||||
shell_app_system_load_from_desktop_file (ShellAppSystem *system,
|
||||
const char *filename,
|
||||
GError **error)
|
||||
{
|
||||
ShellAppInfo *appinfo;
|
||||
GKeyFile *keyfile;
|
||||
char *full_path = NULL;
|
||||
gboolean success;
|
||||
|
||||
keyfile = g_key_file_new ();
|
||||
|
||||
if (strchr (filename, '/') != NULL)
|
||||
for (iter = contents; iter; iter = iter->next)
|
||||
{
|
||||
success = g_key_file_load_from_file (keyfile, filename, G_KEY_FILE_NONE, error);
|
||||
full_path = g_strdup (filename);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *app_path = g_build_filename ("applications", filename, NULL);
|
||||
success = g_key_file_load_from_data_dirs (keyfile, app_path, &full_path,
|
||||
G_KEY_FILE_NONE, error);
|
||||
g_free (app_path);
|
||||
GMenuTreeItem *item = iter->data;
|
||||
|
||||
if (found)
|
||||
break;
|
||||
|
||||
switch (gmenu_tree_item_get_type (item))
|
||||
{
|
||||
case GMENU_TREE_ITEM_ENTRY:
|
||||
{
|
||||
GMenuTreeEntry *entry = (GMenuTreeEntry *)item;
|
||||
const char *id = gmenu_tree_entry_get_desktop_file_id (entry);
|
||||
if (strcmp (id, target_id) == 0)
|
||||
found = TRUE;
|
||||
}
|
||||
break;
|
||||
case GMENU_TREE_ITEM_DIRECTORY:
|
||||
{
|
||||
GMenuTreeDirectory *dir = (GMenuTreeDirectory*)item;
|
||||
found = desktop_id_exists (system, target_id, dir);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
gmenu_tree_item_unref (item);
|
||||
}
|
||||
|
||||
if (!success)
|
||||
{
|
||||
g_key_file_free (keyfile);
|
||||
g_free (full_path);
|
||||
return NULL;
|
||||
}
|
||||
g_slist_free (contents);
|
||||
|
||||
appinfo = shell_app_info_new_from_keyfile_take_ownership (keyfile, full_path);
|
||||
g_free (full_path);
|
||||
|
||||
return appinfo;
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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:
|
||||
* shell_app_system_lookup_basename:
|
||||
* @name: Probable application identifier
|
||||
*
|
||||
* Find a valid application corresponding to a given
|
||||
* Determine whether a valid .desktop file ID corresponding to a given
|
||||
* heuristically determined application identifier
|
||||
* string, or %NULL if none.
|
||||
*
|
||||
* Returns: (transfer full): A #ShellAppInfo for name
|
||||
* string.
|
||||
*/
|
||||
ShellAppInfo *
|
||||
shell_app_system_lookup_heuristic_basename (ShellAppSystem *system,
|
||||
const char *name)
|
||||
char *
|
||||
shell_app_system_lookup_basename (ShellAppSystem *system,
|
||||
const char *name)
|
||||
{
|
||||
ShellAppInfo *result;
|
||||
char **vendor_prefixes;
|
||||
GMenuTreeDirectory *root;
|
||||
char *result;
|
||||
|
||||
result = shell_app_system_lookup_cached_app (system, name);
|
||||
if (result != NULL)
|
||||
return result;
|
||||
root = gmenu_tree_get_directory_from_path (system->priv->apps_tree, "/");
|
||||
g_assert (root != NULL);
|
||||
|
||||
for (vendor_prefixes = (char**)known_vendor_prefixes;
|
||||
*vendor_prefixes; vendor_prefixes++)
|
||||
if (desktop_id_exists (system, name, root))
|
||||
{
|
||||
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;
|
||||
result = g_strdup (name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *
|
||||
shell_app_info_get_id (ShellAppInfo *info)
|
||||
{
|
||||
switch (info->type)
|
||||
{
|
||||
case SHELL_APP_INFO_TYPE_ENTRY:
|
||||
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;
|
||||
}
|
||||
|
||||
#define DESKTOP_ENTRY_GROUP "Desktop Entry"
|
||||
|
||||
char *
|
||||
shell_app_info_get_name (ShellAppInfo *info)
|
||||
{
|
||||
switch (info->type)
|
||||
{
|
||||
case SHELL_APP_INFO_TYPE_ENTRY:
|
||||
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;
|
||||
}
|
||||
|
||||
char *
|
||||
shell_app_info_get_description (ShellAppInfo *info)
|
||||
{
|
||||
switch (info->type)
|
||||
{
|
||||
case SHELL_APP_INFO_TYPE_ENTRY:
|
||||
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;
|
||||
}
|
||||
|
||||
char *
|
||||
shell_app_info_get_executable (ShellAppInfo *info)
|
||||
{
|
||||
switch (info->type)
|
||||
{
|
||||
case SHELL_APP_INFO_TYPE_ENTRY:
|
||||
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;
|
||||
}
|
||||
|
||||
char *
|
||||
shell_app_info_get_desktop_file_path (ShellAppInfo *info)
|
||||
{
|
||||
switch (info->type)
|
||||
{
|
||||
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);
|
||||
case SHELL_APP_INFO_TYPE_WINDOW:
|
||||
return NULL;
|
||||
}
|
||||
g_assert_not_reached ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
GIcon *icon;
|
||||
|
||||
/* This code adapted from gdesktopappinfo.c
|
||||
* Copyright (C) 2006-2007 Red Hat, Inc.
|
||||
* Copyright © 2007 Ryan Lortie
|
||||
* LGPL
|
||||
/* These are common "vendor prefixes". But using
|
||||
* WM_CLASS as a source, we don't get the vendor
|
||||
* prefix. So try stripping them.
|
||||
*/
|
||||
result = g_strjoin ("", "gnome-", name, NULL);
|
||||
if (desktop_id_exists (system, result, root))
|
||||
goto out;
|
||||
|
||||
switch (info->type)
|
||||
{
|
||||
case SHELL_APP_INFO_TYPE_ENTRY:
|
||||
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;
|
||||
}
|
||||
g_assert_not_reached ();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
GSList *
|
||||
shell_app_info_get_categories (ShellAppInfo *info)
|
||||
{
|
||||
return NULL; /* TODO */
|
||||
}
|
||||
|
||||
gboolean
|
||||
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->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:
|
||||
*
|
||||
* Look up the icon for this application, and create a #ClutterTexture
|
||||
* for it at the given size.
|
||||
*
|
||||
* Return value: (transfer none): A floating #ClutterActor
|
||||
*/
|
||||
ClutterActor *
|
||||
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)
|
||||
{
|
||||
ret = clutter_texture_new ();
|
||||
g_object_set (ret, "opacity", 0, "width", size, "height", size, NULL);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return shell_texture_cache_load_gicon (shell_texture_cache_get_default (), icon, (int)size);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_app_info_launch_full:
|
||||
* @timestamp: Event timestamp, or 0 for current event timestamp
|
||||
* @uris: List of uris to pass to application
|
||||
* @workspace: Start on this workspace, or -1 for default
|
||||
* @startup_id: (out): Returned startup notification ID, or %NULL if none
|
||||
* @error: A #GError
|
||||
*/
|
||||
gboolean
|
||||
shell_app_info_launch_full (ShellAppInfo *info,
|
||||
guint timestamp,
|
||||
GList *uris,
|
||||
int workspace,
|
||||
char **startup_id,
|
||||
GError **error)
|
||||
{
|
||||
GDesktopAppInfo *gapp;
|
||||
char *filename;
|
||||
GdkAppLaunchContext *context;
|
||||
gboolean ret;
|
||||
ShellGlobal *global;
|
||||
MetaScreen *screen;
|
||||
MetaDisplay *display;
|
||||
|
||||
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);
|
||||
|
||||
if (!gapp)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "Not found");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
global = shell_global_get ();
|
||||
screen = shell_global_get_screen (global);
|
||||
display = meta_screen_get_display (screen);
|
||||
|
||||
if (timestamp == 0)
|
||||
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);
|
||||
|
||||
context = gdk_app_launch_context_new ();
|
||||
gdk_app_launch_context_set_timestamp (context, timestamp);
|
||||
gdk_app_launch_context_set_desktop (context, workspace);
|
||||
|
||||
ret = g_app_info_launch (G_APP_INFO (gapp), uris, (GAppLaunchContext*) context, error);
|
||||
|
||||
g_object_unref (G_OBJECT (gapp));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
gboolean
|
||||
shell_app_info_launch (ShellAppInfo *info,
|
||||
GError **error)
|
||||
{
|
||||
return shell_app_info_launch_full (info, 0, NULL, -1, NULL, error);
|
||||
result = g_strjoin ("", "fedora-", name, NULL);
|
||||
if (desktop_id_exists (system, result, root))
|
||||
goto out;
|
||||
|
||||
out:
|
||||
gmenu_tree_item_unref (root);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
#ifndef __SHELL_APP_SYSTEM_H__
|
||||
#define __SHELL_APP_SYSTEM_H__
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#include "window.h"
|
||||
#include <glib-object.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))
|
||||
@@ -47,39 +44,7 @@ struct _ShellAppMenuEntry {
|
||||
|
||||
GType shell_app_menu_entry_get_type (void);
|
||||
|
||||
typedef struct _ShellAppInfo ShellAppInfo;
|
||||
|
||||
#define SHELL_TYPE_APP_INFO (shell_app_info_get_type ())
|
||||
GType shell_app_info_get_type (void);
|
||||
|
||||
ShellAppInfo* shell_app_info_ref (ShellAppInfo *info);
|
||||
void shell_app_info_unref (ShellAppInfo *info);
|
||||
|
||||
const char *shell_app_info_get_id (ShellAppInfo *info);
|
||||
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);
|
||||
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,
|
||||
int workspace,
|
||||
char **startup_id,
|
||||
GError **error);
|
||||
gboolean shell_app_info_launch (ShellAppInfo *info,
|
||||
GError **error);
|
||||
|
||||
ShellAppInfo *shell_app_system_load_from_desktop_file (ShellAppSystem *system, const char *filename, GError **error);
|
||||
|
||||
ShellAppInfo *shell_app_system_lookup_cached_app (ShellAppSystem *system, const char *id);
|
||||
|
||||
ShellAppInfo *shell_app_system_lookup_heuristic_basename (ShellAppSystem *system, const char *id);
|
||||
|
||||
ShellAppInfo *shell_app_system_create_from_window (ShellAppSystem *system, MetaWindow *window);
|
||||
char * shell_app_system_lookup_basename (ShellAppSystem *system, const char *id);
|
||||
|
||||
GSList *shell_app_system_get_menus (ShellAppSystem *system);
|
||||
|
||||
|
||||
@@ -1,248 +0,0 @@
|
||||
/* -*- 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 held;
|
||||
gboolean hover;
|
||||
gboolean pressed;
|
||||
};
|
||||
|
||||
/* Signals */
|
||||
enum
|
||||
{
|
||||
ACTIVATE,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
|
||||
PROP_HOVER,
|
||||
PROP_PRESSED,
|
||||
};
|
||||
|
||||
static guint shell_button_box_signals [LAST_SIGNAL] = { 0 };
|
||||
|
||||
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_on_enter (ShellButtonBox *box,
|
||||
ClutterEvent *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
if (shell_button_box_contains (box, event->crossing.related))
|
||||
return TRUE;
|
||||
if (!shell_button_box_contains (box, clutter_event_get_source (event)))
|
||||
return TRUE;
|
||||
|
||||
set_hover (box, TRUE);
|
||||
if (box->priv->held)
|
||||
set_pressed (box, TRUE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
shell_button_box_on_leave (ShellButtonBox *box,
|
||||
ClutterEvent *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
if (shell_button_box_contains (box, event->crossing.related))
|
||||
return TRUE;
|
||||
|
||||
set_hover (box, FALSE);
|
||||
set_pressed (box, FALSE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
shell_button_box_on_press (ShellButtonBox *box,
|
||||
ClutterEvent *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
ClutterActor *source;
|
||||
|
||||
if (box->priv->held)
|
||||
return TRUE;
|
||||
|
||||
source = clutter_event_get_source (event);
|
||||
if (!shell_button_box_contains (box, source))
|
||||
return FALSE;
|
||||
|
||||
box->priv->held = TRUE;
|
||||
clutter_grab_pointer (CLUTTER_ACTOR (box));
|
||||
|
||||
set_pressed (box, TRUE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
shell_button_box_on_release (ShellButtonBox *box,
|
||||
ClutterEvent *event,
|
||||
gpointer user_data)
|
||||
{
|
||||
ClutterActor *source;
|
||||
|
||||
if (!box->priv->held)
|
||||
return TRUE;
|
||||
|
||||
source = clutter_event_get_source (event);
|
||||
|
||||
box->priv->held = FALSE;
|
||||
clutter_ungrab_pointer ();
|
||||
|
||||
if (!shell_button_box_contains (box, source))
|
||||
return FALSE;
|
||||
|
||||
set_pressed (box, FALSE);
|
||||
|
||||
g_signal_emit (G_OBJECT (box), shell_button_box_signals[ACTIVATE], 0);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
shell_button_box_set_property(GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
switch (prop_id)
|
||||
{
|
||||
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_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);
|
||||
|
||||
gobject_class->get_property = shell_button_box_get_property;
|
||||
gobject_class->set_property = shell_button_box_set_property;
|
||||
|
||||
/**
|
||||
* ShellButtonBox::activate
|
||||
* @box: The #ShellButtonBox
|
||||
*
|
||||
* 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, 0);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
g_signal_connect (G_OBJECT (self), "enter-event", G_CALLBACK(shell_button_box_on_enter), NULL);
|
||||
g_signal_connect (G_OBJECT (self), "leave-event", G_CALLBACK(shell_button_box_on_leave), NULL);
|
||||
g_signal_connect (G_OBJECT (self), "button-press-event", G_CALLBACK(shell_button_box_on_press), NULL);
|
||||
g_signal_connect (G_OBJECT (self), "button-release-event", G_CALLBACK(shell_button_box_on_release), NULL);
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
#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;
|
||||
|
||||
#endif /* __SHELL_BUTTON_BOX_H__ */
|
||||
@@ -1,102 +0,0 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/**
|
||||
* SECTION:shell-drawing-area
|
||||
* @short_description: A dynamically-sized Cairo drawing area
|
||||
*
|
||||
* #ShellDrawingArea is similar to #ClutterCairoTexture in that
|
||||
* it allows drawing via Cairo; the primary difference is that
|
||||
* it is dynamically sized. To use, connect to the @redraw
|
||||
* signal, and inside the signal handler, call
|
||||
* clutter_cairo_texture_create() to begin drawing.
|
||||
*/
|
||||
|
||||
#include "shell-drawing-area.h"
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <cairo.h>
|
||||
|
||||
G_DEFINE_TYPE(ShellDrawingArea, shell_drawing_area, CLUTTER_TYPE_GROUP);
|
||||
|
||||
struct _ShellDrawingAreaPrivate {
|
||||
ClutterCairoTexture *texture;
|
||||
};
|
||||
|
||||
/* Signals */
|
||||
enum
|
||||
{
|
||||
REDRAW,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint shell_drawing_area_signals [LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void
|
||||
shell_drawing_area_allocate (ClutterActor *self,
|
||||
const ClutterActorBox *box,
|
||||
ClutterAllocationFlags flags)
|
||||
{
|
||||
ShellDrawingArea *area = SHELL_DRAWING_AREA (self);
|
||||
int width = box->x2 - box->x1;
|
||||
int height = box->y2 - box->y1;
|
||||
ClutterActorBox child_box;
|
||||
|
||||
/* 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,
|
||||
width, height);
|
||||
g_signal_emit (G_OBJECT (self), shell_drawing_area_signals[REDRAW], 0,
|
||||
area->priv->texture);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
shell_drawing_area_class_init (ShellDrawingAreaClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
||||
|
||||
actor_class->allocate = shell_drawing_area_allocate;
|
||||
|
||||
shell_drawing_area_signals[REDRAW] =
|
||||
g_signal_new ("redraw",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (ShellDrawingAreaClass, redraw),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1, G_TYPE_OBJECT);
|
||||
|
||||
g_type_class_add_private (gobject_class, sizeof (ShellDrawingAreaPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
shell_drawing_area_init (ShellDrawingArea *area)
|
||||
{
|
||||
area->priv = G_TYPE_INSTANCE_GET_PRIVATE (area, SHELL_TYPE_DRAWING_AREA,
|
||||
ShellDrawingAreaPrivate);
|
||||
area->priv->texture = CLUTTER_CAIRO_TEXTURE (clutter_cairo_texture_new (1, 1));
|
||||
clutter_container_add_actor (CLUTTER_CONTAINER (area), CLUTTER_ACTOR (area->priv->texture));
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_drawing_area_get_texture:
|
||||
*
|
||||
* Return Value: (transfer none):
|
||||
*/
|
||||
ClutterCairoTexture *
|
||||
shell_drawing_area_get_texture (ShellDrawingArea *area)
|
||||
{
|
||||
return area->priv->texture;
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
#ifndef __SHELL_DRAWING_AREA_H__
|
||||
#define __SHELL_DRAWING_AREA_H__
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define SHELL_TYPE_DRAWING_AREA (shell_drawing_area_get_type ())
|
||||
#define SHELL_DRAWING_AREA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_DRAWING_AREA, ShellDrawingArea))
|
||||
#define SHELL_DRAWING_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_DRAWING_AREA, ShellDrawingAreaClass))
|
||||
#define SHELL_IS_DRAWING_AREA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_TYPE_DRAWING_AREA))
|
||||
#define SHELL_IS_DRAWING_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_DRAWING_AREA))
|
||||
#define SHELL_DRAWING_AREA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_DRAWING_AREA, ShellDrawingAreaClass))
|
||||
|
||||
typedef struct _ShellDrawingArea ShellDrawingArea;
|
||||
typedef struct _ShellDrawingAreaClass ShellDrawingAreaClass;
|
||||
|
||||
typedef struct _ShellDrawingAreaPrivate ShellDrawingAreaPrivate;
|
||||
|
||||
struct _ShellDrawingArea
|
||||
{
|
||||
ClutterGroup parent;
|
||||
|
||||
ShellDrawingAreaPrivate *priv;
|
||||
};
|
||||
|
||||
struct _ShellDrawingAreaClass
|
||||
{
|
||||
ClutterGroupClass parent_class;
|
||||
|
||||
void (*redraw) (ShellDrawingArea *area, ClutterCairoTexture *texture);
|
||||
};
|
||||
|
||||
GType shell_drawing_area_get_type (void) G_GNUC_CONST;
|
||||
|
||||
ClutterCairoTexture *shell_drawing_area_get_texture (ShellDrawingArea *area);
|
||||
|
||||
#endif /* __SHELL_DRAWING_AREA_H__ */
|
||||
@@ -1,258 +0,0 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include "shell-drawing.h"
|
||||
#include <math.h>
|
||||
|
||||
/**
|
||||
* shell_create_vertical_gradient:
|
||||
* @top: the color at the top
|
||||
* @bottom: the color at the bottom
|
||||
*
|
||||
* Creates a vertical gradient actor.
|
||||
*
|
||||
* Return value: (transfer none): a #ClutterCairoTexture actor with the
|
||||
* gradient. The texture actor is floating, hence (transfer none).
|
||||
*/
|
||||
ClutterCairoTexture *
|
||||
shell_create_vertical_gradient (ClutterColor *top,
|
||||
ClutterColor *bottom)
|
||||
{
|
||||
ClutterCairoTexture *texture;
|
||||
cairo_t *cr;
|
||||
cairo_pattern_t *pattern;
|
||||
|
||||
/* Draw the gradient on an 8x8 pixel texture. Because the gradient is drawn
|
||||
* from the uppermost to the lowermost row, after stretching 1/16 of the
|
||||
* texture height has the top color and 1/16 has the bottom color. The 8
|
||||
* pixel width is chosen for reasons related to graphics hardware internals.
|
||||
*/
|
||||
texture = CLUTTER_CAIRO_TEXTURE (clutter_cairo_texture_new (8, 8));
|
||||
cr = clutter_cairo_texture_create (texture);
|
||||
|
||||
pattern = cairo_pattern_create_linear (0, 0, 0, 8);
|
||||
cairo_pattern_add_color_stop_rgba (pattern, 0,
|
||||
top->red / 255.,
|
||||
top->green / 255.,
|
||||
top->blue / 255.,
|
||||
top->alpha / 255.);
|
||||
cairo_pattern_add_color_stop_rgba (pattern, 1,
|
||||
bottom->red / 255.,
|
||||
bottom->green / 255.,
|
||||
bottom->blue / 255.,
|
||||
bottom->alpha / 255.);
|
||||
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_pattern_destroy (pattern);
|
||||
cairo_destroy (cr);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_create_horizontal_gradient:
|
||||
* @left: the color on the left
|
||||
* @right: the color on the right
|
||||
*
|
||||
* Creates a horizontal gradient actor.
|
||||
*
|
||||
* Return value: (transfer none): a #ClutterCairoTexture actor with the
|
||||
* gradient. The texture actor is floating, hence (transfer none).
|
||||
*/
|
||||
ClutterCairoTexture *
|
||||
shell_create_horizontal_gradient (ClutterColor *left,
|
||||
ClutterColor *right)
|
||||
{
|
||||
ClutterCairoTexture *texture;
|
||||
cairo_t *cr;
|
||||
cairo_pattern_t *pattern;
|
||||
|
||||
/* Draw the gradient on an 8x1 pixel texture. Because the gradient is drawn
|
||||
* from the left to the right column, after stretching 1/16 of the
|
||||
* texture width has the left side color and 1/16 has the right side color.
|
||||
* There is no reason to use the 8 pixel height that would be similar to the
|
||||
* reason we are using the 8 pixel width for the vertical gradient, so we
|
||||
* are just using the 1 pixel height instead.
|
||||
*/
|
||||
texture = CLUTTER_CAIRO_TEXTURE (clutter_cairo_texture_new (8, 1));
|
||||
cr = clutter_cairo_texture_create (texture);
|
||||
|
||||
pattern = cairo_pattern_create_linear (0, 0, 8, 0);
|
||||
cairo_pattern_add_color_stop_rgba (pattern, 0,
|
||||
left->red / 255.,
|
||||
left->green / 255.,
|
||||
left->blue / 255.,
|
||||
left->alpha / 255.);
|
||||
cairo_pattern_add_color_stop_rgba (pattern, 1,
|
||||
right->red / 255.,
|
||||
right->green / 255.,
|
||||
right->blue / 255.,
|
||||
right->alpha / 255.);
|
||||
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_pattern_destroy (pattern);
|
||||
cairo_destroy (cr);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
void
|
||||
shell_draw_clock (ClutterCairoTexture *texture,
|
||||
int hour,
|
||||
int minute)
|
||||
{
|
||||
cairo_t *cr;
|
||||
guint width, height;
|
||||
double xc, yc, radius, hour_radius, minute_radius;
|
||||
double angle;
|
||||
|
||||
clutter_cairo_texture_get_surface_size (texture, &width, &height);
|
||||
xc = (double)width / 2;
|
||||
yc = (double)height / 2;
|
||||
radius = (double)(MIN(width, height)) / 2 - 2;
|
||||
minute_radius = radius - 3;
|
||||
hour_radius = radius / 2;
|
||||
|
||||
clutter_cairo_texture_clear (texture);
|
||||
cr = clutter_cairo_texture_create (texture);
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
|
||||
/* Outline */
|
||||
cairo_arc (cr, xc, yc, radius, 0.0, 2.0 * M_PI);
|
||||
cairo_stroke (cr);
|
||||
|
||||
/* Hour hand. (We add a fraction to @hour for the minutes, then
|
||||
* convert to radians, and then subtract pi/2 because cairo's origin
|
||||
* is at 3:00, not 12:00.)
|
||||
*/
|
||||
angle = ((hour + minute / 60.0) / 12.0) * 2.0 * M_PI - M_PI / 2.0;
|
||||
cairo_move_to (cr, xc, yc);
|
||||
cairo_line_to (cr,
|
||||
xc + hour_radius * cos (angle),
|
||||
yc + hour_radius * sin (angle));
|
||||
cairo_stroke (cr);
|
||||
|
||||
/* Minute hand */
|
||||
angle = (minute / 60.0) * 2.0 * M_PI - M_PI / 2.0;
|
||||
cairo_move_to (cr, xc, yc);
|
||||
cairo_line_to (cr,
|
||||
xc + minute_radius * cos (angle),
|
||||
yc + minute_radius * sin (angle));
|
||||
cairo_stroke (cr);
|
||||
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_glow (cairo_t *cr, double red, double green, double blue, double alpha)
|
||||
{
|
||||
cairo_pattern_t *gradient;
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
shell_draw_app_highlight (ClutterCairoTexture *texture,
|
||||
int num_windows,
|
||||
double red,
|
||||
double green,
|
||||
double blue,
|
||||
double alpha)
|
||||
{
|
||||
cairo_t *cr;
|
||||
guint width, height;
|
||||
|
||||
g_return_if_fail (num_windows > 0);
|
||||
|
||||
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);
|
||||
|
||||
if (num_windows == 1)
|
||||
{
|
||||
cairo_scale (cr, width / 2.0, height / 2.0);
|
||||
draw_glow (cr, red, green, blue, alpha);
|
||||
}
|
||||
else
|
||||
{
|
||||
int num_circles, i;
|
||||
double scale, highlight_width;
|
||||
|
||||
num_circles = num_windows == 2 ? 2 : 3;
|
||||
|
||||
/* The circles will have radius 1.0 (diameter 2.0) and overlap
|
||||
* by 0.2, so the total width of the highlight is:
|
||||
*/
|
||||
highlight_width = 2.0 * num_circles - 0.2 * (num_circles - 1);
|
||||
|
||||
scale = MIN (height / 2.0, width / highlight_width);
|
||||
cairo_scale (cr, scale, scale);
|
||||
|
||||
/* The leftmost circle's left side is at -highlight_width/2, so
|
||||
* its center is that plus 1.
|
||||
*/
|
||||
cairo_translate (cr, -highlight_width / 2.0 + 1.0, 0.0);
|
||||
for (i = 0; i < num_circles; i++)
|
||||
{
|
||||
draw_glow (cr, red, green, blue, alpha);
|
||||
cairo_translate (cr, 1.8, 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
cairo_restore (cr);
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
hook_paint_red_border (ClutterActor *actor,
|
||||
gpointer user_data)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
guint
|
||||
shell_add_hook_paint_red_border (ClutterActor *actor)
|
||||
{
|
||||
return g_signal_connect_after (G_OBJECT (actor), "paint",
|
||||
G_CALLBACK (hook_paint_red_border), NULL);
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#ifndef __SHELL_DRAWING_H__
|
||||
#define __SHELL_DRAWING_H__
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
ClutterCairoTexture *shell_create_vertical_gradient (ClutterColor *top,
|
||||
ClutterColor *bottom);
|
||||
|
||||
ClutterCairoTexture *shell_create_horizontal_gradient (ClutterColor *left,
|
||||
ClutterColor *right);
|
||||
|
||||
void shell_draw_clock (ClutterCairoTexture *texture,
|
||||
int hour,
|
||||
int minute);
|
||||
|
||||
void shell_draw_app_highlight (ClutterCairoTexture *texture,
|
||||
int num_windows,
|
||||
double red,
|
||||
double blue,
|
||||
double green,
|
||||
double alpha);
|
||||
|
||||
guint shell_add_hook_paint_red_border (ClutterActor *actor);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __SHELL_GLOBAL_H__ */
|
||||
@@ -1,396 +0,0 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include "shell-gconf.h"
|
||||
|
||||
#include <gconf/gconf-client.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* ShellGConf:
|
||||
*
|
||||
* A wrapper around #GConfClient that cleans up some of its
|
||||
* non-gjs-bindable bits and makes a few gnome-shell-specific
|
||||
* assumptions.
|
||||
*
|
||||
* For all #ShellGConf methods that take a GConf key path as an
|
||||
* argument, you can pass either a full path (eg,
|
||||
* "/desktop/gnome/shell/sidebar/visible"), or just a relative path
|
||||
* starting from the root of the gnome-shell GConf key hierarchy (eg,
|
||||
* "sidebar/visible").
|
||||
*/
|
||||
|
||||
struct _ShellGConf
|
||||
{
|
||||
GObject parent;
|
||||
|
||||
GConfClient *client;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (ShellGConf, shell_gconf, G_TYPE_OBJECT);
|
||||
|
||||
/* Signals */
|
||||
enum
|
||||
{
|
||||
CHANGED,
|
||||
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint shell_gconf_signals [LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void gconf_value_changed (GConfClient *client, const char *key,
|
||||
GConfValue *new_value, gpointer user_data);
|
||||
|
||||
static void
|
||||
shell_gconf_init (ShellGConf *gconf)
|
||||
{
|
||||
gconf->client = gconf_client_get_default ();
|
||||
gconf_client_add_dir (gconf->client, SHELL_GCONF_DIR,
|
||||
GCONF_CLIENT_PRELOAD_RECURSIVE, NULL);
|
||||
g_signal_connect (gconf->client, "value_changed",
|
||||
G_CALLBACK (gconf_value_changed), gconf);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_gconf_finalize (GObject *object)
|
||||
{
|
||||
ShellGConf *gconf = SHELL_GCONF (object);
|
||||
|
||||
g_signal_handlers_disconnect_by_func (gconf->client,
|
||||
gconf_value_changed, gconf);
|
||||
g_object_unref (gconf->client);
|
||||
|
||||
G_OBJECT_CLASS (shell_gconf_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_gconf_class_init (ShellGConfClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
gobject_class->finalize = shell_gconf_finalize;
|
||||
|
||||
/**
|
||||
* ShellGConf::changed:
|
||||
* @gconf: the #ShellGConf
|
||||
*
|
||||
* Emitted when a key in a watched directory is changed. The signal
|
||||
* detail indicates which key changed. Eg, connect to
|
||||
* "changed::sidebar/visible" to be notified when "sidebar/visible"
|
||||
* changes. For gnome-shell's own GConf keys, the signal detail will
|
||||
* be the relative path from the top of the gnome-shell GConf
|
||||
* hierarchy ("/desktop/gnome/shell"). If you want to be notified
|
||||
* about the value of a non-gnome-shell key, you must first call
|
||||
* shell_gconf_watch_directory(), and then use the full GConf key path
|
||||
* as the signal detail.
|
||||
*/
|
||||
shell_gconf_signals[CHANGED] =
|
||||
g_signal_new ("changed",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
|
||||
G_STRUCT_OFFSET (ShellGConfClass, changed),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_gconf_get_default:
|
||||
*
|
||||
* Gets the default #ShellGConf
|
||||
*
|
||||
* Return value: (transfer none): the default #ShellGConf
|
||||
*/
|
||||
ShellGConf *
|
||||
shell_gconf_get_default (void)
|
||||
{
|
||||
static ShellGConf *gconf = NULL;
|
||||
|
||||
if (!gconf)
|
||||
gconf = g_object_new (SHELL_TYPE_GCONF, NULL);
|
||||
|
||||
return gconf;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_gconf_watch_directory:
|
||||
* @gconf: a #ShellGConf
|
||||
* @directory: the path of a GConf directory to watch for changes in
|
||||
*
|
||||
* Adds @directory to the list of directories to watch; you must call
|
||||
* this before connecting to #ShellGConf::changed for a key outside of
|
||||
* the gnome-shell GConf tree.
|
||||
*/
|
||||
void
|
||||
shell_gconf_watch_directory (ShellGConf *gconf, const char *directory)
|
||||
{
|
||||
gconf_client_add_dir (gconf->client, directory,
|
||||
GCONF_CLIENT_PRELOAD_NONE, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gconf_value_changed (GConfClient *client, const char *key,
|
||||
GConfValue *new_value, gpointer user_data)
|
||||
{
|
||||
ShellGConf *gconf = user_data;
|
||||
GQuark detail;
|
||||
|
||||
if (g_str_has_prefix (key, SHELL_GCONF_DIR "/"))
|
||||
key += strlen (SHELL_GCONF_DIR "/");
|
||||
|
||||
/* This will create a lot of junk quarks, but it's the best we
|
||||
* can do with gjs's current callback support.
|
||||
*/
|
||||
detail = g_quark_from_string (key);
|
||||
g_signal_emit (gconf, shell_gconf_signals[CHANGED], detail);
|
||||
}
|
||||
|
||||
static char *
|
||||
resolve_key (const char *key)
|
||||
{
|
||||
if (*key == '/')
|
||||
return g_strdup (key);
|
||||
else
|
||||
return g_build_filename (SHELL_GCONF_DIR, key, NULL);
|
||||
}
|
||||
|
||||
|
||||
#define SIMPLE_GETTER(NAME, TYPE, GCONF_GETTER) \
|
||||
TYPE \
|
||||
NAME (ShellGConf *gconf, const char *key, GError **error) \
|
||||
{ \
|
||||
char *get_key = resolve_key (key); \
|
||||
TYPE value; \
|
||||
\
|
||||
value = GCONF_GETTER (gconf->client, get_key, error); \
|
||||
g_free (get_key); \
|
||||
return value; \
|
||||
}
|
||||
|
||||
#define LIST_GETTER(NAME, ELEMENT_TYPE) \
|
||||
GSList * \
|
||||
NAME (ShellGConf *gconf, const char *key, GError **error) \
|
||||
{ \
|
||||
char *get_key = resolve_key (key); \
|
||||
GSList *value; \
|
||||
\
|
||||
value = gconf_client_get_list (gconf->client, get_key, \
|
||||
ELEMENT_TYPE, error); \
|
||||
g_free (get_key); \
|
||||
return value; \
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_gconf_get_boolean:
|
||||
* @gconf: a #ShellGConf
|
||||
* @key: a GConf key (as described in the #ShellGConf docs)
|
||||
* @error: a #GError, which will be set on error
|
||||
*
|
||||
* Gets the value of @key, which must be boolean-valued.
|
||||
*
|
||||
* Return value: @key's value. If an error occurs, @error will be set
|
||||
* and the return value is undefined.
|
||||
**/
|
||||
SIMPLE_GETTER(shell_gconf_get_boolean, gboolean, gconf_client_get_bool)
|
||||
|
||||
/**
|
||||
* shell_gconf_get_int:
|
||||
* @gconf: a #ShellGConf
|
||||
* @key: a GConf key (as described in the #ShellGConf docs)
|
||||
* @error: a #GError, which will be set on error
|
||||
*
|
||||
* Gets the value of @key, which must be integer-valued.
|
||||
*
|
||||
* Return value: @key's value. If an error occurs, @error will be set
|
||||
* and the return value is undefined.
|
||||
**/
|
||||
SIMPLE_GETTER(shell_gconf_get_int, int, gconf_client_get_int)
|
||||
|
||||
/**
|
||||
* shell_gconf_get_float:
|
||||
* @gconf: a #ShellGConf
|
||||
* @key: a GConf key (as described in the #ShellGConf docs)
|
||||
* @error: a #GError, which will be set on error
|
||||
*
|
||||
* Gets the value of @key, which must be float-valued.
|
||||
*
|
||||
* Return value: @key's value. If an error occurs, @error will be set
|
||||
* and the return value is undefined.
|
||||
**/
|
||||
SIMPLE_GETTER(shell_gconf_get_float, float, gconf_client_get_float)
|
||||
|
||||
/**
|
||||
* shell_gconf_get_string:
|
||||
* @gconf: a #ShellGConf
|
||||
* @key: a GConf key (as described in the #ShellGConf docs)
|
||||
* @error: a #GError, which will be set on error
|
||||
*
|
||||
* Gets the value of @key, which must be string-valued.
|
||||
*
|
||||
* Return value: (transfer full): @key's value, or %NULL if an error
|
||||
* occurs.
|
||||
**/
|
||||
SIMPLE_GETTER(shell_gconf_get_string, char *, gconf_client_get_string)
|
||||
|
||||
/**
|
||||
* shell_gconf_get_boolean_list:
|
||||
* @gconf: a #ShellGConf
|
||||
* @key: a GConf key (as described in the #ShellGConf docs)
|
||||
* @error: a #GError, which will be set on error
|
||||
*
|
||||
* Gets the value of @key, which must be boolean-list-valued.
|
||||
*
|
||||
* Return value: (element-type gboolean) (transfer full): @key's
|
||||
* value, or %NULL if an error occurs.
|
||||
**/
|
||||
LIST_GETTER(shell_gconf_get_boolean_list, GCONF_VALUE_BOOL)
|
||||
|
||||
/**
|
||||
* shell_gconf_get_int_list:
|
||||
* @gconf: a #ShellGConf
|
||||
* @key: a GConf key (as described in the #ShellGConf docs)
|
||||
* @error: a #GError, which will be set on error
|
||||
*
|
||||
* Gets the value of @key, which must be integer-list-valued.
|
||||
*
|
||||
* Return value: (element-type int) (transfer full): @key's
|
||||
* value, or %NULL if an error occurs.
|
||||
**/
|
||||
LIST_GETTER(shell_gconf_get_int_list, GCONF_VALUE_INT)
|
||||
|
||||
/**
|
||||
* shell_gconf_get_float_list:
|
||||
* @gconf: a #ShellGConf
|
||||
* @key: a GConf key (as described in the #ShellGConf docs)
|
||||
* @error: a #GError, which will be set on error
|
||||
*
|
||||
* Gets the value of @key, which must be float-list-valued.
|
||||
*
|
||||
* Return value: (element-type float) (transfer full): @key's
|
||||
* value, or %NULL if an error occurs.
|
||||
**/
|
||||
LIST_GETTER(shell_gconf_get_float_list, GCONF_VALUE_FLOAT)
|
||||
|
||||
/**
|
||||
* shell_gconf_get_string_list:
|
||||
* @gconf: a #ShellGConf
|
||||
* @key: a GConf key (as described in the #ShellGConf docs)
|
||||
* @error: a #GError, which will be set on error
|
||||
*
|
||||
* Gets the value of @key, which must be string-list-valued.
|
||||
*
|
||||
* Return value: (element-type utf8) (transfer full): @key's
|
||||
* value, or %NULL if an error occurs.
|
||||
**/
|
||||
LIST_GETTER(shell_gconf_get_string_list, GCONF_VALUE_STRING)
|
||||
|
||||
|
||||
#define SIMPLE_SETTER(NAME, TYPE, GCONF_SETTER) \
|
||||
void \
|
||||
NAME (ShellGConf *gconf, const char *key, TYPE value, GError **error) \
|
||||
{ \
|
||||
char *set_key = resolve_key (key); \
|
||||
\
|
||||
GCONF_SETTER (gconf->client, set_key, value, error); \
|
||||
g_free (set_key); \
|
||||
}
|
||||
|
||||
#define LIST_SETTER(NAME, ELEMENT_TYPE) \
|
||||
void \
|
||||
NAME (ShellGConf *gconf, const char *key, \
|
||||
GSList *value, GError **error) \
|
||||
{ \
|
||||
char *set_key = resolve_key (key); \
|
||||
\
|
||||
gconf_client_set_list (gconf->client, set_key, ELEMENT_TYPE, \
|
||||
value, error); \
|
||||
g_free (set_key); \
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_gconf_set_boolean:
|
||||
* @gconf: a #ShellGConf
|
||||
* @key: a GConf key (as described in the #ShellGConf docs)
|
||||
* @value: value to set @key to
|
||||
* @error: a #GError, which will be set on error
|
||||
*
|
||||
* Sets the value of @key to @value.
|
||||
**/
|
||||
SIMPLE_SETTER(shell_gconf_set_boolean, gboolean, gconf_client_set_bool)
|
||||
|
||||
/**
|
||||
* shell_gconf_set_int:
|
||||
* @gconf: a #ShellGConf
|
||||
* @key: a GConf key (as described in the #ShellGConf docs)
|
||||
* @value: value to set @key to
|
||||
* @error: a #GError, which will be set on error
|
||||
*
|
||||
* Sets the value of @key to @value.
|
||||
**/
|
||||
SIMPLE_SETTER(shell_gconf_set_int, int, gconf_client_set_int)
|
||||
|
||||
/**
|
||||
* shell_gconf_set_float:
|
||||
* @gconf: a #ShellGConf
|
||||
* @key: a GConf key (as described in the #ShellGConf docs)
|
||||
* @value: value to set @key to
|
||||
* @error: a #GError, which will be set on error
|
||||
*
|
||||
* Sets the value of @key to @value.
|
||||
**/
|
||||
SIMPLE_SETTER(shell_gconf_set_float, float, gconf_client_set_float)
|
||||
|
||||
/**
|
||||
* shell_gconf_set_string:
|
||||
* @gconf: a #ShellGConf
|
||||
* @key: a GConf key (as described in the #ShellGConf docs)
|
||||
* @value: value to set @key to
|
||||
* @error: a #GError, which will be set on error
|
||||
*
|
||||
* Sets the value of @key to @value.
|
||||
**/
|
||||
SIMPLE_SETTER(shell_gconf_set_string, const char *, gconf_client_set_string)
|
||||
|
||||
/**
|
||||
* shell_gconf_set_boolean_list:
|
||||
* @gconf: a #ShellGConf
|
||||
* @key: a GConf key (as described in the #ShellGConf docs)
|
||||
* @value: (transfer none): value to set @key to
|
||||
* @error: a #GError, which will be set on error
|
||||
*
|
||||
* Sets the value of @key to @value.
|
||||
**/
|
||||
LIST_SETTER(shell_gconf_set_boolean_list, GCONF_VALUE_BOOL)
|
||||
|
||||
/**
|
||||
* shell_gconf_set_int_list:
|
||||
* @gconf: a #ShellGConf
|
||||
* @key: a GConf key (as described in the #ShellGConf docs)
|
||||
* @value: (transfer none): value to set @key to
|
||||
* @error: a #GError, which will be set on error
|
||||
*
|
||||
* Sets the value of @key to @value.
|
||||
**/
|
||||
LIST_SETTER(shell_gconf_set_int_list, GCONF_VALUE_INT)
|
||||
|
||||
/**
|
||||
* shell_gconf_set_float_list:
|
||||
* @gconf: a #ShellGConf
|
||||
* @key: a GConf key (as described in the #ShellGConf docs)
|
||||
* @value: (transfer none): value to set @key to
|
||||
* @error: a #GError, which will be set on error
|
||||
*
|
||||
* Sets the value of @key to @value.
|
||||
**/
|
||||
LIST_SETTER(shell_gconf_set_float_list, GCONF_VALUE_FLOAT)
|
||||
|
||||
/**
|
||||
* shell_gconf_set_string_list:
|
||||
* @gconf: a #ShellGConf
|
||||
* @key: a GConf key (as described in the #ShellGConf docs)
|
||||
* @value: (transfer none): value to set @key to
|
||||
* @error: a #GError, which will be set on error
|
||||
*
|
||||
* Sets the value of @key to @value.
|
||||
**/
|
||||
LIST_SETTER(shell_gconf_set_string_list, GCONF_VALUE_STRING)
|
||||
@@ -1,95 +0,0 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#ifndef SHELL_GCONF_H
|
||||
#define SHELL_GCONF_H
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _ShellGConf ShellGConf;
|
||||
typedef struct _ShellGConfClass ShellGConfClass;
|
||||
|
||||
#define SHELL_TYPE_GCONF (shell_gconf_get_type ())
|
||||
#define SHELL_GCONF(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), SHELL_TYPE_GCONF, ShellGConf))
|
||||
#define SHELL_GCONF_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_GCONF, ShellGConfClass))
|
||||
#define SHELL_IS_GCONF(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), SHELL_TYPE_GCONF))
|
||||
#define SHELL_IS_GCONF_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_GCONF))
|
||||
#define SHELL_GCONF_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_GCONF, ShellGConfClass))
|
||||
|
||||
struct _ShellGConfClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
/* signals */
|
||||
void (*changed) (ShellGConf *gconf);
|
||||
};
|
||||
|
||||
#define SHELL_GCONF_DIR "/desktop/gnome/shell"
|
||||
|
||||
GType shell_gconf_get_type (void) G_GNUC_CONST;
|
||||
ShellGConf *shell_gconf_get_default (void);
|
||||
|
||||
void shell_gconf_watch_directory (ShellGConf *gconf,
|
||||
const char *directory);
|
||||
|
||||
gboolean shell_gconf_get_boolean (ShellGConf *gconf,
|
||||
const char *key,
|
||||
GError **error);
|
||||
int shell_gconf_get_int (ShellGConf *gconf,
|
||||
const char *key,
|
||||
GError **error);
|
||||
float shell_gconf_get_float (ShellGConf *gconf,
|
||||
const char *key,
|
||||
GError **error);
|
||||
char *shell_gconf_get_string (ShellGConf *gconf,
|
||||
const char *key,
|
||||
GError **error);
|
||||
GSList *shell_gconf_get_boolean_list (ShellGConf *gconf,
|
||||
const char *key,
|
||||
GError **error);
|
||||
GSList *shell_gconf_get_int_list (ShellGConf *gconf,
|
||||
const char *key,
|
||||
GError **error);
|
||||
GSList *shell_gconf_get_float_list (ShellGConf *gconf,
|
||||
const char *key,
|
||||
GError **error);
|
||||
GSList *shell_gconf_get_string_list (ShellGConf *gconf,
|
||||
const char *key,
|
||||
GError **error);
|
||||
|
||||
void shell_gconf_set_boolean (ShellGConf *gconf,
|
||||
const char *key,
|
||||
gboolean value,
|
||||
GError **error);
|
||||
void shell_gconf_set_int (ShellGConf *gconf,
|
||||
const char *key,
|
||||
int value,
|
||||
GError **error);
|
||||
void shell_gconf_set_float (ShellGConf *gconf,
|
||||
const char *key,
|
||||
float value,
|
||||
GError **error);
|
||||
void shell_gconf_set_string (ShellGConf *gconf,
|
||||
const char *key,
|
||||
const char *value,
|
||||
GError **error);
|
||||
void shell_gconf_set_boolean_list (ShellGConf *gconf,
|
||||
const char *key,
|
||||
GSList *value,
|
||||
GError **error);
|
||||
void shell_gconf_set_int_list (ShellGConf *gconf,
|
||||
const char *key,
|
||||
GSList *value,
|
||||
GError **error);
|
||||
void shell_gconf_set_float_list (ShellGConf *gconf,
|
||||
const char *key,
|
||||
GSList *value,
|
||||
GError **error);
|
||||
void shell_gconf_set_string_list (ShellGConf *gconf,
|
||||
const char *key,
|
||||
GSList *value,
|
||||
GError **error);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,240 +0,0 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/**
|
||||
* SECTION:shell-generic-container
|
||||
* @short_description: A container class with signals for allocation
|
||||
*
|
||||
* #ShellGenericContainer is mainly a workaround for the current
|
||||
* lack of GObject subclassing + vfunc overrides in gjs. We
|
||||
* implement the container interface, but proxy the virtual functions
|
||||
* into signals, which gjs can catch.
|
||||
*/
|
||||
|
||||
/* Example implementation of a horzontal box with PACK_EXPAND for all,
|
||||
vertically and horizontally centering.
|
||||
|
||||
function TestFixedBox() {
|
||||
this._init();
|
||||
}
|
||||
|
||||
TestFixedBox.prototype = {
|
||||
_init : function () {
|
||||
this.actor = new Shell.GenericContainer();
|
||||
this.spacing = 4;
|
||||
this.actor.connect('get-preferred-width', Lang.bind(this, function (actor, for_height, alloc) {
|
||||
let children = this.actor.get_children();
|
||||
let max_child_min = 0;
|
||||
let max_child_nat = 0;
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
let spacing = i > 0 && i < children.length-1 ? this.spacing : 0;
|
||||
let [child_min, child_nat] = children[i].get_preferred_width(for_height);
|
||||
if (child_min > max_child_min)
|
||||
max_child_min = child_min;
|
||||
if (child_nat > max_child_nat)
|
||||
max_child_nat = child_nat;
|
||||
}
|
||||
let totalSpacing = this.spacing * Math.abs(children.length - 1);
|
||||
alloc.min_size = children.length * max_child_min + totalSpacing;
|
||||
alloc.nat_size = children.length * max_child_nat + totalSpacing;
|
||||
}));
|
||||
this.actor.connect('get-preferred-height', Lang.bind(this, function (actor, for_width, alloc) {
|
||||
let children = this.actor.get_children();
|
||||
let max_child_min = 0;
|
||||
let max_child_nat = 0;
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
let [child_min, child_nat] = children[i].get_preferred_height(for_width);
|
||||
if (child_min > max_child_min)
|
||||
max_child_min = child_min;
|
||||
if (child_nat > max_child_nat)
|
||||
max_child_nat = child_nat;
|
||||
}
|
||||
alloc.min_size = max_child_min;
|
||||
alloc.nat_size = max_child_nat;
|
||||
}));
|
||||
this.actor.connect('allocate', Lang.bind(this, function (actor, box, flags) {
|
||||
let children = this.actor.get_children();
|
||||
let totalSpacing = (this.spacing * Math.abs(children.length - 1));
|
||||
let child_width = (box.x2 - box.x1 - totalSpacing) / (children.length);
|
||||
let child_height = box.y2 - box.y1;
|
||||
|
||||
let x = box.x1;
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
let [child_min, child_nat] = children[i].get_preferred_height(child_width);
|
||||
let vSpacing = Math.abs(child_height - child_nat) / 2;
|
||||
let childBox = new Clutter.ActorBox();
|
||||
childBox.x1 = x;
|
||||
childBox.y1 = vSpacing;
|
||||
childBox.x2 = x+child_width;
|
||||
childBox.y2 = child_height - vSpacing;
|
||||
children[i].allocate(childBox, flags);
|
||||
x += this.spacing + child_width;
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
function runTestFixedBox() {
|
||||
let testBox = new TestFixedBox();
|
||||
let c = new Clutter.Color();
|
||||
c.from_pixel(0xff0000a0);
|
||||
let r = new Clutter.Rectangle({ width: 50, height: 100, color: c });
|
||||
testBox.actor.add_actor(r);
|
||||
r = new Clutter.Rectangle({ width: 90, height: 70, color: c });
|
||||
testBox.actor.add_actor(r);
|
||||
r = new Clutter.Rectangle({ width: 90, height: 70, color: c });
|
||||
testBox.actor.add_actor(r);
|
||||
r = new Clutter.Rectangle({ width: 30, height: 10, color: c });
|
||||
testBox.actor.add_actor(r);
|
||||
|
||||
c.from_pixel(0x00ff00a0);
|
||||
let borderBox = new Big.Box({ border: 1, border_color: c });
|
||||
borderBox.set_position(100, 100);
|
||||
borderBox.append(testBox.actor, Big.BoxPackFlags.NONE);
|
||||
Shell.Global.get().stage.add_actor(borderBox);
|
||||
}
|
||||
*/
|
||||
|
||||
#include "shell-generic-container.h"
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <girepository.h>
|
||||
|
||||
G_DEFINE_TYPE(ShellGenericContainer, shell_generic_container, CLUTTER_TYPE_GROUP);
|
||||
|
||||
struct _ShellGenericContainerPrivate {
|
||||
gpointer dummy;
|
||||
};
|
||||
|
||||
/* Signals */
|
||||
enum
|
||||
{
|
||||
GET_PREFERRED_WIDTH,
|
||||
GET_PREFERRED_HEIGHT,
|
||||
ALLOCATE,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint shell_generic_container_signals [LAST_SIGNAL] = { 0 };
|
||||
|
||||
|
||||
static gpointer
|
||||
shell_generic_container_allocation_ref (ShellGenericContainerAllocation *alloc)
|
||||
{
|
||||
alloc->_refcount++;
|
||||
return alloc;
|
||||
}
|
||||
|
||||
static void
|
||||
shell_generic_container_allocation_unref (ShellGenericContainerAllocation *alloc)
|
||||
{
|
||||
if (--alloc->_refcount == 0)
|
||||
{
|
||||
g_slice_free1 (sizeof (ShellGenericContainerAllocation), alloc);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
shell_generic_container_allocate (ClutterActor *self,
|
||||
const ClutterActorBox *box,
|
||||
ClutterAllocationFlags flags)
|
||||
{
|
||||
/* chain up to set actor->allocation */
|
||||
(CLUTTER_ACTOR_CLASS (g_type_class_peek (clutter_actor_get_type ())))->allocate (self, box, flags);
|
||||
|
||||
g_signal_emit (G_OBJECT (self), shell_generic_container_signals[ALLOCATE], 0,
|
||||
box, flags);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_generic_container_get_preferred_width (ClutterActor *actor,
|
||||
gfloat for_height,
|
||||
gfloat *min_width_p,
|
||||
gfloat *natural_width_p)
|
||||
{
|
||||
ShellGenericContainerAllocation *alloc = g_slice_alloc0 (sizeof (ShellGenericContainerAllocation));
|
||||
alloc->_refcount = 1;
|
||||
g_signal_emit (G_OBJECT (actor), shell_generic_container_signals[GET_PREFERRED_WIDTH], 0,
|
||||
for_height, alloc);
|
||||
if (min_width_p)
|
||||
*min_width_p = alloc->min_size;
|
||||
if (natural_width_p)
|
||||
*natural_width_p = alloc->natural_size;
|
||||
shell_generic_container_allocation_unref (alloc);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_generic_container_get_preferred_height (ClutterActor *actor,
|
||||
gfloat for_width,
|
||||
gfloat *min_height_p,
|
||||
gfloat *natural_height_p)
|
||||
{
|
||||
ShellGenericContainerAllocation *alloc = g_slice_alloc0 (sizeof (ShellGenericContainerAllocation));
|
||||
alloc->_refcount = 1;
|
||||
g_signal_emit (G_OBJECT (actor), shell_generic_container_signals[GET_PREFERRED_HEIGHT], 0,
|
||||
for_width, alloc);
|
||||
if (min_height_p)
|
||||
*min_height_p = alloc->min_size;
|
||||
if (natural_height_p)
|
||||
*natural_height_p = alloc->natural_size;
|
||||
shell_generic_container_allocation_unref (alloc);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_generic_container_class_init (ShellGenericContainerClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
||||
|
||||
actor_class->get_preferred_width = shell_generic_container_get_preferred_width;
|
||||
actor_class->get_preferred_height = shell_generic_container_get_preferred_height;
|
||||
actor_class->allocate = shell_generic_container_allocate;
|
||||
|
||||
shell_generic_container_signals[GET_PREFERRED_WIDTH] =
|
||||
g_signal_new ("get-preferred-width",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
gi_cclosure_marshal_generic,
|
||||
G_TYPE_NONE, 2, G_TYPE_FLOAT, SHELL_TYPE_GENERIC_CONTAINER_ALLOCATION);
|
||||
|
||||
shell_generic_container_signals[GET_PREFERRED_HEIGHT] =
|
||||
g_signal_new ("get-preferred-height",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
gi_cclosure_marshal_generic,
|
||||
G_TYPE_NONE, 2, G_TYPE_FLOAT, SHELL_TYPE_GENERIC_CONTAINER_ALLOCATION);
|
||||
|
||||
shell_generic_container_signals[ALLOCATE] =
|
||||
g_signal_new ("allocate",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
gi_cclosure_marshal_generic,
|
||||
G_TYPE_NONE, 2, CLUTTER_TYPE_ACTOR_BOX, CLUTTER_TYPE_ALLOCATION_FLAGS);
|
||||
|
||||
g_type_class_add_private (gobject_class, sizeof (ShellGenericContainerPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
shell_generic_container_init (ShellGenericContainer *area)
|
||||
{
|
||||
area->priv = G_TYPE_INSTANCE_GET_PRIVATE (area, SHELL_TYPE_GENERIC_CONTAINER,
|
||||
ShellGenericContainerPrivate);
|
||||
}
|
||||
|
||||
GType shell_generic_container_allocation_get_type (void)
|
||||
{
|
||||
static GType gtype = G_TYPE_INVALID;
|
||||
if (gtype == G_TYPE_INVALID)
|
||||
{
|
||||
gtype = g_boxed_type_register_static ("ShellGenericContainerAllocation",
|
||||
(GBoxedCopyFunc)shell_generic_container_allocation_ref,
|
||||
(GBoxedFreeFunc)shell_generic_container_allocation_unref);
|
||||
}
|
||||
return gtype;
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
#ifndef __SHELL_GENERIC_CONTAINER_H__
|
||||
#define __SHELL_GENERIC_CONTAINER_H__
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define SHELL_TYPE_GENERIC_CONTAINER (shell_generic_container_get_type ())
|
||||
#define SHELL_GENERIC_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_GENERIC_CONTAINER, ShellGenericContainer))
|
||||
#define SHELL_GENERIC_CONTAINER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_GENERIC_CONTAINER, ShellGenericContainerClass))
|
||||
#define SHELL_IS_GENERIC_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_TYPE_GENERIC_CONTAINER))
|
||||
#define SHELL_IS_GENERIC_CONTAINER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_GENERIC_CONTAINER))
|
||||
#define SHELL_GENERIC_CONTAINER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_GENERIC_CONTAINER, ShellGenericContainerClass))
|
||||
|
||||
typedef struct {
|
||||
float min_size;
|
||||
float natural_size;
|
||||
|
||||
/* <private> */
|
||||
guint _refcount;
|
||||
} ShellGenericContainerAllocation;
|
||||
|
||||
#define SHELL_TYPE_GENERIC_CONTAINER_ALLOCATION (shell_generic_container_allocation_get_type ())
|
||||
GType shell_generic_container_allocation_get_type (void);
|
||||
|
||||
typedef struct _ShellGenericContainer ShellGenericContainer;
|
||||
typedef struct _ShellGenericContainerClass ShellGenericContainerClass;
|
||||
|
||||
typedef struct _ShellGenericContainerPrivate ShellGenericContainerPrivate;
|
||||
|
||||
struct _ShellGenericContainer
|
||||
{
|
||||
ClutterGroup parent;
|
||||
|
||||
ShellGenericContainerPrivate *priv;
|
||||
};
|
||||
|
||||
struct _ShellGenericContainerClass
|
||||
{
|
||||
ClutterGroupClass parent_class;
|
||||
};
|
||||
|
||||
GType shell_generic_container_get_type (void) G_GNUC_CONST;
|
||||
|
||||
#endif /* __SHELL_GENERIC_CONTAINER_H__ */
|
||||
@@ -14,8 +14,7 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <dbus/dbus-glib.h>
|
||||
#include <gio/gio.h>
|
||||
#include <glib/gi18n-lib.h>
|
||||
#include <libgnomeui/gnome-thumbnail.h>
|
||||
#include <math.h>
|
||||
#include <X11/extensions/Xfixes.h>
|
||||
|
||||
@@ -40,6 +39,7 @@ struct _ShellGlobal {
|
||||
|
||||
MutterPlugin *plugin;
|
||||
ShellWM *wm;
|
||||
gboolean keyboard_grabbed;
|
||||
const char *imagedir;
|
||||
const char *configdir;
|
||||
|
||||
@@ -270,6 +270,49 @@ shell_global_class_init (ShellGlobalClass *klass)
|
||||
G_PARAM_READABLE));
|
||||
}
|
||||
|
||||
/**
|
||||
* search_path_init:
|
||||
*
|
||||
* search_path_init and get_applications_search_path below were copied from glib/gio/gdesktopappinfo.c
|
||||
* copyright Red Hat, Inc., written by Alex Larsson, licensed under the LGPL
|
||||
*
|
||||
* Return value: location of an array with user and system application directories.
|
||||
*/
|
||||
static gpointer
|
||||
search_path_init (gpointer data)
|
||||
{
|
||||
char **args = NULL;
|
||||
const char * const *data_dirs;
|
||||
const char *user_data_dir;
|
||||
int i, length, j;
|
||||
|
||||
data_dirs = g_get_system_data_dirs ();
|
||||
length = g_strv_length ((char **)data_dirs);
|
||||
|
||||
args = g_new (char *, length + 2);
|
||||
|
||||
j = 0;
|
||||
user_data_dir = g_get_user_data_dir ();
|
||||
args[j++] = g_build_filename (user_data_dir, "applications", NULL);
|
||||
for (i = 0; i < length; i++)
|
||||
args[j++] = g_build_filename (data_dirs[i],
|
||||
"applications", NULL);
|
||||
args[j++] = NULL;
|
||||
|
||||
return args;
|
||||
}
|
||||
/**
|
||||
* get_applications_search_path:
|
||||
*
|
||||
* Return value: location of an array with user and system application directories.
|
||||
*/
|
||||
static const char * const *
|
||||
get_applications_search_path (void)
|
||||
{
|
||||
static GOnce once_init = G_ONCE_INIT;
|
||||
return g_once (&once_init, search_path_init, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_clutter_texture_set_from_pixbuf:
|
||||
* texture: #ClutterTexture to be modified
|
||||
@@ -295,6 +338,135 @@ shell_clutter_texture_set_from_pixbuf (ClutterTexture *texture,
|
||||
0, NULL);
|
||||
}
|
||||
|
||||
static GnomeThumbnailFactory *thumbnail_factory;
|
||||
|
||||
/**
|
||||
* shell_get_thumbnail:
|
||||
*
|
||||
* @uri: URI of the file to thumbnail
|
||||
*
|
||||
* @mime_type: Mime-Type of the file to thumbnail
|
||||
*
|
||||
* Return value: #GdkPixbuf containing a thumbnail for file @uri
|
||||
* if the thumbnail exists or can be generated, %NULL otherwise
|
||||
*/
|
||||
GdkPixbuf *
|
||||
shell_get_thumbnail(const gchar *uri,
|
||||
const gchar *mime_type)
|
||||
{
|
||||
char *existing_thumbnail;
|
||||
GdkPixbuf *pixbuf = NULL;
|
||||
GError *error = NULL;
|
||||
GFile *file = NULL;
|
||||
GFileInfo *file_info = NULL;
|
||||
GTimeVal mtime_g;
|
||||
time_t mtime = 0;
|
||||
|
||||
file = g_file_new_for_uri (uri);
|
||||
file_info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED, G_FILE_QUERY_INFO_NONE, NULL, NULL);
|
||||
g_object_unref (file);
|
||||
if (file_info) {
|
||||
g_file_info_get_modification_time (file_info, &mtime_g);
|
||||
g_object_unref (file_info);
|
||||
mtime = (time_t) mtime_g.tv_sec;
|
||||
}
|
||||
|
||||
if (thumbnail_factory == NULL)
|
||||
thumbnail_factory = gnome_thumbnail_factory_new (GNOME_THUMBNAIL_SIZE_NORMAL);
|
||||
|
||||
existing_thumbnail = gnome_thumbnail_factory_lookup (thumbnail_factory, uri, mtime);
|
||||
|
||||
if (existing_thumbnail != NULL)
|
||||
{
|
||||
pixbuf = gdk_pixbuf_new_from_file(existing_thumbnail, &error);
|
||||
if (error != NULL)
|
||||
{
|
||||
g_warning("Could not generate a pixbuf from file %s: %s", existing_thumbnail, error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
}
|
||||
else if (gnome_thumbnail_factory_has_valid_failed_thumbnail (thumbnail_factory, uri, mtime))
|
||||
return NULL;
|
||||
else if (gnome_thumbnail_factory_can_thumbnail (thumbnail_factory, uri, mime_type, mtime))
|
||||
{
|
||||
pixbuf = gnome_thumbnail_factory_generate_thumbnail (thumbnail_factory, uri, mime_type);
|
||||
if (pixbuf)
|
||||
{
|
||||
// we need to save the thumbnail so that we don't need to generate it again in the future
|
||||
gnome_thumbnail_factory_save_thumbnail (thumbnail_factory, pixbuf, uri, mtime);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Could not generate thumbnail for %s", uri);
|
||||
gnome_thumbnail_factory_create_failed_thumbnail (thumbnail_factory, uri, mtime);
|
||||
}
|
||||
}
|
||||
|
||||
return pixbuf;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* shell_get_categories_for_desktop_file:
|
||||
*
|
||||
* @desktop_file_name: name of the desktop file for which to retrieve categories
|
||||
*
|
||||
* Return value: (element-type char*) (transfer full): List of categories
|
||||
*
|
||||
*/
|
||||
GSList *
|
||||
shell_get_categories_for_desktop_file(const char *desktop_file_name)
|
||||
{
|
||||
GKeyFile *key_file;
|
||||
const char * const *search_dirs;
|
||||
char **categories = NULL;
|
||||
GSList *categories_list = NULL;
|
||||
GError *error = NULL;
|
||||
gsize len;
|
||||
int i;
|
||||
|
||||
key_file = g_key_file_new ();
|
||||
search_dirs = get_applications_search_path();
|
||||
|
||||
g_key_file_load_from_dirs (key_file, desktop_file_name, (const char **)search_dirs, NULL, 0, &error);
|
||||
|
||||
if (error != NULL)
|
||||
{
|
||||
g_warning ("Error when loading a key file for %s: %s", desktop_file_name, error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
else
|
||||
{
|
||||
categories = g_key_file_get_string_list (key_file,
|
||||
"Desktop Entry",
|
||||
"Categories",
|
||||
&len,
|
||||
&error);
|
||||
if (error != NULL)
|
||||
{
|
||||
// "Categories" is not a required key in the desktop files, so it's ok if we didn't find it
|
||||
g_clear_error (&error);
|
||||
}
|
||||
}
|
||||
|
||||
g_key_file_free (key_file);
|
||||
|
||||
if (categories == NULL)
|
||||
return NULL;
|
||||
|
||||
// gjs currently does not support returning arrays (other than a NULL value for an array), so we need
|
||||
// to convert the array we are returning to GSList, returning which gjs supports.
|
||||
// See http://bugzilla.gnome.org/show_bug.cgi?id=560567 for more info on gjs array support.
|
||||
for (i = 0; categories[i]; i++)
|
||||
{
|
||||
categories_list = g_slist_prepend (categories_list, g_strdup (categories[i]));
|
||||
}
|
||||
|
||||
g_strfreev (categories);
|
||||
|
||||
return categories_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_get_event_key_symbol:
|
||||
*
|
||||
@@ -474,66 +646,66 @@ _shell_global_set_plugin (ShellGlobal *global,
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_global_begin_modal:
|
||||
* shell_global_grab_keyboard:
|
||||
* @global: a #ShellGlobal
|
||||
*
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
gboolean
|
||||
shell_global_begin_modal (ShellGlobal *global,
|
||||
guint32 timestamp)
|
||||
{
|
||||
ClutterStage *stage = CLUTTER_STAGE (mutter_plugin_get_stage (global->plugin));
|
||||
Window stagewin = clutter_x11_get_stage_window (stage);
|
||||
|
||||
return mutter_plugin_begin_modal (global->plugin, stagewin, None, 0, timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_global_end_modal:
|
||||
* @global: a #ShellGlobal
|
||||
*
|
||||
* Undoes the effect of shell_global_begin_modal().
|
||||
*/
|
||||
void
|
||||
shell_global_end_modal (ShellGlobal *global,
|
||||
guint32 timestamp)
|
||||
{
|
||||
mutter_plugin_end_modal (global->plugin, timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
shell_global_grab_keyboard (ShellGlobal *global)
|
||||
{
|
||||
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);
|
||||
|
||||
return meta_display_get_grab_op (display) != META_GRAB_OP_NONE;
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_global_ungrab_keyboard:
|
||||
* @global: a #ShellGlobal
|
||||
*
|
||||
* Undoes the effect of shell_global_grab_keyboard
|
||||
*/
|
||||
void
|
||||
shell_global_ungrab_keyboard (ShellGlobal *global)
|
||||
{
|
||||
MetaScreen *screen;
|
||||
MetaDisplay *display;
|
||||
Display *xdisplay;
|
||||
|
||||
g_return_if_fail (global->keyboard_grabbed);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* Code to close all file descriptors before we exec; copied from gspawn.c in GLib.
|
||||
@@ -696,26 +868,24 @@ shell_global_grab_dbus_service (ShellGlobal *global)
|
||||
*/
|
||||
exit (0);
|
||||
}
|
||||
|
||||
/* Also grab org.gnome.Panel to replace any existing panel process,
|
||||
* unless a special environment variable is passed. The environment
|
||||
* variable is used by the gnome-shell (no --replace) launcher in
|
||||
* Xephyr */
|
||||
if (!g_getenv ("GNOME_SHELL_NO_REPLACE_PANEL"))
|
||||
{
|
||||
if (!dbus_g_proxy_call (bus, "RequestName", &error, G_TYPE_STRING,
|
||||
"org.gnome.Panel", G_TYPE_UINT,
|
||||
DBUS_NAME_FLAG_REPLACE_EXISTING | DBUS_NAME_FLAG_DO_NOT_QUEUE,
|
||||
G_TYPE_INVALID, G_TYPE_UINT,
|
||||
&request_name_result, G_TYPE_INVALID))
|
||||
{
|
||||
g_print ("failed to acquire org.gnome.Panel: %s\n", error->message);
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
g_object_unref (bus);
|
||||
}
|
||||
|
||||
void
|
||||
shell_global_start_task_panel (ShellGlobal *global)
|
||||
{
|
||||
const char* panel_args[] = {"gnomeshell-taskpanel", SHELL_DBUS_SERVICE, NULL};
|
||||
GError *error = NULL;
|
||||
|
||||
if (!g_spawn_async (NULL, (char**)panel_args, NULL, G_SPAWN_SEARCH_PATH, NULL,
|
||||
NULL, NULL, &error))
|
||||
{
|
||||
g_critical ("failed to execute %s: %s", panel_args[0], error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
grab_notify (GtkWidget *widget, gboolean was_grabbed, gpointer user_data)
|
||||
{
|
||||
@@ -727,6 +897,102 @@ grab_notify (GtkWidget *widget, gboolean was_grabbed, gpointer user_data)
|
||||
shell_global_set_stage_input_mode (global, global->input_mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_global_create_vertical_gradient:
|
||||
* @top: the color at the top
|
||||
* @bottom: the color at the bottom
|
||||
*
|
||||
* Creates a vertical gradient actor.
|
||||
*
|
||||
* Return value: (transfer none): a #ClutterCairoTexture actor with the
|
||||
* gradient. The texture actor is floating, hence (transfer none).
|
||||
*/
|
||||
ClutterCairoTexture *
|
||||
shell_global_create_vertical_gradient (ClutterColor *top,
|
||||
ClutterColor *bottom)
|
||||
{
|
||||
ClutterCairoTexture *texture;
|
||||
cairo_t *cr;
|
||||
cairo_pattern_t *pattern;
|
||||
|
||||
/* Draw the gradient on an 8x8 pixel texture. Because the gradient is drawn
|
||||
* from the uppermost to the lowermost row, after stretching 1/16 of the
|
||||
* texture height has the top color and 1/16 has the bottom color. The 8
|
||||
* pixel width is chosen for reasons related to graphics hardware internals.
|
||||
*/
|
||||
texture = CLUTTER_CAIRO_TEXTURE (clutter_cairo_texture_new (8, 8));
|
||||
cr = clutter_cairo_texture_create (texture);
|
||||
|
||||
pattern = cairo_pattern_create_linear (0, 0, 0, 8);
|
||||
cairo_pattern_add_color_stop_rgba (pattern, 0,
|
||||
top->red / 255.,
|
||||
top->green / 255.,
|
||||
top->blue / 255.,
|
||||
top->alpha / 255.);
|
||||
cairo_pattern_add_color_stop_rgba (pattern, 1,
|
||||
bottom->red / 255.,
|
||||
bottom->green / 255.,
|
||||
bottom->blue / 255.,
|
||||
bottom->alpha / 255.);
|
||||
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_pattern_destroy (pattern);
|
||||
cairo_destroy (cr);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_global_create_horizontal_gradient:
|
||||
* @left: the color on the left
|
||||
* @right: the color on the right
|
||||
*
|
||||
* Creates a horizontal gradient actor.
|
||||
*
|
||||
* Return value: (transfer none): a #ClutterCairoTexture actor with the
|
||||
* gradient. The texture actor is floating, hence (transfer none).
|
||||
*/
|
||||
ClutterCairoTexture *
|
||||
shell_global_create_horizontal_gradient (ClutterColor *left,
|
||||
ClutterColor *right)
|
||||
{
|
||||
ClutterCairoTexture *texture;
|
||||
cairo_t *cr;
|
||||
cairo_pattern_t *pattern;
|
||||
|
||||
/* Draw the gradient on an 8x1 pixel texture. Because the gradient is drawn
|
||||
* from the left to the right column, after stretching 1/16 of the
|
||||
* texture width has the left side color and 1/16 has the right side color.
|
||||
* There is no reason to use the 8 pixel height that would be similar to the
|
||||
* reason we are using the 8 pixel width for the vertical gradient, so we
|
||||
* are just using the 1 pixel height instead.
|
||||
*/
|
||||
texture = CLUTTER_CAIRO_TEXTURE (clutter_cairo_texture_new (8, 1));
|
||||
cr = clutter_cairo_texture_create (texture);
|
||||
|
||||
pattern = cairo_pattern_create_linear (0, 0, 8, 0);
|
||||
cairo_pattern_add_color_stop_rgba (pattern, 0,
|
||||
left->red / 255.,
|
||||
left->green / 255.,
|
||||
left->blue / 255.,
|
||||
left->alpha / 255.);
|
||||
cairo_pattern_add_color_stop_rgba (pattern, 1,
|
||||
right->red / 255.,
|
||||
right->green / 255.,
|
||||
right->blue / 255.,
|
||||
right->alpha / 255.);
|
||||
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_pattern_destroy (pattern);
|
||||
cairo_destroy (cr);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
/*
|
||||
* Updates the global->root_pixmap actor with the root window's pixmap or fails
|
||||
* with a warning.
|
||||
@@ -814,46 +1080,6 @@ root_pixmap_destroy (GObject *sender, gpointer data)
|
||||
global->root_pixmap = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_global_format_time_relative_pretty:
|
||||
* @global:
|
||||
* @delta: Time in seconds since the current time
|
||||
* @text: (out): Relative human-consumption-only time string
|
||||
* @next_update: (out): Time in seconds until we should redisplay the time
|
||||
*
|
||||
* Format a time value for human consumption only. The passed time
|
||||
* value is a delta in terms of seconds from the current time.
|
||||
* This function needs to be in C because of its use of ngettext() which
|
||||
* is not accessible from JavaScript.
|
||||
*/
|
||||
void
|
||||
shell_global_format_time_relative_pretty (ShellGlobal *global,
|
||||
guint delta,
|
||||
char **text,
|
||||
guint *next_update)
|
||||
{
|
||||
#define MINUTE (60)
|
||||
#define HOUR (MINUTE*60)
|
||||
#define DAY (HOUR*24)
|
||||
#define WEEK (DAY*7)
|
||||
if (delta < MINUTE) {
|
||||
*text = g_strdup (_("Less than a minute ago"));
|
||||
*next_update = MINUTE - delta;
|
||||
} else if (delta < HOUR) {
|
||||
*text = g_strdup_printf (ngettext ("%d minute ago", "%d minutes ago", delta / MINUTE), delta / MINUTE);
|
||||
*next_update = MINUTE - (delta % MINUTE);
|
||||
} else if (delta < DAY) {
|
||||
*text = g_strdup_printf (ngettext ("%d hour ago", "%d hours ago", delta / HOUR), delta / HOUR);
|
||||
*next_update = HOUR - (delta % HOUR);
|
||||
} else if (delta < WEEK) {
|
||||
*text = g_strdup_printf (ngettext ("%d day ago", "%d days ago", delta / DAY), delta / DAY);
|
||||
*next_update = DAY - (delta % DAY);
|
||||
} else {
|
||||
*text = g_strdup_printf (ngettext ("%d week ago", "%d weeks ago", delta / WEEK), delta / WEEK);
|
||||
*next_update = WEEK - (delta % WEEK);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_global_create_root_pixmap_actor:
|
||||
* @global: a #ShellGlobal
|
||||
@@ -910,3 +1136,50 @@ shell_global_create_root_pixmap_actor (ShellGlobal *global)
|
||||
|
||||
return clutter_clone_new (global->root_pixmap);
|
||||
}
|
||||
|
||||
void
|
||||
shell_global_clutter_cairo_texture_draw_clock (ClutterCairoTexture *texture,
|
||||
int hour,
|
||||
int minute)
|
||||
{
|
||||
cairo_t *cr;
|
||||
guint width, height;
|
||||
double xc, yc, radius, hour_radius, minute_radius;
|
||||
double angle;
|
||||
|
||||
clutter_cairo_texture_get_surface_size (texture, &width, &height);
|
||||
xc = (double)width / 2;
|
||||
yc = (double)height / 2;
|
||||
radius = (double)(MIN(width, height)) / 2 - 2;
|
||||
minute_radius = radius - 3;
|
||||
hour_radius = radius / 2;
|
||||
|
||||
clutter_cairo_texture_clear (texture);
|
||||
cr = clutter_cairo_texture_create (texture);
|
||||
cairo_set_line_width (cr, 1.0);
|
||||
|
||||
/* Outline */
|
||||
cairo_arc (cr, xc, yc, radius, 0.0, 2.0 * M_PI);
|
||||
cairo_stroke (cr);
|
||||
|
||||
/* Hour hand. (We add a fraction to @hour for the minutes, then
|
||||
* convert to radians, and then subtract pi/2 because cairo's origin
|
||||
* is at 3:00, not 12:00.)
|
||||
*/
|
||||
angle = ((hour + minute / 60.0) / 12.0) * 2.0 * M_PI - M_PI / 2.0;
|
||||
cairo_move_to (cr, xc, yc);
|
||||
cairo_line_to (cr,
|
||||
xc + hour_radius * cos (angle),
|
||||
yc + hour_radius * sin (angle));
|
||||
cairo_stroke (cr);
|
||||
|
||||
/* Minute hand */
|
||||
angle = (minute / 60.0) * 2.0 * M_PI - M_PI / 2.0;
|
||||
cairo_move_to (cr, xc, yc);
|
||||
cairo_line_to (cr,
|
||||
xc + minute_radius * cos (angle),
|
||||
yc + minute_radius * sin (angle));
|
||||
cairo_stroke (cr);
|
||||
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
@@ -36,6 +36,10 @@ GType shell_global_get_type (void) G_GNUC_CONST;
|
||||
gboolean shell_clutter_texture_set_from_pixbuf (ClutterTexture *texture,
|
||||
GdkPixbuf *pixbuf);
|
||||
|
||||
GdkPixbuf *shell_get_thumbnail(const gchar *uri, const gchar *mime_type);
|
||||
|
||||
GSList *shell_get_categories_for_desktop_file(const char *desktop_file_name);
|
||||
|
||||
guint16 shell_get_event_key_symbol(ClutterEvent *event);
|
||||
|
||||
guint16 shell_get_button_event_click_count(ClutterEvent *event);
|
||||
@@ -48,6 +52,8 @@ MetaScreen *shell_global_get_screen (ShellGlobal *global);
|
||||
|
||||
void shell_global_grab_dbus_service (ShellGlobal *global);
|
||||
|
||||
void shell_global_start_task_panel (ShellGlobal *global);
|
||||
|
||||
typedef enum {
|
||||
SHELL_STAGE_INPUT_MODE_NONREACTIVE,
|
||||
SHELL_STAGE_INPUT_MODE_NORMAL,
|
||||
@@ -64,19 +70,23 @@ GList *shell_global_get_windows (ShellGlobal *global);
|
||||
void _shell_global_set_plugin (ShellGlobal *global,
|
||||
MutterPlugin *plugin);
|
||||
|
||||
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);
|
||||
gboolean shell_global_grab_keyboard (ShellGlobal *global);
|
||||
void shell_global_ungrab_keyboard (ShellGlobal *global);
|
||||
|
||||
void shell_global_reexec_self (ShellGlobal *global);
|
||||
|
||||
void shell_global_format_time_relative_pretty (ShellGlobal *global, guint delta, char **text, guint *update_time);
|
||||
ClutterCairoTexture *shell_global_create_vertical_gradient (ClutterColor *top,
|
||||
ClutterColor *bottom);
|
||||
|
||||
ClutterCairoTexture *shell_global_create_horizontal_gradient (ClutterColor *left,
|
||||
ClutterColor *right);
|
||||
|
||||
ClutterActor *shell_global_create_root_pixmap_actor (ShellGlobal *global);
|
||||
|
||||
void shell_global_clutter_cairo_texture_draw_clock (ClutterCairoTexture *texture,
|
||||
int hour,
|
||||
int minute);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __SHELL_GLOBAL_H__ */
|
||||
|
||||
@@ -1,4 +1,2 @@
|
||||
VOID:INT,INT,INT
|
||||
VOID:OBJECT,INT,INT,INT,INT
|
||||
VOID:BOXED
|
||||
VOID:BOXED,OBJECT
|
||||
|
||||
@@ -1,426 +0,0 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include "shell-overflow-list.h"
|
||||
|
||||
G_DEFINE_TYPE (ShellOverflowList,
|
||||
shell_overflow_list,
|
||||
CLUTTER_TYPE_GROUP);
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_SPACING,
|
||||
PROP_ITEM_HEIGHT,
|
||||
PROP_DISPLAYED_COUNT,
|
||||
PROP_PAGE,
|
||||
PROP_N_PAGES
|
||||
};
|
||||
|
||||
struct _ShellOverflowListPrivate {
|
||||
guint item_height;
|
||||
guint spacing;
|
||||
guint page;
|
||||
guint n_pages;
|
||||
guint items_per_page;
|
||||
guint displayed_count;
|
||||
};
|
||||
|
||||
static void
|
||||
recalc_displayed_count (ShellOverflowList *self)
|
||||
{
|
||||
GList *children;
|
||||
int n_children;
|
||||
int displayed_count;
|
||||
int page, n_pages;
|
||||
|
||||
children = clutter_container_get_children (CLUTTER_CONTAINER (self));
|
||||
n_children = g_list_length (children);
|
||||
g_list_free (children);
|
||||
|
||||
page = self->priv->page;
|
||||
n_pages = self->priv->n_pages;
|
||||
if (page < n_pages-1)
|
||||
displayed_count = self->priv->items_per_page;
|
||||
else if (n_pages > 0)
|
||||
displayed_count = n_children - (self->priv->items_per_page * (n_pages-1));
|
||||
else
|
||||
displayed_count = 0;
|
||||
if (displayed_count != self->priv->displayed_count)
|
||||
{
|
||||
self->priv->displayed_count = displayed_count;
|
||||
g_object_notify (G_OBJECT (self), "displayed-count");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
shell_overflow_list_set_property(GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ShellOverflowList *self = SHELL_OVERFLOW_LIST (object);
|
||||
ShellOverflowListPrivate *priv = self->priv;
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SPACING:
|
||||
priv->spacing = g_value_get_float (value);
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
|
||||
break;
|
||||
case PROP_ITEM_HEIGHT:
|
||||
priv->item_height = g_value_get_float (value);
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
|
||||
break;
|
||||
case PROP_PAGE:
|
||||
priv->page = g_value_get_uint (value);
|
||||
recalc_displayed_count (self);
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
shell_overflow_list_get_property(GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ShellOverflowList *self = SHELL_OVERFLOW_LIST (object);
|
||||
ShellOverflowListPrivate *priv = self->priv;
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_SPACING:
|
||||
g_value_set_float (value, priv->spacing);
|
||||
break;
|
||||
case PROP_ITEM_HEIGHT:
|
||||
g_value_set_float (value, priv->spacing);
|
||||
break;
|
||||
case PROP_DISPLAYED_COUNT:
|
||||
g_value_set_uint (value, priv->displayed_count);
|
||||
break;
|
||||
case PROP_PAGE:
|
||||
g_value_set_uint (value, priv->page);
|
||||
break;
|
||||
case PROP_N_PAGES:
|
||||
g_value_set_uint (value, priv->n_pages);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
shell_overflow_list_allocate (ClutterActor *actor,
|
||||
const ClutterActorBox *box,
|
||||
ClutterAllocationFlags flags)
|
||||
{
|
||||
ShellOverflowList *self = SHELL_OVERFLOW_LIST (actor);
|
||||
ShellOverflowListPrivate *priv = self->priv;
|
||||
GList *children, *iter;
|
||||
int n_pages;
|
||||
int n_children;
|
||||
int n_fits;
|
||||
float width;
|
||||
float curheight;
|
||||
float avail_height;
|
||||
gboolean overflow;
|
||||
|
||||
/* chain up to set actor->allocation */
|
||||
(CLUTTER_ACTOR_CLASS (g_type_class_peek (clutter_actor_get_type ())))->allocate (actor, box, flags);
|
||||
|
||||
width = box->x2 - box->x1;
|
||||
curheight = 0;
|
||||
avail_height = box->y2 - box->y1;
|
||||
|
||||
children = clutter_container_get_children (CLUTTER_CONTAINER (self));
|
||||
n_children = g_list_length (children);
|
||||
|
||||
n_fits = 0;
|
||||
n_pages = 1;
|
||||
overflow = FALSE;
|
||||
for (iter = children; iter; iter = iter->next)
|
||||
{
|
||||
ClutterActor *actor = CLUTTER_ACTOR (iter->data);
|
||||
ClutterActorBox child_box;
|
||||
|
||||
if (iter != children)
|
||||
curheight += priv->spacing;
|
||||
|
||||
if ((curheight + priv->item_height) > avail_height)
|
||||
{
|
||||
overflow = TRUE;
|
||||
curheight = 0;
|
||||
n_pages++;
|
||||
}
|
||||
else if (!overflow)
|
||||
n_fits++;
|
||||
|
||||
child_box.x1 = 0;
|
||||
child_box.x2 = width;
|
||||
child_box.y1 = curheight;
|
||||
child_box.y2 = child_box.y1 + priv->item_height;
|
||||
clutter_actor_allocate (actor, &child_box, flags);
|
||||
|
||||
curheight += priv->item_height;
|
||||
}
|
||||
|
||||
priv->items_per_page = n_fits;
|
||||
|
||||
if (n_pages != priv->n_pages)
|
||||
{
|
||||
priv->n_pages = n_pages;
|
||||
g_object_notify (G_OBJECT (self), "n-pages");
|
||||
}
|
||||
|
||||
recalc_displayed_count (self);
|
||||
|
||||
g_list_free (children);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_overflow_list_paint (ClutterActor *actor)
|
||||
{
|
||||
ShellOverflowList *self = SHELL_OVERFLOW_LIST (actor);
|
||||
ShellOverflowListPrivate *priv = self->priv;
|
||||
GList *children, *iter;
|
||||
int i;
|
||||
|
||||
children = clutter_container_get_children (CLUTTER_CONTAINER (self));
|
||||
|
||||
if (children == NULL)
|
||||
return;
|
||||
|
||||
iter = g_list_nth (children, (priv->page) * priv->items_per_page);
|
||||
|
||||
i = 0;
|
||||
for (;iter && i < priv->items_per_page; iter = iter->next, i++)
|
||||
{
|
||||
ClutterActor *actor = CLUTTER_ACTOR (iter->data);
|
||||
|
||||
clutter_actor_paint (actor);
|
||||
}
|
||||
g_list_free (children);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_overflow_list_pick (ClutterActor *actor,
|
||||
const ClutterColor *color)
|
||||
{
|
||||
(CLUTTER_ACTOR_CLASS (g_type_class_peek (clutter_actor_get_type ())))->pick (actor, color);
|
||||
|
||||
shell_overflow_list_paint (actor);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
shell_overflow_list_get_preferred_height (ClutterActor *actor,
|
||||
gfloat for_width,
|
||||
gfloat *min_height_p,
|
||||
gfloat *natural_height_p)
|
||||
{
|
||||
ShellOverflowList *self = SHELL_OVERFLOW_LIST (actor);
|
||||
ShellOverflowListPrivate *priv = self->priv;
|
||||
GList *children;
|
||||
|
||||
if (min_height_p)
|
||||
*min_height_p = 0;
|
||||
|
||||
if (natural_height_p)
|
||||
{
|
||||
int n_children;
|
||||
children = clutter_container_get_children (CLUTTER_CONTAINER (self));
|
||||
n_children = g_list_length (children);
|
||||
if (n_children == 0)
|
||||
*natural_height_p = 0;
|
||||
else
|
||||
*natural_height_p = (n_children - 1) * (priv->item_height + priv->spacing) + priv->item_height;
|
||||
g_list_free (children);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
shell_overflow_list_get_preferred_width (ClutterActor *actor,
|
||||
gfloat for_height,
|
||||
gfloat *min_width_p,
|
||||
gfloat *natural_width_p)
|
||||
{
|
||||
ShellOverflowList *self = SHELL_OVERFLOW_LIST (actor);
|
||||
gboolean first = TRUE;
|
||||
float min = 0, natural = 0;
|
||||
GList *iter;
|
||||
GList *children;
|
||||
|
||||
children = clutter_container_get_children (CLUTTER_CONTAINER (self));
|
||||
|
||||
for (iter = children; iter; iter = iter->next)
|
||||
{
|
||||
ClutterActor *child = iter->data;
|
||||
float child_min, child_natural;
|
||||
|
||||
clutter_actor_get_preferred_width (child,
|
||||
for_height,
|
||||
&child_min,
|
||||
&child_natural);
|
||||
|
||||
if (first)
|
||||
{
|
||||
first = FALSE;
|
||||
min = child_min;
|
||||
natural = child_natural;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (child_min > min)
|
||||
min = child_min;
|
||||
|
||||
if (child_natural > natural)
|
||||
natural = child_natural;
|
||||
}
|
||||
}
|
||||
|
||||
if (min_width_p)
|
||||
*min_width_p = min;
|
||||
|
||||
if (natural_width_p)
|
||||
*natural_width_p = natural;
|
||||
g_list_free (children);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_overflow_list_class_init (ShellOverflowListClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
||||
|
||||
gobject_class->get_property = shell_overflow_list_get_property;
|
||||
gobject_class->set_property = shell_overflow_list_set_property;
|
||||
|
||||
actor_class->get_preferred_width = shell_overflow_list_get_preferred_width;
|
||||
actor_class->get_preferred_height = shell_overflow_list_get_preferred_height;
|
||||
actor_class->allocate = shell_overflow_list_allocate;
|
||||
actor_class->paint = shell_overflow_list_paint;
|
||||
actor_class->pick = shell_overflow_list_pick;
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_SPACING,
|
||||
g_param_spec_float ("spacing",
|
||||
"Spacing",
|
||||
"Space between items",
|
||||
0.0, G_MAXFLOAT, 0.0,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_ITEM_HEIGHT,
|
||||
g_param_spec_float ("item-height",
|
||||
"Item height",
|
||||
"Fixed item height value",
|
||||
0.0, G_MAXFLOAT, 0.0,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_DISPLAYED_COUNT,
|
||||
g_param_spec_uint ("displayed-count",
|
||||
"Displayed count",
|
||||
"Number of items displayed on current page",
|
||||
0, G_MAXUINT, 0,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_PAGE,
|
||||
g_param_spec_uint ("page",
|
||||
"Page number",
|
||||
"Page number",
|
||||
0, G_MAXUINT, 0,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_N_PAGES,
|
||||
g_param_spec_uint ("n-pages",
|
||||
"Number of pages",
|
||||
"Number of pages",
|
||||
0, G_MAXUINT, 0,
|
||||
G_PARAM_READABLE));
|
||||
|
||||
g_type_class_add_private (gobject_class, sizeof (ShellOverflowListPrivate));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
shell_overflow_list_init (ShellOverflowList *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
|
||||
SHELL_TYPE_OVERFLOW_LIST,
|
||||
ShellOverflowListPrivate);
|
||||
self->priv->n_pages = 1;
|
||||
self->priv->page = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_overflow_list_get_displayed_actor:
|
||||
* @self:
|
||||
* @index: 0-based index for displayed list
|
||||
*
|
||||
* Returns the actor at the given index on the current page.
|
||||
*
|
||||
* Return value: (transfer none): #ClutterActor at index
|
||||
*/
|
||||
ClutterActor *
|
||||
shell_overflow_list_get_displayed_actor (ShellOverflowList *self,
|
||||
guint index)
|
||||
{
|
||||
GList *children, *iter;
|
||||
|
||||
children = clutter_container_get_children (CLUTTER_CONTAINER (self));
|
||||
|
||||
if (children == NULL)
|
||||
return NULL;
|
||||
|
||||
iter = g_list_nth (children, index + (self->priv->page * self->priv->items_per_page));
|
||||
|
||||
if (!iter)
|
||||
return NULL;
|
||||
|
||||
return iter->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_overflow_list_get_actor_index:
|
||||
* @self:
|
||||
* @actor: a child of the list
|
||||
*
|
||||
* Returns the index on the current page of the given actor.
|
||||
*
|
||||
* Return value: index of @actor in
|
||||
* the currently visible page
|
||||
*/
|
||||
int
|
||||
shell_overflow_list_get_actor_index (ShellOverflowList *self,
|
||||
ClutterActor *actor)
|
||||
{
|
||||
GList *children, *iter;
|
||||
int i;
|
||||
int result;
|
||||
|
||||
children = clutter_container_get_children (CLUTTER_CONTAINER (self));
|
||||
|
||||
if (children == NULL)
|
||||
return -1;
|
||||
|
||||
iter = g_list_nth (children, (self->priv->page) * self->priv->items_per_page);
|
||||
|
||||
result = -1;
|
||||
for (i = 0; iter; iter = iter->next, i++)
|
||||
if (iter->data == actor)
|
||||
{
|
||||
result = i;
|
||||
break;
|
||||
}
|
||||
|
||||
g_list_free (children);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
#ifndef __SHELL_OVERFLOW_LIST_H__
|
||||
#define __SHELL_OVERFLOW_LIST_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
#include <glib.h>
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _ShellOverflowList ShellOverflowList;
|
||||
typedef struct _ShellOverflowListClass ShellOverflowListClass;
|
||||
typedef struct _ShellOverflowListPrivate ShellOverflowListPrivate;
|
||||
|
||||
#define SHELL_TYPE_OVERFLOW_LIST (shell_overflow_list_get_type ())
|
||||
#define SHELL_OVERFLOW_LIST(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), SHELL_TYPE_OVERFLOW_LIST, ShellOverflowList))
|
||||
#define SHELL_OVERFLOW_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_OVERFLOW_LIST, ShellOverflowListClass))
|
||||
#define SHELL_IS_OVERFLOW_LIST(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), SHELL_TYPE_OVERFLOW_LIST))
|
||||
#define SHELL_IS_OVERFLOW_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_OVERFLOW_LIST))
|
||||
#define SHELL_OVERFLOW_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_OVERFLOW_LIST, ShellOverflowListClass))
|
||||
|
||||
struct _ShellOverflowList
|
||||
{
|
||||
ClutterGroup parent_instance;
|
||||
|
||||
ShellOverflowListPrivate *priv;
|
||||
};
|
||||
|
||||
struct _ShellOverflowListClass
|
||||
{
|
||||
ClutterGroupClass parent_class;
|
||||
|
||||
ShellOverflowListPrivate *priv;
|
||||
};
|
||||
|
||||
GType shell_overflow_list_get_type (void) G_GNUC_CONST;
|
||||
|
||||
ClutterActor *shell_overflow_list_get_displayed_actor (ShellOverflowList *list, guint index);
|
||||
int shell_overflow_list_get_actor_index (ShellOverflowList *list, ClutterActor *actor);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __SHELL_OVERFLOW_LIST_H__ */
|
||||
@@ -52,6 +52,8 @@ static void shell_process_init (ShellProcess *self)
|
||||
|
||||
static void shell_process_dispose (GObject *object)
|
||||
{
|
||||
ShellProcess *self = (ShellProcess*)object;
|
||||
|
||||
G_OBJECT_CLASS (shell_process_parent_class)->dispose(object);
|
||||
}
|
||||
|
||||
|
||||
@@ -221,8 +221,7 @@ get_memory_target (void)
|
||||
return mem_total / 2;
|
||||
}
|
||||
/* Skip to the next line and discard what we read */
|
||||
if (fgets(line_buffer, sizeof(line_buffer), f) == NULL)
|
||||
break;
|
||||
fgets(line_buffer, sizeof(line_buffer), f);
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
@@ -233,9 +232,6 @@ get_memory_target (void)
|
||||
static void
|
||||
shell_recorder_init (ShellRecorder *recorder)
|
||||
{
|
||||
/* Calling gst_init() is a no-op if GStreamer was previously initialized */
|
||||
gst_init (NULL, NULL);
|
||||
|
||||
shell_recorder_src_register ();
|
||||
|
||||
recorder->recording_icon = create_recording_icon ();
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/**
|
||||
* SECTION:shell-stack
|
||||
* @short_description: Pure "Z-axis" container class
|
||||
*
|
||||
* A #ShellStack draws its children on top of each other,
|
||||
* aligned to the top left. It will be sized in width/height
|
||||
* according to the largest such dimension of its children, and
|
||||
* all children will be allocated that size. This differs
|
||||
* from #ClutterGroup which allocates its children their natural
|
||||
* size, even if that would overflow the size allocated to the stack.
|
||||
*/
|
||||
|
||||
#include "shell-stack.h"
|
||||
|
||||
G_DEFINE_TYPE (ShellStack,
|
||||
shell_stack,
|
||||
CLUTTER_TYPE_GROUP);
|
||||
|
||||
static void
|
||||
shell_stack_allocate (ClutterActor *self,
|
||||
const ClutterActorBox *box,
|
||||
ClutterAllocationFlags flags)
|
||||
{
|
||||
GList *children, *iter;
|
||||
float width, height;
|
||||
|
||||
width = box->x2 - box->x1;
|
||||
height = box->y2 - box->y1;
|
||||
|
||||
/* 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);
|
||||
|
||||
children = clutter_container_get_children (CLUTTER_CONTAINER (self));
|
||||
for (iter = children; iter; iter = iter->next)
|
||||
{
|
||||
ClutterActor *actor = CLUTTER_ACTOR (iter->data);
|
||||
ClutterActorBox child_box;
|
||||
child_box.x1 = 0;
|
||||
child_box.x2 = width;
|
||||
child_box.y1 = 0;
|
||||
child_box.y2 = height;
|
||||
clutter_actor_allocate (actor, &child_box, flags);
|
||||
}
|
||||
g_list_free (children);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_stack_get_preferred_height (ClutterActor *actor,
|
||||
gfloat for_width,
|
||||
gfloat *min_height_p,
|
||||
gfloat *natural_height_p)
|
||||
{
|
||||
ShellStack *stack = SHELL_STACK (actor);
|
||||
gboolean first = TRUE;
|
||||
float min = 0, natural = 0;
|
||||
GList *children;
|
||||
GList *iter;
|
||||
|
||||
children = clutter_container_get_children (CLUTTER_CONTAINER (stack));
|
||||
|
||||
for (iter = children; iter; iter = iter->next)
|
||||
{
|
||||
ClutterActor *child = iter->data;
|
||||
float child_min, child_natural;
|
||||
|
||||
clutter_actor_get_preferred_height (child,
|
||||
for_width,
|
||||
&child_min,
|
||||
&child_natural);
|
||||
|
||||
if (first)
|
||||
{
|
||||
first = FALSE;
|
||||
min = child_min;
|
||||
natural = child_natural;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (child_min > min)
|
||||
min = child_min;
|
||||
|
||||
if (child_natural > natural)
|
||||
natural = child_natural;
|
||||
}
|
||||
}
|
||||
|
||||
if (min_height_p)
|
||||
*min_height_p = min;
|
||||
|
||||
if (natural_height_p)
|
||||
*natural_height_p = natural;
|
||||
|
||||
g_list_free (children);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_stack_get_preferred_width (ClutterActor *actor,
|
||||
gfloat for_height,
|
||||
gfloat *min_width_p,
|
||||
gfloat *natural_width_p)
|
||||
{
|
||||
ShellStack *stack = SHELL_STACK (actor);
|
||||
gboolean first = TRUE;
|
||||
float min = 0, natural = 0;
|
||||
GList *iter;
|
||||
GList *children;
|
||||
|
||||
children = clutter_container_get_children (CLUTTER_CONTAINER (stack));
|
||||
|
||||
for (iter = children; iter; iter = iter->next)
|
||||
{
|
||||
ClutterActor *child = iter->data;
|
||||
float child_min, child_natural;
|
||||
|
||||
clutter_actor_get_preferred_width (child,
|
||||
for_height,
|
||||
&child_min,
|
||||
&child_natural);
|
||||
|
||||
if (first)
|
||||
{
|
||||
first = FALSE;
|
||||
min = child_min;
|
||||
natural = child_natural;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (child_min > min)
|
||||
min = child_min;
|
||||
|
||||
if (child_natural > natural)
|
||||
natural = child_natural;
|
||||
}
|
||||
}
|
||||
|
||||
if (min_width_p)
|
||||
*min_width_p = min;
|
||||
|
||||
if (natural_width_p)
|
||||
*natural_width_p = natural;
|
||||
g_list_free (children);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_stack_class_init (ShellStackClass *klass)
|
||||
{
|
||||
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
||||
|
||||
actor_class->get_preferred_width = shell_stack_get_preferred_width;
|
||||
actor_class->get_preferred_height = shell_stack_get_preferred_height;
|
||||
actor_class->allocate = shell_stack_allocate;
|
||||
}
|
||||
|
||||
static void
|
||||
shell_stack_init (ShellStack *actor)
|
||||
{
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
#ifndef __SHELL_STACK_H__
|
||||
#define __SHELL_STACK_H__
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define SHELL_TYPE_STACK (shell_stack_get_type ())
|
||||
#define SHELL_STACK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_STACK, ShellStack))
|
||||
#define SHELL_STACK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_STACK, ShellStackClass))
|
||||
#define SHELL_IS_STACK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_TYPE_STACK))
|
||||
#define SHELL_IS_STACK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_STACK))
|
||||
#define SHELL_STACK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_STACK, ShellStackClass))
|
||||
|
||||
typedef struct _ShellStack ShellStack;
|
||||
typedef struct _ShellStackClass ShellStackClass;
|
||||
|
||||
typedef struct _ShellStackPrivate ShellStackPrivate;
|
||||
|
||||
struct _ShellStack
|
||||
{
|
||||
ClutterGroup parent;
|
||||
|
||||
ShellStackPrivate *priv;
|
||||
};
|
||||
|
||||
struct _ShellStackClass
|
||||
{
|
||||
ClutterGroupClass parent_class;
|
||||
};
|
||||
|
||||
GType shell_stack_get_type (void) G_GNUC_CONST;
|
||||
|
||||
#endif /* __SHELL_STACK_H__ */
|
||||
@@ -26,7 +26,7 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <glib/gi18n-lib.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <gdk/gdkkeysyms.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
@@ -39,13 +39,10 @@
|
||||
#include <gdmuser/gdm-user-manager.h>
|
||||
|
||||
#include "shell-global.h"
|
||||
#include "shell-gconf.h"
|
||||
|
||||
#define LOCKDOWN_DIR "/desktop/gnome/lockdown"
|
||||
#define LOCKDOWN_KEY LOCKDOWN_DIR "/disable_user_switching"
|
||||
|
||||
#define SIDEBAR_VISIBLE_KEY SHELL_GCONF_DIR "/sidebar/visible"
|
||||
|
||||
struct _ShellStatusMenuPrivate {
|
||||
GConfClient *client;
|
||||
GdmUserManager *manager;
|
||||
@@ -57,12 +54,10 @@ struct _ShellStatusMenuPrivate {
|
||||
|
||||
GtkWidget *menu;
|
||||
GtkWidget *account_item;
|
||||
GtkWidget *sidebar_item;
|
||||
GtkWidget *control_panel_item;
|
||||
GtkWidget *lock_screen_item;
|
||||
GtkWidget *login_screen_item;
|
||||
GtkWidget *quit_session_item;
|
||||
GtkWidget *shut_down_item;
|
||||
|
||||
guint client_notify_lockdown_id;
|
||||
|
||||
@@ -118,9 +113,12 @@ static void
|
||||
update_name_text (ShellStatusMenu *status)
|
||||
{
|
||||
ShellStatusMenuPrivate *priv = status->priv;
|
||||
char *markup;
|
||||
|
||||
clutter_text_set_text (priv->name,
|
||||
gdm_user_get_real_name (GDM_USER (priv->user)));
|
||||
markup = g_markup_printf_escaped("<b>%s</b>",
|
||||
gdm_user_get_real_name (GDM_USER (priv->user)));
|
||||
clutter_text_set_markup (priv->name, markup);
|
||||
g_free (markup);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -316,18 +314,10 @@ on_account_activate (GtkMenuItem *item,
|
||||
spawn_external (status, "gnome-about-me");
|
||||
}
|
||||
|
||||
static void
|
||||
on_sidebar_toggled (GtkCheckMenuItem *item,
|
||||
ShellStatusMenu *status)
|
||||
{
|
||||
gconf_client_set_bool (status->priv->client, SIDEBAR_VISIBLE_KEY,
|
||||
gtk_check_menu_item_get_active (item), NULL);
|
||||
}
|
||||
|
||||
|
||||
/* Calls 'gnome-session-save arg' */
|
||||
static void
|
||||
gnome_session_save_command (const char *arg)
|
||||
on_quit_session_activate (GtkMenuItem *item,
|
||||
ShellStatusMenu *status)
|
||||
{
|
||||
char *args[3];
|
||||
GError *error;
|
||||
@@ -338,7 +328,7 @@ gnome_session_save_command (const char *arg)
|
||||
if (args[0] == NULL)
|
||||
return;
|
||||
|
||||
args[1] = (char *)arg;
|
||||
args[1] = "--logout-dialog";
|
||||
args[2] = NULL;
|
||||
|
||||
screen = gdk_screen_get_default ();
|
||||
@@ -355,21 +345,6 @@ gnome_session_save_command (const char *arg)
|
||||
g_free (args[0]);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
on_quit_session_activate (GtkMenuItem *item,
|
||||
ShellStatusMenu *status)
|
||||
{
|
||||
gnome_session_save_command ("--logout-dialog");
|
||||
}
|
||||
|
||||
static void
|
||||
on_shut_down_activate (GtkMenuItem *item,
|
||||
ShellStatusMenu *status)
|
||||
{
|
||||
gnome_session_save_command ("--shutdown-dialog");
|
||||
}
|
||||
|
||||
static void
|
||||
update_switch_user (ShellStatusMenu *status)
|
||||
{
|
||||
@@ -455,8 +430,6 @@ menuitem_style_set_cb (GtkWidget *menuitem,
|
||||
icon_name = "user-info";
|
||||
else if (menuitem == priv->control_panel_item)
|
||||
icon_name = "preferences-desktop";
|
||||
else if (menuitem == priv->shut_down_item)
|
||||
icon_name = "system-shutdown";
|
||||
else
|
||||
icon_name = GTK_STOCK_MISSING_IMAGE;
|
||||
|
||||
@@ -499,14 +472,6 @@ create_sub_menu (ShellStatusMenu *status)
|
||||
G_CALLBACK (on_account_activate), status);
|
||||
gtk_widget_show (priv->account_item);
|
||||
|
||||
priv->sidebar_item = gtk_check_menu_item_new_with_label (_("Sidebar"));
|
||||
gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (priv->sidebar_item),
|
||||
gconf_client_get_bool (priv->client, SIDEBAR_VISIBLE_KEY, NULL));
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), priv->sidebar_item);
|
||||
g_signal_connect (priv->sidebar_item, "toggled",
|
||||
G_CALLBACK (on_sidebar_toggled), status);
|
||||
gtk_widget_show (priv->sidebar_item);
|
||||
|
||||
priv->control_panel_item = gtk_image_menu_item_new_with_label (_("System Preferences..."));
|
||||
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (priv->control_panel_item),
|
||||
gtk_image_new ());
|
||||
@@ -542,8 +507,7 @@ create_sub_menu (ShellStatusMenu *status)
|
||||
G_CALLBACK (on_login_screen_activate), status);
|
||||
/* Only show switch user if there are other users */
|
||||
|
||||
/* Log Out */
|
||||
priv->quit_session_item = gtk_image_menu_item_new_with_label (_("Log Out..."));
|
||||
priv->quit_session_item = gtk_image_menu_item_new_with_label (_("Quit..."));
|
||||
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (priv->quit_session_item),
|
||||
gtk_image_new ());
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), priv->quit_session_item);
|
||||
@@ -553,17 +517,6 @@ create_sub_menu (ShellStatusMenu *status)
|
||||
G_CALLBACK (on_quit_session_activate), status);
|
||||
gtk_widget_show (priv->quit_session_item);
|
||||
|
||||
/* Shut down */
|
||||
priv->shut_down_item = gtk_image_menu_item_new_with_label (_("Shut Down..."));
|
||||
gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (priv->shut_down_item),
|
||||
gtk_image_new ());
|
||||
gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), priv->shut_down_item);
|
||||
g_signal_connect (priv->shut_down_item, "style-set",
|
||||
G_CALLBACK (menuitem_style_set_cb), status);
|
||||
g_signal_connect (priv->shut_down_item, "activate",
|
||||
G_CALLBACK (on_shut_down_activate), status);
|
||||
gtk_widget_show (priv->shut_down_item);
|
||||
|
||||
g_signal_connect (G_OBJECT (priv->menu), "deactivate",
|
||||
G_CALLBACK (on_deactivate), status);
|
||||
}
|
||||
@@ -635,98 +588,37 @@ shell_status_menu_class_init (ShellStatusMenuClass *klass)
|
||||
G_TYPE_NONE, 0);
|
||||
}
|
||||
|
||||
ShellStatusMenu *
|
||||
shell_status_menu_new (void)
|
||||
{
|
||||
return g_object_new (SHELL_TYPE_STATUS_MENU, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
position_menu (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data)
|
||||
{
|
||||
ShellStatusMenu *status = SHELL_STATUS_MENU (user_data);
|
||||
ClutterActor *parent;
|
||||
float src_x, src_y;
|
||||
float width, height;
|
||||
int menu_width;
|
||||
|
||||
gtk_widget_get_size_request (GTK_WIDGET (menu), &menu_width, NULL);
|
||||
clutter_actor_get_transformed_position (CLUTTER_ACTOR (status), &src_x, &src_y);
|
||||
|
||||
/* Encapsulation breakage: it looks better if the menu is
|
||||
* aligned with the bottom of the actor's grandparent - the
|
||||
* panel, rather than with the bottom of the actor. We just
|
||||
* assume what the hierarchy is and where we are positioned
|
||||
* in the panel.
|
||||
*/
|
||||
parent = clutter_actor_get_parent (CLUTTER_ACTOR (status));
|
||||
parent = clutter_actor_get_parent (parent);
|
||||
clutter_actor_get_transformed_position (parent, &src_x, &src_y);
|
||||
clutter_actor_get_transformed_size (parent, &width, &height);
|
||||
*x = (gint)(0.5 + src_x + width - menu_width);
|
||||
*y = (gint)(0.5 + src_y + height);
|
||||
*x = (gint)(0.5 + src_x);
|
||||
*y = (gint)(0.5 + src_y);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_status_menu_toggle:
|
||||
* @menu: a #ShellStatusMenu
|
||||
*
|
||||
* If the menu is not currently up, pops it up. Otherwise, hides it.
|
||||
* Popping up may fail if another grab is already active; check with
|
||||
* shell_status_menu_is_active().
|
||||
*/
|
||||
void
|
||||
shell_status_menu_toggle (ShellStatusMenu *status, ClutterEvent *event)
|
||||
{
|
||||
ShellStatusMenuPrivate *priv = status->priv;
|
||||
|
||||
if (GTK_WIDGET_VISIBLE (priv->menu))
|
||||
if (GTK_WIDGET_VISIBLE (GTK_WIDGET (priv->menu)))
|
||||
{
|
||||
gtk_menu_popdown (GTK_MENU (priv->menu));
|
||||
gtk_widget_hide (GTK_WIDGET (priv->menu));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We don't want to overgrab a Mutter grab with the grab that GTK+
|
||||
* uses on menus.
|
||||
*/
|
||||
ShellGlobal *global = shell_global_get ();
|
||||
if (shell_global_display_is_grabbed (global))
|
||||
return;
|
||||
|
||||
gtk_widget_show (GTK_WIDGET (priv->menu));
|
||||
gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL, position_menu,
|
||||
status, 1, event->button.time);
|
||||
status, 1, event->button.time);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_status_menu_is_active:
|
||||
* @menu: a #ShellStatusMenu
|
||||
*
|
||||
* Gets whether the menu is currently popped up
|
||||
*
|
||||
* Return value: %TRUE if the menu is currently popped up
|
||||
*/
|
||||
gboolean
|
||||
shell_status_menu_is_active (ShellStatusMenu *status)
|
||||
{
|
||||
ShellStatusMenuPrivate *priv = status->priv;
|
||||
|
||||
return GTK_WIDGET_VISIBLE (priv->menu);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_status_menu_get_name:
|
||||
* @menu: a #ShellStatusMenu
|
||||
*
|
||||
* Return value: (transfer none): the #ClutterText actor with the user's name.
|
||||
*/
|
||||
ClutterText *
|
||||
shell_status_menu_get_name (ShellStatusMenu *menu)
|
||||
{
|
||||
return menu->priv->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_status_menu_get_icon:
|
||||
* @menu: a #ShellStatusMenu
|
||||
*
|
||||
* Return value: (transfer none): the #ClutterTexture actor with the user icon.
|
||||
*/
|
||||
ClutterTexture *
|
||||
shell_status_menu_get_icon (ShellStatusMenu *menu)
|
||||
{
|
||||
return menu->priv->user_icon;
|
||||
}
|
||||
|
||||
@@ -36,9 +36,6 @@ struct _ShellStatusMenuClass
|
||||
GType shell_status_menu_get_type (void);
|
||||
|
||||
void shell_status_menu_toggle (ShellStatusMenu *menu, ClutterEvent *event);
|
||||
gboolean shell_status_menu_is_active (ShellStatusMenu *menu);
|
||||
ClutterText *shell_status_menu_get_name (ShellStatusMenu *menu);
|
||||
ClutterTexture *shell_status_menu_get_icon (ShellStatusMenu *menu);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
@@ -1,27 +1,16 @@
|
||||
#include "shell-texture-cache.h"
|
||||
#include "shell-global.h"
|
||||
#include <gtk/gtk.h>
|
||||
#define GNOME_DESKTOP_USE_UNSTABLE_API
|
||||
#include <libgnomeui/gnome-desktop-thumbnail.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ShellTextureCachePolicy policy;
|
||||
|
||||
/* These are exclusive */
|
||||
GIcon *icon;
|
||||
gchar *uri;
|
||||
gchar *thumbnail_uri;
|
||||
|
||||
/* This one is common to all */
|
||||
guint size;
|
||||
} CacheKey;
|
||||
|
||||
struct _ShellTextureCachePrivate
|
||||
{
|
||||
GHashTable *keyed_cache; /* CacheKey -> CoglTexture* */
|
||||
GnomeDesktopThumbnailFactory *thumbnails;
|
||||
GHashTable *gicon_cache; /* CacheKey -> CoglTexture* */
|
||||
};
|
||||
|
||||
static void shell_texture_cache_dispose (GObject *object);
|
||||
@@ -33,17 +22,10 @@ static guint
|
||||
cache_key_hash (gconstpointer a)
|
||||
{
|
||||
CacheKey *akey = (CacheKey *)a;
|
||||
guint base_hash;
|
||||
|
||||
if (akey->icon)
|
||||
base_hash = g_icon_hash (akey->icon);
|
||||
else if (akey->uri)
|
||||
base_hash = g_str_hash (akey->uri);
|
||||
else if (akey->thumbnail_uri)
|
||||
base_hash = g_str_hash (akey->thumbnail_uri);
|
||||
else
|
||||
g_assert_not_reached ();
|
||||
return base_hash + 31*akey->size;
|
||||
return g_icon_hash (akey->icon) + 31*akey->size;
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -53,34 +35,11 @@ cache_key_equal (gconstpointer a,
|
||||
CacheKey *akey = (CacheKey*)a;
|
||||
CacheKey *bkey = (CacheKey*)b;
|
||||
|
||||
/* We don't compare policy here, since we need
|
||||
* a way to look up a cache key without respect to
|
||||
* the policy. */
|
||||
|
||||
if (akey->size != bkey->size)
|
||||
return FALSE;
|
||||
|
||||
if (akey->icon && bkey->icon)
|
||||
return g_icon_equal (akey->icon, bkey->icon);
|
||||
else if (akey->uri && bkey->uri)
|
||||
return strcmp (akey->uri, bkey->uri) == 0;
|
||||
else if (akey->thumbnail_uri && bkey->thumbnail_uri)
|
||||
return strcmp (akey->thumbnail_uri, bkey->thumbnail_uri) == 0;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static CacheKey *
|
||||
cache_key_dup (CacheKey *key)
|
||||
{
|
||||
CacheKey *ret = g_new0 (CacheKey, 1);
|
||||
ret->policy = key->policy;
|
||||
if (key->icon)
|
||||
ret->icon = g_object_ref (key->icon);
|
||||
ret->uri = g_strdup (key->uri);
|
||||
ret->thumbnail_uri = g_strdup (key->thumbnail_uri);
|
||||
ret->size = key->size;
|
||||
return ret;
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -89,32 +48,9 @@ cache_key_destroy (gpointer a)
|
||||
CacheKey *akey = (CacheKey*)a;
|
||||
if (akey->icon)
|
||||
g_object_unref (akey->icon);
|
||||
g_free (akey->uri);
|
||||
g_free (akey->thumbnail_uri);
|
||||
g_free (akey);
|
||||
}
|
||||
|
||||
|
||||
/* We want to preserve the aspect ratio by default, also the default
|
||||
* material for an empty texture is full opacity white, which we
|
||||
* definitely don't want. Skip that by setting 0 opacity.
|
||||
*/
|
||||
static ClutterTexture *
|
||||
create_default_texture (ShellTextureCache *self)
|
||||
{
|
||||
ClutterTexture * texture = CLUTTER_TEXTURE (clutter_texture_new ());
|
||||
g_object_set (texture, "keep-aspect-ratio", TRUE, "opacity", 0, NULL);
|
||||
return texture;
|
||||
}
|
||||
|
||||
/* Reverse the opacity we added while loading */
|
||||
static void
|
||||
set_texture_cogl_texture (ClutterTexture *clutter_texture, CoglHandle cogl_texture)
|
||||
{
|
||||
clutter_texture_set_cogl_texture (clutter_texture, cogl_texture);
|
||||
g_object_set (clutter_texture, "opacity", 255, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_texture_cache_class_init (ShellTextureCacheClass *klass)
|
||||
{
|
||||
@@ -128,9 +64,8 @@ static void
|
||||
shell_texture_cache_init (ShellTextureCache *self)
|
||||
{
|
||||
self->priv = g_new0 (ShellTextureCachePrivate, 1);
|
||||
self->priv->keyed_cache = g_hash_table_new_full (cache_key_hash, cache_key_equal,
|
||||
self->priv->gicon_cache = g_hash_table_new_full (cache_key_hash, cache_key_equal,
|
||||
cache_key_destroy, cogl_handle_unref);
|
||||
self->priv->thumbnails = gnome_desktop_thumbnail_factory_new (GNOME_DESKTOP_THUMBNAIL_SIZE_NORMAL);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -138,13 +73,9 @@ shell_texture_cache_dispose (GObject *object)
|
||||
{
|
||||
ShellTextureCache *self = (ShellTextureCache*)object;
|
||||
|
||||
if (self->priv->keyed_cache)
|
||||
g_hash_table_destroy (self->priv->keyed_cache);
|
||||
self->priv->keyed_cache = NULL;
|
||||
|
||||
if (self->priv->thumbnails)
|
||||
g_object_unref (self->priv->thumbnails);
|
||||
self->priv->thumbnails = NULL;
|
||||
if (self->priv->gicon_cache)
|
||||
g_hash_table_destroy (self->priv->gicon_cache);
|
||||
self->priv->gicon_cache = NULL;
|
||||
|
||||
G_OBJECT_CLASS (shell_texture_cache_parent_class)->dispose (object);
|
||||
}
|
||||
@@ -155,19 +86,23 @@ shell_texture_cache_finalize (GObject *object)
|
||||
G_OBJECT_CLASS (shell_texture_cache_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
ShellTextureCache*
|
||||
shell_texture_cache_new ()
|
||||
{
|
||||
return SHELL_TEXTURE_CACHE (g_object_new (SHELL_TYPE_TEXTURE_CACHE,
|
||||
NULL));
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
ShellTextureCache *cache;
|
||||
char *uri;
|
||||
char *mimetype;
|
||||
gboolean thumbnail;
|
||||
GIcon *icon;
|
||||
GtkRecentInfo *recent_info;
|
||||
GtkIconInfo *icon_info;
|
||||
gint width;
|
||||
gint height;
|
||||
gpointer user_data;
|
||||
} AsyncIconLookupData;
|
||||
|
||||
|
||||
static gboolean
|
||||
compute_pixbuf_scale (gint width,
|
||||
gint height,
|
||||
@@ -210,7 +145,7 @@ compute_pixbuf_scale (gint width,
|
||||
}
|
||||
|
||||
// Scale the image only if that will not increase its original dimensions.
|
||||
if (scaled_width > 0 && scaled_height > 0 && scaled_width < width && scaled_height < height)
|
||||
if (scaled_width >= 0 && scaled_height >= 0 && scaled_width < width && scaled_height < height)
|
||||
{
|
||||
*new_width = scaled_width;
|
||||
*new_height = scaled_height;
|
||||
@@ -265,10 +200,6 @@ icon_lookup_data_destroy (gpointer p)
|
||||
}
|
||||
else if (data->uri)
|
||||
g_free (data->uri);
|
||||
if (data->mimetype)
|
||||
g_free (data->mimetype);
|
||||
if (data->recent_info)
|
||||
gtk_recent_info_unref (data->recent_info);
|
||||
|
||||
g_free (data);
|
||||
}
|
||||
@@ -397,71 +328,6 @@ out:
|
||||
return rotated_pixbuf;
|
||||
}
|
||||
|
||||
static GdkPixbuf *
|
||||
impl_load_thumbnail (ShellTextureCache *cache,
|
||||
const char *uri,
|
||||
const char *mime_type,
|
||||
guint size,
|
||||
GError **error)
|
||||
{
|
||||
GnomeDesktopThumbnailFactory *thumbnail_factory;
|
||||
GdkPixbuf *pixbuf = NULL;
|
||||
GFile *file;
|
||||
GFileInfo *file_info;
|
||||
GTimeVal mtime_g;
|
||||
time_t mtime = 0;
|
||||
char *existing_thumbnail;
|
||||
|
||||
file = g_file_new_for_uri (uri);
|
||||
file_info = g_file_query_info (file, G_FILE_ATTRIBUTE_TIME_MODIFIED, G_FILE_QUERY_INFO_NONE, NULL, NULL);
|
||||
g_object_unref (file);
|
||||
if (file_info)
|
||||
{
|
||||
g_file_info_get_modification_time (file_info, &mtime_g);
|
||||
g_object_unref (file_info);
|
||||
mtime = (time_t) mtime_g.tv_sec;
|
||||
}
|
||||
|
||||
thumbnail_factory = cache->priv->thumbnails;
|
||||
|
||||
existing_thumbnail = gnome_desktop_thumbnail_factory_lookup (thumbnail_factory, uri, mtime);
|
||||
|
||||
if (existing_thumbnail != NULL)
|
||||
pixbuf = gdk_pixbuf_new_from_file_at_size (existing_thumbnail, size, size, error);
|
||||
else if (gnome_desktop_thumbnail_factory_has_valid_failed_thumbnail (thumbnail_factory, uri, mtime))
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Has failed thumbnail");
|
||||
else if (gnome_desktop_thumbnail_factory_can_thumbnail (thumbnail_factory, uri, mime_type, mtime))
|
||||
{
|
||||
pixbuf = gnome_desktop_thumbnail_factory_generate_thumbnail (thumbnail_factory, uri, mime_type);
|
||||
if (pixbuf)
|
||||
{
|
||||
// we need to save the thumbnail so that we don't need to generate it again in the future
|
||||
gnome_desktop_thumbnail_factory_save_thumbnail (thumbnail_factory, pixbuf, uri, mtime);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Failed to generate thumbnail");
|
||||
gnome_desktop_thumbnail_factory_create_failed_thumbnail (thumbnail_factory, uri, mtime);
|
||||
}
|
||||
}
|
||||
return pixbuf;
|
||||
}
|
||||
|
||||
static GIcon *
|
||||
icon_for_mimetype (const char *mimetype)
|
||||
{
|
||||
char *content_type;
|
||||
GIcon *icon;
|
||||
|
||||
content_type = g_content_type_from_mime_type (mimetype);
|
||||
if (!content_type)
|
||||
return NULL;
|
||||
|
||||
icon = g_content_type_get_icon (content_type);
|
||||
g_free (content_type);
|
||||
return icon;
|
||||
}
|
||||
|
||||
static void
|
||||
load_pixbuf_thread (GSimpleAsyncResult *result,
|
||||
GObject *object,
|
||||
@@ -471,27 +337,9 @@ load_pixbuf_thread (GSimpleAsyncResult *result,
|
||||
AsyncIconLookupData *data;
|
||||
GError *error = NULL;
|
||||
|
||||
data = g_object_get_data (G_OBJECT (result), "load_pixbuf_async");
|
||||
g_assert (data != NULL);
|
||||
data = g_object_get_data (G_OBJECT (result), "load_icon_pixbuf_async");
|
||||
|
||||
if (data->thumbnail)
|
||||
{
|
||||
const char *uri;
|
||||
const char *mimetype;
|
||||
|
||||
if (data->recent_info)
|
||||
{
|
||||
uri = gtk_recent_info_get_uri (data->recent_info);
|
||||
mimetype = gtk_recent_info_get_mime_type (data->recent_info);
|
||||
}
|
||||
else
|
||||
{
|
||||
uri = data->uri;
|
||||
mimetype = data->mimetype;
|
||||
}
|
||||
pixbuf = impl_load_thumbnail (data->cache, uri, mimetype, data->width, &error);
|
||||
}
|
||||
else if (data->uri)
|
||||
if (data->uri)
|
||||
pixbuf = impl_load_pixbuf_file (data->uri, data->width, data->height, &error);
|
||||
else if (data->icon)
|
||||
pixbuf = impl_load_pixbuf_gicon (data->icon, data->icon_info, data->width, &error);
|
||||
@@ -504,9 +352,8 @@ load_pixbuf_thread (GSimpleAsyncResult *result,
|
||||
return;
|
||||
}
|
||||
|
||||
if (pixbuf)
|
||||
g_simple_async_result_set_op_res_gpointer (result, g_object_ref (pixbuf),
|
||||
g_object_unref);
|
||||
g_simple_async_result_set_op_res_gpointer (result, g_object_ref (pixbuf),
|
||||
g_object_unref);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -528,7 +375,6 @@ load_icon_pixbuf_async (ShellTextureCache *cache,
|
||||
AsyncIconLookupData *data;
|
||||
|
||||
data = g_new0 (AsyncIconLookupData, 1);
|
||||
data->cache = cache;
|
||||
data->icon = g_object_ref (icon);
|
||||
data->icon_info = gtk_icon_info_copy (icon_info);
|
||||
data->width = data->height = size;
|
||||
@@ -536,7 +382,7 @@ load_icon_pixbuf_async (ShellTextureCache *cache,
|
||||
|
||||
result = g_simple_async_result_new (G_OBJECT (cache), callback, user_data, load_icon_pixbuf_async);
|
||||
|
||||
g_object_set_data_full (G_OBJECT (result), "load_pixbuf_async", data, icon_lookup_data_destroy);
|
||||
g_object_set_data_full (G_OBJECT (result), "load_icon_pixbuf_async", data, icon_lookup_data_destroy);
|
||||
g_simple_async_result_run_in_thread (result, load_pixbuf_thread, G_PRIORITY_DEFAULT, cancellable);
|
||||
|
||||
g_object_unref (result);
|
||||
@@ -555,7 +401,6 @@ load_uri_pixbuf_async (ShellTextureCache *cache,
|
||||
AsyncIconLookupData *data;
|
||||
|
||||
data = g_new0 (AsyncIconLookupData, 1);
|
||||
data->cache = cache;
|
||||
data->uri = g_strdup (uri);
|
||||
data->width = width;
|
||||
data->height = height;
|
||||
@@ -563,63 +408,7 @@ load_uri_pixbuf_async (ShellTextureCache *cache,
|
||||
|
||||
result = g_simple_async_result_new (G_OBJECT (cache), callback, user_data, load_uri_pixbuf_async);
|
||||
|
||||
g_object_set_data_full (G_OBJECT (result), "load_pixbuf_async", data, icon_lookup_data_destroy);
|
||||
g_simple_async_result_run_in_thread (result, load_pixbuf_thread, G_PRIORITY_DEFAULT, cancellable);
|
||||
|
||||
g_object_unref (result);
|
||||
}
|
||||
|
||||
static void
|
||||
load_thumbnail_async (ShellTextureCache *cache,
|
||||
const char *uri,
|
||||
const char *mimetype,
|
||||
guint size,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GSimpleAsyncResult *result;
|
||||
AsyncIconLookupData *data;
|
||||
|
||||
data = g_new0 (AsyncIconLookupData, 1);
|
||||
data->cache = cache;
|
||||
data->uri = g_strdup (uri);
|
||||
data->mimetype = g_strdup (mimetype);
|
||||
data->thumbnail = TRUE;
|
||||
data->width = size;
|
||||
data->height = size;
|
||||
data->user_data = user_data;
|
||||
|
||||
result = g_simple_async_result_new (G_OBJECT (cache), callback, user_data, load_thumbnail_async);
|
||||
|
||||
g_object_set_data_full (G_OBJECT (result), "load_pixbuf_async", data, icon_lookup_data_destroy);
|
||||
g_simple_async_result_run_in_thread (result, load_pixbuf_thread, G_PRIORITY_DEFAULT, cancellable);
|
||||
|
||||
g_object_unref (result);
|
||||
}
|
||||
|
||||
static void
|
||||
load_recent_thumbnail_async (ShellTextureCache *cache,
|
||||
GtkRecentInfo *info,
|
||||
guint size,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GSimpleAsyncResult *result;
|
||||
AsyncIconLookupData *data;
|
||||
|
||||
data = g_new0 (AsyncIconLookupData, 1);
|
||||
data->cache = cache;
|
||||
data->thumbnail = TRUE;
|
||||
data->recent_info = gtk_recent_info_ref (info);
|
||||
data->width = size;
|
||||
data->height = size;
|
||||
data->user_data = user_data;
|
||||
|
||||
result = g_simple_async_result_new (G_OBJECT (cache), callback, user_data, load_recent_thumbnail_async);
|
||||
|
||||
g_object_set_data_full (G_OBJECT (result), "load_pixbuf_async", data, icon_lookup_data_destroy);
|
||||
g_object_set_data_full (G_OBJECT (result), "load_uri_pixbuf_async", data, icon_lookup_data_destroy);
|
||||
g_simple_async_result_run_in_thread (result, load_pixbuf_thread, G_PRIORITY_DEFAULT, cancellable);
|
||||
|
||||
g_object_unref (result);
|
||||
@@ -635,11 +424,7 @@ load_pixbuf_async_finish (ShellTextureCache *cache, GAsyncResult *result, GError
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
ShellTextureCachePolicy policy;
|
||||
char *uri;
|
||||
gboolean thumbnail;
|
||||
char *mimetype;
|
||||
GtkRecentInfo *recent_info;
|
||||
GIcon *icon;
|
||||
GtkIconInfo *icon_info;
|
||||
guint width;
|
||||
@@ -659,45 +444,6 @@ pixbuf_to_cogl_handle (GdkPixbuf *pixbuf)
|
||||
gdk_pixbuf_get_pixels (pixbuf));
|
||||
}
|
||||
|
||||
static GdkPixbuf *
|
||||
load_pixbuf_fallback(AsyncTextureLoadData *data)
|
||||
{
|
||||
GdkPixbuf *pixbuf = NULL;
|
||||
|
||||
if (data->thumbnail)
|
||||
{
|
||||
|
||||
GtkIconTheme *theme = gtk_icon_theme_get_default ();
|
||||
|
||||
if (data->recent_info)
|
||||
pixbuf = gtk_recent_info_get_icon (data->recent_info, data->width);
|
||||
else
|
||||
{
|
||||
GIcon *icon = icon_for_mimetype (data->mimetype);
|
||||
if (icon != NULL)
|
||||
{
|
||||
GtkIconInfo *icon_info = gtk_icon_theme_lookup_by_gicon (theme,
|
||||
icon,
|
||||
data->width,
|
||||
GTK_ICON_LOOKUP_USE_BUILTIN);
|
||||
g_object_unref (icon);
|
||||
if (icon_info != NULL)
|
||||
pixbuf = gtk_icon_info_load_icon (icon_info, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (pixbuf == NULL)
|
||||
pixbuf = gtk_icon_theme_load_icon (theme,
|
||||
"gtk-file",
|
||||
data->width,
|
||||
GTK_ICON_LOOKUP_USE_BUILTIN,
|
||||
NULL);
|
||||
}
|
||||
/* Maybe we could need a fallback for outher image types? */
|
||||
|
||||
return pixbuf;
|
||||
}
|
||||
|
||||
static void
|
||||
on_pixbuf_loaded (GObject *source,
|
||||
GAsyncResult *result,
|
||||
@@ -714,39 +460,32 @@ on_pixbuf_loaded (GObject *source,
|
||||
cache = SHELL_TEXTURE_CACHE (source);
|
||||
pixbuf = load_pixbuf_async_finish (cache, result, &error);
|
||||
if (pixbuf == NULL)
|
||||
pixbuf = load_pixbuf_fallback(data);
|
||||
if (pixbuf == NULL)
|
||||
goto out;
|
||||
{
|
||||
/* TODO - we need a "broken image" display of some sort */
|
||||
goto out;
|
||||
}
|
||||
|
||||
texdata = pixbuf_to_cogl_handle (pixbuf);
|
||||
|
||||
g_object_unref (pixbuf);
|
||||
|
||||
if (data->policy != SHELL_TEXTURE_CACHE_POLICY_NONE)
|
||||
if (data->icon)
|
||||
{
|
||||
gpointer orig_key, value;
|
||||
|
||||
key = g_new0 (CacheKey, 1);
|
||||
key->policy = data->policy;
|
||||
if (data->icon)
|
||||
key->icon = g_object_ref (data->icon);
|
||||
else if (data->recent_info && data->thumbnail)
|
||||
key->thumbnail_uri = g_strdup (gtk_recent_info_get_uri (data->recent_info));
|
||||
else if (data->thumbnail)
|
||||
key->thumbnail_uri = g_strdup (data->uri);
|
||||
else if (data->uri)
|
||||
key->uri = g_strdup (data->uri);
|
||||
key->icon = g_object_ref (data->icon);
|
||||
key->size = data->width;
|
||||
|
||||
if (!g_hash_table_lookup_extended (cache->priv->keyed_cache, key,
|
||||
if (!g_hash_table_lookup_extended (cache->priv->gicon_cache, key,
|
||||
&orig_key, &value))
|
||||
g_hash_table_insert (cache->priv->keyed_cache, key,
|
||||
g_hash_table_insert (cache->priv->gicon_cache, key,
|
||||
texdata);
|
||||
else
|
||||
cache_key_destroy (key);
|
||||
}
|
||||
|
||||
set_texture_cogl_texture (data->texture, texdata);
|
||||
clutter_texture_set_cogl_texture (data->texture, texdata);
|
||||
|
||||
out:
|
||||
if (data->icon)
|
||||
@@ -756,122 +495,13 @@ out:
|
||||
}
|
||||
else if (data->uri)
|
||||
g_free (data->uri);
|
||||
|
||||
if (data->recent_info)
|
||||
gtk_recent_info_unref (data->recent_info);
|
||||
if (data->mimetype)
|
||||
g_free (data->mimetype);
|
||||
|
||||
/* Alternatively we could weakref and just do nothing if the texture
|
||||
is destroyed */
|
||||
g_object_unref (data->texture);
|
||||
|
||||
g_clear_error (&error);
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
ShellTextureCache *cache;
|
||||
ClutterTexture *texture;
|
||||
GObject *source;
|
||||
guint notify_signal_id;
|
||||
gboolean weakref_active;
|
||||
} ShellTextureCachePropertyBind;
|
||||
|
||||
static void
|
||||
shell_texture_cache_reset_texture (ShellTextureCachePropertyBind *bind, const char *propname)
|
||||
{
|
||||
GdkPixbuf *pixbuf;
|
||||
CoglHandle texdata;
|
||||
|
||||
g_object_get (bind->source, propname, &pixbuf, NULL);
|
||||
|
||||
g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
|
||||
|
||||
if (pixbuf != NULL)
|
||||
{
|
||||
texdata = pixbuf_to_cogl_handle (pixbuf);
|
||||
g_object_unref (pixbuf);
|
||||
|
||||
clutter_texture_set_cogl_texture (bind->texture, texdata);
|
||||
cogl_handle_unref (texdata);
|
||||
|
||||
clutter_actor_set_opacity (CLUTTER_ACTOR (bind->texture), 255);
|
||||
}
|
||||
else
|
||||
clutter_actor_set_opacity (CLUTTER_ACTOR (bind->texture), 0);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_texture_cache_on_pixbuf_notify (GObject *object,
|
||||
GParamSpec *paramspec,
|
||||
gpointer data)
|
||||
{
|
||||
ShellTextureCachePropertyBind *bind = data;
|
||||
shell_texture_cache_reset_texture (bind, paramspec->name);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_texture_cache_bind_weak_notify (gpointer data,
|
||||
GObject *source_location)
|
||||
{
|
||||
ShellTextureCachePropertyBind *bind = data;
|
||||
bind->weakref_active = FALSE;
|
||||
g_signal_handler_disconnect (bind->source, bind->notify_signal_id);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_texture_cache_free_bind (gpointer data)
|
||||
{
|
||||
ShellTextureCachePropertyBind *bind = data;
|
||||
if (bind->weakref_active)
|
||||
g_object_weak_unref (G_OBJECT(bind->texture), shell_texture_cache_bind_weak_notify, bind);
|
||||
g_free (bind);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_texture_cache_bind_pixbuf_property:
|
||||
* @cache:
|
||||
* @object: A #GObject with a property @property_name of type #GdkPixbuf
|
||||
* @property_name: Name of a property
|
||||
*
|
||||
* Create a #ClutterTexture which tracks the #GdkPixbuf value of a GObject property
|
||||
* named by @property_name. Unlike other methods in ShellTextureCache, the underlying
|
||||
* CoglHandle is not shared by default with other invocations to this method.
|
||||
*
|
||||
* If the source object is destroyed, the texture will continue to show the last
|
||||
* value of the property.
|
||||
*
|
||||
* Return value: (transfer none): A new #ClutterActor
|
||||
*/
|
||||
ClutterActor *
|
||||
shell_texture_cache_bind_pixbuf_property (ShellTextureCache *cache,
|
||||
GObject *object,
|
||||
const char *property_name)
|
||||
{
|
||||
ClutterTexture *texture;
|
||||
gchar *notify_key;
|
||||
ShellTextureCachePropertyBind *bind;
|
||||
|
||||
texture = CLUTTER_TEXTURE (clutter_texture_new ());
|
||||
|
||||
bind = g_new0 (ShellTextureCachePropertyBind, 1);
|
||||
bind->cache = cache;
|
||||
bind->texture = texture;
|
||||
bind->source = object;
|
||||
g_object_weak_ref (G_OBJECT (texture), shell_texture_cache_bind_weak_notify, bind);
|
||||
bind->weakref_active = TRUE;
|
||||
|
||||
shell_texture_cache_reset_texture (bind, property_name);
|
||||
|
||||
notify_key = g_strdup_printf ("notify::%s", property_name);
|
||||
bind->notify_signal_id = g_signal_connect_data (object, notify_key, G_CALLBACK(shell_texture_cache_on_pixbuf_notify),
|
||||
bind, (GClosureNotify)shell_texture_cache_free_bind, 0);
|
||||
g_free (notify_key);
|
||||
|
||||
return CLUTTER_ACTOR(texture);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_texture_cache_load_gicon:
|
||||
*
|
||||
@@ -889,13 +519,12 @@ shell_texture_cache_load_gicon (ShellTextureCache *cache,
|
||||
CoglHandle texdata;
|
||||
CacheKey key;
|
||||
|
||||
texture = create_default_texture (cache);
|
||||
texture = CLUTTER_TEXTURE (clutter_texture_new ());
|
||||
clutter_actor_set_size (CLUTTER_ACTOR (texture), size, size);
|
||||
|
||||
memset (&key, 0, sizeof(key));
|
||||
key.icon = icon;
|
||||
key.size = size;
|
||||
texdata = g_hash_table_lookup (cache->priv->keyed_cache, &key);
|
||||
texdata = g_hash_table_lookup (cache->priv->gicon_cache, &key);
|
||||
|
||||
if (texdata == NULL)
|
||||
{
|
||||
@@ -910,9 +539,7 @@ shell_texture_cache_load_gicon (ShellTextureCache *cache,
|
||||
{
|
||||
AsyncTextureLoadData *data;
|
||||
data = g_new0 (AsyncTextureLoadData, 1);
|
||||
/* hardcoded here for now; we should actually blow this away on
|
||||
* icon theme changes probably */
|
||||
data->policy = SHELL_TEXTURE_CACHE_POLICY_FOREVER;
|
||||
|
||||
data->icon = g_object_ref (icon);
|
||||
data->icon_info = info;
|
||||
data->texture = g_object_ref (texture);
|
||||
@@ -922,39 +549,14 @@ shell_texture_cache_load_gicon (ShellTextureCache *cache,
|
||||
}
|
||||
else
|
||||
{
|
||||
set_texture_cogl_texture (texture, texdata);
|
||||
clutter_texture_set_cogl_texture (texture, texdata);
|
||||
}
|
||||
|
||||
return CLUTTER_ACTOR (texture);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_texture_cache_load_icon_name:
|
||||
* @cache: The texture cache instance
|
||||
* @name: Name of a themed icon
|
||||
* @size: Size of themed
|
||||
*
|
||||
* Load a themed icon into a texture.
|
||||
*
|
||||
* Return Value: (transfer none): A new #ClutterTexture for the icon
|
||||
*/
|
||||
ClutterActor *
|
||||
shell_texture_cache_load_icon_name (ShellTextureCache *cache,
|
||||
const char *name,
|
||||
gint size)
|
||||
{
|
||||
ClutterActor *texture;
|
||||
GIcon *themed;
|
||||
|
||||
themed = g_themed_icon_new (name);
|
||||
texture = shell_texture_cache_load_gicon (cache, themed, size);
|
||||
g_object_unref (themed);
|
||||
|
||||
return CLUTTER_ACTOR (texture);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_texture_cache_load_uri_async:
|
||||
* shell_texture_cache_load_uri:
|
||||
*
|
||||
* @cache: The texture cache instance
|
||||
* @uri: uri of the image file from which to create a pixbuf
|
||||
@@ -976,10 +578,9 @@ shell_texture_cache_load_uri_async (ShellTextureCache *cache,
|
||||
ClutterTexture *texture;
|
||||
AsyncTextureLoadData *data;
|
||||
|
||||
texture = create_default_texture (cache);
|
||||
texture = CLUTTER_TEXTURE (clutter_texture_new ());
|
||||
|
||||
data = g_new0 (AsyncTextureLoadData, 1);
|
||||
data->policy = SHELL_TEXTURE_CACHE_POLICY_NONE;
|
||||
data->uri = g_strdup (uri);
|
||||
data->width = available_width;
|
||||
data->height = available_height;
|
||||
@@ -993,7 +594,6 @@ shell_texture_cache_load_uri_async (ShellTextureCache *cache,
|
||||
* shell_texture_cache_load_uri_sync:
|
||||
*
|
||||
* @cache: The texture cache instance
|
||||
* @policy: Requested lifecycle of cached data
|
||||
* @uri: uri of the image file from which to create a pixbuf
|
||||
* @available_width: available width for the image, can be -1 if not limited
|
||||
* @available_height: available height for the image, can be -1 if not limited
|
||||
@@ -1009,233 +609,27 @@ shell_texture_cache_load_uri_async (ShellTextureCache *cache,
|
||||
*/
|
||||
ClutterActor *
|
||||
shell_texture_cache_load_uri_sync (ShellTextureCache *cache,
|
||||
ShellTextureCachePolicy policy,
|
||||
const gchar *uri,
|
||||
int available_width,
|
||||
int available_height,
|
||||
GError **error)
|
||||
{
|
||||
ClutterTexture *texture;
|
||||
CoglHandle texdata;
|
||||
GdkPixbuf *pixbuf;
|
||||
CacheKey key;
|
||||
|
||||
texture = create_default_texture (cache);
|
||||
|
||||
memset (&key, 0, sizeof (CacheKey));
|
||||
key.policy = policy;
|
||||
key.uri = (char*)uri;
|
||||
key.size = available_width;
|
||||
texdata = g_hash_table_lookup (cache->priv->keyed_cache, &key);
|
||||
|
||||
if (texdata == NULL)
|
||||
{
|
||||
pixbuf = impl_load_pixbuf_file (uri, available_width, available_height, error);
|
||||
if (!pixbuf)
|
||||
{
|
||||
g_object_unref (texture);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
texdata = pixbuf_to_cogl_handle (pixbuf);
|
||||
g_object_unref (pixbuf);
|
||||
|
||||
set_texture_cogl_texture (texture, texdata);
|
||||
|
||||
if (policy == SHELL_TEXTURE_CACHE_POLICY_FOREVER)
|
||||
{
|
||||
g_hash_table_insert (cache->priv->keyed_cache, cache_key_dup (&key), texdata);
|
||||
}
|
||||
else
|
||||
cogl_handle_unref (texdata);
|
||||
}
|
||||
else
|
||||
set_texture_cogl_texture (texture, texdata);
|
||||
|
||||
return CLUTTER_ACTOR (texture);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_texture_cache_load_thumbnail:
|
||||
* @cache:
|
||||
* @size: Size in pixels to use for thumbnail
|
||||
* @uri: Source URI
|
||||
* @mimetype: Source mime type
|
||||
*
|
||||
* Asynchronously load a thumbnail image of a URI into a texture. The
|
||||
* returned texture object will be a new instance; however, its texture data
|
||||
* may be shared with other objects. This implies the texture data is cached.
|
||||
*
|
||||
* The current caching policy is permanent; to uncache, you must explicitly
|
||||
* call shell_texture_cache_unref_thumbnail().
|
||||
*
|
||||
* Returns: (transfer none): A new #ClutterActor
|
||||
*/
|
||||
ClutterActor *
|
||||
shell_texture_cache_load_thumbnail (ShellTextureCache *cache,
|
||||
int size,
|
||||
const char *uri,
|
||||
const char *mimetype)
|
||||
{
|
||||
ClutterTexture *texture;
|
||||
AsyncTextureLoadData *data;
|
||||
CacheKey key;
|
||||
CoglHandle texdata;
|
||||
|
||||
/* Don't attempt to load thumbnails for non-local URIs */
|
||||
if (!g_str_has_prefix (uri, "file://"))
|
||||
{
|
||||
GIcon *icon = icon_for_mimetype (mimetype);
|
||||
return shell_texture_cache_load_gicon (cache, icon, size);
|
||||
}
|
||||
|
||||
texture = create_default_texture (cache);
|
||||
clutter_actor_set_size (CLUTTER_ACTOR (texture), size, size);
|
||||
|
||||
memset (&key, 0, sizeof(key));
|
||||
key.size = size;
|
||||
key.thumbnail_uri = (char*)uri;
|
||||
|
||||
texdata = g_hash_table_lookup (cache->priv->keyed_cache, &key);
|
||||
if (!texdata)
|
||||
{
|
||||
data = g_new0 (AsyncTextureLoadData, 1);
|
||||
data->policy = SHELL_TEXTURE_CACHE_POLICY_FOREVER;
|
||||
data->uri = g_strdup (uri);
|
||||
data->mimetype = g_strdup (mimetype);
|
||||
data->thumbnail = TRUE;
|
||||
data->width = size;
|
||||
data->height = size;
|
||||
data->texture = g_object_ref (texture);
|
||||
load_thumbnail_async (cache, uri, mimetype, size, NULL, on_pixbuf_loaded, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
set_texture_cogl_texture (texture, texdata);
|
||||
}
|
||||
|
||||
return CLUTTER_ACTOR (texture);
|
||||
}
|
||||
|
||||
static GIcon *
|
||||
icon_for_recent (GtkRecentInfo *info)
|
||||
{
|
||||
const char *mimetype;
|
||||
|
||||
mimetype = gtk_recent_info_get_mime_type (info);
|
||||
if (!mimetype)
|
||||
{
|
||||
return g_themed_icon_new (GTK_STOCK_FILE);
|
||||
}
|
||||
|
||||
return icon_for_mimetype (mimetype);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_texture_cache_load_recent_thumbnail:
|
||||
* @cache:
|
||||
* @size: Size in pixels to use for thumbnail
|
||||
* @info: Recent item info
|
||||
*
|
||||
* Asynchronously load a thumbnail image of a #GtkRecentInfo into a texture. The
|
||||
* returned texture object will be a new instance; however, its texture data
|
||||
* may be shared with other objects. This implies the texture data is cached.
|
||||
*
|
||||
* The current caching policy is permanent; to uncache, you must explicitly
|
||||
* call shell_texture_cache_unref_recent_thumbnail().
|
||||
*
|
||||
* Returns: (transfer none): A new #ClutterActor
|
||||
*/
|
||||
ClutterActor *
|
||||
shell_texture_cache_load_recent_thumbnail (ShellTextureCache *cache,
|
||||
int size,
|
||||
GtkRecentInfo *info)
|
||||
{
|
||||
ClutterTexture *texture;
|
||||
AsyncTextureLoadData *data;
|
||||
CacheKey key;
|
||||
CoglHandle texdata;
|
||||
const char *uri;
|
||||
|
||||
uri = gtk_recent_info_get_uri (info);
|
||||
|
||||
/* Don't attempt to load thumbnails for non-local URIs */
|
||||
if (!g_str_has_prefix (uri, "file://"))
|
||||
{
|
||||
GIcon *icon = icon_for_recent (info);
|
||||
return shell_texture_cache_load_gicon (cache, icon, size);
|
||||
}
|
||||
pixbuf = impl_load_pixbuf_file (uri, available_width, available_height, error);
|
||||
if (!pixbuf)
|
||||
return NULL;
|
||||
|
||||
texture = CLUTTER_TEXTURE (clutter_texture_new ());
|
||||
clutter_actor_set_size (CLUTTER_ACTOR (texture), size, size);
|
||||
|
||||
memset (&key, 0, sizeof(key));
|
||||
key.size = size;
|
||||
key.thumbnail_uri = (char*)gtk_recent_info_get_uri (info);
|
||||
|
||||
texdata = g_hash_table_lookup (cache->priv->keyed_cache, &key);
|
||||
if (!texdata)
|
||||
{
|
||||
data = g_new0 (AsyncTextureLoadData, 1);
|
||||
data->policy = SHELL_TEXTURE_CACHE_POLICY_FOREVER;
|
||||
data->thumbnail = TRUE;
|
||||
data->recent_info = gtk_recent_info_ref (info);
|
||||
data->width = size;
|
||||
data->height = size;
|
||||
data->texture = g_object_ref (texture);
|
||||
load_recent_thumbnail_async (cache, info, size, NULL, on_pixbuf_loaded, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
set_texture_cogl_texture (texture, texdata);
|
||||
}
|
||||
texdata = pixbuf_to_cogl_handle (pixbuf);
|
||||
g_object_unref (pixbuf);
|
||||
clutter_texture_set_cogl_texture (texture, texdata);
|
||||
|
||||
return CLUTTER_ACTOR (texture);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_texture_cache_evict_thumbnail:
|
||||
* @cache:
|
||||
* @uri: Source URI
|
||||
*
|
||||
* Removes all references added by shell_texture_cache_load_thumbnail() function
|
||||
* created for the given URI.
|
||||
*/
|
||||
void
|
||||
shell_texture_cache_evict_thumbnail (ShellTextureCache *cache,
|
||||
const char *uri)
|
||||
{
|
||||
GHashTableIter iter;
|
||||
gpointer key, value;
|
||||
|
||||
g_hash_table_iter_init (&iter, cache->priv->keyed_cache);
|
||||
|
||||
while (g_hash_table_iter_next (&iter, &key, &value))
|
||||
{
|
||||
CacheKey *cachekey = key;
|
||||
|
||||
if (cachekey->thumbnail_uri == NULL || strcmp (cachekey->thumbnail_uri, uri) != 0)
|
||||
continue;
|
||||
|
||||
g_hash_table_iter_remove (&iter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_texture_cache_evict_recent_thumbnail:
|
||||
* @cache:
|
||||
* @info: A recent info
|
||||
*
|
||||
* Removes all references added by shell_texture_cache_load_recent_thumbnail() function
|
||||
* for the URI associated with the given @info.
|
||||
*/
|
||||
void
|
||||
shell_texture_cache_evict_recent_thumbnail (ShellTextureCache *cache,
|
||||
GtkRecentInfo *info)
|
||||
{
|
||||
shell_texture_cache_evict_thumbnail (cache, gtk_recent_info_get_uri (info));
|
||||
}
|
||||
|
||||
static ShellTextureCache *instance = NULL;
|
||||
|
||||
/**
|
||||
@@ -1244,7 +638,7 @@ static ShellTextureCache *instance = NULL;
|
||||
* Return value: (transfer none): The global texture cache
|
||||
*/
|
||||
ShellTextureCache*
|
||||
shell_texture_cache_get_default (void)
|
||||
shell_texture_cache_get_default ()
|
||||
{
|
||||
if (instance == NULL)
|
||||
instance = g_object_new (SHELL_TYPE_TEXTURE_CACHE, NULL);
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
#define __SHELL_TEXTURE_CACHE_H__
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
#define SHELL_TYPE_TEXTURE_CACHE (shell_texture_cache_get_type ())
|
||||
@@ -31,49 +29,20 @@ struct _ShellTextureCacheClass
|
||||
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
SHELL_TEXTURE_CACHE_POLICY_NONE,
|
||||
SHELL_TEXTURE_CACHE_POLICY_FOREVER
|
||||
} ShellTextureCachePolicy;
|
||||
|
||||
GType shell_texture_cache_get_type (void) G_GNUC_CONST;
|
||||
|
||||
ShellTextureCache* shell_texture_cache_get_default (void);
|
||||
|
||||
ClutterActor *shell_texture_cache_bind_pixbuf_property (ShellTextureCache *cache,
|
||||
GObject *object,
|
||||
const char *property_name);
|
||||
|
||||
ClutterActor *shell_texture_cache_load_icon_name (ShellTextureCache *cache,
|
||||
const char *name,
|
||||
gint size);
|
||||
ShellTextureCache* shell_texture_cache_get_default();
|
||||
|
||||
ClutterActor *shell_texture_cache_load_gicon (ShellTextureCache *cache,
|
||||
GIcon *icon,
|
||||
gint size);
|
||||
|
||||
ClutterActor *shell_texture_cache_load_thumbnail (ShellTextureCache *cache,
|
||||
int size,
|
||||
const char *uri,
|
||||
const char *mimetype);
|
||||
|
||||
ClutterActor *shell_texture_cache_load_recent_thumbnail (ShellTextureCache *cache,
|
||||
int size,
|
||||
GtkRecentInfo *info);
|
||||
|
||||
void shell_texture_cache_evict_thumbnail (ShellTextureCache *cache,
|
||||
const char *uri);
|
||||
|
||||
void shell_texture_cache_evict_recent_thumbnail (ShellTextureCache *cache,
|
||||
GtkRecentInfo *info);
|
||||
|
||||
ClutterActor *shell_texture_cache_load_uri_async (ShellTextureCache *cache,
|
||||
const gchar *filename,
|
||||
int available_width,
|
||||
int available_height);
|
||||
|
||||
ClutterActor *shell_texture_cache_load_uri_sync (ShellTextureCache *cache,
|
||||
ShellTextureCachePolicy policy,
|
||||
const gchar *filename,
|
||||
int available_width,
|
||||
int available_height,
|
||||
|
||||
@@ -1,383 +0,0 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include "shell-uri-util.h"
|
||||
#include <glib/gi18n.h>
|
||||
#include <gconf/gconf-client.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
/* The code in this file adapted under the GPLv2+ from:
|
||||
*
|
||||
* GNOME panel utils: gnome-panel/gnome-panel/panel-util.c
|
||||
* (C) 1997, 1998, 1999, 2000 The Free Software Foundation
|
||||
* Copyright 2000 Helix Code, Inc.
|
||||
* Copyright 2000,2001 Eazel, Inc.
|
||||
* Copyright 2001 George Lebl
|
||||
* Copyright 2002 Sun Microsystems Inc.
|
||||
*
|
||||
* Authors: George Lebl
|
||||
* Jacob Berkman
|
||||
* Mark McLoughlin
|
||||
*/
|
||||
|
||||
static GFile *
|
||||
shell_util_get_gfile_root (GFile *file)
|
||||
{
|
||||
GFile *parent;
|
||||
GFile *parent_old;
|
||||
|
||||
/* search for the root on the URI */
|
||||
parent_old = g_object_ref (file);
|
||||
parent = g_file_get_parent (file);
|
||||
while (parent != NULL)
|
||||
{
|
||||
g_object_unref (parent_old);
|
||||
parent_old = parent;
|
||||
parent = g_file_get_parent (parent);
|
||||
}
|
||||
|
||||
return parent_old;
|
||||
}
|
||||
|
||||
static char *
|
||||
shell_util_get_file_display_name_if_mount (GFile *file)
|
||||
{
|
||||
GFile *compare;
|
||||
GVolumeMonitor *monitor;
|
||||
GList *mounts, *l;
|
||||
char *ret;
|
||||
|
||||
ret = NULL;
|
||||
|
||||
/* compare with all mounts */
|
||||
monitor = g_volume_monitor_get ();
|
||||
mounts = g_volume_monitor_get_mounts (monitor);
|
||||
for (l = mounts; l != NULL; l = l->next)
|
||||
{
|
||||
GMount *mount;
|
||||
mount = G_MOUNT(l->data);
|
||||
compare = g_mount_get_root (mount);
|
||||
if (!ret && g_file_equal (file, compare))
|
||||
ret = g_mount_get_name (mount);
|
||||
g_object_unref (mount);
|
||||
}
|
||||
g_list_free (mounts);
|
||||
g_object_unref (monitor);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define HOME_NAME_KEY "/apps/nautilus/desktop/home_icon_name"
|
||||
static char *
|
||||
shell_util_get_file_display_for_common_files (GFile *file)
|
||||
{
|
||||
GFile *compare;
|
||||
|
||||
compare = g_file_new_for_path (g_get_home_dir ());
|
||||
if (g_file_equal (file, compare))
|
||||
{
|
||||
char *gconf_name;
|
||||
|
||||
g_object_unref (compare);
|
||||
|
||||
gconf_name = gconf_client_get_string (gconf_client_get_default (),
|
||||
HOME_NAME_KEY, NULL);
|
||||
if (!(gconf_name && gconf_name[0]))
|
||||
{
|
||||
g_free (gconf_name);
|
||||
return g_strdup (_("Home Folder"));
|
||||
}
|
||||
else
|
||||
{
|
||||
return gconf_name;
|
||||
}
|
||||
}
|
||||
g_object_unref (compare);
|
||||
|
||||
compare = g_file_new_for_path ("/");
|
||||
if (g_file_equal (file, compare))
|
||||
{
|
||||
g_object_unref (compare);
|
||||
/* Translators: this is the same string as the one found in
|
||||
* nautilus */
|
||||
return g_strdup (_("File System"));
|
||||
}
|
||||
g_object_unref (compare);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static char *
|
||||
shell_util_get_file_description (GFile *file)
|
||||
{
|
||||
GFileInfo *info;
|
||||
char *ret;
|
||||
|
||||
ret = NULL;
|
||||
|
||||
info = g_file_query_info (file, "standard::description",
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, NULL);
|
||||
|
||||
if (info)
|
||||
{
|
||||
ret = g_strdup (g_file_info_get_attribute_string(info,
|
||||
G_FILE_ATTRIBUTE_STANDARD_DESCRIPTION));
|
||||
g_object_unref (info);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *
|
||||
shell_util_get_file_display_name (GFile *file, gboolean use_fallback)
|
||||
{
|
||||
GFileInfo *info;
|
||||
char *ret;
|
||||
|
||||
ret = NULL;
|
||||
|
||||
info = g_file_query_info (file, "standard::display-name",
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, NULL);
|
||||
|
||||
if (info)
|
||||
{
|
||||
ret = g_strdup (g_file_info_get_display_name (info));
|
||||
g_object_unref (info);
|
||||
}
|
||||
|
||||
if (!ret && use_fallback)
|
||||
{
|
||||
/* can happen with URI schemes non supported by gvfs */
|
||||
char *basename;
|
||||
|
||||
basename = g_file_get_basename (file);
|
||||
ret = g_filename_display_name (basename);
|
||||
g_free (basename);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static GIcon *
|
||||
shell_util_get_file_icon_if_mount (GFile *file)
|
||||
{
|
||||
GFile *compare;
|
||||
GVolumeMonitor *monitor;
|
||||
GList *mounts, *l;
|
||||
GIcon *ret;
|
||||
|
||||
ret = NULL;
|
||||
|
||||
/* compare with all mounts */
|
||||
monitor = g_volume_monitor_get ();
|
||||
mounts = g_volume_monitor_get_mounts (monitor);
|
||||
for (l = mounts; l != NULL; l = l->next)
|
||||
{
|
||||
GMount *mount;
|
||||
mount = G_MOUNT (l->data);
|
||||
compare = g_mount_get_root (mount);
|
||||
if (!ret && g_file_equal (file, compare))
|
||||
{
|
||||
ret = g_mount_get_icon (mount);
|
||||
}
|
||||
g_object_unref (mount);
|
||||
}
|
||||
g_list_free (mounts);
|
||||
g_object_unref (monitor);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char *
|
||||
shell_util_get_icon_for_uri_known_folders (const char *uri)
|
||||
{
|
||||
const char *icon;
|
||||
char *path;
|
||||
int len;
|
||||
|
||||
icon = NULL;
|
||||
|
||||
if (!g_str_has_prefix (uri, "file:"))
|
||||
return NULL;
|
||||
|
||||
path = g_filename_from_uri (uri, NULL, NULL);
|
||||
|
||||
len = strlen (path);
|
||||
if (path[len] == '/')
|
||||
path[len] = '\0';
|
||||
|
||||
if (strcmp (path, "/") == 0)
|
||||
icon = "drive-harddisk";
|
||||
else if (strcmp (path, g_get_home_dir ()) == 0)
|
||||
icon = "user-home";
|
||||
else if (strcmp (path, g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP))
|
||||
== 0)
|
||||
icon = "user-desktop";
|
||||
|
||||
g_free (path);
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
/* This is based on nautilus_compute_title_for_uri() and
|
||||
* nautilus_file_get_display_name_nocopy() */
|
||||
char *
|
||||
shell_util_get_label_for_uri (const char *text_uri)
|
||||
{
|
||||
GFile *file;
|
||||
char *label;
|
||||
GFile *root;
|
||||
char *root_display;
|
||||
|
||||
/* Here's what we do:
|
||||
* + x-nautilus-search: URI
|
||||
* + check if the URI is a mount
|
||||
* + if file: URI:
|
||||
* - check for known file: URI
|
||||
* - check for description of the GFile
|
||||
* - use display name of the GFile
|
||||
* + else:
|
||||
* - check for description of the GFile
|
||||
* - if the URI is a root: "root displayname"
|
||||
* - else: "root displayname: displayname"
|
||||
*/
|
||||
|
||||
label = NULL;
|
||||
|
||||
//FIXME: see nautilus_query_to_readable_string() to have a nice name
|
||||
if (g_str_has_prefix (text_uri, "x-nautilus-search:"))
|
||||
return g_strdup (_("Search"));
|
||||
|
||||
file = g_file_new_for_uri (text_uri);
|
||||
|
||||
label = shell_util_get_file_display_name_if_mount (file);
|
||||
if (label)
|
||||
{
|
||||
g_object_unref (file);
|
||||
return label;
|
||||
}
|
||||
|
||||
if (g_str_has_prefix (text_uri, "file:"))
|
||||
{
|
||||
label = shell_util_get_file_display_for_common_files (file);
|
||||
if (!label)
|
||||
label = shell_util_get_file_description (file);
|
||||
if (!label)
|
||||
label = shell_util_get_file_display_name (file, TRUE);
|
||||
g_object_unref (file);
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
label = shell_util_get_file_description (file);
|
||||
if (label)
|
||||
{
|
||||
g_object_unref (file);
|
||||
return label;
|
||||
}
|
||||
|
||||
root = shell_util_get_gfile_root (file);
|
||||
root_display = shell_util_get_file_description (root);
|
||||
if (!root_display)
|
||||
root_display = shell_util_get_file_display_name (root, FALSE);
|
||||
if (!root_display)
|
||||
/* can happen with URI schemes non supported by gvfs */
|
||||
root_display = g_file_get_uri_scheme (root);
|
||||
|
||||
if (g_file_equal (file, root))
|
||||
label = root_display;
|
||||
else
|
||||
{
|
||||
char *displayname;
|
||||
|
||||
displayname = shell_util_get_file_display_name (file, TRUE);
|
||||
/* 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.
|
||||
*/
|
||||
label = g_strdup_printf (_("%1$s: %2$s"),
|
||||
root_display, displayname);
|
||||
g_free (root_display);
|
||||
g_free (displayname);
|
||||
}
|
||||
|
||||
g_object_unref (root);
|
||||
g_object_unref (file);
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_util_get_icon_for_uri:
|
||||
* @text_uri: A URI
|
||||
*
|
||||
* Look up the icon that should be associated with a given URI. Handles
|
||||
* various special GNOME-internal cases like x-nautilus-search, etc.
|
||||
*
|
||||
* Return Value: (transfer none): A new #GIcon
|
||||
*/
|
||||
GIcon *
|
||||
shell_util_get_icon_for_uri (const char *text_uri)
|
||||
{
|
||||
const char *name;
|
||||
GFile *file;
|
||||
GFileInfo *info;
|
||||
GIcon *retval;
|
||||
|
||||
/* Here's what we do:
|
||||
* + check for known file: URI
|
||||
* + x-nautilus-search: URI
|
||||
* + override burn: URI icon
|
||||
* + check if the URI is a mount
|
||||
* + override trash: URI icon for subfolders
|
||||
* + check for application/x-gnome-saved-search mime type and override
|
||||
* icon of the GFile
|
||||
* + use icon of the GFile
|
||||
*/
|
||||
|
||||
/* this only checks file: URI */
|
||||
name = shell_util_get_icon_for_uri_known_folders (text_uri);
|
||||
if (name)
|
||||
return g_themed_icon_new (name);
|
||||
|
||||
if (g_str_has_prefix (text_uri, "x-nautilus-search:"))
|
||||
return g_themed_icon_new ("folder-saved-search");
|
||||
|
||||
/* gvfs doesn't give us a nice icon, so overriding */
|
||||
if (g_str_has_prefix (text_uri, "burn:"))
|
||||
return g_themed_icon_new ("nautilus-cd-burner");
|
||||
|
||||
file = g_file_new_for_uri (text_uri);
|
||||
|
||||
retval = shell_util_get_file_icon_if_mount (file);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/* gvfs doesn't give us a nice icon for subfolders of the trash, so
|
||||
* overriding */
|
||||
if (g_str_has_prefix (text_uri, "trash:"))
|
||||
{
|
||||
GFile *root;
|
||||
|
||||
root = shell_util_get_gfile_root (file);
|
||||
g_object_unref (file);
|
||||
file = root;
|
||||
}
|
||||
|
||||
info = g_file_query_info (file, "standard::icon", G_FILE_QUERY_INFO_NONE,
|
||||
NULL, NULL);
|
||||
g_object_unref (file);
|
||||
|
||||
if (!info)
|
||||
return g_themed_icon_new ("gtk-file");
|
||||
|
||||
retval = g_file_info_get_icon (info);
|
||||
if (retval)
|
||||
g_object_ref (retval);
|
||||
g_object_unref (info);
|
||||
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
return g_themed_icon_new ("gtk-file");
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
#ifndef __SHELL_UTIL_H__
|
||||
#define __SHELL_UTIL_H__
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
char *shell_util_get_label_for_uri (const char *text_uri);
|
||||
GIcon *shell_util_get_icon_for_uri (const char *text_uri);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __SHELL_UTIL_H__ */
|
||||
30
src/tidy/tidy-enum-types.c.in
Normal file
30
src/tidy/tidy-enum-types.c.in
Normal file
@@ -0,0 +1,30 @@
|
||||
/*** BEGIN file-header ***/
|
||||
#include "tidy-enum-types.h"
|
||||
/*** END file-header ***/
|
||||
|
||||
/*** BEGIN file-production ***/
|
||||
/* enumerations from "@filename@" */
|
||||
#include "@filename@"
|
||||
/*** END file-production ***/
|
||||
|
||||
/*** BEGIN value-header ***/
|
||||
GType
|
||||
@enum_name@_get_type(void) {
|
||||
static GType enum_type_id = 0;
|
||||
if (G_UNLIKELY (!enum_type_id))
|
||||
{
|
||||
static const G@Type@Value values[] = {
|
||||
/*** END value-header ***/
|
||||
|
||||
/*** BEGIN value-production ***/
|
||||
{ @VALUENAME@, "@VALUENAME@", "@valuenick@" },
|
||||
/*** END value-production ***/
|
||||
|
||||
/*** BEGIN value-tail ***/
|
||||
{ 0, NULL, NULL }
|
||||
};
|
||||
enum_type_id = g_@type@_register_static("@EnumName@", values);
|
||||
}
|
||||
return enum_type_id;
|
||||
}
|
||||
/*** END value-tail ***/
|
||||
25
src/tidy/tidy-enum-types.h.in
Normal file
25
src/tidy/tidy-enum-types.h.in
Normal file
@@ -0,0 +1,25 @@
|
||||
/*** BEGIN file-header ***/
|
||||
#ifndef __TIDY_ENUM_TYPES_H__
|
||||
#define __TIDY_ENUM_TYPES_H__
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
/*** END file-header ***/
|
||||
|
||||
/*** BEGIN file-production ***/
|
||||
/* enumerations from "@filename@" */
|
||||
/*** END file-production ***/
|
||||
|
||||
/*** BEGIN file-tail ***/
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* !__TIDY_ENUM_TYPES_H__ */
|
||||
/*** END file-tail ***/
|
||||
|
||||
/*** BEGIN value-header ***/
|
||||
GType @enum_name@_get_type (void) G_GNUC_CONST;
|
||||
#define TIDY_TYPE_@ENUMSHORT@ (@enum_name@_get_type())
|
||||
|
||||
/*** END value-header ***/
|
||||
1001
src/tidy/tidy-grid.c
Normal file
1001
src/tidy/tidy-grid.c
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user