Compare commits
48 Commits
citadel
...
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 |
74
data/close.svg
Normal file
74
data/close.svg
Normal file
@ -0,0 +1,74 @@
|
||||
<?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: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"
|
||||
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"
|
||||
sodipodi:docname="x_circle_16.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" /></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" /><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3173"
|
||||
id="linearGradient3179"
|
||||
x1="7.844358"
|
||||
y1="16"
|
||||
x2="7.7198443"
|
||||
y2="-0.062256809"
|
||||
gradientUnits="userSpaceOnUse" /></defs><sodipodi:namedview
|
||||
inkscape:window-height="713"
|
||||
inkscape:window-width="1197"
|
||||
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="8"
|
||||
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:url(#linearGradient3179)" />
|
||||
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
@ -15,6 +15,21 @@
|
||||
</locale>
|
||||
</schema>
|
||||
|
||||
<schema>
|
||||
<key>/schemas/desktop/gnome/shell/favorite_apps</key>
|
||||
<applyto>/desktop/gnome/shell/favorite_apps</applyto>
|
||||
<owner>gnome-shell</owner>
|
||||
<type>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>
|
||||
<long>
|
||||
The applications corresponding to these identifiers will be displayed in the favorites area.
|
||||
</long>
|
||||
</locale>
|
||||
</schema>
|
||||
|
||||
</schemalist>
|
||||
|
||||
</gconfschemafile>
|
74
data/info.svg
Normal file
74
data/info.svg
Normal file
@ -0,0 +1,74 @@
|
||||
<?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: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"
|
||||
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"
|
||||
sodipodi:docname="info_16.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata
|
||||
id="metadata2389"><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="defs2387"><linearGradient
|
||||
id="linearGradient3710"><stop
|
||||
style="stop-color:#c4c4c4;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3712" /><stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3714" /></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="perspective2391" /><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3710"
|
||||
id="linearGradient3716"
|
||||
x1="7.9066148"
|
||||
y1="15.937743"
|
||||
x2="7.9377432"
|
||||
y2="0.031128405"
|
||||
gradientUnits="userSpaceOnUse" /></defs><sodipodi:namedview
|
||||
inkscape:window-height="713"
|
||||
inkscape:window-width="722"
|
||||
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="8.154146"
|
||||
inkscape:window-x="20"
|
||||
inkscape:window-y="20"
|
||||
inkscape:current-layer="Foreground" />
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M7,3h2v2H7V3z M5.5,12H7V8H5.5V7H9v5h1.5v1h-5V12z M0,8c0-4.418,3.582-8,8-8 s8,3.582,8,8s-3.582,8-8,8S0,12.418,0,8z"
|
||||
id="path2384"
|
||||
style="fill-opacity:1;fill:url(#linearGradient3716)" />
|
||||
</svg>
|
After Width: | Height: | Size: 2.5 KiB |
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 |
79
data/view-more.svg
Normal file
79
data/view-more.svg
Normal file
@ -0,0 +1,79 @@
|
||||
<?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_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" /></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
|
||||
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:#4669a9;fill-opacity:1">
|
||||
<path
|
||||
fill="#FFFFFF"
|
||||
d="M6.246,13.98c-0.319-0.319-0.319-0.837,0-1.157l3.717-3.717c0.319-0.319,0.837-0.319,1.157,0l0.786,0.787 c0.32,0.319,0.32,0.837,0,1.157l-3.717,3.717c-0.32,0.319-0.838,0.319-1.157,0L6.246,13.98L6.246,13.98z"
|
||||
id="path7"
|
||||
style="fill:#4669a9;fill-opacity:1" />
|
||||
<path
|
||||
fill="#FFFFFF"
|
||||
d="M9.076,11.937"
|
||||
id="path9"
|
||||
style="fill:#4669a9;fill-opacity:1" />
|
||||
</g>
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
fill="#FFFFFF"
|
||||
d="M11.25,7.5c0-1.243,1.007-2.25,2.25-2.25s2.25,1.007,2.25,2.25 s-1.007,2.25-2.25,2.25S11.25,8.743,11.25,7.5z M9,7.5C9,5.015,11.015,3,13.5,3S18,5.015,18,7.5S15.985,12,13.5,12S9,9.985,9,7.5z"
|
||||
id="path11"
|
||||
style="fill:#4669a9;fill-opacity:1" />
|
||||
</svg>
|
After Width: | Height: | Size: 2.8 KiB |
@ -7,32 +7,6 @@ const Shell = imports.gi.Shell;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
|
||||
// TODO - move this into GConf once we're not a plugin anymore
|
||||
// but have taken over metacity
|
||||
// This list is taken from GNOME Online popular applications
|
||||
// http://online.gnome.org/applications
|
||||
// but with nautilus removed (since it should already be running)
|
||||
// and evince, totem, and gnome-file-roller removed (since they're
|
||||
// usually started by opening documents, not by opening the app
|
||||
// directly)
|
||||
const DEFAULT_APPLICATIONS = [
|
||||
'mozilla-firefox.desktop',
|
||||
'gnome-terminal.desktop',
|
||||
'evolution.desktop',
|
||||
'gedit.desktop',
|
||||
'mozilla-thunderbird.desktop',
|
||||
'rhythmbox.desktop',
|
||||
'epiphany.desktop',
|
||||
'xchat.desktop',
|
||||
'openoffice.org-1.9-writer.desktop',
|
||||
'emacs.desktop',
|
||||
'gnome-system-monitor.desktop',
|
||||
'openoffice.org-1.9-calc.desktop',
|
||||
'eclipse.desktop',
|
||||
'openoffice.org-1.9-impress.desktop',
|
||||
'vncviewer.desktop'
|
||||
];
|
||||
|
||||
function AppInfo(appId) {
|
||||
this._init(appId);
|
||||
}
|
||||
@ -41,8 +15,9 @@ AppInfo.prototype = {
|
||||
_init : function(appId) {
|
||||
this.appId = appId;
|
||||
this._gAppInfo = Gio.DesktopAppInfo.new(appId);
|
||||
if (!this._gAppInfo)
|
||||
if (!this._gAppInfo) {
|
||||
throw new Error('Unknown appId ' + appId);
|
||||
}
|
||||
|
||||
this.id = this._gAppInfo.get_id();
|
||||
this.name = this._gAppInfo.get_name();
|
||||
@ -52,7 +27,7 @@ AppInfo.prototype = {
|
||||
this._gicon = this._gAppInfo.get_icon();
|
||||
},
|
||||
|
||||
getIcon : function(size) {
|
||||
createIcon : function(size) {
|
||||
if (this._gicon)
|
||||
return Shell.TextureCache.get_default().load_gicon(this._gicon, size);
|
||||
else
|
||||
@ -96,40 +71,64 @@ function getAppInfo(appId) {
|
||||
return info;
|
||||
}
|
||||
|
||||
// getMostUsedApps:
|
||||
// getTopApps:
|
||||
// @count: maximum number of apps to retrieve
|
||||
//
|
||||
// Gets a list of #AppInfos for the @count most-frequently-used
|
||||
// applications
|
||||
// applications, with explicitly-chosen favorites first.
|
||||
//
|
||||
// Return value: the list of #AppInfo
|
||||
function getMostUsedApps(count) {
|
||||
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));
|
||||
let matches = [], alreadyAdded = {};
|
||||
|
||||
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);
|
||||
alreadyAdded[appId] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Fill the list with default applications it's not full yet
|
||||
for (let i = 0; i < DEFAULT_APPLICATIONS.length && matches.length <= count; i++) {
|
||||
let appId = DEFAULT_APPLICATIONS[i];
|
||||
if (alreadyAdded[appId])
|
||||
continue;
|
||||
|
||||
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());
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ DocInfo.prototype = {
|
||||
this.mimeType = recentInfo.get_mime_type();
|
||||
},
|
||||
|
||||
getIcon : function(size) {
|
||||
createIcon : function(size) {
|
||||
let icon = new Clutter.Texture();
|
||||
let iconPixbuf;
|
||||
|
||||
|
@ -5,16 +5,21 @@ const Clutter = imports.gi.Clutter;
|
||||
const Pango = imports.gi.Pango;
|
||||
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 AppInfo = imports.misc.appInfo;
|
||||
const DND = imports.ui.dnd;
|
||||
const GenericDisplay = imports.ui.genericDisplay;
|
||||
|
||||
const ENTERED_MENU_COLOR = new Clutter.Color();
|
||||
ENTERED_MENU_COLOR.from_pixel(0x00ff0022);
|
||||
|
||||
const APP_ICON_SIZE = 48;
|
||||
|
||||
const MENU_ICON_SIZE = 24;
|
||||
const MENU_SPACING = 15;
|
||||
|
||||
@ -36,8 +41,7 @@ AppDisplayItem.prototype = {
|
||||
GenericDisplay.GenericDisplayItem.prototype._init.call(this, availableWidth);
|
||||
this._appInfo = appInfo;
|
||||
|
||||
this._setItemInfo(appInfo.name, appInfo.description,
|
||||
appInfo.getIcon(GenericDisplay.ITEM_DISPLAY_ICON_SIZE));
|
||||
this._setItemInfo(appInfo.name, appInfo.description);
|
||||
},
|
||||
|
||||
//// Public method overrides ////
|
||||
@ -49,6 +53,11 @@ AppDisplayItem.prototype = {
|
||||
|
||||
//// Protected method overrides ////
|
||||
|
||||
// Returns an icon for the item.
|
||||
_createIcon : function() {
|
||||
return this._appInfo.createIcon(GenericDisplay.ITEM_DISPLAY_ICON_SIZE);
|
||||
},
|
||||
|
||||
// Ensures the preview icon is created.
|
||||
_ensurePreviewIconCreated : function() {
|
||||
if (!this._showPreview || this._previewIcon)
|
||||
@ -147,6 +156,7 @@ MenuItem.prototype = {
|
||||
}
|
||||
Signals.addSignalMethods(MenuItem.prototype);
|
||||
|
||||
|
||||
/* This class represents a display containing a collection of application items.
|
||||
* The applications are sorted based on their popularity by default, and based on
|
||||
* their name if some search filter is applied.
|
||||
@ -173,16 +183,15 @@ AppDisplay.prototype = {
|
||||
this._appMonitor = Shell.AppMonitor.get_default();
|
||||
this._appSystem = Shell.AppSystem.get_default();
|
||||
this._appsStale = true;
|
||||
this._appSystem.connect('changed', Lang.bind(this, function(appSys) {
|
||||
this._appSystem.connect('installed-changed', Lang.bind(this, function(appSys) {
|
||||
this._appsStale = true;
|
||||
// We still need to determine what events other than search can trigger
|
||||
// a change in the set of applications that are being shown while the
|
||||
// user in in the overlay mode, however let's redisplay just in case.
|
||||
this._redisplay(false);
|
||||
this._redisplayMenus();
|
||||
}));
|
||||
this._appSystem.connect('favorites-changed', Lang.bind(this, function(appSys) {
|
||||
this._redisplay(false);
|
||||
}));
|
||||
this._appMonitor.connect('changed', Lang.bind(this, function(monitor) {
|
||||
this._appsStale = true;
|
||||
this._redisplay(false);
|
||||
}));
|
||||
|
||||
@ -308,8 +317,6 @@ AppDisplay.prototype = {
|
||||
this._appCategories[appId] = categories;
|
||||
},
|
||||
|
||||
//// Protected method overrides ////
|
||||
|
||||
// Gets information about all applications by calling Gio.app_info_get_all().
|
||||
_refreshCache : function() {
|
||||
let me = this;
|
||||
@ -339,21 +346,12 @@ AppDisplay.prototype = {
|
||||
this._addAppForId(appId);
|
||||
}
|
||||
|
||||
// Some applications, such as Evince, might not be in the menus,
|
||||
// but might be returned by the applications monitor as most used
|
||||
// applications, in which case we include them.
|
||||
let mostUsedAppInfos = AppInfo.getMostUsedApps(MAX_ITEMS);
|
||||
for (let i = 0; i < mostUsedAppInfos.length; i++) {
|
||||
let appInfo = mostUsedAppInfos[i];
|
||||
this._addApp(appInfo);
|
||||
}
|
||||
|
||||
this._appsStale = false;
|
||||
},
|
||||
|
||||
// Sets the list of the displayed items based on the most used apps.
|
||||
_setDefaultList : function() {
|
||||
let matchedInfos = AppInfo.getMostUsedApps(MAX_ITEMS);
|
||||
let matchedInfos = AppInfo.getTopApps(MAX_ITEMS);
|
||||
this._matchedItems = matchedInfos.map(function(info) { return info.appId; });
|
||||
},
|
||||
|
||||
@ -430,3 +428,197 @@ AppDisplay.prototype = {
|
||||
};
|
||||
|
||||
Signals.addSignalMethods(AppDisplay.prototype);
|
||||
|
||||
function WellDisplayItem(appInfo, isFavorite) {
|
||||
this._init(appInfo, isFavorite);
|
||||
}
|
||||
|
||||
WellDisplayItem.prototype = {
|
||||
_init : function(appInfo, isFavorite) {
|
||||
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.launch();
|
||||
this.emit('activated');
|
||||
}));
|
||||
|
||||
let draggable = DND.makeDraggable(this.actor);
|
||||
|
||||
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 {
|
||||
this.actor.append(this._name, Big.BoxPackFlags.NONE);
|
||||
}
|
||||
},
|
||||
|
||||
// Opens an application represented by this display item.
|
||||
launch : function() {
|
||||
this.appInfo.launch();
|
||||
},
|
||||
|
||||
// Draggable interface - FIXME deduplicate with GenericDisplay
|
||||
getDragActor: function(stageX, stageY) {
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
Signals.addSignalMethods(WellDisplayItem.prototype);
|
||||
|
||||
function WellArea(width, isFavorite) {
|
||||
this._init(width, isFavorite);
|
||||
}
|
||||
|
||||
WellArea.prototype = {
|
||||
_init : function(width, isFavorite) {
|
||||
this.isFavorite = isFavorite;
|
||||
|
||||
this.actor = new Tidy.Grid({ width: width });
|
||||
this.actor._delegate = this;
|
||||
},
|
||||
|
||||
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);
|
||||
};
|
||||
},
|
||||
|
||||
// Draggable target interface
|
||||
acceptDrop : function(source, actor, x, y, time) {
|
||||
let global = Shell.Global.get();
|
||||
|
||||
if (!(source instanceof WellDisplayItem)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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 {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Signals.addSignalMethods(WellArea.prototype);
|
||||
|
||||
function AppWell(width) {
|
||||
this._init(width);
|
||||
}
|
||||
|
||||
AppWell.prototype = {
|
||||
_init : function(width) {
|
||||
this._menus = [];
|
||||
this._menuDisplays = [];
|
||||
|
||||
this.actor = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
width: width });
|
||||
|
||||
this._appSystem = Shell.AppSystem.get_default();
|
||||
this._appMonitor = Shell.AppMonitor.get_default();
|
||||
|
||||
this._appSystem.connect('installed-changed', Lang.bind(this, function(appSys) {
|
||||
this._redisplay();
|
||||
}));
|
||||
this._appSystem.connect('favorites-changed', Lang.bind(this, function(appSys) {
|
||||
this._redisplay();
|
||||
}));
|
||||
this._appMonitor.connect('changed', 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();
|
||||
},
|
||||
|
||||
_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);
|
||||
});
|
||||
this._favoritesArea.redisplay(favorites);
|
||||
this._runningArea.redisplay(running);
|
||||
}
|
||||
};
|
||||
|
||||
Signals.addSignalMethods(AppWell.prototype);
|
||||
|
@ -27,8 +27,7 @@ DocDisplayItem.prototype = {
|
||||
GenericDisplay.GenericDisplayItem.prototype._init.call(this, availableWidth);
|
||||
this._docInfo = docInfo;
|
||||
|
||||
this._setItemInfo(docInfo.name, "",
|
||||
docInfo.getIcon(GenericDisplay.ITEM_DISPLAY_ICON_SIZE));
|
||||
this._setItemInfo(docInfo.name, "");
|
||||
},
|
||||
|
||||
//// Public methods ////
|
||||
@ -42,10 +41,15 @@ DocDisplayItem.prototype = {
|
||||
|
||||
//// Protected method overrides ////
|
||||
|
||||
// Returns an icon for the item.
|
||||
_createIcon : function() {
|
||||
return this._docInfo.createIcon(GenericDisplay.ITEM_DISPLAY_ICON_SIZE);
|
||||
},
|
||||
|
||||
// Ensures the preview icon is created.
|
||||
_ensurePreviewIconCreated : function() {
|
||||
if (!this._previewIcon)
|
||||
this._previewIcon = this._docInfo.getIcon(GenericDisplay.PREVIEW_ICON_SIZE);
|
||||
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
|
||||
|
@ -22,7 +22,7 @@ ITEM_DISPLAY_DESCRIPTION_COLOR.from_pixel(0xffffffbb);
|
||||
const ITEM_DISPLAY_BACKGROUND_COLOR = new Clutter.Color();
|
||||
ITEM_DISPLAY_BACKGROUND_COLOR.from_pixel(0x00000000);
|
||||
const ITEM_DISPLAY_SELECTED_BACKGROUND_COLOR = new Clutter.Color();
|
||||
ITEM_DISPLAY_SELECTED_BACKGROUND_COLOR.from_pixel(0x00ff0055);
|
||||
ITEM_DISPLAY_SELECTED_BACKGROUND_COLOR.from_pixel(0x4f6fadaa);
|
||||
const DISPLAY_CONTROL_SELECTED_COLOR = new Clutter.Color();
|
||||
DISPLAY_CONTROL_SELECTED_COLOR.from_pixel(0x112288ff);
|
||||
const PREVIEW_BOX_BACKGROUND_COLOR = new Clutter.Color();
|
||||
@ -30,7 +30,8 @@ PREVIEW_BOX_BACKGROUND_COLOR.from_pixel(0xADADADf0);
|
||||
|
||||
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;
|
||||
|
||||
@ -42,6 +43,8 @@ const PREVIEW_BOX_CORNER_RADIUS = 10;
|
||||
const PREVIEW_PLACING = 3/4;
|
||||
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
|
||||
* it by highlighting it with a different background color than the default.
|
||||
@ -55,22 +58,17 @@ function GenericDisplayItem(availableWidth) {
|
||||
GenericDisplayItem.prototype = {
|
||||
_init: function(availableWidth) {
|
||||
this._availableWidth = availableWidth;
|
||||
this._showPreview = false;
|
||||
this._havePointer = false;
|
||||
this._previewEventSourceId = null;
|
||||
|
||||
this.actor = new Clutter.Group({ reactive: true,
|
||||
width: availableWidth,
|
||||
height: ITEM_DISPLAY_HEIGHT });
|
||||
this.actor._delegate = this;
|
||||
this.actor.connect('button-press-event',
|
||||
this.actor.connect('button-release-event',
|
||||
Lang.bind(this,
|
||||
function(actor, e) {
|
||||
let clickCount = Shell.get_button_event_click_count(e);
|
||||
if (clickCount == 1)
|
||||
this.select();
|
||||
else if (clickCount == 2)
|
||||
this.activate();
|
||||
function() {
|
||||
// Activates the item by launching it
|
||||
this.emit('activate');
|
||||
return true;
|
||||
}));
|
||||
|
||||
let draggable = DND.makeDraggable(this.actor);
|
||||
@ -82,10 +80,39 @@ GenericDisplayItem.prototype = {
|
||||
width: availableWidth, height: ITEM_DISPLAY_HEIGHT });
|
||||
this.actor.add_actor(this._bg);
|
||||
|
||||
let global = Shell.Global.get();
|
||||
let infoIconUri = "file://" + global.imagedir + "info.svg";
|
||||
|
||||
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.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._preview = null;
|
||||
this._previewIcon = null;
|
||||
|
||||
this.dragActor = null;
|
||||
@ -99,8 +126,7 @@ GenericDisplayItem.prototype = {
|
||||
// Returns a cloned texture of the item's icon to represent the item as it
|
||||
// is being dragged.
|
||||
getDragActor: function(stageX, stageY) {
|
||||
this.dragActor = new Clutter.Clone({ source: this._icon });
|
||||
[this.dragActor.width, this.dragActor.height] = this._icon.get_transformed_size();
|
||||
this.dragActor = this._createIcon();
|
||||
|
||||
// If the user dragged from the icon itself, then position
|
||||
// the dragActor over the original icon. Otherwise center it
|
||||
@ -115,58 +141,19 @@ GenericDisplayItem.prototype = {
|
||||
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.
|
||||
// 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
|
||||
// not get accepted by any drop target.
|
||||
getDragActorSource: function() {
|
||||
return this._icon;
|
||||
},
|
||||
|
||||
//// Public methods ////
|
||||
|
||||
// Sets a boolean value that indicates whether the item should display a pop-up preview on mouse over.
|
||||
setShowPreview: function(showPreview) {
|
||||
this._showPreview = showPreview;
|
||||
},
|
||||
|
||||
// Returns a boolean value that indicates whether the item displays a pop-up preview on mouse over.
|
||||
getShowPreview: function() {
|
||||
return this._showPreview;
|
||||
},
|
||||
|
||||
// Displays the preview for the item.
|
||||
showPreview: function() {
|
||||
if(!this._showPreview)
|
||||
return;
|
||||
|
||||
this._ensurePreviewCreated();
|
||||
|
||||
let [x, y] = this.actor.get_transformed_position();
|
||||
let global = Shell.Global.get();
|
||||
let previewX = Math.min(x + this._availableWidth * PREVIEW_PLACING, global.screen_width - this._preview.width);
|
||||
let previewY = Math.min(y, global.screen_height - this._preview.height);
|
||||
this._preview.set_position(previewX, previewY);
|
||||
|
||||
this._preview.show();
|
||||
},
|
||||
|
||||
// Hides the preview for the item and removes the preview event source so that
|
||||
// there is no preview scheduled to show up.
|
||||
hidePreview: function() {
|
||||
if (this._previewEventSourceId) {
|
||||
Mainloop.source_remove(this._previewEventSourceId);
|
||||
this._previewEventSourceId = null;
|
||||
}
|
||||
|
||||
if (this._preview)
|
||||
this._preview.hide();
|
||||
},
|
||||
|
||||
// Shows a preview when the item was drawn under the mouse pointer.
|
||||
// Shows the information button when the item was drawn under the mouse pointer.
|
||||
onDrawnUnderPointer: function() {
|
||||
this._havePointer = true;
|
||||
// This code is usually triggered when we just had a different preview showing on the same spot
|
||||
// and having a delay before showing a new preview looks bad. So we just show it right away.
|
||||
this.showPreview();
|
||||
this._informationButton.show();
|
||||
},
|
||||
|
||||
// Highlights the item by setting a different background color than the default
|
||||
@ -180,17 +167,6 @@ GenericDisplayItem.prototype = {
|
||||
this._bg.background_color = color;
|
||||
},
|
||||
|
||||
// Activates the item, as though it was launched
|
||||
activate: function() {
|
||||
this.hidePreview();
|
||||
this.emit('activate');
|
||||
},
|
||||
|
||||
// Selects the item, as though it was clicked
|
||||
select: function() {
|
||||
this.emit('select');
|
||||
},
|
||||
|
||||
/*
|
||||
* 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.
|
||||
@ -241,28 +217,12 @@ GenericDisplayItem.prototype = {
|
||||
details.append(largePreview, Big.BoxPackFlags.NONE);
|
||||
}
|
||||
|
||||
// We hide the preview pop-up if the details are shown elsewhere.
|
||||
details.connect("show",
|
||||
Lang.bind(this,
|
||||
function() {
|
||||
// Right now "show" signal is emitted when an actor is added to a parent that
|
||||
// has not been added to anything and "visible" property is also set to true
|
||||
// at this point, so checking if the parent that the actor has been added to
|
||||
// has a parent of its own is a temporary workaround. That other actor is
|
||||
// presumed to be displayed, which is a limitation of this workaround, but is
|
||||
// the case with our usage of the details actor now.
|
||||
// http://bugzilla.openedhand.com/show_bug.cgi?id=1138
|
||||
if (details.get_parent() != null && details.get_parent().get_parent() != null)
|
||||
this.hidePreview();
|
||||
}));
|
||||
return details;
|
||||
},
|
||||
|
||||
// Destoys the item, as well as a preview for the item if it exists.
|
||||
// Destoys the item.
|
||||
destroy: function() {
|
||||
this.actor.destroy();
|
||||
if (this._preview != null)
|
||||
this._preview.destroy();
|
||||
},
|
||||
|
||||
//// Pure virtual public methods ////
|
||||
@ -279,9 +239,8 @@ GenericDisplayItem.prototype = {
|
||||
*
|
||||
* nameText - name of the item
|
||||
* descriptionText - short description of the item
|
||||
* iconActor - ClutterTexture containing the icon image which should be ITEM_DISPLAY_ICON_SIZE size
|
||||
*/
|
||||
_setItemInfo: function(nameText, descriptionText, iconActor) {
|
||||
_setItemInfo: function(nameText, descriptionText) {
|
||||
if (this._name != null) {
|
||||
// this also removes this._name from the parent container,
|
||||
// so we don't need to call this.actor.remove_actor(this._name) directly
|
||||
@ -298,27 +257,23 @@ GenericDisplayItem.prototype = {
|
||||
this._icon.destroy();
|
||||
this._icon = null;
|
||||
}
|
||||
// This ensures we'll create a new preview and previewIcon next time we need a preview
|
||||
if (this._preview != null) {
|
||||
this._preview.destroy();
|
||||
this._preview = 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 = iconActor;
|
||||
this._icon = this._createIcon();
|
||||
this.actor.add_actor(this._icon);
|
||||
|
||||
let textWidth = this._availableWidth - (ITEM_DISPLAY_ICON_SIZE + 4);
|
||||
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,
|
||||
x: ITEM_DISPLAY_ICON_SIZE + 4,
|
||||
y: ITEM_DISPLAY_PADDING });
|
||||
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",
|
||||
@ -339,6 +294,11 @@ GenericDisplayItem.prototype = {
|
||||
|
||||
//// Pure virtual protected methods ////
|
||||
|
||||
// Returns an icon for the item.
|
||||
_createIcon: function() {
|
||||
throw new Error("Not implemented");
|
||||
},
|
||||
|
||||
// Ensures the preview icon is created.
|
||||
_ensurePreviewIconCreated: function() {
|
||||
throw new Error("Not implemented");
|
||||
@ -346,79 +306,21 @@ GenericDisplayItem.prototype = {
|
||||
|
||||
//// Private methods ////
|
||||
|
||||
// Ensures the preview actor is created.
|
||||
_ensurePreviewCreated: function() {
|
||||
if (!this._showPreview || this._preview)
|
||||
return;
|
||||
|
||||
this._preview = new Big.Box({ background_color: PREVIEW_BOX_BACKGROUND_COLOR,
|
||||
orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
corner_radius: PREVIEW_BOX_CORNER_RADIUS,
|
||||
padding: PREVIEW_BOX_PADDING,
|
||||
spacing: PREVIEW_BOX_SPACING });
|
||||
|
||||
let textDetailsWidth = this._availableWidth - PREVIEW_BOX_PADDING * 2;
|
||||
|
||||
this._ensurePreviewIconCreated();
|
||||
|
||||
if (this._previewIcon != null) {
|
||||
this._preview.append(this._previewIcon, Big.BoxPackFlags.EXPAND);
|
||||
textDetailsWidth = this._availableWidth - this._previewIcon.width - PREVIEW_BOX_PADDING * 2 - PREVIEW_BOX_SPACING;
|
||||
}
|
||||
|
||||
// Inner box with name and description
|
||||
let textDetails = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
spacing: PREVIEW_BOX_SPACING });
|
||||
let detailsName = new Clutter.Text({ color: ITEM_DISPLAY_NAME_COLOR,
|
||||
font_name: "Sans bold 14px",
|
||||
text: this._name.text});
|
||||
|
||||
textDetails.width = Math.max(PREVIEW_DETAILS_MIN_WIDTH, textDetailsWidth, detailsName.width);
|
||||
|
||||
textDetails.append(detailsName, Big.BoxPackFlags.NONE);
|
||||
|
||||
let detailsDescription = new Clutter.Text({ color: ITEM_DISPLAY_NAME_COLOR,
|
||||
font_name: "Sans 14px",
|
||||
line_wrap: true,
|
||||
text: this._description.text });
|
||||
textDetails.append(detailsDescription, Big.BoxPackFlags.NONE);
|
||||
|
||||
this._preview.append(textDetails, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
// Add the preview to global stage to allow for top-level layering
|
||||
let global = Shell.Global.get();
|
||||
global.stage.add_actor(this._preview);
|
||||
this._preview.hide();
|
||||
},
|
||||
|
||||
// Performs actions on mouse enter event for the item. Currently, shows the preview for the item.
|
||||
// Performs actions on mouse enter event for the item. Currently, shows the information button for the item.
|
||||
_onEnter: function(actor, event) {
|
||||
this._havePointer = true;
|
||||
let tooltipTimeout = Gtk.Settings.get_default().gtk_tooltip_timeout;
|
||||
this._previewEventSourceId = Mainloop.timeout_add(tooltipTimeout,
|
||||
Lang.bind(this,
|
||||
function() {
|
||||
if (this._havePointer) {
|
||||
this.showPreview();
|
||||
}
|
||||
this._previewEventSourceId = null;
|
||||
return false;
|
||||
}));
|
||||
this._informationButton.show();
|
||||
},
|
||||
|
||||
// Performs actions on mouse leave event for the item. Currently, hides the preview for the item.
|
||||
// Performs actions on mouse leave event for the item. Currently, hides the information button for the item.
|
||||
_onLeave: function(actor, event) {
|
||||
this._havePointer = false;
|
||||
this.hidePreview();
|
||||
this._informationButton.hide();
|
||||
},
|
||||
|
||||
// Hides the preview once the item starts being dragged.
|
||||
// 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 the preview box stays behind if we didn't have the call here. It makes sense to hide
|
||||
// the preview as soon as the item starts being dragged anyway.
|
||||
this._havePointer = false;
|
||||
this.hidePreview();
|
||||
// so we should remove the link manually.
|
||||
this._informationButton.hide();
|
||||
}
|
||||
};
|
||||
|
||||
@ -469,8 +371,6 @@ GenericDisplay.prototype = {
|
||||
// See also getSideArea.
|
||||
this.actor = this._grid;
|
||||
this.displayControl = new Big.Box({ background_color: ITEM_DISPLAY_BACKGROUND_COLOR,
|
||||
corner_radius: 4,
|
||||
height: 24,
|
||||
spacing: 12,
|
||||
orientation: Big.BoxOrientation.HORIZONTAL});
|
||||
|
||||
@ -557,14 +457,6 @@ GenericDisplay.prototype = {
|
||||
this._selectIndex(-1);
|
||||
},
|
||||
|
||||
// Hides the preview if any item has one being displayed.
|
||||
hidePreview: function() {
|
||||
for (itemId in this._displayedItems) {
|
||||
let item = this._displayedItems[itemId];
|
||||
item.hidePreview();
|
||||
}
|
||||
},
|
||||
|
||||
// Returns true if the display has any displayed items.
|
||||
hasItems: function() {
|
||||
return this._displayedItemsCount > 0;
|
||||
@ -645,13 +537,13 @@ GenericDisplay.prototype = {
|
||||
Mainloop.timeout_add(5,
|
||||
Lang.bind(this,
|
||||
function() {
|
||||
// Check if the pointer is over one of the items and display the preview pop-up if it is.
|
||||
// Check if the pointer is over one of the items and display the information button if it is.
|
||||
let [child, x, y, mask] = Gdk.Screen.get_default().get_root_window().get_pointer();
|
||||
let global = Shell.Global.get();
|
||||
let actor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE,
|
||||
x, y);
|
||||
if (actor != null) {
|
||||
let item = this._findDisplayedByActor(actor.get_parent());
|
||||
let item = this._findDisplayedByActor(actor);
|
||||
if (item != null) {
|
||||
item.onDrawnUnderPointer();
|
||||
}
|
||||
@ -670,7 +562,6 @@ GenericDisplay.prototype = {
|
||||
|
||||
let itemInfo = this._allItems[itemId];
|
||||
let displayItem = this._createDisplayItem(itemInfo);
|
||||
displayItem.setShowPreview(true);
|
||||
|
||||
displayItem.connect('activate',
|
||||
Lang.bind(this,
|
||||
@ -702,32 +593,8 @@ GenericDisplay.prototype = {
|
||||
this.selectUp();
|
||||
}
|
||||
|
||||
if (displayItem.dragActor) {
|
||||
// The user might be handling a dragActor when the list of items
|
||||
// changes (for example, if the dragging caused us to transition
|
||||
// from an expanded overlay view to the regular view). So we need
|
||||
// to keep the item around so that the drag and drop action initiated
|
||||
// by the user can be completed. However, we remove the item from the list.
|
||||
//
|
||||
// For some reason, just removing the displayItem.actor
|
||||
// is not enough to get displayItem._icon.visible
|
||||
// to return false, so we hide the display item and
|
||||
// all its children first. (We check displayItem._icon.visible
|
||||
// when deciding if a dragActor has a place to snap back to
|
||||
// in case the drop was not accepted by any actor.)
|
||||
displayItem.actor.hide_all();
|
||||
this._grid.remove_actor(displayItem.actor);
|
||||
// We should not destroy the item up-front, because that would also
|
||||
// destroy the icon that was used to clone the image for the drag actor.
|
||||
// We destroy it once the dragActor is destroyed instead.
|
||||
displayItem.dragActor.connect('destroy',
|
||||
function(item) {
|
||||
displayItem.destroy();
|
||||
});
|
||||
displayItem.destroy();
|
||||
|
||||
} else {
|
||||
displayItem.destroy();
|
||||
}
|
||||
delete this._displayedItems[itemId];
|
||||
this._displayedItemsCount--;
|
||||
},
|
||||
|
871
js/ui/overlay.js
871
js/ui/overlay.js
File diff suppressed because it is too large
Load Diff
@ -182,7 +182,7 @@ LauncherWidget.prototype = {
|
||||
spacing: ITEM_SPACING,
|
||||
reactive: true });
|
||||
item._info = info;
|
||||
item.append(info.getIcon(ITEM_ICON_SIZE), Big.BoxPackFlags.NONE);
|
||||
item.append(info.createIcon(ITEM_ICON_SIZE), Big.BoxPackFlags.NONE);
|
||||
item.append(new Clutter.Text({ color: ITEM_NAME_COLOR,
|
||||
font_name: "Sans 14px",
|
||||
ellipsize: Pango.EllipsizeMode.END,
|
||||
@ -203,7 +203,7 @@ LauncherWidget.prototype = {
|
||||
padding: ITEM_PADDING,
|
||||
reactive: true });
|
||||
item._info = info;
|
||||
item.append(info.getIcon(COLLAPSED_WIDTH - 2 * ITEM_PADDING),
|
||||
item.append(info.createIcon(COLLAPSED_WIDTH - 2 * ITEM_PADDING),
|
||||
Big.BoxPackFlags.NONE);
|
||||
|
||||
this.collapsedActor.append(item, Big.BoxPackFlags.NONE);
|
||||
@ -284,7 +284,7 @@ AppsWidget.prototype = {
|
||||
this.actor = new Big.Box({ spacing: 2 });
|
||||
this.collapsedActor = new Big.Box({ spacing: 2});
|
||||
|
||||
let apps = AppInfo.getMostUsedApps(5);
|
||||
let apps = AppInfo.getTopApps(5);
|
||||
for (let i = 0; i < apps.length; i++)
|
||||
this.addItem(apps[i]);
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ 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;
|
||||
@ -752,7 +753,7 @@ Workspace.prototype = {
|
||||
false, // don't create workspace
|
||||
time);
|
||||
return true;
|
||||
} else if (source instanceof GenericDisplay.GenericDisplayItem) {
|
||||
} else if (source instanceof GenericDisplay.GenericDisplayItem || source instanceof AppDisplay.WellDisplayItem) {
|
||||
this._metaWorkspace.activate(time);
|
||||
source.launch();
|
||||
return true;
|
||||
|
@ -13,9 +13,11 @@
|
||||
|
||||
|
||||
#include "shell-app-monitor.h"
|
||||
#include "shell-app-system.h"
|
||||
#include "shell-global.h"
|
||||
|
||||
#include "display.h"
|
||||
#include "window.h"
|
||||
|
||||
/* This file includes modified code from
|
||||
* desktop-data-engine/engine-dbus/hippo-application-monitor.c
|
||||
@ -63,6 +65,7 @@ static struct
|
||||
const char *pattern;
|
||||
GRegex *regex;
|
||||
} title_patterns[] = {
|
||||
{"mozilla-firefox", ".* - Mozilla Firefox", NULL}, \
|
||||
{"openoffice.org-writer", ".* - OpenOffice.org Writer$", NULL}, \
|
||||
{"openoffice.org-calc", ".* - OpenOffice.org Calc$", NULL}, \
|
||||
{"openoffice.org-impress", ".* - OpenOffice.org Impress$", NULL}, \
|
||||
@ -93,6 +96,12 @@ struct _ShellAppMonitor
|
||||
gboolean currently_idle;
|
||||
gboolean enable_monitoring;
|
||||
|
||||
/* <char * appid, guint window_count> */
|
||||
GHashTable *running_appids;
|
||||
|
||||
/* <MetaWindow * window, char * appid> */
|
||||
GHashTable *window_to_appid;
|
||||
|
||||
GHashTable *apps_by_wm_class; /* Seen apps by wm_class */
|
||||
GHashTable *popularities; /* One AppPopularity struct list per activity */
|
||||
int upload_apps_burst_count;
|
||||
@ -191,6 +200,232 @@ destroy_popularity (gpointer key,
|
||||
g_slist_free (list);
|
||||
}
|
||||
|
||||
static char *
|
||||
get_wmclass_for_window (MetaWindow *window)
|
||||
{
|
||||
static gboolean patterns_initialized = FALSE;
|
||||
const char *wm_class;
|
||||
char *title;
|
||||
int i;
|
||||
|
||||
wm_class = meta_window_get_wm_class (window);
|
||||
g_object_get (window, "title", &title, NULL);
|
||||
|
||||
if (!patterns_initialized) /* Generate match patterns once for all */
|
||||
{
|
||||
patterns_initialized = TRUE;
|
||||
for (i = 0; title_patterns[i].app_id; i++)
|
||||
{
|
||||
title_patterns[i].regex = g_regex_new (title_patterns[i].pattern,
|
||||
0, 0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Match window title patterns to identifiers for non-standard apps */
|
||||
if (title)
|
||||
{
|
||||
for (i = 0; title_patterns[i].app_id; i++)
|
||||
{
|
||||
if (g_regex_match (title_patterns[i].regex, title, 0, NULL))
|
||||
{
|
||||
/* Set a pseudo WM class, handled like true ones */
|
||||
wm_class = title_patterns[i].app_id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_free (title);
|
||||
return g_strdup (wm_class);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_cleaned_wmclass_for_window:
|
||||
*
|
||||
* A "cleaned" wmclass is the WM_CLASS property of a window,
|
||||
* after some transformations to turn it into a form
|
||||
* somewhat more resilient to changes, such as lowercasing.
|
||||
*/
|
||||
static char *
|
||||
get_cleaned_wmclass_for_window (MetaWindow *window)
|
||||
{
|
||||
char *wmclass;
|
||||
char *cleaned_wmclass;
|
||||
|
||||
if (meta_window_get_window_type (window) != META_WINDOW_NORMAL)
|
||||
return NULL;
|
||||
|
||||
wmclass = get_wmclass_for_window (window);
|
||||
if (!wmclass)
|
||||
return NULL;
|
||||
|
||||
cleaned_wmclass = g_utf8_strdown (wmclass, -1);
|
||||
g_free (wmclass);
|
||||
/* This handles "Fedora Eclipse", probably others */
|
||||
g_strdelimit (cleaned_wmclass, " ", '-');
|
||||
wmclass = g_strdup (cleaned_wmclass);
|
||||
g_free (cleaned_wmclass);
|
||||
return wmclass;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_appid_for_window:
|
||||
*
|
||||
* Returns a desktop file ID for an application, or %NULL if
|
||||
* we're unable to determine one.
|
||||
*/
|
||||
static char *
|
||||
get_appid_for_window (MetaWindow *window)
|
||||
{
|
||||
char *wmclass;
|
||||
char *with_desktop;
|
||||
char *result;
|
||||
ShellAppSystem *appsys;
|
||||
|
||||
wmclass = get_cleaned_wmclass_for_window (window);
|
||||
|
||||
if (!wmclass)
|
||||
return NULL;
|
||||
|
||||
with_desktop = g_strjoin (NULL, wmclass, ".desktop", NULL);
|
||||
g_free (wmclass);
|
||||
|
||||
appsys = shell_app_system_get_default ();
|
||||
result = shell_app_system_lookup_basename (appsys, with_desktop);
|
||||
g_free (with_desktop);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
track_window (ShellAppMonitor *self,
|
||||
MetaWindow *window)
|
||||
{
|
||||
char *appid;
|
||||
guint window_count;
|
||||
|
||||
appid = get_appid_for_window (window);
|
||||
if (!appid)
|
||||
return;
|
||||
|
||||
g_hash_table_insert (self->window_to_appid, window, appid);
|
||||
|
||||
window_count = GPOINTER_TO_UINT (g_hash_table_lookup (self->running_appids, appid));
|
||||
|
||||
window_count += 1;
|
||||
g_hash_table_insert (self->running_appids, g_strdup (appid), GUINT_TO_POINTER (window_count));
|
||||
if (window_count == 1)
|
||||
g_signal_emit (self, signals[CHANGED], 0);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_app_monitor_on_window_added (MetaWorkspace *workspace,
|
||||
MetaWindow *window,
|
||||
gpointer user_data)
|
||||
{
|
||||
ShellAppMonitor *self = SHELL_APP_MONITOR (user_data);
|
||||
|
||||
track_window (self, window);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_app_monitor_on_window_removed (MetaWorkspace *workspace,
|
||||
MetaWindow *window,
|
||||
gpointer user_data)
|
||||
{
|
||||
ShellAppMonitor *self = SHELL_APP_MONITOR (user_data);
|
||||
char *appid;
|
||||
guint window_count;
|
||||
|
||||
appid = g_hash_table_lookup (self->window_to_appid, window);
|
||||
if (!appid)
|
||||
return;
|
||||
|
||||
window_count = GPOINTER_TO_UINT (g_hash_table_lookup (self->running_appids, appid));
|
||||
|
||||
window_count -= 1;
|
||||
if (window_count == 0)
|
||||
{
|
||||
g_hash_table_remove (self->running_appids, appid);
|
||||
g_free (appid);
|
||||
g_signal_emit (self, signals[CHANGED], 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_hash_table_insert (self->running_appids, appid, GUINT_TO_POINTER (window_count));
|
||||
}
|
||||
g_hash_table_remove (self->window_to_appid, window);
|
||||
}
|
||||
|
||||
static void
|
||||
load_initial_windows (ShellAppMonitor *monitor)
|
||||
{
|
||||
GList *workspaces, *iter;
|
||||
MetaScreen *screen = shell_global_get_screen (shell_global_get ());
|
||||
workspaces = meta_screen_get_workspaces (screen);
|
||||
|
||||
for (iter = workspaces; iter; iter = iter->next)
|
||||
{
|
||||
MetaWorkspace *workspace = iter->data;
|
||||
GList *windows = meta_workspace_list_windows (workspace);
|
||||
GList *window_iter;
|
||||
|
||||
for (window_iter = windows; window_iter; window_iter = window_iter->next)
|
||||
track_window (monitor, (MetaWindow*)window_iter->data);
|
||||
|
||||
g_list_free (windows);
|
||||
}
|
||||
}
|
||||
|
||||
guint
|
||||
shell_app_monitor_get_window_count (ShellAppMonitor *self,
|
||||
const char *appid)
|
||||
{
|
||||
return GPOINTER_TO_UINT (g_hash_table_lookup (self->running_appids, appid));
|
||||
}
|
||||
|
||||
static void
|
||||
shell_app_monitor_on_n_workspaces_changed (MetaScreen *screen,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
ShellAppMonitor *self = SHELL_APP_MONITOR (user_data);
|
||||
GList *workspaces, *iter;
|
||||
|
||||
workspaces = meta_screen_get_workspaces (screen);
|
||||
|
||||
for (iter = workspaces; iter; iter = iter->next)
|
||||
{
|
||||
MetaWorkspace *workspace = iter->data;
|
||||
|
||||
/* This pair of disconnect/connect is idempotent if we were
|
||||
* already connected, while ensuring we get connected for
|
||||
* new workspaces.
|
||||
*/
|
||||
g_signal_handlers_disconnect_by_func (workspace,
|
||||
shell_app_monitor_on_window_added,
|
||||
self);
|
||||
g_signal_handlers_disconnect_by_func (workspace,
|
||||
shell_app_monitor_on_window_removed,
|
||||
self);
|
||||
|
||||
g_signal_connect (workspace, "window-added",
|
||||
G_CALLBACK (shell_app_monitor_on_window_added), self);
|
||||
g_signal_connect (workspace, "window-removed",
|
||||
G_CALLBACK (shell_app_monitor_on_window_removed), self);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
init_window_monitoring (ShellAppMonitor *self)
|
||||
{
|
||||
MetaScreen *screen = shell_global_get_screen (shell_global_get ());
|
||||
|
||||
g_signal_connect (screen, "notify::n-workspaces",
|
||||
G_CALLBACK (shell_app_monitor_on_n_workspaces_changed), self);
|
||||
shell_app_monitor_on_n_workspaces_changed (screen, NULL, self);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_app_monitor_init (ShellAppMonitor *self)
|
||||
{
|
||||
@ -223,6 +458,15 @@ shell_app_monitor_init (ShellAppMonitor *self)
|
||||
(GDestroyNotify) g_free,
|
||||
(GDestroyNotify) g_free);
|
||||
|
||||
self->running_appids = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
g_free, NULL);
|
||||
|
||||
self->window_to_appid = g_hash_table_new_full (g_direct_hash, g_direct_equal,
|
||||
NULL, (GDestroyNotify) g_free);
|
||||
|
||||
load_initial_windows (self);
|
||||
init_window_monitoring (self);
|
||||
|
||||
g_object_get (shell_global_get(), "configdir", &shell_config_dir, NULL),
|
||||
path = g_build_filename (shell_config_dir, DATA_FILENAME, NULL);
|
||||
g_free (shell_config_dir);
|
||||
@ -299,16 +543,31 @@ shell_app_monitor_get_most_used_apps (ShellAppMonitor *monitor,
|
||||
return list;
|
||||
}
|
||||
|
||||
/* Find the active window in order to collect stats */
|
||||
void
|
||||
get_active_app_properties (ShellAppMonitor *monitor,
|
||||
char **wm_class,
|
||||
char **title)
|
||||
/**
|
||||
* shell_app_monitor_get_running_app_ids:
|
||||
*
|
||||
* @monitor: An app monitor instance
|
||||
*
|
||||
* Returns: (element-type utf8) (transfer container): List of application desktop
|
||||
* identifiers
|
||||
*/
|
||||
GList *
|
||||
shell_app_monitor_get_running_app_ids (ShellAppMonitor *monitor)
|
||||
{
|
||||
return g_hash_table_get_keys (monitor->running_appids);
|
||||
}
|
||||
|
||||
void
|
||||
update_app_info (ShellAppMonitor *monitor)
|
||||
{
|
||||
char *wm_class;
|
||||
ShellGlobal *global;
|
||||
GHashTable *app_active_times = NULL; /* last active time for an application */
|
||||
MetaScreen *screen;
|
||||
MetaDisplay *display;
|
||||
MetaWindow *active;
|
||||
int activity;
|
||||
guint32 timestamp;
|
||||
|
||||
global = shell_global_get ();
|
||||
g_object_get (global, "screen", &screen, NULL);
|
||||
@ -317,56 +576,10 @@ get_active_app_properties (ShellAppMonitor *monitor,
|
||||
|
||||
active = meta_display_get_focus_window (display);
|
||||
|
||||
if (wm_class)
|
||||
*wm_class = NULL;
|
||||
if (title)
|
||||
*title = NULL;
|
||||
|
||||
if (active == NULL)
|
||||
return;
|
||||
|
||||
*wm_class = g_strdup (meta_window_get_wm_class (active));
|
||||
g_object_get (active, "title", title, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
update_app_info (ShellAppMonitor *monitor)
|
||||
{
|
||||
char *wm_class;
|
||||
char *title;
|
||||
GHashTable *app_active_times = NULL; /* GTime spent per activity */
|
||||
static gboolean first_time = TRUE;
|
||||
int activity;
|
||||
guint32 timestamp;
|
||||
int i;
|
||||
|
||||
if (first_time) /* Generate match patterns once for all */
|
||||
{
|
||||
first_time = FALSE;
|
||||
for (i = 0; title_patterns[i].app_id; i++)
|
||||
{
|
||||
title_patterns[i].regex = g_regex_new (title_patterns[i].pattern,
|
||||
0, 0, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
get_active_app_properties (monitor, &wm_class, &title);
|
||||
|
||||
/* Match window title patterns to identifiers for non-standard apps */
|
||||
if (title)
|
||||
{
|
||||
for (i = 0; title_patterns[i].app_id; i++)
|
||||
{
|
||||
if ( g_regex_match (title_patterns[i].regex, title, 0, NULL) )
|
||||
{
|
||||
/* Set a pseudo WM class, handled like true ones */
|
||||
g_free (wm_class);
|
||||
wm_class = g_strdup(title_patterns[i].app_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_free (title);
|
||||
}
|
||||
wm_class = get_cleaned_wmclass_for_window (active);
|
||||
|
||||
if (!wm_class)
|
||||
return;
|
||||
|
@ -40,9 +40,10 @@ GSList *shell_app_monitor_get_most_used_apps (ShellAppMonitor *monitor,
|
||||
int activity,
|
||||
gint number);
|
||||
|
||||
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,
|
||||
int activity);
|
||||
GList *shell_app_monitor_get_running_app_ids (ShellAppMonitor *monitor);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -1,19 +1,25 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include "shell-app-system.h"
|
||||
#include <string.h>
|
||||
|
||||
#include <gio/gio.h>
|
||||
#include <gconf/gconf.h>
|
||||
#include <gconf/gconf-client.h>
|
||||
|
||||
#define GMENU_I_KNOW_THIS_IS_UNSTABLE
|
||||
#include <gmenu-tree.h>
|
||||
|
||||
#define SHELL_APP_FAVORITES_KEY "/desktop/gnome/shell/favorite_apps"
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
|
||||
};
|
||||
|
||||
enum {
|
||||
CHANGED,
|
||||
INSTALLED_CHANGED,
|
||||
FAVORITES_CHANGED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
@ -26,11 +32,17 @@ struct _ShellAppSystemPrivate {
|
||||
GSList *cached_app_menus; /* ShellAppMenuEntry */
|
||||
|
||||
GSList *cached_setting_ids; /* utf8 */
|
||||
|
||||
GHashTable *cached_favorites; /* <utf8,integer> */
|
||||
|
||||
gint app_monitor_id;
|
||||
};
|
||||
|
||||
static void shell_app_system_finalize (GObject *object);
|
||||
static void on_tree_changed (GMenuTree *tree, gpointer user_data);
|
||||
static void reread_menus (ShellAppSystem *self);
|
||||
static void on_favorite_apps_changed (GConfClient *client, guint id, GConfEntry *entry, gpointer user_data);
|
||||
static void reread_favorite_apps (ShellAppSystem *system);
|
||||
|
||||
G_DEFINE_TYPE(ShellAppSystem, shell_app_system, G_TYPE_OBJECT);
|
||||
|
||||
@ -63,14 +75,22 @@ static void shell_app_system_class_init(ShellAppSystemClass *klass)
|
||||
|
||||
gobject_class->finalize = shell_app_system_finalize;
|
||||
|
||||
signals[CHANGED] =
|
||||
g_signal_new ("changed",
|
||||
signals[INSTALLED_CHANGED] =
|
||||
g_signal_new ("installed-changed",
|
||||
SHELL_TYPE_APP_SYSTEM,
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (ShellAppSystemClass, changed),
|
||||
G_STRUCT_OFFSET (ShellAppSystemClass, installed_changed),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
signals[FAVORITES_CHANGED] =
|
||||
g_signal_new ("favorites-changed",
|
||||
SHELL_TYPE_APP_SYSTEM,
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (ShellAppSystemClass, favorites_changed),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
g_type_class_add_private (gobject_class, sizeof (ShellAppSystemPrivate));
|
||||
}
|
||||
@ -79,10 +99,16 @@ static void
|
||||
shell_app_system_init (ShellAppSystem *self)
|
||||
{
|
||||
ShellAppSystemPrivate *priv;
|
||||
GConfClient *client;
|
||||
|
||||
self->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
|
||||
SHELL_TYPE_APP_SYSTEM,
|
||||
ShellAppSystemPrivate);
|
||||
|
||||
priv->cached_favorites = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
(GDestroyNotify)g_free,
|
||||
NULL);
|
||||
|
||||
priv->apps_tree = gmenu_tree_lookup ("applications.menu", GMENU_TREE_FLAGS_NONE);
|
||||
priv->settings_tree = gmenu_tree_lookup ("settings.menu", GMENU_TREE_FLAGS_NONE);
|
||||
|
||||
@ -90,6 +116,12 @@ shell_app_system_init (ShellAppSystem *self)
|
||||
gmenu_tree_add_monitor (priv->settings_tree, on_tree_changed, self);
|
||||
|
||||
reread_menus (self);
|
||||
|
||||
client = gconf_client_get_default ();
|
||||
|
||||
self->priv->app_monitor_id = gconf_client_notify_add (client, SHELL_APP_FAVORITES_KEY,
|
||||
on_favorite_apps_changed, self, NULL, NULL);
|
||||
reread_favorite_apps (self);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -112,13 +144,16 @@ shell_app_system_finalize (GObject *object)
|
||||
g_slist_free (priv->cached_setting_ids);
|
||||
priv->cached_setting_ids = NULL;
|
||||
|
||||
g_hash_table_destroy (priv->cached_favorites);
|
||||
|
||||
gconf_client_notify_remove (gconf_client_get_default (), priv->app_monitor_id);
|
||||
|
||||
G_OBJECT_CLASS (shell_app_system_parent_class)->finalize(object);
|
||||
}
|
||||
|
||||
static void
|
||||
reread_directories (ShellAppSystem *self, GSList **cache, GMenuTree *tree)
|
||||
{
|
||||
ShellAppSystemPrivate *priv = self->priv;
|
||||
GMenuTreeDirectory *trunk;
|
||||
GSList *entries;
|
||||
GSList *iter;
|
||||
@ -228,11 +263,58 @@ on_tree_changed (GMenuTree *monitor, gpointer user_data)
|
||||
{
|
||||
ShellAppSystem *self = SHELL_APP_SYSTEM (user_data);
|
||||
|
||||
g_signal_emit (self, signals[CHANGED], 0);
|
||||
g_signal_emit (self, signals[INSTALLED_CHANGED], 0);
|
||||
|
||||
reread_menus (self);
|
||||
}
|
||||
|
||||
static void
|
||||
copy_gconf_value_string_list_to_hashset (GConfValue *value,
|
||||
GHashTable *dest)
|
||||
{
|
||||
GSList *list;
|
||||
GSList *tmp;
|
||||
|
||||
list = gconf_value_get_list (value);
|
||||
|
||||
for (tmp = list ; tmp; tmp = tmp->next)
|
||||
{
|
||||
GConfValue *value = tmp->data;
|
||||
char *str = g_strdup (gconf_value_get_string (value));
|
||||
if (!str)
|
||||
continue;
|
||||
g_hash_table_insert (dest, str, GUINT_TO_POINTER(1));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
reread_favorite_apps (ShellAppSystem *system)
|
||||
{
|
||||
GConfClient *client = gconf_client_get_default ();
|
||||
GConfValue *val;
|
||||
|
||||
val = gconf_client_get (client, SHELL_APP_FAVORITES_KEY, NULL);
|
||||
|
||||
if (!(val && val->type == GCONF_VALUE_LIST && gconf_value_get_list_type (val) == GCONF_VALUE_STRING))
|
||||
return;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
on_favorite_apps_changed (GConfClient *client,
|
||||
guint id,
|
||||
GConfEntry *entry,
|
||||
gpointer user_data)
|
||||
{
|
||||
ShellAppSystem *system = SHELL_APP_SYSTEM (user_data);
|
||||
reread_favorite_apps (system);
|
||||
g_signal_emit (G_OBJECT (system), signals[FAVORITES_CHANGED], 0);
|
||||
}
|
||||
|
||||
GType
|
||||
shell_app_menu_entry_get_type (void)
|
||||
{
|
||||
@ -315,3 +397,160 @@ shell_app_system_get_default ()
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_app_system_get_favorites:
|
||||
*
|
||||
* Return the list of applications which have been explicitly added to the
|
||||
* favorites.
|
||||
*
|
||||
* Return value: (transfer container) (element-type utf8): List of favorite application ids
|
||||
*/
|
||||
GList *
|
||||
shell_app_system_get_favorites (ShellAppSystem *system)
|
||||
{
|
||||
return g_hash_table_get_keys (system->priv->cached_favorites);
|
||||
}
|
||||
|
||||
static void
|
||||
set_gconf_value_string_list (GConfValue *val, GList *items)
|
||||
{
|
||||
GList *iter;
|
||||
GSList *tmp = NULL;
|
||||
|
||||
for (iter = items; iter; iter = iter->next)
|
||||
{
|
||||
const char *str = iter->data;
|
||||
GConfValue *strval = gconf_value_new (GCONF_VALUE_STRING);
|
||||
gconf_value_set_string (strval, str);
|
||||
tmp = g_slist_prepend (tmp, strval);
|
||||
}
|
||||
tmp = g_slist_reverse (tmp);
|
||||
|
||||
gconf_value_set_list (val, tmp);
|
||||
g_slist_free (tmp);
|
||||
}
|
||||
|
||||
void
|
||||
shell_app_system_add_favorite (ShellAppSystem *system, const char *id)
|
||||
{
|
||||
GConfClient *client = gconf_client_get_default ();
|
||||
GConfValue *val;
|
||||
GList *favorites;
|
||||
|
||||
val = gconf_value_new (GCONF_VALUE_LIST);
|
||||
gconf_value_set_list_type (val, GCONF_VALUE_STRING);
|
||||
|
||||
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);
|
||||
|
||||
gconf_client_set (client, SHELL_APP_FAVORITES_KEY, val, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
shell_app_system_remove_favorite (ShellAppSystem *system, const char *id)
|
||||
{
|
||||
GConfClient *client = gconf_client_get_default ();
|
||||
GConfValue *val;
|
||||
GList *favorites;
|
||||
|
||||
if (!g_hash_table_remove (system->priv->cached_favorites, id))
|
||||
return;
|
||||
|
||||
val = gconf_value_new (GCONF_VALUE_LIST);
|
||||
gconf_value_set_list_type (val, GCONF_VALUE_STRING);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
desktop_id_exists (ShellAppSystem *system,
|
||||
const char *target_id,
|
||||
GMenuTreeDirectory *root)
|
||||
{
|
||||
gboolean found = FALSE;
|
||||
GSList *contents, *iter;
|
||||
|
||||
contents = gmenu_tree_directory_get_contents (root);
|
||||
|
||||
for (iter = contents; iter; iter = iter->next)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
g_slist_free (contents);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_app_system_lookup_basename:
|
||||
* @name: Probable application identifier
|
||||
*
|
||||
* Determine whether a valid .desktop file ID corresponding to a given
|
||||
* heuristically determined application identifier
|
||||
* string.
|
||||
*/
|
||||
char *
|
||||
shell_app_system_lookup_basename (ShellAppSystem *system,
|
||||
const char *name)
|
||||
{
|
||||
GMenuTreeDirectory *root;
|
||||
char *result;
|
||||
|
||||
root = gmenu_tree_get_directory_from_path (system->priv->apps_tree, "/");
|
||||
g_assert (root != NULL);
|
||||
|
||||
if (desktop_id_exists (system, name, root))
|
||||
{
|
||||
result = g_strdup (name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
result = g_strjoin ("", "fedora-", name, NULL);
|
||||
if (desktop_id_exists (system, result, root))
|
||||
goto out;
|
||||
|
||||
out:
|
||||
gmenu_tree_item_unref (root);
|
||||
return result;
|
||||
}
|
||||
|
@ -25,7 +25,8 @@ struct _ShellAppSystemClass
|
||||
{
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (*changed)(ShellAppSystem *appsys, gpointer data);
|
||||
void (*installed_changed)(ShellAppSystem *appsys, gpointer user_data);
|
||||
void (*favorites_changed)(ShellAppSystem *appsys, gpointer user_data);
|
||||
};
|
||||
|
||||
GType shell_app_system_get_type (void) G_GNUC_CONST;
|
||||
@ -43,8 +44,16 @@ struct _ShellAppMenuEntry {
|
||||
|
||||
GType shell_app_menu_entry_get_type (void);
|
||||
|
||||
char * shell_app_system_lookup_basename (ShellAppSystem *system, const char *id);
|
||||
|
||||
GSList *shell_app_system_get_menus (ShellAppSystem *system);
|
||||
|
||||
GSList *shell_app_system_get_all_settings (ShellAppSystem *system);
|
||||
|
||||
GList *shell_app_system_get_favorites (ShellAppSystem *system);
|
||||
|
||||
void shell_app_system_add_favorite (ShellAppSystem *system, const char *id);
|
||||
|
||||
void shell_app_system_remove_favorite (ShellAppSystem *system, const char *id);
|
||||
|
||||
#endif /* __SHELL_APP_SYSTEM_H__ */
|
||||
|
@ -101,7 +101,7 @@ shell_global_get_property(GObject *object,
|
||||
g_value_set_object (value, mutter_plugin_get_overlay_group (global->plugin));
|
||||
break;
|
||||
case PROP_SCREEN:
|
||||
g_value_set_object (value, mutter_plugin_get_screen (global->plugin));
|
||||
g_value_set_object (value, shell_global_get_screen (global));
|
||||
break;
|
||||
case PROP_SCREEN_WIDTH:
|
||||
{
|
||||
@ -608,6 +608,17 @@ shell_global_set_stage_input_region (ShellGlobal *global,
|
||||
shell_global_set_stage_input_mode (global, global->input_mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_global_get_screen:
|
||||
*
|
||||
* Return value: (transfer none): The default #MetaScreen
|
||||
*/
|
||||
MetaScreen *
|
||||
shell_global_get_screen (ShellGlobal *global)
|
||||
{
|
||||
return mutter_plugin_get_screen (global->plugin);
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_global_get_windows:
|
||||
*
|
||||
@ -933,6 +944,55 @@ shell_global_create_vertical_gradient (ClutterColor *top,
|
||||
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.
|
||||
|
@ -48,6 +48,8 @@ ClutterActor *shell_get_event_related(ClutterEvent *event);
|
||||
|
||||
ShellGlobal *shell_global_get (void);
|
||||
|
||||
MetaScreen *shell_global_get_screen (ShellGlobal *global);
|
||||
|
||||
void shell_global_grab_dbus_service (ShellGlobal *global);
|
||||
|
||||
void shell_global_start_task_panel (ShellGlobal *global);
|
||||
@ -76,6 +78,9 @@ void shell_global_reexec_self (ShellGlobal *global);
|
||||
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,
|
||||
|
Loading…
Reference in New Issue
Block a user