[gnome-shell] New workspaces view
- From: Colin Walters <walters src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnome-shell] New workspaces view
- Date: Fri, 22 Jan 2010 18:48:57 +0000 (UTC)
commit 20abc4cb99485b586972ad3445f8323036cad266
Author: Maxim Ermilov <zaspire rambler ru>
Date: Fri Jan 22 05:33:48 2010 +0300
New workspaces view
Matching the 20091114 mockup, the default workspace view
is now a scrollable horizontal list, with a control to
switch between this and the previous grid view.
https://bugzilla.gnome.org/show_bug.cgi?id=593844
data/Makefile.am | 18 +-
data/theme/add-workspace.svg | 98 ++++
data/theme/gnome-shell.css | 79 +++
data/theme/mosaic-view-active.svg | 113 ++++
data/theme/mosaic-view.svg | 113 ++++
data/theme/remove-workspace.svg | 92 ++++
data/theme/single-view-active.svg | 81 +++
data/theme/single-view.svg | 81 +++
data/theme/switch-scroll-hhandle.svg | 123 +++++
js/ui/Makefile.am | 3 +-
js/ui/appDisplay.js | 6 +-
js/ui/overview.js | 124 ++---
js/ui/{workspaces.js => workspace.js} | 573 +++------------------
js/ui/workspacesView.js | 956 +++++++++++++++++++++++++++++++++
14 files changed, 1870 insertions(+), 590 deletions(-)
---
diff --git a/data/Makefile.am b/data/Makefile.am
index f0ca34e..6fa151e 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -21,16 +21,24 @@ dist_images_DATA = \
themedir = $(pkgdatadir)/theme
dist_theme_DATA = \
- theme/gnome-shell.css \
- theme/close.svg \
+ theme/add-workspace.svg \
theme/close-window.svg \
- theme/scroll-button-down.png \
+ theme/close.svg \
+ theme/gnome-shell.css \
+ theme/mosaic-view-active.svg \
+ theme/mosaic-view.svg \
+ theme/remove-workspace.svg \
theme/scroll-button-down-hover.png \
- theme/scroll-button-up.png \
+ theme/scroll-button-down.png \
theme/scroll-button-up-hover.png \
+ theme/scroll-button-up.png \
theme/scroll-vhandle.png \
theme/section-back.svg \
- theme/section-more.svg
+ theme/section-more.svg \
+ theme/single-view-active.svg \
+ theme/single-view.svg \
+ theme/switch-scroll-hhandle.svg
+
schemadir = @GCONF_SCHEMA_FILE_DIR@
schema_DATA = gnome-shell.schemas
diff --git a/data/theme/add-workspace.svg b/data/theme/add-workspace.svg
new file mode 100644
index 0000000..6df7cbd
--- /dev/null
+++ b/data/theme/add-workspace.svg
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="23"
+ height="15"
+ id="svg6375"
+ version="1.1"
+ inkscape:version="0.47pre4 r22446"
+ sodipodi:docname="New document 13">
+ <defs
+ id="defs6377">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 16 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="32 : 16 : 1"
+ inkscape:persp3d-origin="16 : 10.666667 : 1"
+ id="perspective6383" />
+ <inkscape:perspective
+ id="perspective6366"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="11.197802"
+ inkscape:cx="16"
+ inkscape:cy="16"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:window-width="1680"
+ inkscape:window-height="997"
+ inkscape:window-x="0"
+ inkscape:window-y="26"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata6380">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ transform="translate(0,-17)">
+ <g
+ style="display:inline"
+ id="g6243"
+ transform="translate(-986.28859,-658.2796)">
+ <rect
+ style="fill:#000000;fill-opacity:0.98770495;stroke:#666666;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+ id="rect5318"
+ width="22"
+ height="14"
+ x="986.89801"
+ y="675.86743"
+ rx="0.49999979"
+ ry="0.5" />
+ <g
+ id="g5320"
+ transform="translate(402.77304,-12.882544)">
+ <path
+ id="path5322"
+ d="m 595.125,692.53048 0,6.43903"
+ style="fill:none;stroke:#666666;stroke-width:1.99999952;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ <path
+ id="path5324"
+ d="m 598.34451,695.75 -6.43902,0"
+ style="fill:none;stroke:#666666;stroke-width:1.99999952;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" />
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
index 67d917b..5828beb 100644
--- a/data/theme/gnome-shell.css
+++ b/data/theme/gnome-shell.css
@@ -137,6 +137,24 @@ StTooltip {
color: white;
}
+.workspaces-bar {
+ height: 60px;
+}
+
+.workspace-indicator {
+ width: 24px;
+ height: 15px;
+ background: rgba(155,155,155,0.8);
+ border-spacing: 15px;
+}
+
+.workspace-indicator-active {
+ width: 24px;
+ height: 15px;
+ background: rgba(255,255,255,0.8);
+ border-spacing: 15px;
+}
+
.window-caption {
background: rgba(0,0,0,0.8);
border: 1px solid rgba(128,128,128,0.40);
@@ -154,6 +172,67 @@ StTooltip {
-shell-close-overlap: 16px;
}
+.single-view-add {
+ background-image: url("add-workspace.svg");
+ width: 24px;
+ height: 15px;
+}
+
+.single-view-remove {
+ background-image: url("remove-workspace.svg");
+ width: 24px;
+ height: 15px;
+}
+
+.switch-view-single {
+ background-image: url("single-view.svg");
+ width: 24px;
+ height: 15px;
+}
+
+.switch-view-mosaic {
+ background-image: url("mosaic-view.svg");
+ width: 24px;
+ height: 15px;
+}
+
+.switch-view-single:checked {
+ background-image: url("single-view-active.svg");
+ width: 24px;
+ height: 15px;
+}
+
+.switch-view-mosaic:checked {
+ background-image: url("mosaic-view-active.svg");
+ width: 24px;
+ height: 15px;
+}
+
+.scroll-separator {
+ width: 9px;
+ height: 15px;
+}
+
+#SwitchScroll {
+ height: 15px;
+}
+
+#SwitchScroll StBin{
+ border: 1px solid rgba(128,128,128,0.40);
+ border-radius: 5px;
+}
+
+#SwitchScroll StButton#hhandle {
+ border-image: url("switch-scroll-hhandle.svg") 5;
+}
+
+#SwitchScroll StButton#backward-stepper,
+#SwitchScroll StButton#forward-stepper
+{
+ width: 0px;
+ border: 0px;
+}
+
/* Dash */
#dash {
diff --git a/data/theme/mosaic-view-active.svg b/data/theme/mosaic-view-active.svg
new file mode 100644
index 0000000..296e776
--- /dev/null
+++ b/data/theme/mosaic-view-active.svg
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="24"
+ height="16"
+ id="svg6503"
+ version="1.1"
+ inkscape:version="0.47pre4 r22446"
+ sodipodi:docname="mosaic-view-active.svg">
+ <defs
+ id="defs6505">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 16 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="32 : 16 : 1"
+ inkscape:persp3d-origin="16 : 10.666667 : 1"
+ id="perspective6511" />
+ <inkscape:perspective
+ id="perspective6494"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="11.197802"
+ inkscape:cx="-15.97056"
+ inkscape:cy="16"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:window-width="1680"
+ inkscape:window-height="997"
+ inkscape:window-x="0"
+ inkscape:window-y="26"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata6508">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ transform="translate(0,-16)">
+ <g
+ style="display:inline;fill:#cbcbcb;fill-opacity:1"
+ transform="translate(-449.85476,-685.85869)"
+ id="g5306">
+ <rect
+ style="fill:#cbcbcb;fill-opacity:1;stroke:#000000;stroke-width:0.99999970000000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.44262299999999999;stroke-dasharray:none"
+ id="rect5308"
+ width="11"
+ height="7"
+ x="450.5"
+ y="710.5"
+ rx="0.99999958"
+ ry="1" />
+ <rect
+ style="fill:#cbcbcb;fill-opacity:1;stroke:#000000;stroke-width:0.99999970000000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.44262299999999999;stroke-dasharray:none;display:inline"
+ id="rect5310"
+ width="11"
+ height="7"
+ x="462.5"
+ y="702.5"
+ rx="0.99999958"
+ ry="1" />
+ <rect
+ style="fill:#cbcbcb;fill-opacity:1;stroke:#000000;stroke-width:0.99999976000000002;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.44262299999999999;stroke-dasharray:none;display:inline"
+ id="rect5312"
+ width="11"
+ height="7"
+ x="450.5"
+ y="702.5"
+ rx="0.99999958"
+ ry="1" />
+ <rect
+ style="fill:#cbcbcb;fill-opacity:1;stroke:#000000;stroke-width:0.99999970000000005;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.44262299999999999;stroke-dasharray:none;display:inline"
+ id="rect5314"
+ width="11"
+ height="7"
+ x="462.5"
+ y="710.5"
+ rx="0.99999958"
+ ry="1" />
+ </g>
+ </g>
+</svg>
diff --git a/data/theme/mosaic-view.svg b/data/theme/mosaic-view.svg
new file mode 100644
index 0000000..b6ec4c3
--- /dev/null
+++ b/data/theme/mosaic-view.svg
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="24"
+ height="16"
+ id="svg6503"
+ version="1.1"
+ inkscape:version="0.47pre4 r22446"
+ sodipodi:docname="New document 19">
+ <defs
+ id="defs6505">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 16 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="32 : 16 : 1"
+ inkscape:persp3d-origin="16 : 10.666667 : 1"
+ id="perspective6511" />
+ <inkscape:perspective
+ id="perspective6494"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="11.197802"
+ inkscape:cx="16"
+ inkscape:cy="16"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:window-width="1680"
+ inkscape:window-height="997"
+ inkscape:window-x="0"
+ inkscape:window-y="26"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata6508">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ transform="translate(0,-16)">
+ <g
+ style="display:inline"
+ transform="translate(-449.85476,-685.85869)"
+ id="g5306">
+ <rect
+ style="fill:#666666;fill-opacity:1;stroke:#000000;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.442623;stroke-dasharray:none"
+ id="rect5308"
+ width="11"
+ height="7"
+ x="450.5"
+ y="710.5"
+ rx="0.99999958"
+ ry="1" />
+ <rect
+ style="fill:#666666;fill-opacity:1;stroke:#000000;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.442623;stroke-dasharray:none;display:inline"
+ id="rect5310"
+ width="11"
+ height="7"
+ x="462.5"
+ y="702.5"
+ rx="0.99999958"
+ ry="1" />
+ <rect
+ style="fill:#666666;fill-opacity:1;stroke:#000000;stroke-width:0.99999976;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.442623;stroke-dasharray:none;display:inline"
+ id="rect5312"
+ width="11"
+ height="7"
+ x="450.5"
+ y="702.5"
+ rx="0.99999958"
+ ry="1" />
+ <rect
+ style="fill:#666666;fill-opacity:1;stroke:#000000;stroke-width:0.9999997;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:0.442623;stroke-dasharray:none;display:inline"
+ id="rect5314"
+ width="11"
+ height="7"
+ x="462.5"
+ y="710.5"
+ rx="0.99999958"
+ ry="1" />
+ </g>
+ </g>
+</svg>
diff --git a/data/theme/remove-workspace.svg b/data/theme/remove-workspace.svg
new file mode 100644
index 0000000..0063302
--- /dev/null
+++ b/data/theme/remove-workspace.svg
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="23"
+ height="15"
+ id="svg5501"
+ version="1.1"
+ inkscape:version="0.47pre4 r22446"
+ sodipodi:docname="add-workspace.svg">
+ <defs
+ id="defs5503">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 16 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="32 : 16 : 1"
+ inkscape:persp3d-origin="16 : 10.666667 : 1"
+ id="perspective5509" />
+ <inkscape:perspective
+ id="perspective5314"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="11.197802"
+ inkscape:cx="-0.074583208"
+ inkscape:cy="16"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:window-width="1680"
+ inkscape:window-height="997"
+ inkscape:window-x="0"
+ inkscape:window-y="26"
+ inkscape:window-maximized="1"
+ inkscape:snap-grids="true"
+ inkscape:snap-bbox="true" />
+ <metadata
+ id="metadata5506">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ transform="translate(0,-17)">
+ <g
+ style="display:inline"
+ id="g6239"
+ transform="translate(-953.97989,-657.32287)">
+ <rect
+ style="fill:#000000;fill-opacity:0.98770495;stroke:#666666;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+ id="rect5318-6"
+ width="22"
+ height="14"
+ x="954.5"
+ y="675"
+ rx="0.49999979"
+ ry="0.5" />
+ <path
+ style="fill:none;stroke:#666666;stroke-width:1.99999952;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline"
+ d="m 968.71951,682 -6.43902,0"
+ id="path5324-5" />
+ </g>
+ </g>
+</svg>
diff --git a/data/theme/single-view-active.svg b/data/theme/single-view-active.svg
new file mode 100644
index 0000000..d7350ac
--- /dev/null
+++ b/data/theme/single-view-active.svg
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="23"
+ height="15"
+ id="svg6446"
+ version="1.1"
+ inkscape:version="0.47pre4 r22446"
+ sodipodi:docname="single-view-active.svg">
+ <defs
+ id="defs6448">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 16 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="32 : 16 : 1"
+ inkscape:persp3d-origin="16 : 10.666667 : 1"
+ id="perspective6454" />
+ <inkscape:perspective
+ id="perspective6441"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="11.197802"
+ inkscape:cx="0.014720032"
+ inkscape:cy="16"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:window-width="1680"
+ inkscape:window-height="997"
+ inkscape:window-x="0"
+ inkscape:window-y="26"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata6451">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ transform="translate(0,-17)">
+ <rect
+ ry="0.5"
+ rx="0.49999979"
+ y="17.483809"
+ x="0.53483802"
+ height="14"
+ width="22"
+ id="rect5304"
+ style="fill:#cccccc;fill-opacity:1;stroke:#cccccc;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" />
+ </g>
+</svg>
diff --git a/data/theme/single-view.svg b/data/theme/single-view.svg
new file mode 100644
index 0000000..c053e4f
--- /dev/null
+++ b/data/theme/single-view.svg
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="23"
+ height="15"
+ id="svg6446"
+ version="1.1"
+ inkscape:version="0.47pre4 r22446"
+ sodipodi:docname="single-view.svg">
+ <defs
+ id="defs6448">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 16 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="32 : 16 : 1"
+ inkscape:persp3d-origin="16 : 10.666667 : 1"
+ id="perspective6454" />
+ <inkscape:perspective
+ id="perspective6441"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="11.197802"
+ inkscape:cx="0.014720032"
+ inkscape:cy="16"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:window-width="1680"
+ inkscape:window-height="997"
+ inkscape:window-x="0"
+ inkscape:window-y="26"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata6451">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ transform="translate(0,-17)">
+ <rect
+ ry="0.5"
+ rx="0.49999979"
+ y="17.483809"
+ x="0.53483802"
+ height="14"
+ width="22"
+ id="rect5304"
+ style="fill:#626262;fill-opacity:1;stroke:#cccccc;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" />
+ </g>
+</svg>
diff --git a/data/theme/switch-scroll-hhandle.svg b/data/theme/switch-scroll-hhandle.svg
new file mode 100644
index 0000000..ae465d9
--- /dev/null
+++ b/data/theme/switch-scroll-hhandle.svg
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="300"
+ height="16"
+ id="svg5337"
+ version="1.1"
+ inkscape:version="0.47pre4 r22446"
+ sodipodi:docname="New document 2">
+ <defs
+ id="defs5339">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 16 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="32 : 16 : 1"
+ inkscape:persp3d-origin="16 : 10.666667 : 1"
+ id="perspective5345" />
+ <inkscape:perspective
+ id="perspective5323"
+ inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+ inkscape:vp_z="1 : 0.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_x="0 : 0.5 : 1"
+ sodipodi:type="inkscape:persp3d" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient356"
+ id="linearGradient5313"
+ gradientUnits="userSpaceOnUse"
+ x1="495.75"
+ y1="675.5"
+ x2="495.75"
+ y2="683" />
+ <linearGradient
+ id="linearGradient356">
+ <stop
+ style="stop-color:#999999;stop-opacity:0.60000002;"
+ offset="0"
+ id="stop357" />
+ <stop
+ style="stop-color:#fffff3;stop-opacity:0.0000000;"
+ offset="1.0000000"
+ id="stop358" />
+ </linearGradient>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="2.7994505"
+ inkscape:cx="111.6181"
+ inkscape:cy="33.67855"
+ inkscape:current-layer="layer1"
+ showgrid="true"
+ inkscape:grid-bbox="true"
+ inkscape:document-units="px"
+ inkscape:window-width="1680"
+ inkscape:window-height="997"
+ inkscape:window-x="0"
+ inkscape:window-y="26"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata5342">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ id="layer1"
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ transform="translate(0,-16)">
+ <g
+ style="display:inline"
+ id="g6342"
+ transform="translate(-334.52404,-658.85869)">
+ <rect
+ ry="8"
+ rx="8"
+ y="675.5"
+ x="335.5"
+ height="15"
+ width="299"
+ id="rect5457-5"
+ style="fill:url(#linearGradient5313);fill-opacity:1;stroke:#999999;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;display:inline" />
+ <g
+ transform="translate(0.5,0)"
+ id="g6337">
+ <path
+ style="fill:none;stroke:#666666;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.8"
+ d="m 480.5,680.3717 0,5.2566"
+ id="path6304" />
+ <path
+ style="fill:none;stroke:#666666;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.8;display:inline"
+ d="m 484.5,680.3717 0,5.2566"
+ id="path6304-0" />
+ <path
+ style="fill:none;stroke:#666666;stroke-width:0.99999994px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.8;display:inline"
+ d="m 488.5,680.3717 0,5.2566"
+ id="path6304-8" />
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/js/ui/Makefile.am b/js/ui/Makefile.am
index 4eb3883..9d54f74 100644
--- a/js/ui/Makefile.am
+++ b/js/ui/Makefile.am
@@ -30,4 +30,5 @@ dist_jsui_DATA = \
widget.js \
widgetBox.js \
windowManager.js \
- workspaces.js
+ workspacesView.js \
+ workspace.js
diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js
index 4749228..b9ba04f 100644
--- a/js/ui/appDisplay.js
+++ b/js/ui/appDisplay.js
@@ -19,7 +19,7 @@ const DND = imports.ui.dnd;
const GenericDisplay = imports.ui.genericDisplay;
const Main = imports.ui.main;
const Search = imports.ui.search;
-const Workspaces = imports.ui.workspaces;
+const Workspace = imports.ui.workspace;
const APPICON_SIZE = 48;
const WELL_MAX_COLUMNS = 8;
@@ -697,7 +697,7 @@ AppIconMenu.prototype = {
},
_findMetaWindowForActor: function (actor) {
- if (actor._delegate instanceof Workspaces.WindowClone)
+ if (actor._delegate instanceof Workspace.WindowClone)
return actor._delegate.metaWindow;
else if (actor.get_meta_window)
return actor.get_meta_window();
@@ -1011,7 +1011,7 @@ AppWell.prototype = {
let app = null;
if (source instanceof AppDisplayItem) {
app = this._appSystem.get_app(source.getId());
- } else if (source instanceof Workspaces.WindowClone) {
+ } else if (source instanceof Workspace.WindowClone) {
app = this._tracker.get_window_app(source.metaWindow);
}
diff --git a/js/ui/overview.js b/js/ui/overview.js
index ce6fbfa..3ec61a1 100644
--- a/js/ui/overview.js
+++ b/js/ui/overview.js
@@ -8,6 +8,7 @@ const Mainloop = imports.mainloop;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
const Lang = imports.lang;
+const St = imports.gi.St;
const AppDisplay = imports.ui.appDisplay;
const DocDisplay = imports.ui.docDisplay;
@@ -16,7 +17,7 @@ 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 WorkspacesView = imports.ui.workspacesView;
const ROOT_OVERVIEW_COLOR = new Clutter.Color();
ROOT_OVERVIEW_COLOR.from_pixel(0x000000ff);
@@ -76,7 +77,6 @@ const NUMBER_OF_SECTIONS_IN_SEARCH = 2;
let wideScreen = false;
let displayGridColumnWidth = null;
let displayGridRowHeight = null;
-let addRemoveButtonSize = null;
function Overview() {
this._init();
@@ -87,6 +87,9 @@ Overview.prototype = {
this._group = new Clutter.Group();
this._group._delegate = this;
+ this._workspacesViewSwitch = new WorkspacesView.WorkspacesViewSwitch();
+ this._workspacesViewSwitch.connect('view-changed', Lang.bind(this, this._onViewChanged));
+
this.visible = false;
this.animationInProgress = false;
this._hideInProgress = false;
@@ -139,6 +142,45 @@ Overview.prototype = {
this._workspaces = null;
},
+ _createControlsBar: function() {
+ this._workspacesBar = new St.BoxLayout({ 'pack-start': true,
+ style_class: 'workspaces-bar' });
+ this._workspacesBar.move_by(this._workspacesBarX, this._workspacesBarY);
+
+ let controlsBar = this._workspacesViewSwitch.createControlsBar();
+ let bar = this._workspaces.createControllerBar();
+ this._workspacesBar.add(bar, { expand: true, 'x-fill': true, 'y-fill': true,
+ y_align: St.Align.MIDDLE, x_align: St.Align.START });
+ this._workspacesBar.add(controlsBar, {x_align: St.Align.END});
+ this._workspacesBar.width = this._workspacesBarWidth;
+
+ this._group.add_actor(this._workspacesBar);
+ this._workspacesBar.raise(this._workspaces.actor);
+ },
+
+ _onViewChanged: function() {
+ if (!this.visible)
+ return;
+ //Remove old worspacesView
+ this._group.remove_actor(this._workspacesBar);
+ this._workspaces.hide();
+ this._group.remove_actor(this._workspaces.actor);
+ this._workspaces.destroy();
+ this._workspacesBar.destroy();
+
+ this._workspaces = this._workspacesViewSwitch.createCurrentWorkspaceView(this._workspacesWidth, this._workspacesHeight,
+ this._workspacesX, this._workspacesY, false);
+
+ //Show new workspacesView
+ this._group.add_actor(this._workspaces.actor);
+ this._dash.actor.raise(this._workspaces.actor);
+
+ this._createControlsBar();
+
+ // Set new position and scale to workspaces.
+ this.emit('showing');
+ },
+
_recalculateGridSizes: function () {
let primary = global.get_primary_monitor();
wideScreen = (primary.width/primary.height > WIDE_SCREEN_CUT_OFF_RATIO) &&
@@ -188,9 +230,9 @@ Overview.prototype = {
this._dash.searchResults.actor.height = this._workspacesHeight;
// place the 'Add Workspace' button in the bottom row of the grid
- addRemoveButtonSize = Math.floor(displayGridRowHeight * 3/5);
- this._addButtonX = this._workspacesX + this._workspacesWidth - addRemoveButtonSize;
- this._addButtonY = primary.height - Math.floor(displayGridRowHeight * 4/5);
+ this._workspacesBarX = this._workspacesX;
+ this._workspacesBarWidth = primary.width - this._workspacesBarX - WORKSPACE_GRID_PADDING;
+ this._workspacesBarY = primary.height - displayGridRowHeight + 5;
// The parent (this._group) is positioned at the top left of the primary monitor
// while this._backOver occupies the entire screen.
@@ -298,8 +340,8 @@ Overview.prototype = {
this._dash.show();
/* TODO: make this stuff dynamic */
- this._workspaces = new Workspaces.Workspaces(this._workspacesWidth, this._workspacesHeight,
- this._workspacesX, this._workspacesY);
+ this._workspaces = this._workspacesViewSwitch.createCurrentWorkspaceView(this._workspacesWidth, this._workspacesHeight,
+ this._workspacesX, this._workspacesY, true);
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
@@ -307,11 +349,7 @@ Overview.prototype = {
// be as big as the screen.
this._dash.actor.raise(this._workspaces.actor);
- // Create (+) button
- this._addButton = new AddWorkspaceButton(addRemoveButtonSize, this._addButtonX, this._addButtonY, Lang.bind(this, this._acceptNewWorkspaceDrop));
- this._addButton.actor.connect('button-release-event', Lang.bind(this, this._addNewWorkspace));
- this._group.add_actor(this._addButton.actor);
- this._addButton.actor.raise(this._workspaces.actor);
+ this._createControlsBar();
// All the the actors in the window group are completely obscured,
// hiding the group holding them while the Overview is displayed greatly
@@ -363,9 +401,8 @@ Overview.prototype = {
this._activeDisplayPane.close();
this._workspaces.hide();
- this._addButton.actor.destroy();
- this._addButton.actor = null;
- this._addButton = null;
+ this._workspacesBar.destroy();
+ this._workspacesBar = null;
// Create a zoom in effect by transforming the Overview group so that
// the active workspace fills up the whole screen. The opposite
@@ -448,7 +485,7 @@ Overview.prototype = {
this._dash.hide();
this._group.hide();
- this.visible = false;
+ this.visible = false;
this.animationInProgress = false;
this._hideInProgress = false;
@@ -456,61 +493,6 @@ Overview.prototype = {
Main.popModal(this._dash.actor);
this.emit('hidden');
- },
-
- _addNewWorkspace: function() {
- global.screen.append_new_workspace(false, global.get_current_time());
- },
-
- _acceptNewWorkspaceDrop: function(source, dropActor, x, y, time) {
- this._addNewWorkspace();
- return this._workspaces.acceptNewWorkspaceDrop(source, dropActor, x, y, time);
}
};
Signals.addSignalMethods(Overview.prototype);
-
-// Note that mutter has a compile-time limit of 36
-const MAX_WORKSPACES = 16;
-
-function AddWorkspaceButton(buttonSize, buttonX, buttonY, acceptDropCallback) {
- this._init(buttonSize, buttonX, buttonY, acceptDropCallback);
-}
-
-AddWorkspaceButton.prototype = {
- _init: function(buttonSize, buttonX, buttonY, acceptDropCallback) {
- this.actor = new Clutter.Group({ x: buttonX,
- y: buttonY,
- width: global.screen_width - buttonX,
- height: global.screen_height - buttonY,
- reactive: true });
- this.actor._delegate = this;
- this._acceptDropCallback = acceptDropCallback;
-
- let plus = new Clutter.Texture({ x: 0,
- y: 0,
- width: buttonSize,
- height: buttonSize });
- plus.set_from_file(global.imagedir + 'add-workspace.svg');
- this.actor.add_actor(plus);
-
- global.screen.connect('notify::n-workspaces', Lang.bind(this, this._nWorkspacesChanged));
- this._nWorkspacesChanged();
- },
-
- _nWorkspacesChanged: function() {
- let canAddAnother = global.screen.n_workspaces < MAX_WORKSPACES;
-
- if (canAddAnother && !this.actor.reactive) {
- this.actor.reactive = true;
- this.actor.opacity = 255;
- } else if (!canAddAnother && this.actor.reactive) {
- this.actor.reactive = false;
- this.actor.opacity = 85;
- }
- },
-
- // Draggable target interface
- acceptDrop: function(source, actor, x, y, time) {
- return this.reactive && this._acceptDropCallback(source, actor, x, y, time);
- }
-};
diff --git a/js/ui/workspaces.js b/js/ui/workspace.js
similarity index 70%
rename from js/ui/workspaces.js
rename to js/ui/workspace.js
index 427d313..49d0bed 100644
--- a/js/ui/workspaces.js
+++ b/js/ui/workspace.js
@@ -322,7 +322,7 @@ WindowOverlay.prototype = {
this._parentActor = parentActor;
let title = new St.Label({ style_class: "window-caption",
- text : metaWindow.title });
+ text: metaWindow.title });
title.connect('style-changed',
Lang.bind(this, this._onStyleChanged));
title.clutter_text.ellipsize = Pango.EllipsizeMode.END;
@@ -368,6 +368,8 @@ WindowOverlay.prototype = {
x, y);
if (actor == this._windowClone.actor) {
this.closeButton.show();
+ // Reposition the close button in case we've changed display modes
+ this._updatePositions();
}
this.title.show();
},
@@ -375,7 +377,7 @@ WindowOverlay.prototype = {
fadeIn: function() {
this.title.opacity = 0;
this.title.show();
- this.title.raise_top();
+ this._parentActor.raise_top();
Tweener.addTween(this.title,
{ opacity: 255,
time: Overview.ANIMATION_TIME,
@@ -391,6 +393,12 @@ WindowOverlay.prototype = {
this.title.height + this.title._spacing;
},
+ _updatePositions: function() {
+ let [cloneX, cloneY] = this._windowClone.actor.get_transformed_position();
+ let [cloneWidth, cloneHeight] = this._windowClone.actor.get_transformed_size();
+ this.updatePositions(cloneX, cloneY, cloneWidth, cloneHeight);
+ },
+
/**
* @cloneX: x position of windowClone
* @cloneY: y position of windowClone
@@ -460,7 +468,9 @@ WindowOverlay.prototype = {
},
_onEnter: function() {
- this.closeButton.raise_top();
+ this._updatePositions();
+
+ this._parentActor.raise_top();
this.closeButton.show();
this.emit('show-close-button');
},
@@ -510,6 +520,10 @@ WindowOverlay.prototype = {
Signals.addSignalMethods(WindowOverlay.prototype);
+const WindowPositionFlags = {
+ ZOOM: 1 << 0,
+ ANIMATE: 1 << 1
+};
/**
* @workspaceNum: Workspace index
@@ -524,9 +538,14 @@ function Workspace(workspaceNum, parentActor) {
Workspace.prototype = {
_init : function(workspaceNum, parentActor) {
this.workspaceNum = workspaceNum;
+ this._windowOverlaysGroup = new Clutter.Group();
+ // Without this the drop area will be overlapped.
+ this._windowOverlaysGroup.set_size(0, 0);
+
this._metaWorkspace = global.screen.get_workspace_by_index(workspaceNum);
- this.parentActor = parentActor;
+ parentActor.add_actor(this._windowOverlaysGroup);
+ this._parentActor = parentActor;
this.actor = new Clutter.Group();
this.actor._delegate = this;
@@ -578,7 +597,6 @@ Workspace.prototype = {
this._windowRemovedId = this._metaWorkspace.connect('window-removed',
Lang.bind(this, this._windowRemoved));
- this._removeButton = null;
this._visible = false;
this._frame = null;
@@ -586,51 +604,6 @@ Workspace.prototype = {
this.leavingOverview = false;
},
- updateRemovable : function() {
- let removable = (this._windows.length == 1 /* just desktop */ &&
- this.workspaceNum != 0 &&
- this.workspaceNum == global.screen.n_workspaces - 1);
-
- if (removable) {
- if (this._removeButton)
- return;
-
- this._removeButton = new Clutter.Texture({ width: Overview.addRemoveButtonSize,
- height: Overview.addRemoveButtonSize,
- reactive: true
- });
- this._removeButton.set_from_file(global.imagedir + "remove-workspace.svg");
- this._removeButton.connect('button-release-event', Lang.bind(this, this._removeSelf));
-
- this.actor.add_actor(this._removeButton);
- this._adjustRemoveButton();
- this._adjustRemoveButtonId = this.actor.connect('notify::scale-x', Lang.bind(this, this._adjustRemoveButton));
-
- if (this._visible) {
- this._removeButton.set_opacity(0);
- Tweener.addTween(this._removeButton,
- { opacity: 255,
- time: Overview.ANIMATION_TIME,
- transition: "easeOutQuad"
- });
- }
- } else {
- if (!this._removeButton)
- return;
-
- if (this._visible) {
- Tweener.addTween(this._removeButton,
- { opacity: 0,
- time: Overview.ANIMATION_TIME,
- transition: "easeOutQuad",
- onComplete: this._removeRemoveButton,
- onCompleteScope: this
- });
- } else
- this._removeRemoveButton();
- }
- },
-
_lookupIndex: function (metaWindow) {
let index, clone;
for (let i = 0; i < this._windows.length; i++) {
@@ -661,7 +634,7 @@ Workspace.prototype = {
this._showOnlyWindows = showOnlyWindows;
this._resetCloneVisibility();
if (reposition)
- this.positionWindows(false);
+ this.positionWindows(WindowPositionFlags.ANIMATE);
},
/**
@@ -697,20 +670,6 @@ Workspace.prototype = {
this._lightbox.highlight(actor);
},
- _adjustRemoveButton : function() {
- this._removeButton.set_scale(1.0 / this.actor.scale_x,
- 1.0 / this.actor.scale_y);
- this._removeButton.set_position(
- (this.actor.width - this._removeButton.width / this.actor.scale_x) / 2,
- (this.actor.height - this._removeButton.height / this.actor.scale_y) / 2);
- },
-
- _removeRemoveButton : function() {
- this._removeButton.destroy();
- this._removeButton = null;
- this.actor.disconnect(this._adjustRemoveButtonId);
- },
-
// Mark the workspace selected/not-selected
setSelected : function(selected) {
// Don't draw a frame if we only have one workspace
@@ -1007,13 +966,18 @@ Workspace.prototype = {
/**
* positionWindows:
- * @workspaceZooming: If true, then the workspace is moving at the same time and we need to take that into account.
+ * @flags:
+ * ZOOM - workspace is moving at the same time and we need to take that into account.
+ * ANIMATE - Indicates that we need animate changing position.
*/
- positionWindows : function(workspaceZooming) {
+ positionWindows : function(flags) {
let totalVisible = 0;
let visibleWindows = this._getVisibleWindows();
+ let workspaceZooming = flags & WindowPositionFlags.ZOOM;
+ let animate = flags & WindowPositionFlags.ANIMATE;
+
// Start the animations
let slots = this._computeAllWindowSlots(visibleWindows.length);
visibleWindows = this._orderWindowsByMotionAndStartup(visibleWindows, slots);
@@ -1028,18 +992,24 @@ Workspace.prototype = {
let [x, y, scale] = this._computeWindowRelativeLayout(metaWindow, slot);
overlay.hide();
- Tweener.addTween(clone.actor,
- { x: x,
- y: y,
- scale_x: scale,
- scale_y: scale,
- workspace_relative: workspaceZooming ? this : null,
- time: Overview.ANIMATION_TIME,
- transition: "easeOutQuad",
- onComplete: Lang.bind(this, function() {
- this._fadeInWindowOverlay(clone, overlay);
- })
- });
+ if (animate) {
+ Tweener.addTween(clone.actor,
+ { x: x,
+ y: y,
+ scale_x: scale,
+ scale_y: scale,
+ workspace_relative: workspaceZooming ? this : null,
+ time: Overview.ANIMATION_TIME,
+ transition: "easeOutQuad",
+ onComplete: Lang.bind(this, function() {
+ this._fadeInWindowOverlay(clone, overlay);
+ })
+ });
+ } else {
+ clone.actor.set_position(x, y);
+ clone.actor.set_scale(scale, scale);
+ this._fadeInWindowOverlay(clone, overlay);
+ }
}
},
@@ -1127,8 +1097,7 @@ Workspace.prototype = {
}
clone.destroy();
- this.positionWindows(false);
- this.updateRemovable();
+ this.positionWindows(WindowPositionFlags.ANIMATE);
},
_windowAdded : function(metaWorkspace, metaWin) {
@@ -1148,9 +1117,9 @@ Workspace.prototype = {
}));
return;
}
-
+
if (!this._isOverviewWindow(win))
- return;
+ return;
let clone = this._addWindowClone(win);
@@ -1164,29 +1133,19 @@ Workspace.prototype = {
clone.actor.set_scale (scale, scale);
}
- this.positionWindows(false);
- this.updateRemovable();
+ this.positionWindows(WindowPositionFlags.ANIMATE);
},
// Animate the full-screen to Overview transition.
- zoomToOverview : function() {
+ zoomToOverview : function(animate) {
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'
- });
- }
+ if (animate)
+ this.positionWindows(WindowPositionFlags.ANIMATE | WindowPositionFlags.ZOOM);
+ else
+ this.positionWindows(WindowPositionFlags.ZOOM);
this._visible = true;
},
@@ -1200,17 +1159,6 @@ Workspace.prototype = {
Main.overview.connect('hidden', Lang.bind(this,
this._doneLeavingOverview));
- // 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];
@@ -1226,7 +1174,7 @@ Workspace.prototype = {
});
}
- this._visible = false;
+ this._visible = false;
},
// Animates grid shrinking/expanding when a row or column
@@ -1264,7 +1212,7 @@ Workspace.prototype = {
this._visible = true;
},
-
+
// Animates the removal of a workspace
slideOut : function(onComplete) {
let destX = this.actor.x, destY = this.actor.y;
@@ -1291,11 +1239,12 @@ Workspace.prototype = {
// making its exit.
this._desktop.reactive = false;
},
-
+
destroy : function() {
Tweener.removeTweens(this.actor);
this.actor.destroy();
this.actor = null;
+ this._windowOverlaysGroup.destroy();
this._metaWorkspace.disconnect(this._windowAddedId);
this._metaWorkspace.disconnect(this._windowRemovedId);
@@ -1321,7 +1270,7 @@ Workspace.prototype = {
// Create a clone of a (non-desktop) window and add it to the window list
_addWindowClone : function(win) {
let clone = new WindowClone(win);
- let overlay = new WindowOverlay(clone, this.parentActor);
+ let overlay = new WindowOverlay(clone, this._windowOverlaysGroup);
clone.connect('selected',
Lang.bind(this, this._onCloneSelected));
@@ -1421,399 +1370,3 @@ Workspace.prototype = {
};
Signals.addSignalMethods(Workspace.prototype);
-
-function Workspaces(width, height, x, y) {
- this._init(width, height, x, y);
-}
-
-Workspaces.prototype = {
- _init : function(width, height, x, y) {
- this.actor = new St.Bin({ style_class: "workspaces" });
- this._actor = new Clutter.Group();
-
- this.actor.add_actor(this._actor);
-
- this._width = width;
- this._height = height;
- this._x = x;
- this._y = y;
-
- this._windowSelectionAppId = null;
-
- this._workspaces = [];
-
- this._highlightWindow = null;
-
- let activeWorkspaceIndex = global.screen.get_active_workspace_index();
- let activeWorkspace;
-
- // Create and position workspace objects
- for (let w = 0; w < global.screen.n_workspaces; w++) {
- this._addWorkspaceActor(w);
- if (w == activeWorkspaceIndex) {
- activeWorkspace = this._workspaces[w];
- activeWorkspace.setSelected(true);
- }
- }
- activeWorkspace.actor.raise_top();
- this._positionWorkspaces();
-
- 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.
- this._overviewShowingId =
- Main.overview.connect('showing',
- Lang.bind(this, function() {
- this._onRestacked();
- for (let w = 0; w < this._workspaces.length; w++)
- this._workspaces[w].zoomToOverview();
- }));
-
- // Track changes to the number of workspaces
- this._nWorkspacesNotifyId =
- global.screen.connect('notify::n-workspaces',
- Lang.bind(this, this._workspacesChanged));
- this._switchWorkspaceNotifyId =
- global.window_manager.connect('switch-workspace',
- Lang.bind(this, this._activeWorkspaceChanged));
- this._restackedNotifyId =
- global.screen.connect('restacked',
- Lang.bind(this, this._onRestacked));
- },
-
- _lookupWorkspaceForMetaWindow: function (metaWindow) {
- for (let i = 0; i < this._workspaces.length; i++) {
- if (this._workspaces[i].containsMetaWindow(metaWindow))
- return this._workspaces[i];
- }
- return null;
- },
-
- _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;
- },
-
- setHighlightWindow: function (metaWindow) {
- // Looping over all workspaces is easier than keeping track of the last
- // highlighted window while trying to handle the window or workspace possibly
- // going away.
- for (let i = 0; i < this._workspaces.length; i++) {
- this._workspaces[i].setHighlightWindow(null);
- }
- if (metaWindow != null) {
- let workspace = this._lookupWorkspaceForMetaWindow(metaWindow);
- workspace.setHighlightWindow(metaWindow);
- }
- },
-
- _clearApplicationWindowSelection: function(reposition) {
- if (this._windowSelectionAppId == null)
- return;
- this._windowSelectionAppId = null;
-
- for (let i = 0; i < this._workspaces.length; i++) {
- this._workspaces[i].setLightboxMode(false);
- this._workspaces[i].setShowOnlyWindows(null, reposition);
- }
- },
-
- /**
- * setApplicationWindowSelection:
- * @appid: Application identifier string
- *
- * Enter a mode which shows only the windows owned by the
- * given application, and allow highlighting of a specific
- * window with setHighlightWindow().
- */
- setApplicationWindowSelection: function (appId) {
- if (appId == null) {
- this._clearApplicationWindowSelection(true);
- return;
- }
-
- if (appId == this._windowSelectionAppId)
- return;
-
- this._windowSelectionAppId = appId;
-
- let appSys = Shell.AppSystem.get_default();
-
- let showOnlyWindows = {};
- let app = appSys.get_app(appId);
- let windows = app.get_windows();
- for (let i = 0; i < windows.length; i++) {
- showOnlyWindows[windows[i]] = 1;
- }
-
- for (let i = 0; i < this._workspaces.length; i++) {
- this._workspaces[i].setLightboxMode(true);
- this._workspaces[i].setShowOnlyWindows(showOnlyWindows, true);
- }
- },
-
- /**
- * activateWindowFromOverview:
- * @metaWindow: A #MetaWindow
- * @time: Integer even timestamp
- *
- * This function exits the overview, switching to the given @metaWindow.
- * If an application filter is in effect, it will be cleared.
- */
- activateWindowFromOverview: function (metaWindow, time) {
- if (this._windowSelectionAppId != null) {
- this._clearApplicationWindowSelection(false);
- }
-
- Main.activateWindow(metaWindow, time);
- Main.overview.hide();
- },
-
- hide : function() {
- let activeWorkspaceIndex = global.screen.get_active_workspace_index();
- let activeWorkspace = this._workspaces[activeWorkspaceIndex];
-
- this._positionWorkspaces();
- activeWorkspace.actor.raise_top();
-
- for (let w = 0; w < this._workspaces.length; w++)
- this._workspaces[w].zoomFromOverview();
- },
-
- destroy : function() {
- for (let w = 0; w < this._workspaces.length; w++)
- this._workspaces[w].destroy();
- this._workspaces = [];
-
- this.actor.destroy();
- this.actor = null;
-
- Main.overview.disconnect(this._overviewShowingId);
- global.screen.disconnect(this._nWorkspacesNotifyId);
- global.window_manager.disconnect(this._switchWorkspaceNotifyId);
- global.screen.disconnect(this._restackedNotifyId);
- },
-
- getScale : function() {
- return this._workspaces[0].scale;
- },
-
- // Get the grid position of the active workspace.
- getActiveWorkspacePosition : function() {
- let activeWorkspaceIndex = global.screen.get_active_workspace_index();
- let activeWorkspace = this._workspaces[activeWorkspaceIndex];
-
- return [activeWorkspace.gridX, activeWorkspace.gridY];
- },
-
- // Assign grid positions to workspaces. We can't just do a simple
- // row-major or column-major numbering, because we don't want the
- // existing workspaces to get rearranged when we add a row or
- // column. So we alternate between adding to rows and adding to
- // columns. (So, eg, when going from a 2x2 grid of 4 workspaces to
- // a 3x2 grid of 5 workspaces, the 4 existing workspaces stay
- // where they are, and the 5th one is added to the end of the
- // first row.)
- //
- // FIXME: need to make the metacity internal layout agree with this!
- _positionWorkspaces : function() {
- let gridWidth = Math.ceil(Math.sqrt(this._workspaces.length));
- let gridHeight = Math.ceil(this._workspaces.length / gridWidth);
-
- let wsWidth = (this._width - (gridWidth - 1) * GRID_SPACING) / gridWidth;
- let wsHeight = (this._height - (gridHeight - 1) * GRID_SPACING) / gridHeight;
- let scale = wsWidth / global.screen_width;
-
- let span = 1, n = 0, row = 0, col = 0, horiz = true;
-
- for (let w = 0; w < this._workspaces.length; w++) {
- let workspace = this._workspaces[w];
-
- workspace.gridRow = row;
- workspace.gridCol = col;
-
- workspace.gridX = this._x + workspace.gridCol * (wsWidth + GRID_SPACING);
- workspace.gridY = this._y + workspace.gridRow * (wsHeight + GRID_SPACING);
- workspace.scale = scale;
-
- if (horiz) {
- col++;
- if (col == span) {
- row = 0;
- horiz = false;
- }
- } else {
- row++;
- if (row == span) {
- col = 0;
- horiz = true;
- span++;
- }
- }
- }
- },
-
- _workspacesChanged : function() {
- let oldNumWorkspaces = this._workspaces.length;
- let newNumWorkspaces = global.screen.n_workspaces;
-
- if (oldNumWorkspaces == newNumWorkspaces)
- return;
-
- let oldScale = this._workspaces[0].scale;
- let oldGridWidth = Math.ceil(Math.sqrt(oldNumWorkspaces));
- let oldGridHeight = Math.ceil(oldNumWorkspaces / oldGridWidth);
- let lostWorkspaces = [];
-
- // The old last workspace is no longer removable.
- this._workspaces[oldNumWorkspaces - 1].updateRemovable();
-
- if (newNumWorkspaces > oldNumWorkspaces) {
- // Create new workspace groups
- for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
- this._addWorkspaceActor(w);
- }
-
- } else {
- // Truncate the list of workspaces
- // FIXME: assumes that the workspaces are being removed from
- // the end of the list, not the start/middle
- lostWorkspaces = this._workspaces.splice(newNumWorkspaces);
- }
-
- // The new last workspace may be removable
- let newLastWorkspace = this._workspaces[this._workspaces.length - 1];
- newLastWorkspace.updateRemovable();
-
- // Figure out the new layout
- this._positionWorkspaces();
- let newScale = this._workspaces[0].scale;
- let newGridWidth = Math.ceil(Math.sqrt(newNumWorkspaces));
- let newGridHeight = Math.ceil(newNumWorkspaces / newGridWidth);
-
- if (newGridWidth != oldGridWidth || newGridHeight != oldGridHeight) {
- // We need to resize/move the existing workspaces/windows
- let existingWorkspaces = Math.min(oldNumWorkspaces, newNumWorkspaces);
- for (let w = 0; w < existingWorkspaces; w++)
- 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++)
- this._workspaces[w].slideIn(oldScale);
- } else {
- // Slide old workspaces out
- for (let w = 0; w < lostWorkspaces.length; w++) {
- let workspace = lostWorkspaces[w];
- workspace.slideOut(function () { workspace.destroy(); });
- }
-
- // 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) {
- this._workspaces[from].setSelected(false);
- this._workspaces[to].setSelected(true);
- },
-
- _addWorkspaceActor : function(workspaceNum) {
- let workspace = new Workspace(workspaceNum, this._actor);
- this._workspaces[workspaceNum] = workspace;
- this._actor.add_actor(workspace.actor);
- },
-
- _onRestacked: function() {
- let stack = global.get_windows();
- let stackIndices = {};
-
- for (let i = 0; i < stack.length; i++) {
- // Use the stable sequence for an integer to use as a hash key
- stackIndices[stack[i].get_meta_window().get_stable_sequence()] = i;
- }
-
- for (let i = 0; i < this._workspaces.length; i++)
- this._workspaces[i].syncStacking(stackIndices);
- },
-
- // Handles a drop onto the (+) button; assumes the new workspace
- // has already been added
- acceptNewWorkspaceDrop : function(source, dropActor, x, y, time) {
- return this._workspaces[this._workspaces.length - 1].acceptDrop(source, dropActor, x, y, time);
- }
-};
-
-// Create a SpecialPropertyModifier to let us move windows in a
-// straight line on the screen even though their containing workspace
-// is also moving.
-Tweener.registerSpecialPropertyModifier("workspace_relative", _workspaceRelativeModifier, _workspaceRelativeGet);
-
-function _workspaceRelativeModifier(workspace) {
- let [startX, startY] = Main.overview.getPosition();
- let overviewPosX, overviewPosY, overviewScale;
-
- 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() };
- } else {
- overviewPosX = { begin: startX, end: 0 };
- overviewPosY = { begin: startY, end: 0 };
- overviewScale = { begin: Main.overview.getScale(), end: 1 };
- }
-
- return [ { name: "x",
- parameters: { workspacePos: workspace.gridX,
- overviewPos: overviewPosX,
- overviewScale: overviewScale } },
- { name: "y",
- parameters: { workspacePos: workspace.gridY,
- overviewPos: overviewPosY,
- overviewScale: overviewScale } }
- ];
-}
-
-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;
-}
diff --git a/js/ui/workspacesView.js b/js/ui/workspacesView.js
new file mode 100644
index 0000000..d75e3e3
--- /dev/null
+++ b/js/ui/workspacesView.js
@@ -0,0 +1,956 @@
+/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
+
+const Big = imports.gi.Big;
+const Clutter = imports.gi.Clutter;
+const GdkPixbuf = imports.gi.GdkPixbuf;
+const Gdk = imports.gi.Gdk;
+const Gtk = imports.gi.Gtk;
+const Lang = imports.lang;
+const Mainloop = imports.mainloop;
+const Meta = imports.gi.Meta;
+const Pango = imports.gi.Pango;
+const Shell = imports.gi.Shell;
+const St = imports.gi.St;
+const Signals = imports.signals;
+
+const DND = imports.ui.dnd;
+const Lightbox = imports.ui.lightbox;
+const Main = imports.ui.main;
+const Overview = imports.ui.overview;
+const Panel = imports.ui.panel;
+const Tweener = imports.ui.tweener;
+const Workspace = imports.ui.workspace;
+
+const WORKSPACE_SWITCH_TIME = 0.25;
+// Note that mutter has a compile-time limit of 36
+const MAX_WORKSPACES = 16;
+
+const GRID_SPACING = 15;
+
+const WorkspacesViewType = {
+ SINGLE: 0,
+ MOSAIC: 1
+};
+
+function GenericWorkspacesView(width, height, x, y, animate) {
+ this._init(width, height, x, y, animate);
+}
+
+GenericWorkspacesView.prototype = {
+ _init: function(width, height, x, y, animate) {
+ this.actor = new St.Bin({ style_class: "workspaces" });
+ this._actor = new Clutter.Group();
+
+ this.actor.add_actor(this._actor);
+
+ this._width = width;
+ this._height = height;
+ this._x = x;
+ this._y = y;
+
+ this._windowSelectionAppId = null;
+
+ this._workspaces = [];
+
+ this._highlightWindow = null;
+
+ let activeWorkspaceIndex = global.screen.get_active_workspace_index();
+
+ // Create and position workspace objects
+ for (let w = 0; w < global.screen.n_workspaces; w++) {
+ this._addWorkspaceActor(w);
+ }
+ this._workspaces[activeWorkspaceIndex].actor.raise_top();
+ this._positionWorkspaces();
+
+ // 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.
+ this._overviewShowingId =
+ Main.overview.connect('showing',
+ Lang.bind(this, function() {
+ this._onRestacked();
+ for (let w = 0; w < this._workspaces.length; w++)
+ this._workspaces[w].zoomToOverview(animate);
+ }));
+
+ // Track changes to the number of workspaces
+ this._nWorkspacesNotifyId =
+ global.screen.connect('notify::n-workspaces',
+ Lang.bind(this, this._workspacesChanged));
+ this._switchWorkspaceNotifyId =
+ global.window_manager.connect('switch-workspace',
+ Lang.bind(this, this._activeWorkspaceChanged));
+ this._restackedNotifyId =
+ global.screen.connect('restacked',
+ Lang.bind(this, this._onRestacked));
+ },
+
+ _lookupWorkspaceForMetaWindow: function (metaWindow) {
+ for (let i = 0; i < this._workspaces.length; i++) {
+ if (this._workspaces[i].containsMetaWindow(metaWindow))
+ return this._workspaces[i];
+ }
+ return null;
+ },
+
+ _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;
+ },
+
+ setHighlightWindow: function (metaWindow) {
+ // Looping over all workspaces is easier than keeping track of the last
+ // highlighted window while trying to handle the window or workspace possibly
+ // going away.
+ for (let i = 0; i < this._workspaces.length; i++) {
+ this._workspaces[i].setHighlightWindow(null);
+ }
+ if (metaWindow != null) {
+ let workspace = this._lookupWorkspaceForMetaWindow(metaWindow);
+ workspace.setHighlightWindow(metaWindow);
+ }
+ },
+
+ _clearApplicationWindowSelection: function(reposition) {
+ if (this._windowSelectionAppId == null)
+ return;
+ this._windowSelectionAppId = null;
+
+ for (let i = 0; i < this._workspaces.length; i++) {
+ this._workspaces[i].setLightboxMode(false);
+ this._workspaces[i].setShowOnlyWindows(null, reposition);
+ }
+ },
+
+ /**
+ * setApplicationWindowSelection:
+ * @appid: Application identifier string
+ *
+ * Enter a mode which shows only the windows owned by the
+ * given application, and allow highlighting of a specific
+ * window with setHighlightWindow().
+ */
+ setApplicationWindowSelection: function (appId) {
+ if (appId == null) {
+ this._clearApplicationWindowSelection(true);
+ return;
+ }
+
+ if (appId == this._windowSelectionAppId)
+ return;
+
+ this._windowSelectionAppId = appId;
+
+ let appSys = Shell.AppSystem.get_default();
+
+ let showOnlyWindows = {};
+ let app = appSys.get_app(appId);
+ let windows = app.get_windows();
+ for (let i = 0; i < windows.length; i++) {
+ showOnlyWindows[windows[i]] = 1;
+ }
+
+ for (let i = 0; i < this._workspaces.length; i++) {
+ this._workspaces[i].setLightboxMode(true);
+ this._workspaces[i].setShowOnlyWindows(showOnlyWindows, true);
+ }
+ },
+
+ /**
+ * activateWindowFromOverview:
+ * @metaWindow: A #MetaWindow
+ * @time: Integer even timestamp
+ *
+ * This function exits the overview, switching to the given @metaWindow.
+ * If an application filter is in effect, it will be cleared.
+ */
+ activateWindowFromOverview: function (metaWindow, time) {
+ if (this._windowSelectionAppId != null) {
+ this._clearApplicationWindowSelection(false);
+ }
+
+ Main.activateWindow(metaWindow, time);
+ Main.overview.hide();
+ },
+
+ hide: function() {
+ let activeWorkspaceIndex = global.screen.get_active_workspace_index();
+ let activeWorkspace = this._workspaces[activeWorkspaceIndex];
+
+ this._positionWorkspaces();
+ activeWorkspace.actor.raise_top();
+
+ for (let w = 0; w < this._workspaces.length; w++)
+ this._workspaces[w].zoomFromOverview();
+ },
+
+ destroy: function() {
+ for (let w = 0; w < this._workspaces.length; w++)
+ this._workspaces[w].destroy();
+ this._workspaces = [];
+
+ this.actor.destroy();
+ this.actor = null;
+
+ Main.overview.disconnect(this._overviewShowingId);
+ global.screen.disconnect(this._nWorkspacesNotifyId);
+ global.window_manager.disconnect(this._switchWorkspaceNotifyId);
+ global.screen.disconnect(this._restackedNotifyId);
+ },
+
+ getScale: function() {
+ return this._workspaces[0].scale;
+ },
+
+ _onRestacked: function() {
+ let stack = global.get_windows();
+ let stackIndices = {};
+
+ for (let i = 0; i < stack.length; i++) {
+ // Use the stable sequence for an integer to use as a hash key
+ stackIndices[stack[i].get_meta_window().get_stable_sequence()] = i;
+ }
+
+ for (let i = 0; i < this._workspaces.length; i++)
+ this._workspaces[i].syncStacking(stackIndices);
+ },
+
+ // Handles a drop onto the (+) button; assumes the new workspace
+ // has already been added
+ acceptNewWorkspaceDrop: function(source, dropActor, x, y, time) {
+ return this._workspaces[this._workspaces.length - 1].acceptDrop(source, dropActor, x, y, time);
+ },
+
+ // Get the grid position of the active workspace.
+ getActiveWorkspacePosition: function() {
+ let activeWorkspaceIndex = global.screen.get_active_workspace_index();
+ let activeWorkspace = this._workspaces[activeWorkspaceIndex];
+
+ return [activeWorkspace.gridX, activeWorkspace.gridY];
+ },
+
+ createControllerBar: function() {
+ throw new Error("Not implemented");
+ },
+
+ _positionWorkspaces: function() {
+ throw new Error("Not implemented");
+ },
+
+ _workspacesChanged: function() {
+ throw new Error("Not implemented");
+ },
+
+ _activeWorkspaceChanged: function() {
+ throw new Error("Not implemented");
+ },
+
+ _addWorkspaceActor: function() {
+ throw new Error("Not implemented");
+ }
+}
+
+function MosaicView(width, height, x, y, animate) {
+ this._init(width, height, x, y, animate);
+}
+
+MosaicView.prototype = {
+ __proto__: GenericWorkspacesView.prototype,
+
+ _init: function(width, height, x, y, animate) {
+ GenericWorkspacesView.prototype._init.call(this, width, height, x, y, animate);
+
+ this._workspaces[global.screen.get_active_workspace_index()].setSelected(true);
+
+ this._removeButton = null;
+ this._addButton = null;
+ },
+
+ // Assign grid positions to workspaces. We can't just do a simple
+ // row-major or column-major numbering, because we don't want the
+ // existing workspaces to get rearranged when we add a row or
+ // column. So we alternate between adding to rows and adding to
+ // columns. (So, eg, when going from a 2x2 grid of 4 workspaces to
+ // a 3x2 grid of 5 workspaces, the 4 existing workspaces stay
+ // where they are, and the 5th one is added to the end of the
+ // first row.)
+ //
+ // FIXME: need to make the metacity internal layout agree with this!
+ _positionWorkspaces: function() {
+ let gridWidth = Math.ceil(Math.sqrt(this._workspaces.length));
+ let gridHeight = Math.ceil(this._workspaces.length / gridWidth);
+
+ let wsWidth = (this._width - (gridWidth - 1) * GRID_SPACING) / gridWidth;
+ let wsHeight = (this._height - (gridHeight - 1) * GRID_SPACING) / gridHeight;
+ let scale = wsWidth / global.screen_width;
+
+ let span = 1, n = 0, row = 0, col = 0, horiz = true;
+
+ for (let w = 0; w < this._workspaces.length; w++) {
+ let workspace = this._workspaces[w];
+
+ workspace.gridRow = row;
+ workspace.gridCol = col;
+
+ workspace.gridX = this._x + workspace.gridCol * (wsWidth + GRID_SPACING);
+ workspace.gridY = this._y + workspace.gridRow * (wsHeight + GRID_SPACING);
+ workspace.scale = scale;
+
+ if (horiz) {
+ col++;
+ if (col == span) {
+ row = 0;
+ horiz = false;
+ }
+ } else {
+ row++;
+ if (row == span) {
+ col = 0;
+ horiz = true;
+ span++;
+ }
+ }
+ }
+ },
+
+ _workspacesChanged: function() {
+ let oldNumWorkspaces = this._workspaces.length;
+ let newNumWorkspaces = global.screen.n_workspaces;
+
+ if (oldNumWorkspaces == newNumWorkspaces)
+ return;
+
+ let oldScale = this._workspaces[0].scale;
+ let oldGridWidth = Math.ceil(Math.sqrt(oldNumWorkspaces));
+ let oldGridHeight = Math.ceil(oldNumWorkspaces / oldGridWidth);
+ let lostWorkspaces = [];
+
+ // The old last workspace is no longer removable.
+
+ if (newNumWorkspaces > oldNumWorkspaces) {
+ // Create new workspace groups
+ for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
+ this._addWorkspaceActor(w);
+ }
+
+ } else {
+ // Truncate the list of workspaces
+ // FIXME: assumes that the workspaces are being removed from
+ // the end of the list, not the start/middle
+ lostWorkspaces = this._workspaces.splice(newNumWorkspaces);
+ }
+
+ // The new last workspace may be removable
+ let newLastWorkspace = this._workspaces[this._workspaces.length - 1];
+
+ // Figure out the new layout
+ this._positionWorkspaces();
+ let newScale = this._workspaces[0].scale;
+ let newGridWidth = Math.ceil(Math.sqrt(newNumWorkspaces));
+ let newGridHeight = Math.ceil(newNumWorkspaces / newGridWidth);
+
+ if (newGridWidth != oldGridWidth || newGridHeight != oldGridHeight) {
+ // We need to resize/move the existing workspaces/windows
+ let existingWorkspaces = Math.min(oldNumWorkspaces, newNumWorkspaces);
+ for (let w = 0; w < existingWorkspaces; w++)
+ 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(Workspace.WindowPositionFlags.ANIMATE);
+ }
+
+ if (newNumWorkspaces > oldNumWorkspaces) {
+ // Slide new workspaces in from offscreen
+ for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++)
+ this._workspaces[w].slideIn(oldScale);
+ } else {
+ // Slide old workspaces out
+ for (let w = 0; w < lostWorkspaces.length; w++) {
+ let workspace = lostWorkspaces[w];
+ workspace.slideOut(function () { workspace.destroy(); });
+ }
+
+ // 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);
+
+ this._updateButtonsVisibility();
+ },
+
+ _activeWorkspaceChanged: function(wm, from, to, direction) {
+ this._workspaces[from].setSelected(false);
+ this._workspaces[to].setSelected(true);
+ },
+
+ _addWorkspaceActor: function(workspaceNum) {
+ let workspace = new Workspace.Workspace(workspaceNum, this._actor);
+ this._workspaces[workspaceNum] = workspace;
+ this._actor.add_actor(workspace.actor);
+ },
+
+ createControllerBar: function() {
+ let actor = new St.BoxLayout({ 'pack-start': true });
+ let bin = new St.Bin();
+ let addButton = new St.Button({ style_class: "single-view-add" });
+ this._addButton = addButton;
+ addButton.connect('clicked', Lang.bind(this, this._addNewWorkspace));
+ addButton._delegate = addButton;
+ addButton._delegate.acceptDrop = Lang.bind(this, function(source, actor, x, y, time) {
+ return this._acceptNewWorkspaceDrop(source, actor, x, y, time);
+ });
+ actor.add(bin, { x_align: St.Align.END });
+ bin.set_child(addButton);
+ bin.set_alignment(St.Align.END, St.Align.START);
+
+ bin = new St.Bin();
+ let removeButton = new St.Button({ style_class: "single-view-remove" });
+ this._removeButton = removeButton;
+ removeButton.connect('clicked', Lang.bind(this, function() {
+ if (this._workspaces.length <= 1)
+ return;
+ global.screen.remove_workspace(this._workspaces[this._workspaces.length - 1]._metaWorkspace, global.get_current_time());
+ }));
+ actor.add(bin, { expand: true, x_fill: true, x_align: St.Align.END });
+ this._updateButtonsVisibility();
+ bin.set_child(removeButton);
+ bin.set_alignment(St.Align.END, St.Align.START);
+
+ return actor;
+ },
+
+ _updateButtonsVisibility: function() {
+ //_removeButton may yet not exist.
+ if (this._removeButton == null)
+ return;
+ if (global.screen.n_workspaces == 1)
+ this._removeButton.hide();
+ else
+ this._removeButton.show();
+ if (this._addButton == null)
+ return;
+ if (global.screen.n_workspaces >= MAX_WORKSPACES)
+ this._addButton.hide();
+ else
+ this._addButton.show();
+ },
+
+ _addNewWorkspace: function() {
+ global.screen.append_new_workspace(false, global.get_current_time());
+ },
+
+ _acceptNewWorkspaceDrop: function(source, dropActor, x, y, time) {
+ this._addNewWorkspace();
+ return this.acceptNewWorkspaceDrop(source, dropActor, x, y, time);
+ }
+};
+
+// Create a SpecialPropertyModifier to let us move windows in a
+// straight line on the screen even though their containing workspace
+// is also moving.
+Tweener.registerSpecialPropertyModifier("workspace_relative", _workspaceRelativeModifier, _workspaceRelativeGet);
+
+function SingleView(width, height, x, y, animate) {
+ this._init(width, height, x, y, animate);
+}
+
+SingleView.prototype = {
+ __proto__: GenericWorkspacesView.prototype,
+
+ _init: function(width, height, x, y, animate) {
+ this._scroll = null;
+ GenericWorkspacesView.prototype._init.call(this, width, height, x, y, animate);
+
+ this._actor.set_clip(x, y, width, height);
+ this._addButton = null;
+ this._removeButton = null;
+ this._indicatorsPanel = null;
+ this._indicatorsPanelWidth = null;
+
+ let activeWorkspaceIndex = global.screen.get_active_workspace_index();
+ for (let w = 0; w < this._workspaces.length; w++) {
+ if (w != activeWorkspaceIndex) {
+ this._workspaces[w].actor.hide();
+ continue;
+ }
+ this._workspaces[w].actor.show();
+ this._workspaces[w]._windowOverlaysGroup.show();
+ }
+ },
+
+ _positionWorkspaces: function() {
+ let position = global.screen.get_active_workspace_index();
+ let scale = this._width / global.screen_width;
+
+ if (this._scroll != null)
+ position = this._scroll.adjustment.value;
+ let isInt = (Math.round(position) === position);
+
+ for (let w = 0; w < this._workspaces.length; w++) {
+ let workspace = this._workspaces[w];
+
+ workspace.gridRow = 0;
+ workspace.gridCol = 0;
+
+ workspace.scale = scale;
+ workspace.actor.set_scale(scale, scale);
+ workspace.gridX = this._x + (w - position) * workspace.actor.width;
+ workspace.gridY = this._y;
+ workspace.actor.set_position(workspace.gridX, workspace.gridY);
+ if (isInt) {
+ if (this.actor.get_stage() != null)
+ workspace.positionWindows(0);
+ if (w == position) {
+ workspace._windowOverlaysGroup.show();
+ workspace.actor.show();
+ } else {
+ workspace._windowOverlaysGroup.hide();
+ workspace.actor.hide();
+ }
+ } else {
+ workspace._windowOverlaysGroup.hide();
+ if (Math.abs(w - position) <= 1)
+ workspace.actor.show();
+ else
+ workspace.actor.hide();
+ }
+ }
+ },
+
+ _workspacesChanged: function() {
+ let oldNumWorkspaces = this._workspaces.length;
+ let newNumWorkspaces = global.screen.n_workspaces;
+
+ if (oldNumWorkspaces == newNumWorkspaces)
+ return;
+
+ if (this._scroll != null) {
+ let adj = this._scroll.get_adjustment();
+ adj.upper = newNumWorkspaces;
+ this._scroll.adjustment = adj;
+ }
+ let lostWorkspaces = [];
+
+ if (newNumWorkspaces > oldNumWorkspaces) {
+ // Create new workspace groups
+ for (let w = oldNumWorkspaces; w < newNumWorkspaces; w++) {
+ this._addWorkspaceActor(w);
+ this._workspaces[w].actor.hide();
+ }
+
+ } else {
+ for (let i = 0; i < this._workspaces.length; i++)
+ this._workspaces[i].destroy();
+ this._actor.remove_all();
+
+ //Without this will be a lot of warnings
+ this._actor.hide();
+
+ this._workspaces = [];
+ let activeWorkspaceIndex = global.screen.get_active_workspace_index();
+ for (let w = 0; w < global.screen.n_workspaces; w++) {
+ this._addWorkspaceActor(w);
+ if (w == activeWorkspaceIndex) {
+ this._workspaces[w].actor.show();
+ } else {
+ this._workspaces[w].actor.hide();
+ }
+ }
+ this._actor.show();
+ }
+ this._positionWorkspaces();
+
+ // 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].actor.show();
+ this._workspaces[activeIndex]._windowOverlaysGroup.show();
+
+ this._updatePanelVisibility();
+ },
+
+ _activeWorkspaceChanged: function(wm, from, to, direction) {
+ this._updatePanelVisibility();
+ let showAnimation = true;
+
+ if (this._scroll != null) {
+ let adj = this._scroll.get_adjustment();
+ if (Math.round(adj.value - to) != adj.value - to)
+ showAnimation = false;
+ if (adj.value - to == 0)
+ showAnimation = false;
+ adj.value = to;
+ this._scroll.adjustment = adj;
+ }
+ if (showAnimation) {
+ let fx;
+ if (from > to) {
+ fx = this._workspaces[0].actor.width;
+ } else {
+ fx = -this._workspaces[0].actor.width;
+ }
+ this._workspaces[from]._windowOverlaysGroup.hide();
+ this._workspaces[to].actor.set_position(this._x - fx, this._workspaces[to].gridY);
+ this._workspaces[to].actor.show();
+ Tweener.addTween(this._workspaces[to].actor,
+ { x: this._x,
+ transition: 'easeOutQuad',
+ time: WORKSPACE_SWITCH_TIME
+ });
+
+ Tweener.addTween(this._workspaces[from].actor,
+ { x: this._x + fx,
+ transition: 'easeOutQuad',
+ time: WORKSPACE_SWITCH_TIME,
+ onComplete: this._positionWorkspaces,
+ onCompleteScope: this
+ });
+ } else
+ this._positionWorkspaces();
+ },
+
+ _addWorkspaceActor: function(workspaceNum) {
+ let workspace = new Workspace.Workspace(workspaceNum, this._actor);
+ this._actor.add_actor(workspace.actor);
+ workspace._windowOverlaysGroup.hide();
+
+ this._workspaces[workspaceNum] = workspace;
+ },
+
+ createControllerBar: function() {
+ let panel = new St.BoxLayout({ 'pack-start': true, vertical: true });
+
+ let actor = new St.BoxLayout({ 'pack-start': true });
+ let adj = new St.Adjustment({ value: global.screen.get_active_workspace_index(),
+ lower: 0,
+ 'page-increment': 1,
+ 'page-size': 1,
+ 'step-increment': 1,
+ upper: this._workspaces.length });
+ this._scroll = new St.ScrollBar({ adjustment: null, vertical: false, name: 'SwitchScroll' });
+
+ this._scroll.connect('notify::adjustment', Lang.bind(this, function() {
+ this._scroll.adjustment.connect('notify::value', Lang.bind(this, function () {
+ if (Math.abs(Math.round(this._scroll.adjustment.value) - this._scroll.adjustment.value) < 0.1) {
+ this._scroll.adjustment.set_value (Math.round(this._scroll.adjustment.value));
+ this._workspaces[Math.round(this._scroll.adjustment.value)]._metaWorkspace.activate(global.get_current_time());
+ } else
+ this._positionWorkspaces();
+ }));
+ }));
+ this._scroll.adjustment = adj;
+
+ let addButton = new St.Button({ style_class: "single-view-add" });
+ this._addButton = addButton;
+ addButton.connect('clicked', Lang.bind(this, this._addNewWorkspace));
+ addButton._delegate = addButton;
+ addButton._delegate.acceptDrop = Lang.bind(this, function(source, actor, x, y, time) {
+ return this._acceptNewWorkspaceDrop(source, actor, x, y, time);
+ });
+ actor.add(addButton, {x_align: St.Align.END, y_align: St.Align.START, 'y-fill': false});
+
+ let removeButton = new St.Button({ style_class: "single-view-remove" });
+ this._removeButton = removeButton;
+ removeButton.connect('clicked', Lang.bind(this, function() {
+ if (this._workspaces.length <= 1)
+ return;
+ let index = global.screen.get_active_workspace_index();
+ if (index == 0)
+ return;
+ global.screen.remove_workspace(this._workspaces[index]._metaWorkspace, global.get_current_time());
+ }));
+ actor.add(removeButton, { x_align: St.Align.END, y_align: St.Align.START, 'y-fill': false });
+ this._updatePanelVisibility();
+
+ panel.add(this._createPositionalIndicator(), {expand: true, 'x-fill': true, 'y-fill': true});
+ panel.add(this._scroll, { expand: true,
+ 'x-fill': true,
+ 'y-fill': false,
+ y_align: St.Align.START });
+ // backward-stepper/forward-stepper has const width (= height)
+ let separator = new St.Button({ style_class: 'scroll-separator' });
+ actor.add(separator, {});
+
+ actor.add(panel, {expand: true, 'x-fill': true, 'y-fill': true});
+
+ separator = new St.Button({ style_class: 'scroll-separator' });
+ actor.add(separator, {});
+
+ return actor;
+ },
+
+ _addIndicatorClone: function(i, active) {
+ let actor = new St.Button({ style_class: 'workspace-indicator' });
+ if (active) {
+ actor.style_class = 'workspace-indicator-active';
+ }
+ actor.connect('button-release-event', Lang.bind(this, function() {
+ if (this._workspaces[i] != undefined)
+ this._workspaces[i]._metaWorkspace.activate(global.get_current_time());
+ }));
+
+ this._indicatorsPanel.add_actor(actor);
+
+ let [a, spacing] = actor.get_theme_node().get_length('border-spacing', false);
+ if (this._indicatorsPanelWidth < spacing * (i + 1) + actor.width * (i + 1))
+ actor.hide();
+ actor.x = spacing * i + actor.width * i;
+ },
+
+ _fillPositionalIndicator: function() {
+ if (this._indicatorsPanel == null || this._indicatorsPanelWidth == null)
+ return;
+ let width = this._indicatorsPanelWidth;
+ this._indicatorsPanel.remove_all();
+
+ let activeWorkspaceIndex = global.screen.get_active_workspace_index();
+ for (let i = 0; i < this._workspaces.length; i++) {
+ this._addIndicatorClone(i, i == activeWorkspaceIndex);
+ }
+ this._indicatorsPanel.x = (this._indicatorsPanelWidth - this._indicatorsPanel.width) / 2;
+ },
+
+ _createPositionalIndicator: function() {
+ let actor = new St.Bin({ style_class: 'panel-button' });
+ let group = new Clutter.Group();
+
+ this._indicatorsPanel = new Shell.GenericContainer();
+ this._indicatorsPanel.connect('get-preferred-width', Lang.bind(this, function (actor, fh, alloc) {
+ let children = actor.get_children();
+ let width = 0;
+ for (let i = 0; i < children.length; i++) {
+ if (!children[i].visible)
+ continue;
+ if (children[i].x + children[i].width <= width)
+ continue;
+ width = children[i].x + children[i].width;
+ }
+ alloc.min_size = width;
+ alloc.nat_size = width;
+ }));
+ this._indicatorsPanel.connect('get-preferred-height', Lang.bind(this, function (actor, fw, alloc) {
+ let children = actor.get_children();
+ let height = 0;
+ if (children.length)
+ height = children[0].height;
+ alloc.min_size = height;
+ alloc.nat_size = height;
+ }));
+ this._indicatorsPanel.connect('allocate', Lang.bind(this, function (actor, box, flags) {
+ let children = actor.get_children();
+ for (let i = 0; i < children.length; i++) {
+ if (!children[i].visible)
+ continue;
+ let childBox = new Clutter.ActorBox();
+ childBox.x1 = children[i].x;
+ childBox.y1 = 0;
+ childBox.x2 = children[i].x + children[i].width;
+ childBox.y2 = children[i].height;
+ children[i].allocate(childBox, flags);
+ }
+ }));
+
+ group.add_actor(this._indicatorsPanel);
+ actor.set_child(group);
+ actor.set_alignment(St.Align.START, St.Align.START);
+ actor.set_fill(true, true);
+ this._indicatorsPanel.hide();
+ actor.connect('notify::width', Lang.bind(this, function(actor) {
+ this._indicatorsPanelWidth = actor.width;
+ this._updatePanelVisibility();
+ }));
+ actor.connect('destroy', Lang.bind(this, function() {
+ this._indicatorsPanel = null;
+ }));
+ return actor;
+ },
+
+ _updatePanelVisibility: function() {
+ let n = global.screen.n_workspaces;
+ if (this._removeButton != null) {
+ // set opacity here, because if hide it, _scroll will fill this space.
+ if (global.screen.get_active_workspace_index() == 0)
+ this._removeButton.set_opacity(0);
+ else
+ this._removeButton.set_opacity(255);
+ }
+ if (this._addButton != null) {
+ // same here
+ this._addButton.set_opacity((global.screen.n_workspaces < MAX_WORKSPACES) * 255);
+ }
+ if (this._scroll != null) {
+ if (n > 1)
+ this._scroll.show();
+ else
+ this._scroll.hide();
+ }
+ if (this._indicatorsPanel != null) {
+ if (n == 1) {
+ this._indicatorsPanel.hide();
+ } else {
+ this._indicatorsPanel.show();
+ }
+ }
+ this._fillPositionalIndicator();
+ },
+
+ _addNewWorkspace: function() {
+ // Button with opacity 0 is clickable.
+ if (global.screen.n_workspaces >= MAX_WORKSPACES)
+ return;
+ global.screen.append_new_workspace(false, global.get_current_time());
+ this._workspaces[this._workspaces.length - 1]._metaWorkspace.activate(Clutter.get_current_event_time());
+ },
+
+ _acceptNewWorkspaceDrop: function(source, dropActor, x, y, time) {
+ this._addNewWorkspace();
+ return this.acceptNewWorkspaceDrop(source, dropActor, x, y, time);
+ }
+};
+
+function _workspaceRelativeModifier(workspace) {
+ let [startX, startY] = Main.overview.getPosition();
+ let overviewPosX, overviewPosY, overviewScale;
+
+ 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() };
+ } else {
+ overviewPosX = { begin: startX, end: 0 };
+ overviewPosY = { begin: startY, end: 0 };
+ overviewScale = { begin: Main.overview.getScale(), end: 1 };
+ }
+
+ return [ { name: "x",
+ parameters: { workspacePos: workspace.gridX,
+ overviewPos: overviewPosX,
+ overviewScale: overviewScale } },
+ { name: "y",
+ parameters: { workspacePos: workspace.gridY,
+ overviewPos: overviewPosY,
+ overviewScale: overviewScale } }
+ ];
+}
+
+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;
+}
+
+function WorkspacesViewSwitch() {
+ this._init();
+}
+
+WorkspacesViewSwitch.prototype = {
+ VIEW_KEY: 'view',
+
+ _init: function() {
+ this._gconf = Shell.GConf.get_default();
+ this._mosaicViewButton = null;
+ this._singleViewButton = null;
+ this._currentViewType = this._gconf.get_int(this.VIEW_KEY);
+ this._controlsBar = null;
+ },
+
+ _setView: function(view) {
+ this._mosaicViewButton.set_checked(WorkspacesViewType.MOSAIC == view);
+ this._singleViewButton.set_checked(WorkspacesViewType.SINGLE == view);
+
+ if (this._currentViewType == view)
+ return;
+ this._currentViewType = view;
+ this._gconf.set_int(this.VIEW_KEY, view);
+ this.emit('view-changed');
+ },
+
+ createCurrentWorkspaceView: function(width, height, x, y, animate) {
+ switch (this._currentViewType) {
+ case WorkspacesViewType.SINGLE:
+ return new SingleView(width, height, x, y, animate);
+ case WorkspacesViewType.MOSAIC:
+ return new MosaicView(width, height, x, y, animate);
+ default:
+ return new MosaicView(width, height, x, y, animate);
+ }
+ },
+
+ createControlsBar: function() {
+ let actor = new St.BoxLayout();
+
+ this._mosaicViewButton = new St.Button({ style_class: "switch-view-mosaic" });
+ this._mosaicViewButton.set_toggle_mode(true);
+ this._mosaicViewButton.connect('clicked', Lang.bind(this, function() {
+ this._setView(WorkspacesViewType.MOSAIC);
+ }));
+ actor.add(this._mosaicViewButton, {'y-fill' : false, 'y-align' : St.Align.START});
+
+ this._singleViewButton = new St.Button({ style_class: "switch-view-single" });
+ this._singleViewButton.set_toggle_mode(true);
+ this._singleViewButton.connect('clicked', Lang.bind(this, function() {
+ this._setView(WorkspacesViewType.SINGLE);
+ }));
+ actor.add(this._singleViewButton, {'y-fill' : false, 'y-align' : St.Align.START});
+
+ if (this._currentViewType == WorkspacesViewType.MOSAIC)
+ this._mosaicViewButton.set_checked(true);
+ else
+ this._singleViewButton.set_checked(true);
+
+ this._nWorkspacesNotifyId =
+ global.screen.connect('notify::n-workspaces',
+ Lang.bind(this, this._workspacesChanged));
+
+ actor.connect('destroy', Lang.bind(this, function() {
+ this._controlsBar = null;
+ global.screen.disconnect(this._nWorkspacesNotifyId);
+ }));
+
+ this._controlsBar = actor;
+ this._workspacesChanged();
+ return actor;
+ },
+
+ _workspacesChanged: function() {
+ if (this._controlsBar == null)
+ return;
+ if (global.screen.n_workspaces == 1)
+ this._controlsBar.set_opacity(0);
+ else
+ this._controlsBar.set_opacity(255);
+ }
+};
+
+Signals.addSignalMethods(WorkspacesViewSwitch.prototype);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]