Compare commits
	
		
			48 Commits
		
	
	
		
			wip/gcampa
			...
			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; | ||||
|  | ||||
| @@ -33,11 +38,10 @@ AppDisplayItem.prototype = { | ||||
|     __proto__:  GenericDisplay.GenericDisplayItem.prototype, | ||||
|  | ||||
|     _init : function(appInfo, availableWidth) { | ||||
|         GenericDisplay.GenericDisplayItem.prototype._init.call(this, availableWidth);  | ||||
|         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,15 +53,20 @@ 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) | ||||
|             return;  | ||||
|             return; | ||||
|  | ||||
|         let previewIconPath = this._appInfo.getIconPath(GenericDisplay.PREVIEW_ICON_SIZE); | ||||
|         if (previewIconPath) { | ||||
|             try { | ||||
|                 this._previewIcon = new Clutter.Texture({ width: GenericDisplay.PREVIEW_ICON_SIZE, height: GenericDisplay.PREVIEW_ICON_SIZE});                | ||||
|                 this._previewIcon = new Clutter.Texture({ width: GenericDisplay.PREVIEW_ICON_SIZE, height: GenericDisplay.PREVIEW_ICON_SIZE}); | ||||
|                 this._previewIcon.set_from_file(previewIconPath); | ||||
|             } catch (e) { | ||||
|                 // we can get an error here if the file path doesn't exist on the system | ||||
| @@ -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', | ||||
|                            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(); | ||||
|         this.actor.connect('button-release-event',  | ||||
|                            Lang.bind(this,  | ||||
|                                      function() { | ||||
|                                          // Activates the item by launching it | ||||
|                                          this.emit('activate'); | ||||
|                                          return true;   | ||||
|                                      })); | ||||
|  | ||||
|         let draggable = DND.makeDraggable(this.actor); | ||||
| @@ -81,11 +79,40 @@ GenericDisplayItem.prototype = { | ||||
|                                  x: 0, y: 0, | ||||
|                                  width: availableWidth, height: ITEM_DISPLAY_HEIGHT }); | ||||
|         this.actor.add_actor(this._bg); | ||||
|          | ||||
|  | ||||
|         let global = Shell.Global.get(); | ||||
|         let infoIconUri = "file://" + global.imagedir + "info.svg"; | ||||
|  | ||||
|         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. | ||||
| @@ -199,7 +175,7 @@ GenericDisplayItem.prototype = { | ||||
|      * availableHeight - height available for displaying details | ||||
|      */  | ||||
|     createDetailsActor: function(availableWidth, availableHeight) { | ||||
|  | ||||
|   | ||||
|         let details = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL, | ||||
|                                     spacing: PREVIEW_BOX_SPACING, | ||||
|                                     width: availableWidth }); | ||||
| @@ -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(); | ||||
|                                           }); | ||||
|             | ||||
|         } else { | ||||
|             displayItem.destroy(); | ||||
|         } | ||||
|         displayItem.destroy(); | ||||
|  | ||||
|         delete this._displayedItems[itemId]; | ||||
|         this._displayedItemsCount--;         | ||||
|     }, | ||||
|   | ||||
							
								
								
									
										889
									
								
								js/ui/overlay.js
									
									
									
									
									
								
							
							
						
						
									
										889
									
								
								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,60 +576,14 @@ 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); | ||||
| } | ||||
|   wm_class = get_cleaned_wmclass_for_window (active); | ||||
|  | ||||
| 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); | ||||
|     }   | ||||
|    | ||||
|   if (!wm_class) | ||||
|     return; | ||||
|    | ||||
|  | ||||
|   app_active_times = g_hash_table_lookup (monitor->apps_by_wm_class, wm_class); | ||||
|   if (!app_active_times) | ||||
|     { | ||||
|   | ||||
| @@ -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, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user