Compare commits
	
		
			24 Commits
		
	
	
		
			cherry-pic
			...
			overview-r
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					9efa271888 | ||
| 
						 | 
					9ed3ce9006 | ||
| 
						 | 
					b400fc2837 | ||
| 
						 | 
					a66af6fbac | ||
| 
						 | 
					1bbc138ed2 | ||
| 
						 | 
					868d4756e4 | ||
| 
						 | 
					dfa3be59dc | ||
| 
						 | 
					62677336a5 | ||
| 
						 | 
					264a82cbfc | ||
| 
						 | 
					f8cfd9f903 | ||
| 
						 | 
					13f8cd3bcf | ||
| 
						 | 
					e1f336374b | ||
| 
						 | 
					0ba1387d19 | ||
| 
						 | 
					8832ce3a2b | ||
| 
						 | 
					91d7a022a9 | ||
| 
						 | 
					95d15725fc | ||
| 
						 | 
					bb2b7d83af | ||
| 
						 | 
					0abac6f67d | ||
| 
						 | 
					e00398e2ac | ||
| 
						 | 
					0f19492545 | ||
| 
						 | 
					9d46a6ceea | ||
| 
						 | 
					6432de95cc | ||
| 
						 | 
					738fc375c0 | ||
| 
						 | 
					4e9a530a64 | 
@@ -25,6 +25,7 @@ dist_theme_DATA =				\
 | 
			
		||||
	theme/close-window.svg			\
 | 
			
		||||
	theme/close.svg				\
 | 
			
		||||
	theme/corner-ripple.png			\
 | 
			
		||||
	theme/dash-placeholder.svg		\
 | 
			
		||||
	theme/dialog-error.svg			\
 | 
			
		||||
	theme/gnome-shell.css			\
 | 
			
		||||
	theme/mosaic-view-active.svg		\
 | 
			
		||||
@@ -32,6 +33,7 @@ dist_theme_DATA =				\
 | 
			
		||||
	theme/move-window-on-new.svg		\
 | 
			
		||||
	theme/process-working.png		\
 | 
			
		||||
	theme/remove-workspace.svg		\
 | 
			
		||||
	theme/running-indicator.svg		\
 | 
			
		||||
	theme/scroll-button-down-hover.png	\
 | 
			
		||||
	theme/scroll-button-down.png		\
 | 
			
		||||
	theme/scroll-button-up-hover.png	\
 | 
			
		||||
 
 | 
			
		||||
@@ -41,18 +41,6 @@
 | 
			
		||||
      <default>[]</default>
 | 
			
		||||
      <_summary>History for command (Alt-F2) dialog</_summary>
 | 
			
		||||
    </key>
 | 
			
		||||
    <key name="workspaces-view" type="s">
 | 
			
		||||
      <default>'single'</default>
 | 
			
		||||
      <_summary>Overview workspace view mode</_summary>
 | 
			
		||||
      <_description>
 | 
			
		||||
        The selected workspace view mode in the overview.
 | 
			
		||||
        Supported values are "single" and "grid".
 | 
			
		||||
      </_description>
 | 
			
		||||
      <choices>
 | 
			
		||||
        <choice value="single"/>
 | 
			
		||||
        <choice value="grid"/>
 | 
			
		||||
      </choices>
 | 
			
		||||
    </key>
 | 
			
		||||
    <child name="clock" schema="org.gnome.shell.clock"/>
 | 
			
		||||
    <child name="calendar" schema="org.gnome.shell.calendar"/>
 | 
			
		||||
    <child name="recorder" schema="org.gnome.shell.recorder"/>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										84
									
								
								data/theme/dash-placeholder.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								data/theme/dash-placeholder.svg
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,84 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
			
		||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
 | 
			
		||||
 | 
			
		||||
<svg
 | 
			
		||||
   xmlns:svg="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns:xlink="http://www.w3.org/1999/xlink"
 | 
			
		||||
   width="76"
 | 
			
		||||
   height="27"
 | 
			
		||||
   id="svg11252"
 | 
			
		||||
   version="1.1">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs11254">
 | 
			
		||||
    <radialGradient
 | 
			
		||||
       xlink:href="#linearGradient39563-4-2"
 | 
			
		||||
       id="radialGradient68155-2-3"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       gradientTransform="matrix(1,0,0,0.3486842,0,317.8421)"
 | 
			
		||||
       cx="49"
 | 
			
		||||
       cy="488"
 | 
			
		||||
       fx="49"
 | 
			
		||||
       fy="488"
 | 
			
		||||
       r="38" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       id="linearGradient39563-4-2">
 | 
			
		||||
      <stop
 | 
			
		||||
         style="stop-color:#ffffff;stop-opacity:1;"
 | 
			
		||||
         offset="0"
 | 
			
		||||
         id="stop39565-1-4" />
 | 
			
		||||
      <stop
 | 
			
		||||
         style="stop-color:#ffffff;stop-opacity:0;"
 | 
			
		||||
         offset="1"
 | 
			
		||||
         id="stop39567-7-9" />
 | 
			
		||||
    </linearGradient>
 | 
			
		||||
    <radialGradient
 | 
			
		||||
       xlink:href="#linearGradient39573-6-1"
 | 
			
		||||
       id="radialGradient68157-0-8"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       cx="50.5"
 | 
			
		||||
       cy="487.5"
 | 
			
		||||
       fx="50.5"
 | 
			
		||||
       fy="487.5"
 | 
			
		||||
       r="10.5" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       id="linearGradient39573-6-1">
 | 
			
		||||
      <stop
 | 
			
		||||
         style="stop-color:#ffffff;stop-opacity:1;"
 | 
			
		||||
         offset="0"
 | 
			
		||||
         id="stop39575-5-6" />
 | 
			
		||||
      <stop
 | 
			
		||||
         style="stop-color:#ffffff;stop-opacity:0;"
 | 
			
		||||
         offset="1"
 | 
			
		||||
         id="stop39577-1-2" />
 | 
			
		||||
    </linearGradient>
 | 
			
		||||
  </defs>
 | 
			
		||||
  <g
 | 
			
		||||
     id="layer1"
 | 
			
		||||
     transform="translate(-337,-518.86218)">
 | 
			
		||||
    <g
 | 
			
		||||
       id="g99967"
 | 
			
		||||
       style="display:inline"
 | 
			
		||||
       transform="translate(326,44.862171)">
 | 
			
		||||
      <rect
 | 
			
		||||
         style="opacity:0.49375;color:#000000;fill:url(#radialGradient68155-2-3);fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
 | 
			
		||||
         id="rect99969"
 | 
			
		||||
         width="76"
 | 
			
		||||
         height="2"
 | 
			
		||||
         x="11"
 | 
			
		||||
         y="487"
 | 
			
		||||
         rx="0"
 | 
			
		||||
         ry="0" />
 | 
			
		||||
      <path
 | 
			
		||||
         style="opacity:0.43125;color:#000000;fill:url(#radialGradient68157-0-8);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
 | 
			
		||||
         id="path99971"
 | 
			
		||||
         d="M 61,487.5 C 61,493.29899 56.29899,498 50.5,498 44.70101,498 40,493.29899 40,487.5 40,481.70101 44.70101,477 50.5,477 c 5.79899,0 10.5,4.70101 10.5,10.5 z"
 | 
			
		||||
         transform="matrix(1.2857143,0,0,1.2857143,-14.428572,-139.28571)" />
 | 
			
		||||
      <path
 | 
			
		||||
         transform="matrix(0.43589747,0,0,0.43589747,28.487179,275)"
 | 
			
		||||
         d="M 61,487.5 C 61,493.29899 56.29899,498 50.5,498 44.70101,498 40,493.29899 40,487.5 40,481.70101 44.70101,477 50.5,477 c 5.79899,0 10.5,4.70101 10.5,10.5 z"
 | 
			
		||||
         id="path99973"
 | 
			
		||||
         style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
 | 
			
		||||
    </g>
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 2.9 KiB  | 
@@ -257,25 +257,9 @@ StTooltip StLabel {
 | 
			
		||||
 | 
			
		||||
/* Overview */
 | 
			
		||||
 | 
			
		||||
.overview {
 | 
			
		||||
    background-color: #111;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.info-bar {
 | 
			
		||||
    color: #fff;
 | 
			
		||||
    font-size: 14px;
 | 
			
		||||
    spacing: 20px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.info-bar-link-button {
 | 
			
		||||
    background-color: #2d2d2d;
 | 
			
		||||
    padding: 2px 14px;
 | 
			
		||||
    border-radius: 10px;
 | 
			
		||||
    border: 1px solid #181818;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.info-bar-link-button:hover {
 | 
			
		||||
    border: 1px solid #666666;
 | 
			
		||||
#overview {
 | 
			
		||||
    spacing: 12px;
 | 
			
		||||
    background-color: rgba(0,0,0,0.6);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.new-workspace-area {
 | 
			
		||||
@@ -323,18 +307,17 @@ StTooltip StLabel {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.workspaces-bar {
 | 
			
		||||
    height: 48px;
 | 
			
		||||
    spacing: 5px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.workspaces-bar {
 | 
			
		||||
    spacing: 5px;
 | 
			
		||||
.workspace-indicator-panel {
 | 
			
		||||
    spacing: 8px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.workspace-indicator {
 | 
			
		||||
    width: 24px;
 | 
			
		||||
    height: 16px;
 | 
			
		||||
    background: rgba(155,155,155,0.8);
 | 
			
		||||
    border-spacing: 16px;
 | 
			
		||||
    background: rgba(255,255,255,0.2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.workspace-indicator.active {
 | 
			
		||||
@@ -359,44 +342,33 @@ StTooltip StLabel {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.single-view-controls {
 | 
			
		||||
    padding: 0px 15px;
 | 
			
		||||
    padding: 8px 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.workspace-controls {
 | 
			
		||||
    width: 24px;
 | 
			
		||||
    height: 16px;
 | 
			
		||||
    width: 48px;
 | 
			
		||||
    font-size: 32px;
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
    color: #ffffff;
 | 
			
		||||
    border: 2px solid rgba(128, 128, 128, 0.4);
 | 
			
		||||
    border-right: 0px;
 | 
			
		||||
    border-radius: 9px 0px 0px 9px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.workspace-controls.add {
 | 
			
		||||
    background-image: url("add-workspace.svg");
 | 
			
		||||
.add-workspace {
 | 
			
		||||
    background-color: rgba(128, 128, 128, 0.4);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.workspace-controls.remove {
 | 
			
		||||
    background-image: url("remove-workspace.svg");
 | 
			
		||||
.add-workspace:hover {
 | 
			
		||||
    background-color: rgba(128, 128, 128, 0.6);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.workspace-controls.switch-single {
 | 
			
		||||
    background-image: url("single-view.svg");
 | 
			
		||||
.remove-workspace {
 | 
			
		||||
    height: 48px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.workspace-controls.switch-mosaic {
 | 
			
		||||
    background-image: url("mosaic-view.svg");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.workspace-controls.switch-single:checked {
 | 
			
		||||
    background-image: url("single-view-active.svg");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.workspace-controls.switch-mosaic:checked {
 | 
			
		||||
    background-image: url("mosaic-view-active.svg");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#SwitchScroll {
 | 
			
		||||
    height: 14px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#SwitchScroll #hhandle {
 | 
			
		||||
    border-radius: 7px;
 | 
			
		||||
.remove-workspace:hover {
 | 
			
		||||
    background-color: rgba(128, 128, 128, 0.2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Dash */
 | 
			
		||||
@@ -404,115 +376,111 @@ StTooltip StLabel {
 | 
			
		||||
#dash {
 | 
			
		||||
    color: #5f5f5f;
 | 
			
		||||
    font-size: 12px;
 | 
			
		||||
    padding: 0px 14px;
 | 
			
		||||
    padding: 6px 0px;
 | 
			
		||||
    background-color: rgba(0, 0, 0, 0.5);
 | 
			
		||||
    border: 2px solid rgba(128, 128, 128, 0.4);
 | 
			
		||||
    border-left: 0px;
 | 
			
		||||
    border-radius: 0px 9px 9px 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#dashSections {
 | 
			
		||||
    spacing: 12px;
 | 
			
		||||
.dash-placeholder {
 | 
			
		||||
    background-image: url("dash-placeholder.svg");
 | 
			
		||||
    height: 27px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#viewSelector {
 | 
			
		||||
    spacing: 16px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#searchArea {
 | 
			
		||||
    padding: 0px 12px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#searchEntry {
 | 
			
		||||
    padding: 4px;
 | 
			
		||||
    border-radius: 4px;
 | 
			
		||||
    color: #a8a8a8;
 | 
			
		||||
    border: 1px solid #565656;
 | 
			
		||||
    background-color: #404040;
 | 
			
		||||
    caret-color: #fff;
 | 
			
		||||
    padding: 4px 8px;
 | 
			
		||||
    border-radius: 12px;
 | 
			
		||||
    color: rgb(128, 128, 128);
 | 
			
		||||
    border: 2px solid rgba(128, 128, 128, 0.4);
 | 
			
		||||
    background-gradient-start: rgba(0, 0, 0, 0.2);
 | 
			
		||||
    background-gradient-end: rgba(128, 128, 128, 0.2);
 | 
			
		||||
    background-gradient-direction: vertical;
 | 
			
		||||
    caret-color: rgb(128, 128, 128);
 | 
			
		||||
    caret-size: 1px;
 | 
			
		||||
    height: 16px;
 | 
			
		||||
    width: 250px;
 | 
			
		||||
    transition-duration: 300;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#searchEntry:focus {
 | 
			
		||||
    color: #545454;
 | 
			
		||||
    border: 1px solid #3a3a3a;
 | 
			
		||||
    background-color: #e8e8e8;
 | 
			
		||||
    caret-color: #545454;
 | 
			
		||||
    border: 2px solid #ffffff;
 | 
			
		||||
    background-gradient-start: rgba(0, 0, 0, 0.2);
 | 
			
		||||
    background-gradient-end: #ffffff;
 | 
			
		||||
    background-gradient-direction: vertical;
 | 
			
		||||
    color: rgb(64, 64, 64);
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
    -st-shadow: 0px 0px 6px 2px rgba(255,255,255,0.9);
 | 
			
		||||
    transition-duration: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#searchEntry:hover {
 | 
			
		||||
    color: #a8a8a8;
 | 
			
		||||
    border: 1px solid #4d4d4d;
 | 
			
		||||
    background-color: #e8e8e8;
 | 
			
		||||
    border: 2px solid #e8e8e8;
 | 
			
		||||
    caret-color: #545454;
 | 
			
		||||
    transition-duration: 500;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dash-section {
 | 
			
		||||
.view-tab-title {
 | 
			
		||||
    color: #888a85;
 | 
			
		||||
    font-weight: bold;
 | 
			
		||||
    padding: 0px 12px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.view-tab-title:selected {
 | 
			
		||||
    color: white;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.view-tab-boxpointer {
 | 
			
		||||
    -arrow-border-radius: 9px;
 | 
			
		||||
    -arrow-background-color: rgba(0,0,0,0.5);
 | 
			
		||||
    -arrow-border-width: 2px;
 | 
			
		||||
    -arrow-border-color: rgba(255,255,255,0.5);
 | 
			
		||||
    -arrow-base: 30px;
 | 
			
		||||
    -arrow-rise: 15px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#searchResults {
 | 
			
		||||
    padding: 20px 10px 10px 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#searchResultsContent {
 | 
			
		||||
    padding: 0 10px;
 | 
			
		||||
    spacing: 8px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.section-header {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.section-header-inner {
 | 
			
		||||
.search-statustext,
 | 
			
		||||
.search-section-header {
 | 
			
		||||
    padding: 4px 12px;
 | 
			
		||||
    spacing: 4px;
 | 
			
		||||
    color: #6f6f6f;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.section-text-content {
 | 
			
		||||
    padding: 4px 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dash-section-content {
 | 
			
		||||
    color: #ffffff;
 | 
			
		||||
    spacing: 8px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.more-link {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.more-link-expander {
 | 
			
		||||
    background-image: url("section-more.svg");
 | 
			
		||||
    width: 9px;
 | 
			
		||||
    height: 9px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.more-link-expander.open {
 | 
			
		||||
    background-image: url("section-more-open.svg");
 | 
			
		||||
    width: 9px;
 | 
			
		||||
    height: 9px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dash-pane {
 | 
			
		||||
.search-section {
 | 
			
		||||
    background-color: rgba(128, 128, 128, .1);
 | 
			
		||||
    border: 1px solid rgba(50, 50, 50, .4);
 | 
			
		||||
    border-radius: 10px;
 | 
			
		||||
    background-color: #111111;
 | 
			
		||||
    border: 2px solid #868686;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.search-section-results {
 | 
			
		||||
    color: #ffffff;
 | 
			
		||||
    padding: 30px 10px 10px 20px;
 | 
			
		||||
    border-radius: 10px;
 | 
			
		||||
    border: 1px solid rgba(50, 50, 50, .4);
 | 
			
		||||
    padding: 6px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#dashAppSearchResults {
 | 
			
		||||
    padding: 8px 0px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dash-search-statustext,
 | 
			
		||||
.dash-search-section-header {
 | 
			
		||||
    padding: 4px 0px;
 | 
			
		||||
.search-section-list-results {
 | 
			
		||||
    spacing: 4px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dash-search-section-results {
 | 
			
		||||
    color: #ffffff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dash-search-section-list-results {
 | 
			
		||||
    spacing: 4px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dash-search-result-content {
 | 
			
		||||
    padding: 3px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dash-search-result-content:selected {
 | 
			
		||||
    padding: 2px;
 | 
			
		||||
    border: 1px solid #5c5c5c;
 | 
			
		||||
    border-radius: 2px;
 | 
			
		||||
    background-color: #1e1e1e;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.dash-results-container {
 | 
			
		||||
.results-container {
 | 
			
		||||
    spacing: 4px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -564,10 +532,7 @@ StTooltip StLabel {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.all-app {
 | 
			
		||||
    border-radius: 10px;
 | 
			
		||||
    background-color: #111111;
 | 
			
		||||
    border: 2px solid #868686;
 | 
			
		||||
    color: #ffffff;
 | 
			
		||||
    padding: 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.app-section-divider-container {
 | 
			
		||||
@@ -580,46 +545,48 @@ StTooltip StLabel {
 | 
			
		||||
    background-image: url("separator-white.png");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.all-app-controls-panel {
 | 
			
		||||
    height: 30px;
 | 
			
		||||
#dash > .app-well-app {
 | 
			
		||||
    padding: 6px 12px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.all-app-scroll-view {
 | 
			
		||||
    padding-right: 10px;
 | 
			
		||||
    padding-left: 10px;
 | 
			
		||||
    padding-bottom: 10px;
 | 
			
		||||
.remove-favorite-icon {
 | 
			
		||||
    color: #a0a0a0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.app-well-app {
 | 
			
		||||
    border: 1px solid #181818;
 | 
			
		||||
.remove-favorite-icon:hover {
 | 
			
		||||
    color: white;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.app-well-app > .overview-icon,
 | 
			
		||||
.remove-favorite > .overview-icon,
 | 
			
		||||
.search-result-content > .overview-icon {
 | 
			
		||||
    border-radius: 4px;
 | 
			
		||||
    padding: 4px;
 | 
			
		||||
    width: 70px;
 | 
			
		||||
    height: 70px;
 | 
			
		||||
    font-size: 10px;
 | 
			
		||||
    color: white;
 | 
			
		||||
    transition-duration: 100;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.app-well-app.running {
 | 
			
		||||
    background-gradient-direction: vertical;
 | 
			
		||||
    background-gradient-start: #3d3d3d;
 | 
			
		||||
    background-gradient-end: #181818;
 | 
			
		||||
.app-well-app.running > .overview-icon {
 | 
			
		||||
    text-shadow: black 0px 2px 2px;
 | 
			
		||||
    background-image: url("running-indicator.svg");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.app-well-app.selected {
 | 
			
		||||
    border: 1px solid #666666;
 | 
			
		||||
.app-well-app:selected > .overview-icon,
 | 
			
		||||
.search-result-content:selected > .overview-icon {
 | 
			
		||||
    background: rgba(255,255,255,0.33);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.app-well-app:hover {
 | 
			
		||||
    border: 1px solid #666666;
 | 
			
		||||
    background-gradient-direction: vertical;
 | 
			
		||||
    background-gradient-start: rgba(61,61,61,0.8);
 | 
			
		||||
    background-gradient-end: rgba(24,24,24,0.2);
 | 
			
		||||
.app-well-app:hover > .overview-icon,
 | 
			
		||||
.remove-favorite:hover > .overview-icon,
 | 
			
		||||
.search-result-content:hover > .overview-icon {
 | 
			
		||||
    background: rgba(255,255,255,0.33);
 | 
			
		||||
    text-shadow: black 0px 2px 2px;
 | 
			
		||||
    transition-duration: 100;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.app-well-app:active {
 | 
			
		||||
.app-well-app:active > .overview-icon {
 | 
			
		||||
    background-color: #1e1e1e;
 | 
			
		||||
    border: 1px solid #5f5f5f;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										89
									
								
								data/theme/running-indicator.svg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								data/theme/running-indicator.svg
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,89 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
 | 
			
		||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
 | 
			
		||||
 | 
			
		||||
<svg
 | 
			
		||||
   xmlns:svg="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns="http://www.w3.org/2000/svg"
 | 
			
		||||
   xmlns:xlink="http://www.w3.org/1999/xlink"
 | 
			
		||||
   width="74.01342"
 | 
			
		||||
   height="74.006706"
 | 
			
		||||
   id="svg7355"
 | 
			
		||||
   version="1.1">
 | 
			
		||||
  <defs
 | 
			
		||||
     id="defs7357">
 | 
			
		||||
    <radialGradient
 | 
			
		||||
       xlink:href="#linearGradient36429"
 | 
			
		||||
       id="radialGradient7461"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       gradientTransform="matrix(1.0525552,0,0,1.0525552,-2.5162753,-9.0000838)"
 | 
			
		||||
       cx="47.878681"
 | 
			
		||||
       cy="171.25"
 | 
			
		||||
       fx="47.878681"
 | 
			
		||||
       fy="171.25"
 | 
			
		||||
       r="37" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       id="linearGradient36429">
 | 
			
		||||
      <stop
 | 
			
		||||
         id="stop36431"
 | 
			
		||||
         offset="0"
 | 
			
		||||
         style="stop-color:#ffffff;stop-opacity:1;" />
 | 
			
		||||
      <stop
 | 
			
		||||
         id="stop36433"
 | 
			
		||||
         offset="1"
 | 
			
		||||
         style="stop-color:#ffffff;stop-opacity:0;" />
 | 
			
		||||
    </linearGradient>
 | 
			
		||||
    <radialGradient
 | 
			
		||||
       xlink:href="#linearGradient36471"
 | 
			
		||||
       id="radialGradient7463"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       gradientTransform="matrix(1.1891549,0,0,0.55513246,-9.281289,36.12653)"
 | 
			
		||||
       cx="49.067139"
 | 
			
		||||
       cy="242.50381"
 | 
			
		||||
       fx="49.067139"
 | 
			
		||||
       fy="242.50381"
 | 
			
		||||
       r="37.00671" />
 | 
			
		||||
    <linearGradient
 | 
			
		||||
       id="linearGradient36471">
 | 
			
		||||
      <stop
 | 
			
		||||
         id="stop36473"
 | 
			
		||||
         offset="0"
 | 
			
		||||
         style="stop-color:#ffffff;stop-opacity:1;" />
 | 
			
		||||
      <stop
 | 
			
		||||
         id="stop36475"
 | 
			
		||||
         offset="1"
 | 
			
		||||
         style="stop-color:#ffffff;stop-opacity:0;" />
 | 
			
		||||
    </linearGradient>
 | 
			
		||||
    <radialGradient
 | 
			
		||||
       r="37.00671"
 | 
			
		||||
       fy="242.50381"
 | 
			
		||||
       fx="49.067139"
 | 
			
		||||
       cy="242.50381"
 | 
			
		||||
       cx="49.067139"
 | 
			
		||||
       gradientTransform="matrix(1.1891549,0,0,0.55513246,-9.281289,36.12653)"
 | 
			
		||||
       gradientUnits="userSpaceOnUse"
 | 
			
		||||
       id="radialGradient7488"
 | 
			
		||||
       xlink:href="#linearGradient36471" />
 | 
			
		||||
  </defs>
 | 
			
		||||
  <g
 | 
			
		||||
     id="layer1"
 | 
			
		||||
     transform="translate(-266.21629,-168.11809)">
 | 
			
		||||
    <g
 | 
			
		||||
       style="display:inline"
 | 
			
		||||
       id="g30864"
 | 
			
		||||
       transform="translate(255.223,70.118091)">
 | 
			
		||||
      <rect
 | 
			
		||||
         ry="3.5996203"
 | 
			
		||||
         rx="3.5996203"
 | 
			
		||||
         y="98"
 | 
			
		||||
         x="11"
 | 
			
		||||
         height="74"
 | 
			
		||||
         width="74"
 | 
			
		||||
         id="rect14000"
 | 
			
		||||
         style="opacity:0.371875;fill:url(#radialGradient7461);fill-opacity:1;stroke:none" />
 | 
			
		||||
      <path
 | 
			
		||||
         id="rect34520"
 | 
			
		||||
         d="m 84.506708,167.95508 c 6e-6,1.96759 -1.584022,3.55162 -3.551629,3.55163 l -65.910146,0 c -1.967608,-1e-5 -3.551648,-1.58402 -3.551643,-3.55164"
 | 
			
		||||
         style="opacity:0.2;fill:none;stroke:url(#radialGradient7488);stroke-width:1;stroke-opacity:1" />
 | 
			
		||||
    </g>
 | 
			
		||||
  </g>
 | 
			
		||||
</svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 2.6 KiB  | 
@@ -39,6 +39,7 @@ nobase_dist_js_DATA = 	\
 | 
			
		||||
	ui/runDialog.js		\
 | 
			
		||||
	ui/scripting.js		\
 | 
			
		||||
	ui/search.js		\
 | 
			
		||||
	ui/searchDisplay.js	\
 | 
			
		||||
	ui/shellDBus.js		\
 | 
			
		||||
	ui/statusIconDispatcher.js	\
 | 
			
		||||
	ui/statusMenu.js	\
 | 
			
		||||
@@ -47,6 +48,7 @@ nobase_dist_js_DATA = 	\
 | 
			
		||||
	ui/status/volume.js	\
 | 
			
		||||
	ui/telepathyClient.js	\
 | 
			
		||||
	ui/tweener.js		\
 | 
			
		||||
	ui/viewSelector.js	\
 | 
			
		||||
	ui/windowAttentionHandler.js	\
 | 
			
		||||
	ui/windowManager.js	\
 | 
			
		||||
	ui/workspace.js		\
 | 
			
		||||
 
 | 
			
		||||
@@ -272,7 +272,9 @@ const ChannelTextIface = {
 | 
			
		||||
    ],
 | 
			
		||||
    signals: [
 | 
			
		||||
        { name: 'Received',
 | 
			
		||||
          inSignature: 'uuuuus' }
 | 
			
		||||
          inSignature: 'uuuuus' },
 | 
			
		||||
        { name: 'Sent',
 | 
			
		||||
          inSignature: 'uus' }
 | 
			
		||||
    ]
 | 
			
		||||
};
 | 
			
		||||
let ChannelText = DBus.makeProxyClass(ChannelTextIface);
 | 
			
		||||
 
 | 
			
		||||
@@ -21,8 +21,6 @@ const Tweener = imports.ui.tweener;
 | 
			
		||||
const Workspace = imports.ui.workspace;
 | 
			
		||||
const Params = imports.misc.params;
 | 
			
		||||
 | 
			
		||||
const WELL_MAX_COLUMNS = 16;
 | 
			
		||||
const WELL_MAX_SEARCH_ROWS = 1;
 | 
			
		||||
const MENU_POPUP_TIMEOUT = 600;
 | 
			
		||||
 | 
			
		||||
function AlphabeticalView() {
 | 
			
		||||
@@ -148,22 +146,14 @@ AllAppDisplay.prototype = {
 | 
			
		||||
            Main.queueDeferredWork(this._workId);
 | 
			
		||||
        }));
 | 
			
		||||
 | 
			
		||||
        let bin = new St.BoxLayout({ style_class: 'all-app-controls-panel',
 | 
			
		||||
                                     reactive: true });
 | 
			
		||||
        this.actor = new St.BoxLayout({ style_class: 'all-app', vertical: true });
 | 
			
		||||
        this.actor.hide();
 | 
			
		||||
 | 
			
		||||
        let view = new St.ScrollView({ x_fill: true,
 | 
			
		||||
                                       y_fill: false,
 | 
			
		||||
                                       style_class: 'all-app-scroll-view',
 | 
			
		||||
                                       vshadows: true });
 | 
			
		||||
        this._scrollView = view;
 | 
			
		||||
        this.actor.add(bin);
 | 
			
		||||
        this.actor.add(view, { expand: true, y_fill: false, y_align: St.Align.START });
 | 
			
		||||
        this._scrollView = new St.ScrollView({ x_fill: true,
 | 
			
		||||
                                               y_fill: false,
 | 
			
		||||
                                               vshadows: true });
 | 
			
		||||
        this.actor = new St.Bin({ style_class: 'all-app',
 | 
			
		||||
                                  y_align: St.Align.START,
 | 
			
		||||
                                  child: this._scrollView });
 | 
			
		||||
 | 
			
		||||
        this._appView = new ViewByCategories();
 | 
			
		||||
        this._appView.connect('launching', Lang.bind(this, this.close));
 | 
			
		||||
        this._appView.connect('drag-begin', Lang.bind(this, this.close));
 | 
			
		||||
        this._scrollView.add_actor(this._appView.actor);
 | 
			
		||||
 | 
			
		||||
        this._scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
 | 
			
		||||
@@ -177,101 +167,10 @@ AllAppDisplay.prototype = {
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this._appView.refresh(apps);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    toggle: function() {
 | 
			
		||||
        if (this.actor.visible) {
 | 
			
		||||
            Tweener.addTween(this.actor,
 | 
			
		||||
                             { opacity: 0,
 | 
			
		||||
                               time: Overview.PANE_FADE_TIME,
 | 
			
		||||
                               transition: 'easeOutQuad',
 | 
			
		||||
                               onComplete: Lang.bind(this,
 | 
			
		||||
                                   function() {
 | 
			
		||||
                                       this.actor.hide();
 | 
			
		||||
                                       this.emit('open-state-changed',
 | 
			
		||||
                                                 this.actor.visible);
 | 
			
		||||
                                   })
 | 
			
		||||
                             });
 | 
			
		||||
        } else {
 | 
			
		||||
            this.actor.show();
 | 
			
		||||
            this.emit('open-state-changed', this.actor.visible);
 | 
			
		||||
            this.actor.opacity = 0;
 | 
			
		||||
            Tweener.addTween(this.actor,
 | 
			
		||||
                             { opacity: 255,
 | 
			
		||||
                               time: Overview.PANE_FADE_TIME,
 | 
			
		||||
                               transition: 'easeOutQuad'
 | 
			
		||||
                             });
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    close: function() {
 | 
			
		||||
        if (!this.actor.visible)
 | 
			
		||||
            return;
 | 
			
		||||
        this.toggle();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Signals.addSignalMethods(AllAppDisplay.prototype);
 | 
			
		||||
 | 
			
		||||
function AppSearchResultDisplay(provider) {
 | 
			
		||||
    this._init(provider);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AppSearchResultDisplay.prototype = {
 | 
			
		||||
    __proto__: Search.SearchResultDisplay.prototype,
 | 
			
		||||
 | 
			
		||||
    _init: function (provider) {
 | 
			
		||||
        Search.SearchResultDisplay.prototype._init.call(this, provider);
 | 
			
		||||
        this._grid = new IconGrid.IconGrid({ rowLimit: WELL_MAX_SEARCH_ROWS });
 | 
			
		||||
        this.actor = new St.Bin({ name: 'dashAppSearchResults',
 | 
			
		||||
                                  x_align: St.Align.START });
 | 
			
		||||
        this.actor.set_child(this._grid.actor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    renderResults: function(results, terms) {
 | 
			
		||||
        let appSys = Shell.AppSystem.get_default();
 | 
			
		||||
        let maxItems = WELL_MAX_SEARCH_ROWS * WELL_MAX_COLUMNS;
 | 
			
		||||
        for (let i = 0; i < results.length && i < maxItems; i++) {
 | 
			
		||||
            let result = results[i];
 | 
			
		||||
            let app = appSys.get_app(result);
 | 
			
		||||
            let display = new AppWellIcon(app);
 | 
			
		||||
            this._grid.addItem(display.actor);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    clear: function () {
 | 
			
		||||
        this._grid.removeAll();
 | 
			
		||||
        this.selectionIndex = -1;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getVisibleResultCount: function() {
 | 
			
		||||
        return this._grid.visibleItemsCount();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    selectIndex: function (index) {
 | 
			
		||||
        let nVisible = this.getVisibleResultCount();
 | 
			
		||||
        if (this.selectionIndex >= 0) {
 | 
			
		||||
            let prevActor = this._grid.getItemAtIndex(this.selectionIndex);
 | 
			
		||||
            prevActor._delegate.setSelected(false);
 | 
			
		||||
        }
 | 
			
		||||
        this.selectionIndex = -1;
 | 
			
		||||
        if (index >= nVisible)
 | 
			
		||||
            return false;
 | 
			
		||||
        else if (index < 0)
 | 
			
		||||
            return false;
 | 
			
		||||
        let targetActor = this._grid.getItemAtIndex(index);
 | 
			
		||||
        targetActor._delegate.setSelected(true);
 | 
			
		||||
        this.selectionIndex = index;
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    activateSelected: function() {
 | 
			
		||||
        if (this.selectionIndex < 0)
 | 
			
		||||
            return;
 | 
			
		||||
        let targetActor = this._grid.getItemAtIndex(this.selectionIndex);
 | 
			
		||||
        this.provider.activateResult(targetActor._delegate.app.get_id());
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function BaseAppSearchProvider() {
 | 
			
		||||
    this._init();
 | 
			
		||||
@@ -324,12 +223,10 @@ AppSearchProvider.prototype = {
 | 
			
		||||
        return this._appSys.subsearch(false, previousResults, terms);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    createResultContainerActor: function () {
 | 
			
		||||
        return new AppSearchResultDisplay(this);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    createResultActor: function (resultMeta, terms) {
 | 
			
		||||
        return new AppIcon(resultMeta.id);
 | 
			
		||||
        let app = this._appSys.get_app(resultMeta['id']);
 | 
			
		||||
        let icon = new AppWellIcon(app);
 | 
			
		||||
        return icon.actor;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    expandSearch: function(terms) {
 | 
			
		||||
@@ -375,7 +272,9 @@ AppIcon.prototype = {
 | 
			
		||||
 | 
			
		||||
        let label = this.app.get_name();
 | 
			
		||||
 | 
			
		||||
        IconGrid.BaseIcon.prototype._init.call(this, label);
 | 
			
		||||
        IconGrid.BaseIcon.prototype._init.call(this,
 | 
			
		||||
                                               label,
 | 
			
		||||
                                               { setSizeManually: true });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    createIcon: function(iconSize) {
 | 
			
		||||
@@ -396,8 +295,8 @@ AppWellIcon.prototype = {
 | 
			
		||||
                                         y_fill: true });
 | 
			
		||||
        this.actor._delegate = this;
 | 
			
		||||
 | 
			
		||||
        this._icon = new AppIcon(app);
 | 
			
		||||
        this.actor.set_child(this._icon.actor);
 | 
			
		||||
        this.icon = new AppIcon(app);
 | 
			
		||||
        this.actor.set_child(this.icon.actor);
 | 
			
		||||
 | 
			
		||||
        this.actor.connect('clicked', Lang.bind(this, this._onClicked));
 | 
			
		||||
 | 
			
		||||
@@ -526,14 +425,6 @@ AppWellIcon.prototype = {
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setSelected: function (isSelected) {
 | 
			
		||||
        this._selected = isSelected;
 | 
			
		||||
        if (this._selected)
 | 
			
		||||
            this.actor.add_style_class_name('selected');
 | 
			
		||||
        else
 | 
			
		||||
            this.actor.remove_style_class_name('selected');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onMenuPoppedUp: function() {
 | 
			
		||||
        if (this._getRunning()) {
 | 
			
		||||
            Main.overview.getWorkspacesForWindow(null).setApplicationWindowSelection(this.app.get_id());
 | 
			
		||||
@@ -581,13 +472,13 @@ AppWellIcon.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getDragActor: function() {
 | 
			
		||||
        return this.app.create_icon_texture(this._icon.iconSize);
 | 
			
		||||
        return this.app.create_icon_texture(this.icon.iconSize);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // Returns the original actor that should align with the actor
 | 
			
		||||
    // we show as the item is being dragged.
 | 
			
		||||
    getDragActorSource: function() {
 | 
			
		||||
        return this._icon.icon;
 | 
			
		||||
        return this.icon.icon;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
Signals.addSignalMethods(AppWellIcon.prototype);
 | 
			
		||||
@@ -756,135 +647,3 @@ AppIconMenu.prototype = {
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
Signals.addSignalMethods(AppIconMenu.prototype);
 | 
			
		||||
 | 
			
		||||
function AppWell() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AppWell.prototype = {
 | 
			
		||||
    _init : function() {
 | 
			
		||||
        this._placeholderText = null;
 | 
			
		||||
        this._menus = [];
 | 
			
		||||
        this._menuDisplays = [];
 | 
			
		||||
 | 
			
		||||
        this._favorites = [];
 | 
			
		||||
 | 
			
		||||
        this._grid = new IconGrid.IconGrid();
 | 
			
		||||
        this.actor = this._grid.actor;
 | 
			
		||||
        this.actor._delegate = this;
 | 
			
		||||
 | 
			
		||||
        this._workId = Main.initializeDeferredWork(this.actor, Lang.bind(this, this._redisplay));
 | 
			
		||||
 | 
			
		||||
        this._tracker = Shell.WindowTracker.get_default();
 | 
			
		||||
        this._appSystem = Shell.AppSystem.get_default();
 | 
			
		||||
 | 
			
		||||
        this._appSystem.connect('installed-changed', Lang.bind(this, this._queueRedisplay));
 | 
			
		||||
        AppFavorites.getAppFavorites().connect('changed', Lang.bind(this, this._queueRedisplay));
 | 
			
		||||
        this._tracker.connect('app-state-changed', Lang.bind(this, this._queueRedisplay));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _appIdListToHash: function(apps) {
 | 
			
		||||
        let ids = {};
 | 
			
		||||
        for (let i = 0; i < apps.length; i++)
 | 
			
		||||
            ids[apps[i].get_id()] = apps[i];
 | 
			
		||||
        return ids;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _queueRedisplay: function () {
 | 
			
		||||
        Main.queueDeferredWork(this._workId);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _redisplay: function () {
 | 
			
		||||
        this._grid.removeAll();
 | 
			
		||||
 | 
			
		||||
        let favorites = AppFavorites.getAppFavorites().getFavoriteMap();
 | 
			
		||||
 | 
			
		||||
        /* hardcode here pending some design about how exactly desktop contexts behave */
 | 
			
		||||
        let contextId = '';
 | 
			
		||||
 | 
			
		||||
        let running = this._tracker.get_running_apps(contextId);
 | 
			
		||||
        let runningIds = this._appIdListToHash(running);
 | 
			
		||||
 | 
			
		||||
        let nFavorites = 0;
 | 
			
		||||
        for (let id in favorites) {
 | 
			
		||||
            let app = favorites[id];
 | 
			
		||||
            let display = new AppWellIcon(app);
 | 
			
		||||
            this._grid.addItem(display.actor);
 | 
			
		||||
            nFavorites++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < running.length; i++) {
 | 
			
		||||
            let app = running[i];
 | 
			
		||||
            if (app.get_id() in favorites)
 | 
			
		||||
                continue;
 | 
			
		||||
            let display = new AppWellIcon(app);
 | 
			
		||||
            this._grid.addItem(display.actor);
 | 
			
		||||
        }
 | 
			
		||||
        if (this._placeholderText) {
 | 
			
		||||
            this._placeholderText.destroy();
 | 
			
		||||
            this._placeholderText = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (running.length == 0 && nFavorites == 0) {
 | 
			
		||||
            this._placeholderText = new St.Label({ text: _("Drag here to add favorites") });
 | 
			
		||||
            this.actor.add_actor(this._placeholderText);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    handleDragOver : function(source, actor, x, y, time) {
 | 
			
		||||
        let app = null;
 | 
			
		||||
        if (source instanceof AppWellIcon)
 | 
			
		||||
            app = this._appSystem.get_app(source.getId());
 | 
			
		||||
        else if (source instanceof Workspace.WindowClone)
 | 
			
		||||
            app = this._tracker.get_window_app(source.metaWindow);
 | 
			
		||||
 | 
			
		||||
        // Don't allow favoriting of transient apps
 | 
			
		||||
        if (app == null || app.is_transient())
 | 
			
		||||
            return DND.DragMotionResult.NO_DROP;
 | 
			
		||||
 | 
			
		||||
        let id = app.get_id();
 | 
			
		||||
 | 
			
		||||
        let favorites = AppFavorites.getAppFavorites().getFavoriteMap();
 | 
			
		||||
 | 
			
		||||
        let srcIsFavorite = (id in favorites);
 | 
			
		||||
 | 
			
		||||
        if (srcIsFavorite)
 | 
			
		||||
            return DND.DragMotionResult.NO_DROP;
 | 
			
		||||
 | 
			
		||||
        return DND.DragMotionResult.COPY_DROP;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // Draggable target interface
 | 
			
		||||
    acceptDrop : function(source, actor, x, y, time) {
 | 
			
		||||
        let app = null;
 | 
			
		||||
        if (source instanceof AppWellIcon) {
 | 
			
		||||
            app = this._appSystem.get_app(source.getId());
 | 
			
		||||
        } else if (source instanceof Workspace.WindowClone) {
 | 
			
		||||
            app = this._tracker.get_window_app(source.metaWindow);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Don't allow favoriting of transient apps
 | 
			
		||||
        if (app == null || app.is_transient()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let id = app.get_id();
 | 
			
		||||
 | 
			
		||||
        let favorites = AppFavorites.getAppFavorites().getFavoriteMap();
 | 
			
		||||
 | 
			
		||||
        let srcIsFavorite = (id in favorites);
 | 
			
		||||
 | 
			
		||||
        if (srcIsFavorite) {
 | 
			
		||||
            return false;
 | 
			
		||||
        } else {
 | 
			
		||||
            Mainloop.idle_add(Lang.bind(this, function () {
 | 
			
		||||
                AppFavorites.getAppFavorites().addFavorite(id);
 | 
			
		||||
                return false;
 | 
			
		||||
            }));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Signals.addSignalMethods(AppWell.prototype);
 | 
			
		||||
 
 | 
			
		||||
@@ -63,7 +63,7 @@ AppFavorites.prototype = {
 | 
			
		||||
        return appId in this._favorites;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _addFavorite: function(appId) {
 | 
			
		||||
    _addFavorite: function(appId, pos) {
 | 
			
		||||
        if (appId in this._favorites)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
@@ -73,23 +73,35 @@ AppFavorites.prototype = {
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        let ids = this._getIds();
 | 
			
		||||
        ids.push(appId);
 | 
			
		||||
        if (pos == -1)
 | 
			
		||||
            ids.push(appId);
 | 
			
		||||
        else
 | 
			
		||||
            ids.splice(pos, 0, appId);
 | 
			
		||||
        global.settings.set_strv(this.FAVORITE_APPS_KEY, ids);
 | 
			
		||||
        this._favorites[appId] = app;
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addFavorite: function(appId) {
 | 
			
		||||
        if (!this._addFavorite(appId))
 | 
			
		||||
    addFavoriteAtPos: function(appId, pos) {
 | 
			
		||||
        if (!this._addFavorite(appId, pos))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        let app = Shell.AppSystem.get_default().get_app(appId);
 | 
			
		||||
 | 
			
		||||
        Main.overview.infoBar.setMessage(_("%s has been added to your favorites.").format(app.get_name()), Lang.bind(this, function () {
 | 
			
		||||
        Main.overview.shellInfo.setMessage(_("%s has been added to your favorites.").format(app.get_name()), Lang.bind(this, function () {
 | 
			
		||||
            this._removeFavorite(appId);
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addFavorite: function(appId) {
 | 
			
		||||
        this.addFavoriteAtPos(appId, -1);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    moveFavoriteToPos: function(appId, pos) {
 | 
			
		||||
        this._removeFavorite(appId);
 | 
			
		||||
        this._addFavorite(appId, pos);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _removeFavorite: function(appId) {
 | 
			
		||||
        if (!appId in this._favorites)
 | 
			
		||||
            return false;
 | 
			
		||||
@@ -100,13 +112,16 @@ AppFavorites.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    removeFavorite: function(appId) {
 | 
			
		||||
        let ids = this._getIds();
 | 
			
		||||
        let pos = ids.indexOf(appId);
 | 
			
		||||
 | 
			
		||||
        let app = this._favorites[appId];
 | 
			
		||||
        if (!this._removeFavorite(appId))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        Main.overview.infoBar.setMessage(_("%s has been removed from your favorites.").format(app.get_name()),
 | 
			
		||||
        Main.overview.shellInfo.setMessage(_("%s has been removed from your favorites.").format(app.get_name()),
 | 
			
		||||
                                         Lang.bind(this, function () {
 | 
			
		||||
            this._addFavorite(appId);
 | 
			
		||||
            this._addFavorite(appId, pos);
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1148
									
								
								js/ui/dash.js
									
									
									
									
									
								
							
							
						
						
									
										1148
									
								
								js/ui/dash.js
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,6 +1,7 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Meta = imports.gi.Meta;
 | 
			
		||||
const Mainloop = imports.mainloop;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
@@ -8,104 +9,60 @@ const St = imports.gi.St;
 | 
			
		||||
const Gettext = imports.gettext.domain('gnome-shell');
 | 
			
		||||
const _ = Gettext.gettext;
 | 
			
		||||
 | 
			
		||||
const AppDisplay = imports.ui.appDisplay;
 | 
			
		||||
const Dash = imports.ui.dash;
 | 
			
		||||
const DocDisplay = imports.ui.docDisplay;
 | 
			
		||||
const GenericDisplay = imports.ui.genericDisplay;
 | 
			
		||||
const Lightbox = imports.ui.lightbox;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const MessageTray = imports.ui.messageTray;
 | 
			
		||||
const Panel = imports.ui.panel;
 | 
			
		||||
const Dash = imports.ui.dash;
 | 
			
		||||
const PlaceDisplay = imports.ui.placeDisplay;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
const ViewSelector = imports.ui.viewSelector;
 | 
			
		||||
const WorkspacesView = imports.ui.workspacesView;
 | 
			
		||||
 | 
			
		||||
// Time for initial animation going into Overview mode
 | 
			
		||||
const ANIMATION_TIME = 0.25;
 | 
			
		||||
 | 
			
		||||
// Time for pane menus to fade in/out
 | 
			
		||||
const PANE_FADE_TIME = 0.1;
 | 
			
		||||
// We split the screen vertically between the dash and the view selector.
 | 
			
		||||
const DASH_SPLIT_FRACTION = 0.1;
 | 
			
		||||
 | 
			
		||||
// We divide the screen into a grid of rows and columns, which we use
 | 
			
		||||
// to help us position the Overview components, such as the side panel
 | 
			
		||||
// that lists applications and documents, the workspaces display, and 
 | 
			
		||||
// the button for adding additional workspaces.
 | 
			
		||||
// In the regular mode, the side panel takes up one column on the left,
 | 
			
		||||
// and the workspaces display takes up the remaining columns.
 | 
			
		||||
// In the expanded side panel display mode, the side panel takes up two
 | 
			
		||||
// columns, and the workspaces display slides all the way to the right,
 | 
			
		||||
// being visible only in the last quarter of the right-most column.
 | 
			
		||||
// In the future, this mode will have more components, such as a display 
 | 
			
		||||
// of documents which were recently opened with a given application, which 
 | 
			
		||||
// will take up the remaining sections of the display.
 | 
			
		||||
const SHELL_INFO_HIDE_TIMEOUT = 10;
 | 
			
		||||
 | 
			
		||||
const WIDE_SCREEN_CUT_OFF_RATIO = 1.4;
 | 
			
		||||
// A common netbook resolution is 1024x600, which trips the widescreen
 | 
			
		||||
// ratio.  However that leaves way too few pixels for the dash.  So
 | 
			
		||||
// just treat this as a regular screen.
 | 
			
		||||
const WIDE_SCREEN_MINIMUM_HEIGHT = 768;
 | 
			
		||||
 | 
			
		||||
const COLUMNS_REGULAR_SCREEN = 4;
 | 
			
		||||
const ROWS_REGULAR_SCREEN = 8;
 | 
			
		||||
const COLUMNS_WIDE_SCREEN = 5;
 | 
			
		||||
const ROWS_WIDE_SCREEN = 10;
 | 
			
		||||
 | 
			
		||||
const DEFAULT_PADDING = 4;
 | 
			
		||||
 | 
			
		||||
// Padding around workspace grid / Spacing between Dash and Workspaces
 | 
			
		||||
const WORKSPACE_GRID_PADDING = 12;
 | 
			
		||||
 | 
			
		||||
const COLUMNS_FOR_WORKSPACES_REGULAR_SCREEN = 3;
 | 
			
		||||
const ROWS_FOR_WORKSPACES_REGULAR_SCREEN = 6;
 | 
			
		||||
 | 
			
		||||
const COLUMNS_FOR_WORKSPACES_WIDE_SCREEN = 4;
 | 
			
		||||
const ROWS_FOR_WORKSPACES_WIDE_SCREEN = 8;
 | 
			
		||||
 | 
			
		||||
// A multi-state; PENDING is used during animations
 | 
			
		||||
const STATE_ACTIVE = true;
 | 
			
		||||
const STATE_PENDING_INACTIVE = false;
 | 
			
		||||
const STATE_INACTIVE = false;
 | 
			
		||||
 | 
			
		||||
const SHADOW_COLOR = new Clutter.Color();
 | 
			
		||||
SHADOW_COLOR.from_pixel(0x00000033);
 | 
			
		||||
const TRANSPARENT_COLOR = new Clutter.Color();
 | 
			
		||||
TRANSPARENT_COLOR.from_pixel(0x00000000);
 | 
			
		||||
 | 
			
		||||
const SHADOW_WIDTH = 6;
 | 
			
		||||
 | 
			
		||||
const NUMBER_OF_SECTIONS_IN_SEARCH = 2;
 | 
			
		||||
 | 
			
		||||
const INFO_BAR_HIDE_TIMEOUT = 10;
 | 
			
		||||
 | 
			
		||||
let wideScreen = false;
 | 
			
		||||
let displayGridColumnWidth = null;
 | 
			
		||||
let displayGridRowHeight = null;
 | 
			
		||||
 | 
			
		||||
function InfoBar() {
 | 
			
		||||
function Source() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
InfoBar.prototype = {
 | 
			
		||||
Source.prototype = {
 | 
			
		||||
    __proto__:  MessageTray.Source.prototype,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this.actor = new St.Bin({ style_class: 'info-bar-panel',
 | 
			
		||||
                                  x_fill: true,
 | 
			
		||||
                                  y_fill: false });
 | 
			
		||||
        this._label = new St.Label();
 | 
			
		||||
        this._undo = new St.Button({ style_class: 'info-bar-link-button' });
 | 
			
		||||
        MessageTray.Source.prototype._init.call(this,
 | 
			
		||||
                                                "System Information");
 | 
			
		||||
        this._setSummaryIcon(this.createNotificationIcon());
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
        let bin = new St.Bin({ x_fill: false,
 | 
			
		||||
                               y_fill: false,
 | 
			
		||||
                               x_align: St.Align.MIDDLE,
 | 
			
		||||
                               y_align: St.Align.MIDDLE });
 | 
			
		||||
        this.actor.set_child(bin);
 | 
			
		||||
    createNotificationIcon: function() {
 | 
			
		||||
        return new St.Icon({ icon_name: 'info',
 | 
			
		||||
                             icon_type: St.IconType.FULLCOLOR,
 | 
			
		||||
                             icon_size: this.ICON_SIZE });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
        let box = new St.BoxLayout({ style_class: 'info-bar' });
 | 
			
		||||
        bin.set_child(box);
 | 
			
		||||
    _notificationClicked: function() {
 | 
			
		||||
        this.destroy();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function ShellInfo() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ShellInfo.prototype = {
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._source = null;
 | 
			
		||||
        this._timeoutId = 0;
 | 
			
		||||
 | 
			
		||||
        box.add(this._label, {'y-fill' : false, 'y-align' : St.Align.MIDDLE});
 | 
			
		||||
        box.add(this._undo);
 | 
			
		||||
 | 
			
		||||
        this.actor.set_opacity(0);
 | 
			
		||||
 | 
			
		||||
        this._undoCallback = null;
 | 
			
		||||
        this._undo.connect('clicked', Lang.bind(this, this._onUndoClicked));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onUndoClicked: function() {
 | 
			
		||||
@@ -114,27 +71,16 @@ InfoBar.prototype = {
 | 
			
		||||
 | 
			
		||||
        if (this._undoCallback)
 | 
			
		||||
            this._undoCallback();
 | 
			
		||||
        this.actor.set_opacity(0);
 | 
			
		||||
        this._undoCallback = null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _hideDone: function() {
 | 
			
		||||
        this._undoCallback = null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _hide: function() {
 | 
			
		||||
        Tweener.addTween(this.actor,
 | 
			
		||||
                         { opacity: 0,
 | 
			
		||||
                           transition: 'easeOutQuad',
 | 
			
		||||
                           time: ANIMATION_TIME,
 | 
			
		||||
                           onComplete: this._hideDone,
 | 
			
		||||
                           onCompleteScope: this
 | 
			
		||||
                         });
 | 
			
		||||
        if (this._source)
 | 
			
		||||
            this._source.destroy();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onTimeout: function() {
 | 
			
		||||
        this._timeoutId = 0;
 | 
			
		||||
        this._hide();
 | 
			
		||||
        if (this._source)
 | 
			
		||||
            this._source.destroy();
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -142,28 +88,33 @@ InfoBar.prototype = {
 | 
			
		||||
        if (this._timeoutId)
 | 
			
		||||
            Mainloop.source_remove(this._timeoutId);
 | 
			
		||||
 | 
			
		||||
        this._timeout = false;
 | 
			
		||||
        this._timeoutId = Mainloop.timeout_add_seconds(SHELL_INFO_HIDE_TIMEOUT,
 | 
			
		||||
                                                       Lang.bind(this, this._onTimeout));
 | 
			
		||||
 | 
			
		||||
        this._label.text = text;
 | 
			
		||||
        if (this._source == null) {
 | 
			
		||||
            this._source = new Source();
 | 
			
		||||
            this._source.connect('destroy', Lang.bind(this,
 | 
			
		||||
                function() {
 | 
			
		||||
                    this._source = null;
 | 
			
		||||
                }));
 | 
			
		||||
            Main.messageTray.add(this._source);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Tweener.addTween(this.actor,
 | 
			
		||||
                         { opacity: 255,
 | 
			
		||||
                           transition: 'easeOutQuad',
 | 
			
		||||
                           time: ANIMATION_TIME
 | 
			
		||||
                         });
 | 
			
		||||
 | 
			
		||||
        this._timeoutId = Mainloop.timeout_add_seconds(INFO_BAR_HIDE_TIMEOUT, Lang.bind(this, this._onTimeout));
 | 
			
		||||
 | 
			
		||||
        if (undoLabel)
 | 
			
		||||
            this._undo.label = undoLabel;
 | 
			
		||||
        let notification = this._source.notification;
 | 
			
		||||
        if (notification == null)
 | 
			
		||||
            notification = new MessageTray.Notification(this._source, text, null);
 | 
			
		||||
        else
 | 
			
		||||
            this._undo.label = _("Undo");
 | 
			
		||||
            notification.update(text, null, { clear: true });
 | 
			
		||||
 | 
			
		||||
        this._undoCallback = undoCallback;
 | 
			
		||||
        if (undoCallback)
 | 
			
		||||
            this._undo.show();
 | 
			
		||||
        else
 | 
			
		||||
            this._undo.hide();
 | 
			
		||||
        if (undoCallback) {
 | 
			
		||||
            notification.addButton('system-undo',
 | 
			
		||||
                                   undoLabel ? undoLabel : _("Undo"));
 | 
			
		||||
            notification.connect('action-invoked',
 | 
			
		||||
                                 Lang.bind(this, this._onUndoClicked));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._source.notify(notification);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -173,30 +124,37 @@ function Overview() {
 | 
			
		||||
 | 
			
		||||
Overview.prototype = {
 | 
			
		||||
    _init : function() {
 | 
			
		||||
        this._group = new St.Group({ style_class: 'overview' });
 | 
			
		||||
        this._desktopFade = new St.Bin();
 | 
			
		||||
        global.overlay_group.add_actor(this._desktopFade);
 | 
			
		||||
 | 
			
		||||
        // The actual global.background_actor is inside global.window_group,
 | 
			
		||||
        // which is hidden when displaying the overview, so we display a clone.
 | 
			
		||||
        this._background = new Clutter.Clone({ source: global.background_actor });
 | 
			
		||||
        this._background.hide();
 | 
			
		||||
        global.overlay_group.add_actor(this._background);
 | 
			
		||||
 | 
			
		||||
        this._spacing = 0;
 | 
			
		||||
 | 
			
		||||
        this._group = new St.Group({ name: 'overview' });
 | 
			
		||||
        this._group._delegate = this;
 | 
			
		||||
        this._group.connect('destroy', Lang.bind(this,
 | 
			
		||||
            function() {
 | 
			
		||||
                if (this._lightbox) {
 | 
			
		||||
                    this._lightbox.destroy();
 | 
			
		||||
                    this._lightbox = null;
 | 
			
		||||
        this._group.connect('style-changed',
 | 
			
		||||
            Lang.bind(this, function() {
 | 
			
		||||
                let node = this._group.get_theme_node();
 | 
			
		||||
                let spacing = node.get_length('spacing');
 | 
			
		||||
                if (spacing != this._spacing) {
 | 
			
		||||
                    this._spacing = spacing;
 | 
			
		||||
                    this.relayout();
 | 
			
		||||
                }
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
        this.infoBar = new InfoBar();
 | 
			
		||||
        this._group.add_actor(this.infoBar.actor);
 | 
			
		||||
        this.shellInfo = new ShellInfo();
 | 
			
		||||
 | 
			
		||||
        this._workspacesManager = null;
 | 
			
		||||
        this._lightbox = null;
 | 
			
		||||
        this._workspacesDisplay = null;
 | 
			
		||||
 | 
			
		||||
        this.visible = false;
 | 
			
		||||
        this.animationInProgress = false;
 | 
			
		||||
        this._hideInProgress = false;
 | 
			
		||||
 | 
			
		||||
        this._recalculateGridSizes();
 | 
			
		||||
 | 
			
		||||
        this._activeDisplayPane = null;
 | 
			
		||||
 | 
			
		||||
        // During transitions, we raise this to the top to avoid having the overview
 | 
			
		||||
        // area be reactive; it causes too many issues such as double clicks on
 | 
			
		||||
        // Dash elements, or mouseover handlers in the workspaces.
 | 
			
		||||
@@ -205,196 +163,87 @@ Overview.prototype = {
 | 
			
		||||
        this._group.add_actor(this._coverPane);
 | 
			
		||||
        this._coverPane.connect('event', Lang.bind(this, function (actor, event) { return true; }));
 | 
			
		||||
 | 
			
		||||
        // Similar to the cover pane but used for dialogs ("panes"); see the comments
 | 
			
		||||
        // in addPane below.
 | 
			
		||||
        this._transparentBackground = new Clutter.Rectangle({ opacity: 0,
 | 
			
		||||
                                                              reactive: true });
 | 
			
		||||
        this._group.add_actor(this._transparentBackground);
 | 
			
		||||
 | 
			
		||||
        // Background color for the Overview
 | 
			
		||||
        this._backOver = new St.Label();
 | 
			
		||||
        this._group.add_actor(this._backOver);
 | 
			
		||||
 | 
			
		||||
        this._group.hide();
 | 
			
		||||
        global.overlay_group.add_actor(this._group);
 | 
			
		||||
 | 
			
		||||
        this.viewSelector = new ViewSelector.ViewSelector();
 | 
			
		||||
        this._group.add_actor(this.viewSelector.actor);
 | 
			
		||||
 | 
			
		||||
        this._workspacesDisplay = new WorkspacesView.WorkspacesDisplay();
 | 
			
		||||
        this.viewSelector.addViewTab("Windows", this._workspacesDisplay.actor);
 | 
			
		||||
 | 
			
		||||
        let appView = new AppDisplay.AllAppDisplay();
 | 
			
		||||
        this.viewSelector.addViewTab("Applications", appView.actor);
 | 
			
		||||
 | 
			
		||||
        // Default search providers
 | 
			
		||||
        this.viewSelector.addSearchProvider(new AppDisplay.AppSearchProvider());
 | 
			
		||||
        this.viewSelector.addSearchProvider(new AppDisplay.PrefsSearchProvider());
 | 
			
		||||
        this.viewSelector.addSearchProvider(new PlaceDisplay.PlaceSearchProvider());
 | 
			
		||||
        this.viewSelector.addSearchProvider(new DocDisplay.DocSearchProvider());
 | 
			
		||||
        this.viewSelector.addSearchProvider(new WorkspacesView.WindowSearchProvider());
 | 
			
		||||
 | 
			
		||||
        // TODO - recalculate everything when desktop size changes
 | 
			
		||||
        this._dash = new Dash.Dash();
 | 
			
		||||
        this._group.add_actor(this._dash.actor);
 | 
			
		||||
 | 
			
		||||
        // Container to hold popup pane chrome.
 | 
			
		||||
        this._paneContainer = new St.BoxLayout({ style_class: 'overview-pane' });
 | 
			
		||||
        // Note here we explicitly don't set the paneContainer to be reactive yet; that's done
 | 
			
		||||
        // inside the notify::visible handler on panes.
 | 
			
		||||
        this._paneContainer.connect('button-release-event', Lang.bind(this, function(background) {
 | 
			
		||||
            this._activeDisplayPane.close();
 | 
			
		||||
            return true;
 | 
			
		||||
        }));
 | 
			
		||||
        this._group.add_actor(this._paneContainer);
 | 
			
		||||
 | 
			
		||||
        this._transparentBackground.lower_bottom();
 | 
			
		||||
        this._paneContainer.hide();
 | 
			
		||||
        this._dash.actor.add_constraint(this.viewSelector.constrainY);
 | 
			
		||||
        this._dash.actor.add_constraint(this.viewSelector.constrainHeight);
 | 
			
		||||
 | 
			
		||||
        this._coverPane.lower_bottom();
 | 
			
		||||
 | 
			
		||||
        this.workspaces = null;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onViewChanged: function() {
 | 
			
		||||
        if (!this.visible)
 | 
			
		||||
            return;
 | 
			
		||||
    _getDesktopClone: function() {
 | 
			
		||||
        let windows = global.get_window_actors().filter(function(w) {
 | 
			
		||||
            return w.meta_window.get_window_type() == Meta.WindowType.DESKTOP;
 | 
			
		||||
        });
 | 
			
		||||
        if (windows.length == 0)
 | 
			
		||||
            return null;
 | 
			
		||||
 | 
			
		||||
        this.workspaces = this._workspacesManager.workspacesView;
 | 
			
		||||
 | 
			
		||||
        // Show new workspacesView
 | 
			
		||||
        this._group.add_actor(this.workspaces.actor);
 | 
			
		||||
        this._workspacesBar.raise(this.workspaces.actor);
 | 
			
		||||
        this._dash.actor.raise(this.workspaces.actor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _recalculateGridSizes: function () {
 | 
			
		||||
        let primary = global.get_primary_monitor();
 | 
			
		||||
        wideScreen = (primary.width/primary.height > WIDE_SCREEN_CUT_OFF_RATIO) &&
 | 
			
		||||
                     (primary.height >= WIDE_SCREEN_MINIMUM_HEIGHT);
 | 
			
		||||
 | 
			
		||||
        // We divide the screen into an imaginary grid which helps us determine the layout of
 | 
			
		||||
        // different visual components.
 | 
			
		||||
        if (wideScreen) {
 | 
			
		||||
            displayGridColumnWidth = Math.floor(primary.width / COLUMNS_WIDE_SCREEN);
 | 
			
		||||
            displayGridRowHeight = Math.floor(primary.height / ROWS_WIDE_SCREEN);
 | 
			
		||||
        } else {
 | 
			
		||||
            displayGridColumnWidth = Math.floor(primary.width / COLUMNS_REGULAR_SCREEN);
 | 
			
		||||
            displayGridRowHeight = Math.floor(primary.height / ROWS_REGULAR_SCREEN);
 | 
			
		||||
        }
 | 
			
		||||
        let clone = new Clutter.Clone({ source: windows[0].get_texture() });
 | 
			
		||||
        clone.source.connect('destroy', Lang.bind(this, function() {
 | 
			
		||||
            clone.destroy();
 | 
			
		||||
        }));
 | 
			
		||||
        return clone;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    relayout: function () {
 | 
			
		||||
        let primary = global.get_primary_monitor();
 | 
			
		||||
        let rtl = (St.Widget.get_default_direction () == St.TextDirection.RTL);
 | 
			
		||||
 | 
			
		||||
        this._recalculateGridSizes();
 | 
			
		||||
        let contentY = Panel.PANEL_HEIGHT;
 | 
			
		||||
        let contentHeight = primary.height - contentY - Main.messageTray.actor.height;
 | 
			
		||||
 | 
			
		||||
        this._group.set_position(primary.x, primary.y);
 | 
			
		||||
        this._group.set_size(primary.width, primary.height);
 | 
			
		||||
 | 
			
		||||
        let contentY = Panel.PANEL_HEIGHT;
 | 
			
		||||
        let contentHeight = primary.height - contentY;
 | 
			
		||||
 | 
			
		||||
        this._coverPane.set_position(0, contentY);
 | 
			
		||||
        this._coverPane.set_size(primary.width, contentHeight);
 | 
			
		||||
 | 
			
		||||
        let workspaceColumnsUsed = wideScreen ? COLUMNS_FOR_WORKSPACES_WIDE_SCREEN : COLUMNS_FOR_WORKSPACES_REGULAR_SCREEN;
 | 
			
		||||
        let workspaceRowsUsed = wideScreen ? ROWS_FOR_WORKSPACES_WIDE_SCREEN : ROWS_FOR_WORKSPACES_REGULAR_SCREEN;
 | 
			
		||||
 | 
			
		||||
        this._workspacesWidth = displayGridColumnWidth * workspaceColumnsUsed
 | 
			
		||||
                                  - WORKSPACE_GRID_PADDING * 2;
 | 
			
		||||
        // We scale the vertical padding by (primary.height / primary.width)
 | 
			
		||||
        // so that the workspace preserves its aspect ratio.
 | 
			
		||||
        this._workspacesHeight = Math.floor(displayGridRowHeight * workspaceRowsUsed
 | 
			
		||||
                                   - WORKSPACE_GRID_PADDING * (primary.height / primary.width) * 2);
 | 
			
		||||
        let viewWidth = (1.0 - DASH_SPLIT_FRACTION) * primary.width - this._spacing;
 | 
			
		||||
        let viewHeight = contentHeight - 2 * this._spacing;
 | 
			
		||||
        let viewY = contentY + this._spacing;
 | 
			
		||||
        let viewX = rtl ? 0
 | 
			
		||||
                        : Math.floor(DASH_SPLIT_FRACTION * primary.width) + this._spacing;
 | 
			
		||||
 | 
			
		||||
        // Set the dash's x position - y is handled by a constraint
 | 
			
		||||
        let dashX;
 | 
			
		||||
        if (rtl) {
 | 
			
		||||
            this._workspacesX = WORKSPACE_GRID_PADDING;
 | 
			
		||||
            this._dash.actor.set_anchor_point_from_gravity(Clutter.Gravity.NORTH_EAST);
 | 
			
		||||
            dashX = primary.width;
 | 
			
		||||
        } else {
 | 
			
		||||
            this._workspacesX = displayGridColumnWidth + WORKSPACE_GRID_PADDING;
 | 
			
		||||
            dashX = 0;
 | 
			
		||||
        }
 | 
			
		||||
        this._workspacesY = Math.floor(displayGridRowHeight + WORKSPACE_GRID_PADDING * (primary.height / primary.width));
 | 
			
		||||
        this._dash.actor.set_x(dashX);
 | 
			
		||||
 | 
			
		||||
        if (rtl) {
 | 
			
		||||
            this._dash.actor.set_position(primary.width - displayGridColumnWidth, contentY);
 | 
			
		||||
        } else {
 | 
			
		||||
            this._dash.actor.set_position(0, contentY);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._dash.actor.set_size(displayGridColumnWidth, contentHeight);
 | 
			
		||||
        this._dash.searchArea.height = this._workspacesY - contentY;
 | 
			
		||||
        this._dash.sectionArea.height = this._workspacesHeight;
 | 
			
		||||
        this._dash.searchResults.actor.height = this._workspacesHeight;
 | 
			
		||||
 | 
			
		||||
        this.infoBar.actor.set_position(displayGridColumnWidth, Panel.PANEL_HEIGHT);
 | 
			
		||||
        this.infoBar.actor.set_size(primary.width - displayGridColumnWidth, this._workspacesY - Panel.PANEL_HEIGHT);
 | 
			
		||||
        this.infoBar.actor.raise_top();
 | 
			
		||||
 | 
			
		||||
        // place the 'Add Workspace' button in the bottom row of the grid
 | 
			
		||||
        this._workspacesBarX = this._workspacesX;
 | 
			
		||||
        this._workspacesBarWidth = this._workspacesWidth;
 | 
			
		||||
        this._workspacesBarY = primary.height - displayGridRowHeight;
 | 
			
		||||
 | 
			
		||||
        // The parent (this._group) is positioned at the top left of the primary monitor
 | 
			
		||||
        // while this._backOver occupies the entire screen.
 | 
			
		||||
        this._backOver.set_position(- primary.x, - primary.y);
 | 
			
		||||
        this._backOver.set_size(global.screen_width, global.screen_height);
 | 
			
		||||
 | 
			
		||||
        this._paneContainer.set_position(this._dash.actor.x + this._dash.actor.width + DEFAULT_PADDING,
 | 
			
		||||
                                         this._workspacesY);
 | 
			
		||||
        // Dynamic width
 | 
			
		||||
        this._paneContainer.height = this._workspacesHeight;
 | 
			
		||||
        if (rtl) {
 | 
			
		||||
            this._paneContainer.connect('notify::width', Lang.bind(this, function (paneContainer) {
 | 
			
		||||
                paneContainer.x = this._dash.actor.x - (DEFAULT_PADDING + paneContainer.width);
 | 
			
		||||
            }));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._transparentBackground.set_position(primary.x, primary.y);
 | 
			
		||||
        this._transparentBackground.set_size(primary.width, primary.height);
 | 
			
		||||
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addPane: function (pane, align) {
 | 
			
		||||
        pane.actor.height = .9 * this._workspacesHeight;
 | 
			
		||||
        this._paneContainer.add(pane.actor, { expand: true,
 | 
			
		||||
                                              y_fill: false,
 | 
			
		||||
                                              y_align: align });
 | 
			
		||||
        // When a pane is displayed, we raise the transparent background to the top
 | 
			
		||||
        // and connect to button-release-event on it, then raise the pane above that.
 | 
			
		||||
        // The idea here is that clicking anywhere outside the pane should close it.
 | 
			
		||||
        // When the active pane is closed, undo the effect.
 | 
			
		||||
        let backgroundEventId = null;
 | 
			
		||||
        pane.connect('open-state-changed', Lang.bind(this, function (pane, isOpen) {
 | 
			
		||||
            if (isOpen) {
 | 
			
		||||
                this._activeDisplayPane = pane;
 | 
			
		||||
                this._transparentBackground.raise_top();
 | 
			
		||||
                this._paneContainer.raise_top();
 | 
			
		||||
                this._paneContainer.show();
 | 
			
		||||
                this._paneReady = false;
 | 
			
		||||
                if (backgroundEventId != null)
 | 
			
		||||
                    this._transparentBackground.disconnect(backgroundEventId);
 | 
			
		||||
                backgroundEventId = this._transparentBackground.connect('captured-event', Lang.bind(this, function (actor, event) {
 | 
			
		||||
                    if (event.get_source() != this._transparentBackground)
 | 
			
		||||
                        return false;
 | 
			
		||||
                    if (event.type() == Clutter.EventType.BUTTON_PRESS)
 | 
			
		||||
                        this._paneReady = true;
 | 
			
		||||
                    if (event.type() == Clutter.EventType.BUTTON_RELEASE
 | 
			
		||||
                        && this._paneReady)
 | 
			
		||||
                        this._activeDisplayPane.close();
 | 
			
		||||
                    return true;
 | 
			
		||||
                }));
 | 
			
		||||
                if (!this._lightbox)
 | 
			
		||||
                    this._lightbox = new Lightbox.Lightbox(this._group,
 | 
			
		||||
                                                           { fadeTime: PANE_FADE_TIME });
 | 
			
		||||
                this._lightbox.show();
 | 
			
		||||
                this._lightbox.highlight(this._paneContainer);
 | 
			
		||||
            } else if (pane == this._activeDisplayPane) {
 | 
			
		||||
                this._activeDisplayPane = null;
 | 
			
		||||
                if (backgroundEventId != null) {
 | 
			
		||||
                    this._transparentBackground.disconnect(backgroundEventId);
 | 
			
		||||
                    backgroundEventId = null;
 | 
			
		||||
                }
 | 
			
		||||
                this._transparentBackground.lower_bottom();
 | 
			
		||||
                this._paneContainer.hide();
 | 
			
		||||
                this._lightbox.hide();
 | 
			
		||||
            }
 | 
			
		||||
        }));
 | 
			
		||||
        this.viewSelector.actor.set_position(viewX, viewY);
 | 
			
		||||
        this.viewSelector.actor.set_size(viewWidth, viewHeight);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    //// Public methods ////
 | 
			
		||||
 | 
			
		||||
    beginItemDrag: function(source) {
 | 
			
		||||
        // Close any active panes if @source is a GenericDisplayItem.
 | 
			
		||||
        // This allows the user to place the item on any workspace.
 | 
			
		||||
        if (source instanceof GenericDisplay.GenericDisplayItem)
 | 
			
		||||
            if (this._activeDisplayPane != null)
 | 
			
		||||
                this._activeDisplayPane.close();
 | 
			
		||||
        this.emit('item-drag-begin');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -402,6 +251,14 @@ Overview.prototype = {
 | 
			
		||||
        this.emit('item-drag-end');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    beginWindowDrag: function(source) {
 | 
			
		||||
        this.emit('window-drag-begin');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    endWindowDrag: function(source) {
 | 
			
		||||
        this.emit('window-drag-end');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // Returns the scale the Overview has when we just start zooming out
 | 
			
		||||
    // to overview mode. That is, when just the active workspace is showing.
 | 
			
		||||
    getZoomedInScale : function() {
 | 
			
		||||
@@ -419,49 +276,23 @@ Overview.prototype = {
 | 
			
		||||
 | 
			
		||||
    // Returns the current scale of the Overview.
 | 
			
		||||
    getScale : function() {
 | 
			
		||||
        return this._group.scaleX;
 | 
			
		||||
        return this.workspaces.actor.scaleX;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // Returns the current position of the Overview.
 | 
			
		||||
    getPosition : function() {
 | 
			
		||||
        return [this._group.x, this._group.y];
 | 
			
		||||
        return [this.workspaces.actor.x, this.workspaces.actor.y];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    show : function() {
 | 
			
		||||
        if (this.visible)
 | 
			
		||||
            return;
 | 
			
		||||
        if (!Main.pushModal(this._dash.actor))
 | 
			
		||||
        if (!Main.pushModal(this.viewSelector.actor))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this.visible = true;
 | 
			
		||||
        this.animationInProgress = true;
 | 
			
		||||
 | 
			
		||||
        this._dash.show();
 | 
			
		||||
 | 
			
		||||
        /* TODO: make this stuff dynamic */
 | 
			
		||||
        this._workspacesManager =
 | 
			
		||||
            new WorkspacesView.WorkspacesManager(this._workspacesWidth,
 | 
			
		||||
                                                 this._workspacesHeight,
 | 
			
		||||
                                                 this._workspacesX,
 | 
			
		||||
                                                 this._workspacesY);
 | 
			
		||||
        this._workspacesManager.connect('view-changed',
 | 
			
		||||
                                        Lang.bind(this, this._onViewChanged));
 | 
			
		||||
        this.workspaces = this._workspacesManager.workspacesView;
 | 
			
		||||
        this._group.add_actor(this.workspaces.actor);
 | 
			
		||||
 | 
			
		||||
        // The workspaces actor is as big as the screen, so we have to raise the dash above it
 | 
			
		||||
        // for drag and drop to work.  In the future we should fix the workspaces to not
 | 
			
		||||
        // be as big as the screen.
 | 
			
		||||
        this._dash.actor.raise(this.workspaces.actor);
 | 
			
		||||
 | 
			
		||||
        this._workspacesBar = this._workspacesManager.controlsBar.actor;
 | 
			
		||||
        this._workspacesBar.set_position(this._workspacesBarX,
 | 
			
		||||
                                         this._workspacesBarY);
 | 
			
		||||
        this._workspacesBar.width = this._workspacesBarWidth;
 | 
			
		||||
 | 
			
		||||
        this._group.add_actor(this._workspacesBar);
 | 
			
		||||
        this._workspacesBar.raise(this.workspaces.actor);
 | 
			
		||||
 | 
			
		||||
        // All the the actors in the window group are completely obscured,
 | 
			
		||||
        // hiding the group holding them while the Overview is displayed greatly
 | 
			
		||||
        // increases performance of the Overview especially when there are many
 | 
			
		||||
@@ -471,17 +302,38 @@ Overview.prototype = {
 | 
			
		||||
        // clones of them, this would obviously no longer be necessary.
 | 
			
		||||
        global.window_group.hide();
 | 
			
		||||
        this._group.show();
 | 
			
		||||
        this._background.show();
 | 
			
		||||
 | 
			
		||||
        // Create a zoom out effect. First scale the Overview group up and
 | 
			
		||||
        this.viewSelector.show();
 | 
			
		||||
        this._workspacesDisplay.show();
 | 
			
		||||
        this._dash.show();
 | 
			
		||||
 | 
			
		||||
        this.workspaces = this._workspacesDisplay.workspacesView;
 | 
			
		||||
        global.overlay_group.add_actor(this.workspaces.actor);
 | 
			
		||||
 | 
			
		||||
        if (!this._desktopFade.child)
 | 
			
		||||
            this._desktopFade.child = this._getDesktopClone();
 | 
			
		||||
 | 
			
		||||
        if (!this.workspaces.getActiveWorkspace().hasMaximizedWindows()) {
 | 
			
		||||
            this._desktopFade.opacity = 255;
 | 
			
		||||
            this._desktopFade.show();
 | 
			
		||||
            Tweener.addTween(this._desktopFade,
 | 
			
		||||
                             { opacity: 0,
 | 
			
		||||
                               time: ANIMATION_TIME,
 | 
			
		||||
                               transition: 'easeOutQuad'
 | 
			
		||||
                             });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Create a zoom out effect. First scale the workspaces view up and
 | 
			
		||||
        // position it so that the active workspace fills up the whole screen,
 | 
			
		||||
        // then transform the group to its normal dimensions and position.
 | 
			
		||||
        // then transform it to its normal dimensions and position.
 | 
			
		||||
        // The opposite transition is used in hide().
 | 
			
		||||
        this._group.scaleX = this._group.scaleY = this.getZoomedInScale();
 | 
			
		||||
        [this._group.x, this._group.y] = this.getZoomedInPosition();
 | 
			
		||||
        this.workspaces.actor.scaleX = this.workspaces.actor.scaleY = this.getZoomedInScale();
 | 
			
		||||
        [this.workspaces.actor.x, this.workspaces.actor.y] = this.getZoomedInPosition();
 | 
			
		||||
        let primary = global.get_primary_monitor();
 | 
			
		||||
        Tweener.addTween(this._group,
 | 
			
		||||
                         { x: primary.x,
 | 
			
		||||
                           y: primary.y,
 | 
			
		||||
        Tweener.addTween(this.workspaces.actor,
 | 
			
		||||
                         { x: primary.x - this._group.x,
 | 
			
		||||
                           y: primary.y - this._group.y,
 | 
			
		||||
                           scaleX: 1,
 | 
			
		||||
                           scaleY: 1,
 | 
			
		||||
                           transition: 'easeOutQuad',
 | 
			
		||||
@@ -490,9 +342,9 @@ Overview.prototype = {
 | 
			
		||||
                           onCompleteScope: this
 | 
			
		||||
                          });
 | 
			
		||||
 | 
			
		||||
        // Make Dash fade in so that it doesn't appear too big.
 | 
			
		||||
        this._dash.actor.opacity = 0;
 | 
			
		||||
        Tweener.addTween(this._dash.actor,
 | 
			
		||||
        // Make the other elements fade in.
 | 
			
		||||
        this._group.opacity = 0;
 | 
			
		||||
        Tweener.addTween(this._group,
 | 
			
		||||
                         { opacity: 255,
 | 
			
		||||
                           transition: 'easeOutQuad',
 | 
			
		||||
                           time: ANIMATION_TIME
 | 
			
		||||
@@ -508,16 +360,24 @@ Overview.prototype = {
 | 
			
		||||
 | 
			
		||||
        this.animationInProgress = true;
 | 
			
		||||
        this._hideInProgress = true;
 | 
			
		||||
        if (this._activeDisplayPane != null)
 | 
			
		||||
            this._activeDisplayPane.close();
 | 
			
		||||
 | 
			
		||||
        if (!this.workspaces.getActiveWorkspace().hasMaximizedWindows()) {
 | 
			
		||||
            this._desktopFade.opacity = 0;
 | 
			
		||||
            this._desktopFade.show();
 | 
			
		||||
            Tweener.addTween(this._desktopFade,
 | 
			
		||||
                             { opacity: 255,
 | 
			
		||||
                               time: ANIMATION_TIME,
 | 
			
		||||
                               transition: 'easeOutQuad' });
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.workspaces.hide();
 | 
			
		||||
 | 
			
		||||
        // Create a zoom in effect by transforming the Overview group so that
 | 
			
		||||
        // Create a zoom in effect by transforming the workspaces view so that
 | 
			
		||||
        // the active workspace fills up the whole screen. The opposite
 | 
			
		||||
        // transition is used in show().
 | 
			
		||||
        let scale = this.getZoomedInScale();
 | 
			
		||||
        let [posX, posY] = this.getZoomedInPosition();
 | 
			
		||||
        Tweener.addTween(this._group,
 | 
			
		||||
        Tweener.addTween(this.workspaces.actor,
 | 
			
		||||
                         { x: posX,
 | 
			
		||||
                           y: posY,
 | 
			
		||||
                           scaleX: scale,
 | 
			
		||||
@@ -528,8 +388,8 @@ Overview.prototype = {
 | 
			
		||||
                           onCompleteScope: this
 | 
			
		||||
                          });
 | 
			
		||||
 | 
			
		||||
        // Make Dash fade out so that it doesn't appear to big.
 | 
			
		||||
        Tweener.addTween(this._dash.actor,
 | 
			
		||||
        // Make other elements fade out.
 | 
			
		||||
        Tweener.addTween(this._group,
 | 
			
		||||
                         { opacity: 0,
 | 
			
		||||
                           transition: 'easeOutQuad',
 | 
			
		||||
                           time: ANIMATION_TIME
 | 
			
		||||
@@ -565,6 +425,7 @@ Overview.prototype = {
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this.animationInProgress = false;
 | 
			
		||||
        this._desktopFade.hide();
 | 
			
		||||
        this._coverPane.lower_bottom();
 | 
			
		||||
 | 
			
		||||
        this.emit('shown');
 | 
			
		||||
@@ -576,12 +437,12 @@ Overview.prototype = {
 | 
			
		||||
        this.workspaces.destroy();
 | 
			
		||||
        this.workspaces = null;
 | 
			
		||||
 | 
			
		||||
        this._workspacesBar.destroy();
 | 
			
		||||
        this._workspacesBar = null;
 | 
			
		||||
 | 
			
		||||
        this._workspacesManager = null;
 | 
			
		||||
 | 
			
		||||
        this._workspacesDisplay.hide();
 | 
			
		||||
        this.viewSelector.hide();
 | 
			
		||||
        this._dash.hide();
 | 
			
		||||
 | 
			
		||||
        this._desktopFade.hide();
 | 
			
		||||
        this._background.hide();
 | 
			
		||||
        this._group.hide();
 | 
			
		||||
 | 
			
		||||
        this.visible = false;
 | 
			
		||||
@@ -590,7 +451,7 @@ Overview.prototype = {
 | 
			
		||||
 | 
			
		||||
        this._coverPane.lower_bottom();
 | 
			
		||||
 | 
			
		||||
        Main.popModal(this._dash.actor);
 | 
			
		||||
        Main.popModal(this.viewSelector.actor);
 | 
			
		||||
        this.emit('hidden');
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -109,7 +109,7 @@ PlaceDeviceInfo.prototype = {
 | 
			
		||||
                this._mount.unmount_finish(res);
 | 
			
		||||
        } catch (e) {
 | 
			
		||||
            let message = _("Failed to unmount '%s'").format(o.get_name());
 | 
			
		||||
            Main.overview.infoBar.setMessage(message,
 | 
			
		||||
            Main.overview.shellInfo.setMessage(message,
 | 
			
		||||
                                             Lang.bind(this, this.remove),
 | 
			
		||||
                                             _("Retry"));
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,7 @@
 | 
			
		||||
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
 | 
			
		||||
const RESULT_ICON_SIZE = 24;
 | 
			
		||||
const RESULT_ICON_SIZE = 48;
 | 
			
		||||
 | 
			
		||||
// Not currently referenced by the search API, but
 | 
			
		||||
// this enumeration can be useful for provider
 | 
			
		||||
@@ -182,7 +182,7 @@ SearchProvider.prototype = {
 | 
			
		||||
     * implementation will show the icon next to the name.
 | 
			
		||||
     *
 | 
			
		||||
     * The actor should be an instance of St.Widget, with the style class
 | 
			
		||||
     * 'dash-search-result-content'.
 | 
			
		||||
     * 'search-result-content'.
 | 
			
		||||
     */
 | 
			
		||||
    createResultActor: function(resultMeta, terms) {
 | 
			
		||||
        return null;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										332
									
								
								js/ui/searchDisplay.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										332
									
								
								js/ui/searchDisplay.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,332 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Gettext = imports.gettext.domain('gnome-shell');
 | 
			
		||||
const _ = Gettext.gettext;
 | 
			
		||||
const Gtk = imports.gi.Gtk;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
 | 
			
		||||
const DND = imports.ui.dnd;
 | 
			
		||||
const IconGrid = imports.ui.iconGrid;
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const Search = imports.ui.search;
 | 
			
		||||
 | 
			
		||||
const MAX_SEARCH_RESULTS_ROWS = 2;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function SearchResult(provider, metaInfo, terms) {
 | 
			
		||||
    this._init(provider, metaInfo, terms);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SearchResult.prototype = {
 | 
			
		||||
    _init: function(provider, metaInfo, terms) {
 | 
			
		||||
        this.provider = provider;
 | 
			
		||||
        this.metaInfo = metaInfo;
 | 
			
		||||
        this.actor = new St.Clickable({ style_class: 'search-result',
 | 
			
		||||
                                        reactive: true,
 | 
			
		||||
                                        x_align: St.Align.START,
 | 
			
		||||
                                        y_fill: true });
 | 
			
		||||
        this.actor._delegate = this;
 | 
			
		||||
 | 
			
		||||
        let content = provider.createResultActor(metaInfo, terms);
 | 
			
		||||
        if (content == null) {
 | 
			
		||||
            content = new St.Bin({ style_class: 'search-result-content',
 | 
			
		||||
                                   reactive: true,
 | 
			
		||||
                                   track_hover: true });
 | 
			
		||||
            let icon = new IconGrid.BaseIcon(this.metaInfo['name'],
 | 
			
		||||
                                             { createIcon: Lang.bind(this, function(size) {
 | 
			
		||||
                                                 return this.metaInfo['icon'];
 | 
			
		||||
                                             })});
 | 
			
		||||
            content.set_child(icon.actor);
 | 
			
		||||
        }
 | 
			
		||||
        this._content = content;
 | 
			
		||||
        this.actor.set_child(content);
 | 
			
		||||
 | 
			
		||||
        this.actor.connect('clicked', Lang.bind(this, this._onResultClicked));
 | 
			
		||||
 | 
			
		||||
        let draggable = DND.makeDraggable(this.actor);
 | 
			
		||||
        draggable.connect('drag-begin',
 | 
			
		||||
                          Lang.bind(this, function() {
 | 
			
		||||
                              Main.overview.beginItemDrag(this);
 | 
			
		||||
                          }));
 | 
			
		||||
        draggable.connect('drag-end',
 | 
			
		||||
                          Lang.bind(this, function() {
 | 
			
		||||
                              Main.overview.endItemDrag(this);
 | 
			
		||||
                          }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setSelected: function(selected) {
 | 
			
		||||
        if (selected)
 | 
			
		||||
            this._content.add_style_pseudo_class('selected');
 | 
			
		||||
        else
 | 
			
		||||
            this._content.remove_style_pseudo_class('selected');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    activate: function() {
 | 
			
		||||
        this.provider.activateResult(this.metaInfo.id);
 | 
			
		||||
        Main.overview.toggle();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onResultClicked: function(actor, event) {
 | 
			
		||||
        this.activate();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getDragActorSource: function() {
 | 
			
		||||
        return this.metaInfo['icon'];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getDragActor: function(stageX, stageY) {
 | 
			
		||||
        return new Clutter.Clone({ source: this.metaInfo['icon'] });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    shellWorkspaceLaunch: function() {
 | 
			
		||||
        if (this.provider.dragActivateResult)
 | 
			
		||||
            this.provider.dragActivateResult(this.metaInfo.id);
 | 
			
		||||
        else
 | 
			
		||||
            this.provider.activateResult(this.metaInfo.id);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function GridSearchResults(provider) {
 | 
			
		||||
    this._init(provider);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GridSearchResults.prototype = {
 | 
			
		||||
    __proto__: Search.SearchResultDisplay.prototype,
 | 
			
		||||
 | 
			
		||||
    _init: function(provider) {
 | 
			
		||||
        Search.SearchResultDisplay.prototype._init.call(this, provider);
 | 
			
		||||
        this._grid = new IconGrid.IconGrid({ rowLimit: MAX_SEARCH_RESULTS_ROWS,
 | 
			
		||||
                                             xAlign: St.Align.START });
 | 
			
		||||
        this.actor = new St.Bin({ x_align: St.Align.START });
 | 
			
		||||
        this.actor.set_child(this._grid.actor);
 | 
			
		||||
        this.selectionIndex = -1;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getVisibleResultCount: function() {
 | 
			
		||||
        return this._grid.visibleItemsCount();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    renderResults: function(results, terms) {
 | 
			
		||||
        for (let i = 0; i < results.length; i++) {
 | 
			
		||||
            let result = results[i];
 | 
			
		||||
            let meta = this.provider.getResultMeta(result);
 | 
			
		||||
            let display = new SearchResult(this.provider, meta, terms);
 | 
			
		||||
            this._grid.addItem(display.actor);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    clear: function () {
 | 
			
		||||
        this._grid.removeAll();
 | 
			
		||||
        this.selectionIndex = -1;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    selectIndex: function (index) {
 | 
			
		||||
        let nVisible = this.getVisibleResultCount();
 | 
			
		||||
        if (this.selectionIndex >= 0) {
 | 
			
		||||
            let prevActor = this._grid.getItemAtIndex(this.selectionIndex);
 | 
			
		||||
            prevActor._delegate.setSelected(false);
 | 
			
		||||
        }
 | 
			
		||||
        this.selectionIndex = -1;
 | 
			
		||||
        if (index >= nVisible)
 | 
			
		||||
            return false;
 | 
			
		||||
        else if (index < 0)
 | 
			
		||||
            return false;
 | 
			
		||||
        let targetActor = this._grid.getItemAtIndex(index);
 | 
			
		||||
        targetActor._delegate.setSelected(true);
 | 
			
		||||
        this.selectionIndex = index;
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    activateSelected: function() {
 | 
			
		||||
        if (this.selectionIndex < 0)
 | 
			
		||||
            return;
 | 
			
		||||
        let targetActor = this._grid.getItemAtIndex(this.selectionIndex);
 | 
			
		||||
        targetActor._delegate.activate();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function SearchResults(searchSystem) {
 | 
			
		||||
    this._init(searchSystem);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SearchResults.prototype = {
 | 
			
		||||
    _init: function(searchSystem) {
 | 
			
		||||
        this._searchSystem = searchSystem;
 | 
			
		||||
 | 
			
		||||
        this.actor = new St.Bin({ name: 'searchResults',
 | 
			
		||||
                                  y_align: St.Align.START,
 | 
			
		||||
                                  x_align: St.Align.START,
 | 
			
		||||
                                  x_fill: true });
 | 
			
		||||
        this._content = new St.BoxLayout({ name: 'searchResultsContent',
 | 
			
		||||
                                           vertical: true });
 | 
			
		||||
 | 
			
		||||
        let scrollView = new St.ScrollView({ x_fill: true,
 | 
			
		||||
                                             y_fill: false,
 | 
			
		||||
                                             vshadows: true });
 | 
			
		||||
        scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
 | 
			
		||||
        scrollView.add_actor(this._content);
 | 
			
		||||
 | 
			
		||||
        this.actor.set_child(scrollView);
 | 
			
		||||
 | 
			
		||||
        this._statusText = new St.Label({ style_class: 'search-statustext' });
 | 
			
		||||
        this._content.add(this._statusText);
 | 
			
		||||
        this._selectedProvider = -1;
 | 
			
		||||
        this._providers = this._searchSystem.getProviders();
 | 
			
		||||
        this._providerMeta = [];
 | 
			
		||||
        for (let i = 0; i < this._providers.length; i++)
 | 
			
		||||
            this.createProviderMeta(this._providers[i]);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    createProviderMeta: function(provider) {
 | 
			
		||||
        let providerBox = new St.BoxLayout({ style_class: 'search-section',
 | 
			
		||||
                                             vertical: true });
 | 
			
		||||
        let titleButton = new St.Button({ style_class: 'search-section-header',
 | 
			
		||||
                                          reactive: true,
 | 
			
		||||
                                          x_fill: true,
 | 
			
		||||
                                          y_fill: true });
 | 
			
		||||
        titleButton.connect('clicked', Lang.bind(this, function () { this._onHeaderClicked(provider); }));
 | 
			
		||||
        providerBox.add(titleButton);
 | 
			
		||||
        let titleBox = new St.BoxLayout();
 | 
			
		||||
        titleButton.set_child(titleBox);
 | 
			
		||||
        let title = new St.Label({ text: provider.title });
 | 
			
		||||
        let count = new St.Label();
 | 
			
		||||
        titleBox.add(title, { expand: true });
 | 
			
		||||
        titleBox.add(count);
 | 
			
		||||
 | 
			
		||||
        let resultDisplayBin = new St.Bin({ style_class: 'search-section-results',
 | 
			
		||||
                                            x_fill: true,
 | 
			
		||||
                                            y_fill: true });
 | 
			
		||||
        providerBox.add(resultDisplayBin, { expand: true });
 | 
			
		||||
        let resultDisplay = provider.createResultContainerActor();
 | 
			
		||||
        if (resultDisplay == null) {
 | 
			
		||||
            resultDisplay = new GridSearchResults(provider);
 | 
			
		||||
        }
 | 
			
		||||
        resultDisplayBin.set_child(resultDisplay.actor);
 | 
			
		||||
 | 
			
		||||
        this._providerMeta.push({ actor: providerBox,
 | 
			
		||||
                                  resultDisplay: resultDisplay,
 | 
			
		||||
                                  count: count });
 | 
			
		||||
        this._content.add(providerBox);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _clearDisplay: function() {
 | 
			
		||||
        this._selectedProvider = -1;
 | 
			
		||||
        this._visibleResultsCount = 0;
 | 
			
		||||
        for (let i = 0; i < this._providerMeta.length; i++) {
 | 
			
		||||
            let meta = this._providerMeta[i];
 | 
			
		||||
            meta.resultDisplay.clear();
 | 
			
		||||
            meta.actor.hide();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    reset: function() {
 | 
			
		||||
        this._searchSystem.reset();
 | 
			
		||||
        this._statusText.hide();
 | 
			
		||||
        this._clearDisplay();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    startingSearch: function() {
 | 
			
		||||
        this.reset();
 | 
			
		||||
        this._statusText.set_text(_("Searching..."));
 | 
			
		||||
        this._statusText.show();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _metaForProvider: function(provider) {
 | 
			
		||||
        return this._providerMeta[this._providers.indexOf(provider)];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    updateSearch: function (searchString) {
 | 
			
		||||
        let results = this._searchSystem.updateSearch(searchString);
 | 
			
		||||
 | 
			
		||||
        this._clearDisplay();
 | 
			
		||||
 | 
			
		||||
        if (results.length == 0) {
 | 
			
		||||
            this._statusText.set_text(_("No matching results."));
 | 
			
		||||
            this._statusText.show();
 | 
			
		||||
            return true;
 | 
			
		||||
        } else {
 | 
			
		||||
            this._statusText.hide();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let terms = this._searchSystem.getTerms();
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < results.length; i++) {
 | 
			
		||||
            let [provider, providerResults] = results[i];
 | 
			
		||||
            let meta = this._metaForProvider(provider);
 | 
			
		||||
            meta.actor.show();
 | 
			
		||||
            meta.resultDisplay.renderResults(providerResults, terms);
 | 
			
		||||
            meta.count.set_text('' + providerResults.length);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.selectDown(false);
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onHeaderClicked: function(provider) {
 | 
			
		||||
        provider.expandSearch(this._searchSystem.getTerms());
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _modifyActorSelection: function(resultDisplay, up) {
 | 
			
		||||
        let success;
 | 
			
		||||
        let index = resultDisplay.getSelectionIndex();
 | 
			
		||||
        if (up && index == -1)
 | 
			
		||||
            index = resultDisplay.getVisibleResultCount() - 1;
 | 
			
		||||
        else if (up)
 | 
			
		||||
            index = index - 1;
 | 
			
		||||
        else
 | 
			
		||||
            index = index + 1;
 | 
			
		||||
        return resultDisplay.selectIndex(index);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    selectUp: function(recursing) {
 | 
			
		||||
        for (let i = this._selectedProvider; i >= 0; i--) {
 | 
			
		||||
            let meta = this._providerMeta[i];
 | 
			
		||||
            if (!meta.actor.visible)
 | 
			
		||||
                continue;
 | 
			
		||||
            let success = this._modifyActorSelection(meta.resultDisplay, true);
 | 
			
		||||
            if (success) {
 | 
			
		||||
                this._selectedProvider = i;
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (this._providerMeta.length > 0 && !recursing) {
 | 
			
		||||
            this._selectedProvider = this._providerMeta.length - 1;
 | 
			
		||||
            this.selectUp(true);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    selectDown: function(recursing) {
 | 
			
		||||
        let current = this._selectedProvider;
 | 
			
		||||
        if (current == -1)
 | 
			
		||||
            current = 0;
 | 
			
		||||
        for (let i = current; i < this._providerMeta.length; i++) {
 | 
			
		||||
            let meta = this._providerMeta[i];
 | 
			
		||||
            if (!meta.actor.visible)
 | 
			
		||||
                continue;
 | 
			
		||||
            let success = this._modifyActorSelection(meta.resultDisplay, false);
 | 
			
		||||
            if (success) {
 | 
			
		||||
                this._selectedProvider = i;
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (this._providerMeta.length > 0 && !recursing) {
 | 
			
		||||
            this._selectedProvider = 0;
 | 
			
		||||
            this.selectDown(true);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    activateSelected: function() {
 | 
			
		||||
        let current = this._selectedProvider;
 | 
			
		||||
        if (current < 0)
 | 
			
		||||
            return;
 | 
			
		||||
        let meta = this._providerMeta[current];
 | 
			
		||||
        let resultDisplay = meta.resultDisplay;
 | 
			
		||||
        resultDisplay.activateSelected();
 | 
			
		||||
        Main.overview.hide();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
@@ -469,11 +469,15 @@ Source.prototype = {
 | 
			
		||||
                }));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this._notification = undefined;
 | 
			
		||||
        this._sentMessages = [];
 | 
			
		||||
 | 
			
		||||
        // Since we only create sources when receiving a message, this
 | 
			
		||||
        // is a plausible default
 | 
			
		||||
        this._presence = Telepathy.ConnectionPresenceType.AVAILABLE;
 | 
			
		||||
 | 
			
		||||
        this._channelText = new Telepathy.ChannelText(DBus.session, connName, channelPath);
 | 
			
		||||
        this._sentId = this._channelText.connect('Sent', Lang.bind(this, this._messageSent));
 | 
			
		||||
        this._receivedId = this._channelText.connect('Received', Lang.bind(this, this._messageReceived));
 | 
			
		||||
 | 
			
		||||
        this._channelText.ListPendingMessagesRemote(false, Lang.bind(this, this._gotPendingMessages));
 | 
			
		||||
@@ -517,6 +521,7 @@ Source.prototype = {
 | 
			
		||||
    _channelClosed: function() {
 | 
			
		||||
        this._channel.disconnect(this._closedId);
 | 
			
		||||
        this._channelText.disconnect(this._receivedId);
 | 
			
		||||
        this._channelText.disconnect(this._sentId);
 | 
			
		||||
        this.destroy();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -524,17 +529,30 @@ Source.prototype = {
 | 
			
		||||
        if (!Main.messageTray.contains(this))
 | 
			
		||||
            Main.messageTray.add(this);
 | 
			
		||||
 | 
			
		||||
        if (!this._notification)
 | 
			
		||||
        if (!this._notification) {
 | 
			
		||||
            this._notification = new Notification(this);
 | 
			
		||||
            for (let i = 0; i < this._sentMessages.length; i ++)
 | 
			
		||||
                this._notification.appendMessage(this._sentMessages[i], false, true);
 | 
			
		||||
            this._sentMessages = [];
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _messageReceived: function(channel, id, timestamp, sender,
 | 
			
		||||
                               type, flags, text) {
 | 
			
		||||
        this._ensureNotification();
 | 
			
		||||
        this._notification.appendMessage(text);
 | 
			
		||||
        this._notification.appendMessage(text, false, false);
 | 
			
		||||
        this.notify(this._notification);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _messageSent: function(channel, timestamp, type, text) {
 | 
			
		||||
        if (this._notification) {
 | 
			
		||||
            this._notification.appendMessage(text, false, true);
 | 
			
		||||
            this.notify(this._notification);
 | 
			
		||||
        } else {
 | 
			
		||||
            this._sentMessages.push(text);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    respond: function(text) {
 | 
			
		||||
        this._channelText.SendRemote(Telepathy.ChannelTextMessageType.NORMAL, text);
 | 
			
		||||
    },
 | 
			
		||||
@@ -565,7 +583,7 @@ Source.prototype = {
 | 
			
		||||
            msg += ' <i>(' + GLib.markup_escape_text(message, -1) + ')</i>';
 | 
			
		||||
 | 
			
		||||
        this._ensureNotification();
 | 
			
		||||
        this._notification.appendMessage(msg, true);
 | 
			
		||||
        this._notification.appendMessage(msg, true, false);
 | 
			
		||||
        if (notify)
 | 
			
		||||
            this.notify(this._notification);
 | 
			
		||||
    }
 | 
			
		||||
@@ -588,12 +606,12 @@ Notification.prototype = {
 | 
			
		||||
        this._history = [];
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    appendMessage: function(text, asTitle) {
 | 
			
		||||
    appendMessage: function(text, asTitle, sent) {
 | 
			
		||||
        if (asTitle)
 | 
			
		||||
            this.update(text, null, { customContent: true });
 | 
			
		||||
        else
 | 
			
		||||
            this.update(this.source.title, text, { customContent: true });
 | 
			
		||||
        this._append(text, 'chat-received');
 | 
			
		||||
        this._append(text, sent ? 'chat-sent' : 'chat-received');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _append: function(text, style) {
 | 
			
		||||
@@ -635,7 +653,6 @@ Notification.prototype = {
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        this._responseEntry.set_text('');
 | 
			
		||||
        this._append(text, 'chat-sent');
 | 
			
		||||
        this.source.respond(text);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										628
									
								
								js/ui/viewSelector.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										628
									
								
								js/ui/viewSelector.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,628 @@
 | 
			
		||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
 | 
			
		||||
 | 
			
		||||
const Clutter = imports.gi.Clutter;
 | 
			
		||||
const Mainloop = imports.mainloop;
 | 
			
		||||
const Meta = imports.gi.Meta;
 | 
			
		||||
const Signals = imports.signals;
 | 
			
		||||
const Lang = imports.lang;
 | 
			
		||||
const Shell = imports.gi.Shell;
 | 
			
		||||
const St = imports.gi.St;
 | 
			
		||||
const Gettext = imports.gettext.domain('gnome-shell');
 | 
			
		||||
const _ = Gettext.gettext;
 | 
			
		||||
 | 
			
		||||
const Main = imports.ui.main;
 | 
			
		||||
const Search = imports.ui.search;
 | 
			
		||||
const SearchDisplay = imports.ui.searchDisplay;
 | 
			
		||||
const Tweener = imports.ui.tweener;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function SearchEntry() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SearchEntry.prototype = {
 | 
			
		||||
    _init : function() {
 | 
			
		||||
        this.actor = new St.Entry({ name: 'searchEntry',
 | 
			
		||||
                                    hint_text: _("Search your computer") });
 | 
			
		||||
        this.entry = this.actor.clutter_text;
 | 
			
		||||
 | 
			
		||||
        this.actor.clutter_text.connect('text-changed', Lang.bind(this,
 | 
			
		||||
            function() {
 | 
			
		||||
                if (this.isActive())
 | 
			
		||||
                    this.actor.set_secondary_icon_from_file(global.imagedir +
 | 
			
		||||
                                                            'close-black.svg');
 | 
			
		||||
                else
 | 
			
		||||
                    this.actor.set_secondary_icon_from_file(null);
 | 
			
		||||
            }));
 | 
			
		||||
        this.actor.connect('secondary-icon-clicked', Lang.bind(this,
 | 
			
		||||
            function() {
 | 
			
		||||
                this.reset();
 | 
			
		||||
            }));
 | 
			
		||||
        this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
 | 
			
		||||
 | 
			
		||||
        global.stage.connect('notify::key-focus', Lang.bind(this, this._updateCursorVisibility));
 | 
			
		||||
 | 
			
		||||
        this.pane = null;
 | 
			
		||||
 | 
			
		||||
        this._capturedEventId = 0;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateCursorVisibility: function() {
 | 
			
		||||
        let focus = global.stage.get_key_focus();
 | 
			
		||||
        if (focus == global.stage || focus == this.entry)
 | 
			
		||||
            this.entry.set_cursor_visible(true);
 | 
			
		||||
        else
 | 
			
		||||
            this.entry.set_cursor_visible(false);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    show: function() {
 | 
			
		||||
        if (this._capturedEventId == 0)
 | 
			
		||||
            this._capturedEventId = global.stage.connect('captured-event',
 | 
			
		||||
                                 Lang.bind(this, this._onCapturedEvent));
 | 
			
		||||
        this.entry.set_cursor_visible(true);
 | 
			
		||||
        this.entry.set_selection(0, 0);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    hide: function() {
 | 
			
		||||
        if (this._capturedEventId > 0) {
 | 
			
		||||
            global.stage.disconnect(this._capturedEventId);
 | 
			
		||||
            this._capturedEventId = 0;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    reset: function () {
 | 
			
		||||
        let [x, y, mask] = global.get_pointer();
 | 
			
		||||
        let actor = global.stage.get_actor_at_pos (Clutter.PickMode.REACTIVE,
 | 
			
		||||
                                                   x, y);
 | 
			
		||||
        // this.actor is never hovered directly, only its clutter_text and icon
 | 
			
		||||
        let hovered = this.actor == actor.get_parent();
 | 
			
		||||
 | 
			
		||||
        this.actor.set_hover(hovered);
 | 
			
		||||
 | 
			
		||||
        this.entry.text = '';
 | 
			
		||||
 | 
			
		||||
        // Return focus to the stage
 | 
			
		||||
        global.stage.set_key_focus(null);
 | 
			
		||||
 | 
			
		||||
        this.entry.set_cursor_visible(true);
 | 
			
		||||
        this.entry.set_selection(0, 0);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    getText: function () {
 | 
			
		||||
        return this.entry.get_text().replace(/^\s+/g, '').replace(/\s+$/g, '');
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // some search term has been entered
 | 
			
		||||
    isActive: function() {
 | 
			
		||||
        return this.actor.get_text() != '';
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // the entry does not show the hint
 | 
			
		||||
    _isActivated: function() {
 | 
			
		||||
        return this.entry.text == this.actor.get_text();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onCapturedEvent: function(actor, event) {
 | 
			
		||||
        let source = event.get_source();
 | 
			
		||||
        let panelEvent = source && Main.panel.actor.contains(source);
 | 
			
		||||
 | 
			
		||||
        switch (event.type()) {
 | 
			
		||||
            case Clutter.EventType.BUTTON_PRESS:
 | 
			
		||||
                // the user clicked outside after activating the entry, but
 | 
			
		||||
                // with no search term entered - cancel the search
 | 
			
		||||
                if (source != this.entry && this.entry.text == '') {
 | 
			
		||||
                    this.reset();
 | 
			
		||||
                    // allow only panel events to continue
 | 
			
		||||
                    return !panelEvent;
 | 
			
		||||
                }
 | 
			
		||||
                return false;
 | 
			
		||||
            case Clutter.EventType.KEY_PRESS:
 | 
			
		||||
                // If neither the stage nor our entry have key focus, some
 | 
			
		||||
                // "special" actor grabbed the focus (run dialog, looking
 | 
			
		||||
                // glass); we don't want to interfere with that
 | 
			
		||||
                let focus = global.stage.get_key_focus();
 | 
			
		||||
                if (focus != global.stage && focus != this.entry)
 | 
			
		||||
                    return false;
 | 
			
		||||
 | 
			
		||||
                let sym = event.get_key_symbol();
 | 
			
		||||
 | 
			
		||||
                // If we have an active search, Escape cancels it - if we
 | 
			
		||||
                // haven't, the key is ignored
 | 
			
		||||
                if (sym == Clutter.Escape)
 | 
			
		||||
                    if (this._isActivated()) {
 | 
			
		||||
                        this.reset();
 | 
			
		||||
                        return true;
 | 
			
		||||
                    } else {
 | 
			
		||||
                        return false;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                 // Ignore non-printable keys
 | 
			
		||||
                 if (!Clutter.keysym_to_unicode(sym))
 | 
			
		||||
                     return false;
 | 
			
		||||
 | 
			
		||||
                // Search started - move the key focus to the entry and
 | 
			
		||||
                // "repeat" the event
 | 
			
		||||
                if (!this._isActivated()) {
 | 
			
		||||
                    global.stage.set_key_focus(this.entry);
 | 
			
		||||
                    this.entry.event(event, false);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return false;
 | 
			
		||||
            default:
 | 
			
		||||
                // Suppress all other events outside the panel while the entry
 | 
			
		||||
                // is activated and no search has been entered - any click
 | 
			
		||||
                // outside the entry will cancel the search
 | 
			
		||||
                return (this.entry.text == '' && !panelEvent);
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onDestroy: function() {
 | 
			
		||||
        if (this._capturedEventId > 0) {
 | 
			
		||||
            global.stage.disconnect(this._capturedEventId);
 | 
			
		||||
            this._capturedEventId = 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
Signals.addSignalMethods(SearchEntry.prototype);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function BaseTab(titleActor, pageActor) {
 | 
			
		||||
    this._init(titleActor, pageActor);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BaseTab.prototype = {
 | 
			
		||||
    _init: function(titleActor, pageActor) {
 | 
			
		||||
        this.title = titleActor;
 | 
			
		||||
        this.page = new St.Bin({ child: pageActor,
 | 
			
		||||
                                 x_align: St.Align.START,
 | 
			
		||||
                                 y_align: St.Align.START,
 | 
			
		||||
                                 x_fill: true,
 | 
			
		||||
                                 y_fill: true,
 | 
			
		||||
                                 style_class: 'view-tab-page' });
 | 
			
		||||
 | 
			
		||||
        this.visible = false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    show: function() {
 | 
			
		||||
        this.visible = true;
 | 
			
		||||
        this.page.opacity = 0;
 | 
			
		||||
        this.page.show();
 | 
			
		||||
 | 
			
		||||
        Tweener.addTween(this.page,
 | 
			
		||||
                         { opacity: 255,
 | 
			
		||||
                           time: 0.1,
 | 
			
		||||
                           transition: 'easeOutQuad' });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    hide: function() {
 | 
			
		||||
        this.visible = false;
 | 
			
		||||
        Tweener.addTween(this.page,
 | 
			
		||||
                         { opacity: 0,
 | 
			
		||||
                           time: 0.1,
 | 
			
		||||
                           transition: 'easeOutQuad',
 | 
			
		||||
                           onComplete: Lang.bind(this,
 | 
			
		||||
                               function() {
 | 
			
		||||
                                   this.page.hide();
 | 
			
		||||
                               })
 | 
			
		||||
                         });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _activate: function() {
 | 
			
		||||
        this.emit('activated');
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
Signals.addSignalMethods(BaseTab.prototype);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function ViewTab(label, pageActor) {
 | 
			
		||||
    this._init(label, pageActor);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ViewTab.prototype = {
 | 
			
		||||
    __proto__: BaseTab.prototype,
 | 
			
		||||
 | 
			
		||||
    _init: function(label, pageActor) {
 | 
			
		||||
        let titleActor = new St.Button({ label: label,
 | 
			
		||||
                                         style_class: 'view-tab-title' });
 | 
			
		||||
        titleActor.connect('clicked', Lang.bind(this, this._activate));
 | 
			
		||||
 | 
			
		||||
        BaseTab.prototype._init.call(this, titleActor, pageActor);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function SearchTab() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SearchTab.prototype = {
 | 
			
		||||
    __proto__: BaseTab.prototype,
 | 
			
		||||
 | 
			
		||||
    _init: function() {
 | 
			
		||||
        this._searchActive = false;
 | 
			
		||||
        this._searchPending = false;
 | 
			
		||||
        this._keyPressId = 0;
 | 
			
		||||
        this._searchTimeoutId = 0;
 | 
			
		||||
 | 
			
		||||
        this._searchSystem = new Search.SearchSystem();
 | 
			
		||||
 | 
			
		||||
        this._searchEntry = new SearchEntry();
 | 
			
		||||
        this._searchResults = new SearchDisplay.SearchResults(this._searchSystem);
 | 
			
		||||
        BaseTab.prototype._init.call(this,
 | 
			
		||||
                                     this._searchEntry.actor,
 | 
			
		||||
                                     this._searchResults.actor);
 | 
			
		||||
        this._searchEntry.entry.connect('text-changed',
 | 
			
		||||
                                        Lang.bind(this, this._onTextChanged));
 | 
			
		||||
        this._searchEntry.entry.connect('activate', Lang.bind(this, function (se) {
 | 
			
		||||
            if (this._searchTimeoutId > 0) {
 | 
			
		||||
                Mainloop.source_remove(this._searchTimeoutId);
 | 
			
		||||
                this._doSearch();
 | 
			
		||||
            }
 | 
			
		||||
            this._searchResults.activateSelected();
 | 
			
		||||
            return true;
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    setFindAsYouType: function(enabled) {
 | 
			
		||||
        if (enabled)
 | 
			
		||||
            this._searchEntry.show();
 | 
			
		||||
        else
 | 
			
		||||
            this._searchEntry.hide();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    show: function() {
 | 
			
		||||
        BaseTab.prototype.show.call(this);
 | 
			
		||||
 | 
			
		||||
        if (this._keyPressId == 0)
 | 
			
		||||
            this._keyPressId = global.stage.connect('key-press-event',
 | 
			
		||||
                                                    Lang.bind(this, this._onKeyPress));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    hide: function() {
 | 
			
		||||
        BaseTab.prototype.hide.call(this);
 | 
			
		||||
 | 
			
		||||
        if (this._keyPressId > 0) {
 | 
			
		||||
            global.stage.disconnect(this._keyPressId);
 | 
			
		||||
            this._keyPressId = 0;
 | 
			
		||||
        }
 | 
			
		||||
        this._searchEntry.reset();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addSearchProvider: function(provider) {
 | 
			
		||||
        this._searchSystem.registerProvider(provider);
 | 
			
		||||
        this._searchResults.createProviderMeta(provider);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onTextChanged: function (se, prop) {
 | 
			
		||||
        let searchPreviouslyActive = this._searchActive;
 | 
			
		||||
        this._searchActive = this._searchEntry.isActive();
 | 
			
		||||
        this._searchPending = this._searchActive && !searchPreviouslyActive;
 | 
			
		||||
        if (this._searchPending) {
 | 
			
		||||
            this._searchResults.startingSearch();
 | 
			
		||||
        }
 | 
			
		||||
        if (this._searchActive) {
 | 
			
		||||
            this._activate();
 | 
			
		||||
        } else {
 | 
			
		||||
            this.emit('search-cancelled');
 | 
			
		||||
        }
 | 
			
		||||
        if (!this._searchActive) {
 | 
			
		||||
            if (this._searchTimeoutId > 0) {
 | 
			
		||||
                Mainloop.source_remove(this._searchTimeoutId);
 | 
			
		||||
                this._searchTimeoutId = 0;
 | 
			
		||||
            }
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        if (this._searchTimeoutId > 0)
 | 
			
		||||
            return;
 | 
			
		||||
        this._searchTimeoutId = Mainloop.timeout_add(150, Lang.bind(this, this._doSearch));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onKeyPress: function(stage, event) {
 | 
			
		||||
        // If neither the stage nor the search entry have key focus, some
 | 
			
		||||
        // "special" actor grabbed the focus (run dialog, looking glass);
 | 
			
		||||
        // we don't want to interfere with that
 | 
			
		||||
        let focus = stage.get_key_focus();
 | 
			
		||||
        if (focus != stage && focus != this._searchEntry.entry)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        let symbol = event.get_key_symbol();
 | 
			
		||||
        if (symbol == Clutter.Up) {
 | 
			
		||||
            if (!this._searchActive)
 | 
			
		||||
                return true;
 | 
			
		||||
            this._searchResults.selectUp(false);
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        } else if (symbol == Clutter.Down) {
 | 
			
		||||
            if (!this._searchActive)
 | 
			
		||||
                return true;
 | 
			
		||||
 | 
			
		||||
            this._searchResults.selectDown(false);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _doSearch: function () {
 | 
			
		||||
        this._searchTimeoutId = 0;
 | 
			
		||||
        let text = this._searchEntry.getText();
 | 
			
		||||
        this._searchResults.updateSearch(text);
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function ViewSelector() {
 | 
			
		||||
    this._init();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ViewSelector.prototype = {
 | 
			
		||||
    _init : function() {
 | 
			
		||||
        this.actor = new St.BoxLayout({ name: 'viewSelector',
 | 
			
		||||
                                        vertical: true });
 | 
			
		||||
 | 
			
		||||
        // The tab bar is located at the top of the view selector and
 | 
			
		||||
        // holds both "normal" tab labels and the search entry. The former
 | 
			
		||||
        // is left aligned, the latter right aligned - unless the text
 | 
			
		||||
        // direction is RTL, in which case the order is reversed.
 | 
			
		||||
        this._tabBar = new Shell.GenericContainer();
 | 
			
		||||
        this._tabBar.connect('get-preferred-width',
 | 
			
		||||
                             Lang.bind(this, this._getPreferredTabBarWidth));
 | 
			
		||||
        this._tabBar.connect('get-preferred-height',
 | 
			
		||||
                             Lang.bind(this, this._getPreferredTabBarHeight));
 | 
			
		||||
        this._tabBar.connect('allocate',
 | 
			
		||||
                             Lang.bind(this, this._allocateTabBar));
 | 
			
		||||
        this.actor.add(this._tabBar);
 | 
			
		||||
 | 
			
		||||
        // Box to hold "normal" tab labels
 | 
			
		||||
        this._tabBox = new St.BoxLayout({ name: 'viewSelectorTabBar' });
 | 
			
		||||
        this._tabBar.add_actor(this._tabBox);
 | 
			
		||||
 | 
			
		||||
        // The searchArea just holds the entry
 | 
			
		||||
        this._searchArea = new St.Bin({ name: 'searchArea' });
 | 
			
		||||
        this._tabBar.add_actor(this._searchArea);
 | 
			
		||||
 | 
			
		||||
        // The page area holds the tab pages. Every page is given the
 | 
			
		||||
        // area's full allocation, so that the pages would appear on top
 | 
			
		||||
        // of each other if the inactive ones weren't hidden.
 | 
			
		||||
        this._pageArea = new Shell.Stack();
 | 
			
		||||
        this.actor.add(this._pageArea, { x_fill: true,
 | 
			
		||||
                                         y_fill: true,
 | 
			
		||||
                                         expand: true });
 | 
			
		||||
 | 
			
		||||
        this._tabs = [];
 | 
			
		||||
        this._activeTab = null;
 | 
			
		||||
 | 
			
		||||
        this._searchTab = new SearchTab();
 | 
			
		||||
        this._searchArea.set_child(this._searchTab.title);
 | 
			
		||||
        this._addTab(this._searchTab);
 | 
			
		||||
 | 
			
		||||
        this._searchTab.connect('search-cancelled', Lang.bind(this,
 | 
			
		||||
            function() {
 | 
			
		||||
                this._switchTab(this._activeTab);
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
        this._keyPressId = 0;
 | 
			
		||||
        this._itemDragBeginId = 0;
 | 
			
		||||
        this._overviewHidingId = 0;
 | 
			
		||||
 | 
			
		||||
        // Public constraints which may be used to tie actors' height or
 | 
			
		||||
        // vertical position to the current tab's content; as the content's
 | 
			
		||||
        // height and position depend on the view selector's style properties
 | 
			
		||||
        // (e.g. font size, padding, spacing, ...) it would be extremely hard
 | 
			
		||||
        // and ugly to get these from the outside. While it would be possible
 | 
			
		||||
        // to use position and height properties directly, outside code would
 | 
			
		||||
        // need to ensure that the content is properly allocated before
 | 
			
		||||
        // accessing the properties.
 | 
			
		||||
        this.constrainY = new Clutter.BindConstraint({ source: this._pageArea,
 | 
			
		||||
                                                       coordinate: Clutter.BindCoordinate.Y });
 | 
			
		||||
        this.constrainHeight = new Clutter.BindConstraint({ source: this._pageArea,
 | 
			
		||||
                                                            coordinate: Clutter.BindCoordinate.HEIGHT });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _addTab: function(tab) {
 | 
			
		||||
        tab.page.hide();
 | 
			
		||||
        this._pageArea.add_actor(tab.page);
 | 
			
		||||
        tab.connect('activated', Lang.bind(this, function(tab) {
 | 
			
		||||
            this._switchTab(tab);
 | 
			
		||||
        }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addViewTab: function(title, pageActor) {
 | 
			
		||||
        let viewTab = new ViewTab(title, pageActor);
 | 
			
		||||
        this._tabs.push(viewTab);
 | 
			
		||||
        this._tabBox.add(viewTab.title);
 | 
			
		||||
        this._addTab(viewTab);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _switchTab: function(tab) {
 | 
			
		||||
        if (this._activeTab && this._activeTab.visible) {
 | 
			
		||||
            if (this._activeTab == tab)
 | 
			
		||||
                return;
 | 
			
		||||
            this._activeTab.title.remove_style_pseudo_class('selected');
 | 
			
		||||
            this._activeTab.hide();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (tab != this._searchTab) {
 | 
			
		||||
            tab.title.add_style_pseudo_class('selected');
 | 
			
		||||
            this._activeTab = tab;
 | 
			
		||||
            if (this._searchTab.visible) {
 | 
			
		||||
                this._searchTab.hide();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!tab.visible)
 | 
			
		||||
            tab.show();
 | 
			
		||||
 | 
			
		||||
        // Pull a Meg Ryan:
 | 
			
		||||
        if (Main.overview && Main.overview.workspaces) {
 | 
			
		||||
            if (tab != this._tabs[0]) {
 | 
			
		||||
                Tweener.addTween(Main.overview.workspaces.actor,
 | 
			
		||||
                                 { opacity: 0,
 | 
			
		||||
                                   time: 0.1,
 | 
			
		||||
                                   transition: 'easeOutQuad',
 | 
			
		||||
                                   onComplete: Lang.bind(this,
 | 
			
		||||
                                       function() {
 | 
			
		||||
                                           Main.overview.workspaces.actor.hide();
 | 
			
		||||
                                           Main.overview.workspaces.actor.opacity = 255;
 | 
			
		||||
                                       })
 | 
			
		||||
                                });
 | 
			
		||||
            } else {
 | 
			
		||||
                Main.overview.workspaces.actor.opacity = 0;
 | 
			
		||||
                Main.overview.workspaces.actor.show();
 | 
			
		||||
                Tweener.addTween(Main.overview.workspaces.actor,
 | 
			
		||||
                                 { opacity: 255,
 | 
			
		||||
                                   time: 0.1,
 | 
			
		||||
                                   transition: 'easeOutQuad' });
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _switchDefaultTab: function() {
 | 
			
		||||
        if (this._tabs.length > 0)
 | 
			
		||||
            this._switchTab(this._tabs[0]);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _nextTab: function() {
 | 
			
		||||
        if (this._tabs.length == 0 ||
 | 
			
		||||
            this._tabs[this._tabs.length - 1] == this._activeTab)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < this._tabs.length; i++)
 | 
			
		||||
            if (this._tabs[i] == this._activeTab) {
 | 
			
		||||
                this._switchTab(this._tabs[i + 1]);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _prevTab: function() {
 | 
			
		||||
        if (this._tabs.length == 0 || this._tabs[0] == this._activeTab)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        for (let i = 0; i < this._tabs.length; i++)
 | 
			
		||||
            if (this._tabs[i] == this._activeTab) {
 | 
			
		||||
                this._switchTab(this._tabs[i - 1]);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getPreferredTabBarWidth: function(box, forHeight, alloc) {
 | 
			
		||||
        let children = box.get_children();
 | 
			
		||||
        for (let i = 0; i < children.length; i++) {
 | 
			
		||||
            let [childMin, childNat] = children[i].get_preferred_width(forHeight);
 | 
			
		||||
            alloc.min_size += childMin;
 | 
			
		||||
            alloc.natural_size += childNat;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _getPreferredTabBarHeight: function(box, forWidth, alloc) {
 | 
			
		||||
        let children = box.get_children();
 | 
			
		||||
        for (let i = 0; i < children.length; i++) {
 | 
			
		||||
            let [childMin, childNatural] = children[i].get_preferred_height(forWidth);
 | 
			
		||||
            if (childMin > alloc.min_size)
 | 
			
		||||
                alloc.min_size = childMin;
 | 
			
		||||
            if (childNatural > alloc.natural_size)
 | 
			
		||||
                alloc.natural_size = childNatural;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _allocateTabBar: function(container, box, flags) {
 | 
			
		||||
        let allocWidth = box.x2 - box.x1;
 | 
			
		||||
        let allocHeight = box.y2 - box.y1;
 | 
			
		||||
 | 
			
		||||
        let [searchMinWidth, searchNatWidth] = this._searchArea.get_preferred_width(-1);
 | 
			
		||||
        let [barMinWidth, barNatWidth] = this._tabBox.get_preferred_width(-1);
 | 
			
		||||
        let childBox = new Clutter.ActorBox();
 | 
			
		||||
        childBox.y1 = 0;
 | 
			
		||||
        childBox.y2 = allocHeight;
 | 
			
		||||
        if (this.actor.get_direction() == St.TextDirection.RTL) {
 | 
			
		||||
            childBox.x1 = allocWidth - barNatWidth;
 | 
			
		||||
            childBox.x2 = allocWidth;
 | 
			
		||||
        } else {
 | 
			
		||||
            childBox.x1 = 0;
 | 
			
		||||
            childBox.x2 = barNatWidth;
 | 
			
		||||
        }
 | 
			
		||||
        this._tabBox.allocate(childBox, flags);
 | 
			
		||||
 | 
			
		||||
        if (this.actor.get_direction() == St.TextDirection.RTL) {
 | 
			
		||||
            childBox.x1 = 0;
 | 
			
		||||
            childBox.x2 = searchNatWidth;
 | 
			
		||||
        } else {
 | 
			
		||||
            childBox.x1 = allocWidth - searchNatWidth;
 | 
			
		||||
            childBox.x2 = allocWidth;
 | 
			
		||||
        }
 | 
			
		||||
        this._searchArea.allocate(childBox, flags);
 | 
			
		||||
 | 
			
		||||
        Meta.later_add(Meta.LaterType.BEFORE_REDRAW, Lang.bind(this,
 | 
			
		||||
            function() {
 | 
			
		||||
                this.constrainY.offset = this.actor.y;
 | 
			
		||||
            }));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onKeyPress: function(stage, event) {
 | 
			
		||||
        // Only process events if the stage has key focus - search is handled
 | 
			
		||||
        // by the search tab, and we do not want to interfere with "special"
 | 
			
		||||
        // actors grabbing focus (run dialog, looking glass, notifications).
 | 
			
		||||
        let focus = stage.get_key_focus();
 | 
			
		||||
        if (focus != stage)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        let modifiers = Shell.get_event_state(event);
 | 
			
		||||
        let symbol = event.get_key_symbol();
 | 
			
		||||
        if (symbol == Clutter.Escape) {
 | 
			
		||||
            Main.overview.hide();
 | 
			
		||||
            return true;
 | 
			
		||||
        } else if (modifiers & Clutter.ModifierType.CONTROL_MASK) {
 | 
			
		||||
            if (symbol == Clutter.Page_Up) {
 | 
			
		||||
                if (!this._searchActive)
 | 
			
		||||
                    this._prevTab();
 | 
			
		||||
                return true;
 | 
			
		||||
            } else if (symbol == Clutter.Page_Down) {
 | 
			
		||||
                if (!this._searchActive)
 | 
			
		||||
                    this._nextTab();
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    addSearchProvider: function(provider) {
 | 
			
		||||
        this._searchTab.addSearchProvider(provider);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    show: function() {
 | 
			
		||||
        this._searchTab.setFindAsYouType(true);
 | 
			
		||||
 | 
			
		||||
        if (this._itemDragBeginId == 0)
 | 
			
		||||
            this._itemDragBeginId = Main.overview.connect('item-drag-begin',
 | 
			
		||||
                                                          Lang.bind(this, this._switchDefaultTab));
 | 
			
		||||
        if (this._overviewHidingId == 0)
 | 
			
		||||
            this._overviewHidingId = Main.overview.connect('hiding',
 | 
			
		||||
                                                           Lang.bind(this, this._switchDefaultTab));
 | 
			
		||||
        if (this._keyPressId == 0)
 | 
			
		||||
            this._keyPressId = global.stage.connect('key-press-event',
 | 
			
		||||
                                                    Lang.bind(this, this._onKeyPress));
 | 
			
		||||
 | 
			
		||||
        this._switchDefaultTab();
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    hide: function() {
 | 
			
		||||
        this._searchTab.setFindAsYouType(false);
 | 
			
		||||
 | 
			
		||||
        if (this._keyPressId > 0) {
 | 
			
		||||
            global.stage.disconnect(this._keyPressId);
 | 
			
		||||
            this._keyPressId = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this._itemDragBeginId > 0) {
 | 
			
		||||
            Main.overview.disconnect(this._itemDragBeginId);
 | 
			
		||||
            this._itemDragBeginId = 0;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (this._overviewHidingId > 0) {
 | 
			
		||||
            Main.overview.disconnect(this._overviewHidingId);
 | 
			
		||||
            this._overviewHidingId = 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
Signals.addSignalMethods(ViewSelector.prototype);
 | 
			
		||||
@@ -20,9 +20,6 @@ const FOCUS_ANIMATION_TIME = 0.15;
 | 
			
		||||
 | 
			
		||||
const WINDOW_DND_SIZE = 256;
 | 
			
		||||
 | 
			
		||||
const FRAME_COLOR = new Clutter.Color();
 | 
			
		||||
FRAME_COLOR.from_pixel(0xffffffff);
 | 
			
		||||
 | 
			
		||||
const SCROLL_SCALE_AMOUNT = 100 / 5;
 | 
			
		||||
 | 
			
		||||
const LIGHTBOX_FADE_TIME = 0.1;
 | 
			
		||||
@@ -54,11 +51,6 @@ function _clamp(value, min, max) {
 | 
			
		||||
    return Math.max(min, Math.min(max, value));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Spacing between workspaces. At the moment, the same spacing is used
 | 
			
		||||
// in both zoomed-in and zoomed-out views; this is slightly
 | 
			
		||||
// metaphor-breaking, but the alternatives are also weird.
 | 
			
		||||
const GRID_SPACING = 15;
 | 
			
		||||
const FRAME_SIZE = GRID_SPACING / 3;
 | 
			
		||||
 | 
			
		||||
function ScaledPoint(x, y, scaleX, scaleY) {
 | 
			
		||||
    [this.x, this.y, this.scaleX, this.scaleY] = arguments;
 | 
			
		||||
@@ -289,76 +281,9 @@ WindowClone.prototype = {
 | 
			
		||||
        this.emit('drag-end');
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Signals.addSignalMethods(WindowClone.prototype);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function DesktopClone(window) {
 | 
			
		||||
    this._init(window);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
DesktopClone.prototype = {
 | 
			
		||||
    _init : function(window) {
 | 
			
		||||
        this.actor = new Clutter.Group({ reactive: true });
 | 
			
		||||
 | 
			
		||||
        let background = new Clutter.Clone({ source: global.background_actor });
 | 
			
		||||
        this.actor.add_actor(background);
 | 
			
		||||
 | 
			
		||||
        if (window) {
 | 
			
		||||
            this._desktop = new Clutter.Clone({ source: window.get_texture() });
 | 
			
		||||
            this.actor.add_actor(this._desktop);
 | 
			
		||||
            this._desktop.hide();
 | 
			
		||||
        } else {
 | 
			
		||||
            this._desktop = null;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        this.actor.connect('button-release-event',
 | 
			
		||||
                           Lang.bind(this, this._onButtonRelease));
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    zoomFromOverview: function(fadeInIcons) {
 | 
			
		||||
        if (this._desktop == null)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (fadeInIcons) {
 | 
			
		||||
            this._desktop.opacity = 0;
 | 
			
		||||
            this._desktop.show();
 | 
			
		||||
            Tweener.addTween(this._desktop,
 | 
			
		||||
                             { opacity: 255,
 | 
			
		||||
                               time: Overview.ANIMATION_TIME,
 | 
			
		||||
                               transition: 'easeOutQuad' });
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    zoomToOverview: function(fadeOutIcons) {
 | 
			
		||||
        if (this._desktop == null)
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        if (fadeOutIcons) {
 | 
			
		||||
            this._desktop.opacity = 255;
 | 
			
		||||
            this._desktop.show();
 | 
			
		||||
            Tweener.addTween(this._desktop,
 | 
			
		||||
                             { opacity: 0,
 | 
			
		||||
                               time: Overview.ANIMATION_TIME,
 | 
			
		||||
                               transition: 'easeOutQuad',
 | 
			
		||||
                               onComplete: Lang.bind(this,
 | 
			
		||||
                                   function() {
 | 
			
		||||
                                       this._desktop.hide();
 | 
			
		||||
                                   })
 | 
			
		||||
                             });
 | 
			
		||||
        } else {
 | 
			
		||||
            this._desktop.hide();
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onButtonRelease : function (actor, event) {
 | 
			
		||||
        this.emit('selected', event.get_time());
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Signals.addSignalMethods(DesktopClone.prototype);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @windowClone: Corresponding window clone
 | 
			
		||||
 * @parentActor: The actor which will be the parent of all overlay items
 | 
			
		||||
@@ -561,7 +486,6 @@ WindowOverlay.prototype = {
 | 
			
		||||
        this._parentActor.queue_relayout();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Signals.addSignalMethods(WindowOverlay.prototype);
 | 
			
		||||
 | 
			
		||||
const WindowPositionFlags = {
 | 
			
		||||
@@ -585,10 +509,20 @@ Workspace.prototype = {
 | 
			
		||||
        // Without this the drop area will be overlapped.
 | 
			
		||||
        this._windowOverlaysGroup.set_size(0, 0);
 | 
			
		||||
 | 
			
		||||
        this.actor = new Clutter.Group();
 | 
			
		||||
        this.actor = new Clutter.Group({ reactive: true });
 | 
			
		||||
        this.actor._delegate = this;
 | 
			
		||||
 | 
			
		||||
        this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
 | 
			
		||||
        this.actor.connect('button-release-event', Lang.bind(this,
 | 
			
		||||
            function(actor, event) {
 | 
			
		||||
                // Only switch to the workspace when there's no application
 | 
			
		||||
                // windows open. The problem is that it's too easy to miss
 | 
			
		||||
                // an app window and get the wrong one focused.
 | 
			
		||||
                if (this._windows.length == 0) {
 | 
			
		||||
                    this.metaWorkspace.activate(event.get_time());
 | 
			
		||||
                    Main.overview.hide();
 | 
			
		||||
                }
 | 
			
		||||
            }));
 | 
			
		||||
 | 
			
		||||
        // Items in _windowOverlaysGroup should not be scaled, so we don't
 | 
			
		||||
        // add them to this.actor, but to its parent whenever it changes
 | 
			
		||||
@@ -604,35 +538,10 @@ Workspace.prototype = {
 | 
			
		||||
 | 
			
		||||
        let windows = global.get_window_actors().filter(this._isMyWindow, this);
 | 
			
		||||
 | 
			
		||||
        // Find the desktop window
 | 
			
		||||
        for (let i = 0; i < windows.length; i++) {
 | 
			
		||||
            if (windows[i].meta_window.get_window_type() == Meta.WindowType.DESKTOP) {
 | 
			
		||||
                this._desktop = new DesktopClone(windows[i]);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        // If there wasn't one, fake it
 | 
			
		||||
        if (!this._desktop)
 | 
			
		||||
            this._desktop = new DesktopClone();
 | 
			
		||||
 | 
			
		||||
        this._desktop.connect('selected',
 | 
			
		||||
                              Lang.bind(this,
 | 
			
		||||
                                        function(clone, time) {
 | 
			
		||||
                                            // Only switch to the workspace when there's no application windows
 | 
			
		||||
                                            // open (we always have one window for the desktop).  The problem
 | 
			
		||||
                                            // is that it's too easy to miss an app window and get the wrong
 | 
			
		||||
                                            // one focused.
 | 
			
		||||
                                            if (this._windows.length == 1) {
 | 
			
		||||
                                                this.metaWorkspace.activate(time);
 | 
			
		||||
                                                Main.overview.hide();
 | 
			
		||||
                                            }
 | 
			
		||||
                                        }));
 | 
			
		||||
        this.actor.add_actor(this._desktop.actor);
 | 
			
		||||
 | 
			
		||||
        // Create clones for remaining windows that should be
 | 
			
		||||
        // visible in the Overview
 | 
			
		||||
        this._windows = [this._desktop];
 | 
			
		||||
        this._windowOverlays = [ null ];
 | 
			
		||||
        this._windows = [];
 | 
			
		||||
        this._windowOverlays = [];
 | 
			
		||||
        for (let i = 0; i < windows.length; i++) {
 | 
			
		||||
            if (this._isOverviewWindow(windows[i])) {
 | 
			
		||||
                this._addWindowClone(windows[i]);
 | 
			
		||||
@@ -651,8 +560,6 @@ Workspace.prototype = {
 | 
			
		||||
 | 
			
		||||
        this._visible = false;
 | 
			
		||||
 | 
			
		||||
        this._frame = null;
 | 
			
		||||
 | 
			
		||||
        this.leavingOverview = false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -714,9 +621,6 @@ Workspace.prototype = {
 | 
			
		||||
            this._lightbox.show();
 | 
			
		||||
        else
 | 
			
		||||
            this._lightbox.hide();
 | 
			
		||||
 | 
			
		||||
        if (this._frame)
 | 
			
		||||
            this._frame.set_opacity(showLightbox ? 150 : 255);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
@@ -737,32 +641,6 @@ Workspace.prototype = {
 | 
			
		||||
        this._lightbox.highlight(actor);
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // Mark the workspace selected/not-selected
 | 
			
		||||
    setSelected : function(selected) {
 | 
			
		||||
        // Don't draw a frame if we only have one workspace
 | 
			
		||||
        if (selected && global.screen.n_workspaces > 1) {
 | 
			
		||||
            if (this._frame)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            // FIXME: do something cooler-looking using clutter-cairo
 | 
			
		||||
            this._frame = new Clutter.Rectangle({ color: FRAME_COLOR });
 | 
			
		||||
            this.actor.add_actor(this._frame);
 | 
			
		||||
            this._frame.set_position(this._desktop.actor.x - FRAME_SIZE / this.actor.scale_x,
 | 
			
		||||
                                     this._desktop.actor.y - FRAME_SIZE / this.actor.scale_y);
 | 
			
		||||
            this._frame.set_size(this._desktop.actor.width + 2 * FRAME_SIZE / this.actor.scale_x,
 | 
			
		||||
                                 this._desktop.actor.height + 2 * FRAME_SIZE / this.actor.scale_y);
 | 
			
		||||
            this._frame.lower_bottom();
 | 
			
		||||
 | 
			
		||||
            this._framePosHandler = this.actor.connect('notify::scale-x', Lang.bind(this, this._updateFramePosition));
 | 
			
		||||
        } else {
 | 
			
		||||
            if (!this._frame)
 | 
			
		||||
                return;
 | 
			
		||||
            this.actor.disconnect(this._framePosHandler);
 | 
			
		||||
            this._frame.destroy();
 | 
			
		||||
            this._frame = null;
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * setReactive:
 | 
			
		||||
     * @reactive: %true iff the workspace should be reactive
 | 
			
		||||
@@ -770,14 +648,7 @@ Workspace.prototype = {
 | 
			
		||||
     * Set the workspace (desktop) reactive
 | 
			
		||||
     **/
 | 
			
		||||
    setReactive: function(reactive) {
 | 
			
		||||
        this._desktop.actor.reactive = reactive;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _updateFramePosition : function() {
 | 
			
		||||
        this._frame.set_position(this._desktop.actor.x - FRAME_SIZE / this.actor.scale_x,
 | 
			
		||||
                                 this._desktop.actor.y - FRAME_SIZE / this.actor.scale_y);
 | 
			
		||||
        this._frame.set_size(this._desktop.actor.width + 2 * FRAME_SIZE / this.actor.scale_x,
 | 
			
		||||
                             this._desktop.actor.height + 2 * FRAME_SIZE / this.actor.scale_y);
 | 
			
		||||
        this.actor.reactive = reactive;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _isCloneVisible: function(clone) {
 | 
			
		||||
@@ -788,7 +659,7 @@ Workspace.prototype = {
 | 
			
		||||
     * _getVisibleClones:
 | 
			
		||||
     *
 | 
			
		||||
     * Returns a list WindowClone objects where the clone isn't filtered
 | 
			
		||||
     * out by any application filter.  The clone for the desktop is excluded.
 | 
			
		||||
     * out by any application filter.
 | 
			
		||||
     * The returned array will always be newly allocated; it is not in any
 | 
			
		||||
     * defined order, and thus it's convenient to call .sort() with your
 | 
			
		||||
     * choice of sorting function.
 | 
			
		||||
@@ -796,7 +667,7 @@ Workspace.prototype = {
 | 
			
		||||
    _getVisibleClones: function() {
 | 
			
		||||
        let visible = [];
 | 
			
		||||
 | 
			
		||||
        for (let i = 1; i < this._windows.length; i++) {
 | 
			
		||||
        for (let i = 0; i < this._windows.length; i++) {
 | 
			
		||||
            let clone = this._windows[i];
 | 
			
		||||
 | 
			
		||||
            if (!this._isCloneVisible(clone))
 | 
			
		||||
@@ -808,7 +679,7 @@ Workspace.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _resetCloneVisibility: function () {
 | 
			
		||||
        for (let i = 1; i < this._windows.length; i++) {
 | 
			
		||||
        for (let i = 0; i < this._windows.length; i++) {
 | 
			
		||||
            let clone = this._windows[i];
 | 
			
		||||
            let overlay = this._windowOverlays[i];
 | 
			
		||||
 | 
			
		||||
@@ -1007,9 +878,9 @@ Workspace.prototype = {
 | 
			
		||||
        let buttonOuterHeight, captionHeight;
 | 
			
		||||
        let buttonOuterWidth = 0;
 | 
			
		||||
 | 
			
		||||
        if (this._windowOverlays[1]) {
 | 
			
		||||
            [buttonOuterHeight, captionHeight] = this._windowOverlays[1].chromeHeights();
 | 
			
		||||
            buttonOuterWidth = this._windowOverlays[1].chromeWidth() / this.scale;
 | 
			
		||||
        if (this._windowOverlays[0]) {
 | 
			
		||||
            [buttonOuterHeight, captionHeight] = this._windowOverlays[0].chromeHeights();
 | 
			
		||||
            buttonOuterWidth = this._windowOverlays[0].chromeWidth() / this.scale;
 | 
			
		||||
        } else
 | 
			
		||||
            [buttonOuterHeight, captionHeight] = [0, 0];
 | 
			
		||||
        buttonOuterHeight /= this.scale;
 | 
			
		||||
@@ -1157,8 +1028,8 @@ Workspace.prototype = {
 | 
			
		||||
        // be after the workspace animation finishes.
 | 
			
		||||
        let [cloneX, cloneY] = clone.actor.get_position();
 | 
			
		||||
        let [cloneWidth, cloneHeight] = clone.actor.get_size();
 | 
			
		||||
        cloneX = this.gridX + this.scale * cloneX;
 | 
			
		||||
        cloneY = this.gridY + this.scale * cloneY;
 | 
			
		||||
        cloneX = this.x + this.scale * cloneX;
 | 
			
		||||
        cloneY = this.y + this.scale * cloneY;
 | 
			
		||||
        cloneWidth = this.scale * clone.actor.scale_x * cloneWidth;
 | 
			
		||||
        cloneHeight = this.scale * clone.actor.scale_y * cloneHeight;
 | 
			
		||||
 | 
			
		||||
@@ -1172,7 +1043,7 @@ Workspace.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _fadeInAllOverlays: function() {
 | 
			
		||||
        for (let i = 1; i < this._windows.length; i++) {
 | 
			
		||||
        for (let i = 0; i < this._windows.length; i++) {
 | 
			
		||||
            let clone = this._windows[i];
 | 
			
		||||
            let overlay = this._windowOverlays[i];
 | 
			
		||||
            if (this._showOnlyWindows != null && !(clone.metaWindow in this._showOnlyWindows))
 | 
			
		||||
@@ -1182,7 +1053,7 @@ Workspace.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _hideAllOverlays: function() {
 | 
			
		||||
        for (let i = 1; i< this._windows.length; i++) {
 | 
			
		||||
        for (let i = 0; i < this._windows.length; i++) {
 | 
			
		||||
            let overlay = this._windowOverlays[i];
 | 
			
		||||
            overlay.hide();
 | 
			
		||||
        }
 | 
			
		||||
@@ -1197,8 +1068,8 @@ Workspace.prototype = {
 | 
			
		||||
        let wsHeight = this.actor.height * this.scale;
 | 
			
		||||
 | 
			
		||||
        let pointerHasMoved = (this._cursorX != x && this._cursorY != y);
 | 
			
		||||
        let inWorkspace = (this.gridX < x && x < this.gridX + wsWidth &&
 | 
			
		||||
                           this.gridY < y && y < this.gridY + wsHeight);
 | 
			
		||||
        let inWorkspace = (this.x < x && x < this.x + wsWidth &&
 | 
			
		||||
                           this.y < y && y < this.y + wsHeight);
 | 
			
		||||
 | 
			
		||||
        if (pointerHasMoved && inWorkspace) {
 | 
			
		||||
            // store current cursor position
 | 
			
		||||
@@ -1309,8 +1180,8 @@ Workspace.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // check for maximized windows on the workspace
 | 
			
		||||
    _haveMaximizedWindows: function() {
 | 
			
		||||
        for (let i = 1; i < this._windows.length; i++) {
 | 
			
		||||
    hasMaximizedWindows: function() {
 | 
			
		||||
        for (let i = 0; i < this._windows.length; i++) {
 | 
			
		||||
            let metaWindow = this._windows[i].metaWindow;
 | 
			
		||||
            if (metaWindow.showing_on_its_workspace() &&
 | 
			
		||||
                metaWindow.maximized_horizontally &&
 | 
			
		||||
@@ -1322,7 +1193,7 @@ Workspace.prototype = {
 | 
			
		||||
 | 
			
		||||
    // Animate the full-screen to Overview transition.
 | 
			
		||||
    zoomToOverview : function() {
 | 
			
		||||
        this.actor.set_position(this.gridX, this.gridY);
 | 
			
		||||
        this.actor.set_position(this.x, this.y);
 | 
			
		||||
        this.actor.set_scale(this.scale, this.scale);
 | 
			
		||||
 | 
			
		||||
        // Position and scale the windows.
 | 
			
		||||
@@ -1331,12 +1202,6 @@ Workspace.prototype = {
 | 
			
		||||
        else
 | 
			
		||||
            this.positionWindows(WindowPositionFlags.ZOOM);
 | 
			
		||||
 | 
			
		||||
        let active = global.screen.get_active_workspace();
 | 
			
		||||
        let fadeInIcons = (Main.overview.animationInProgress &&
 | 
			
		||||
                           active == this.metaWorkspace &&
 | 
			
		||||
                           !this._haveMaximizedWindows());
 | 
			
		||||
        this._desktop.zoomToOverview(fadeInIcons);
 | 
			
		||||
 | 
			
		||||
        this._visible = true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
@@ -1354,7 +1219,7 @@ Workspace.prototype = {
 | 
			
		||||
                                                                           this._doneLeavingOverview));
 | 
			
		||||
 | 
			
		||||
        // Position and scale the windows.
 | 
			
		||||
        for (let i = 1; i < this._windows.length; i++) {
 | 
			
		||||
        for (let i = 0; i < this._windows.length; i++) {
 | 
			
		||||
            let clone = this._windows[i];
 | 
			
		||||
 | 
			
		||||
            clone.zoomFromOverview();
 | 
			
		||||
@@ -1383,77 +1248,9 @@ Workspace.prototype = {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let active = global.screen.get_active_workspace();
 | 
			
		||||
        let fadeOutIcons = (active == this.metaWorkspace &&
 | 
			
		||||
                            !this._haveMaximizedWindows());
 | 
			
		||||
        this._desktop.zoomFromOverview(fadeOutIcons);
 | 
			
		||||
 | 
			
		||||
        this._visible = false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // Animates grid shrinking/expanding when a row or column
 | 
			
		||||
    // of workspaces is added or removed
 | 
			
		||||
    resizeToGrid : function (oldScale) {
 | 
			
		||||
        this._hideAllOverlays();
 | 
			
		||||
        Tweener.addTween(this.actor,
 | 
			
		||||
                         { x: this.gridX,
 | 
			
		||||
                           y: this.gridY,
 | 
			
		||||
                           scale_x: this.scale,
 | 
			
		||||
                           scale_y: this.scale,
 | 
			
		||||
                           time: Overview.ANIMATION_TIME,
 | 
			
		||||
                           transition: 'easeOutQuad',
 | 
			
		||||
                           onComplete: Lang.bind(this, this._fadeInAllOverlays)
 | 
			
		||||
                         });
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // Animates the addition of a new (empty) workspace
 | 
			
		||||
    slideIn : function(oldScale) {
 | 
			
		||||
        if (this.gridCol > this.gridRow) {
 | 
			
		||||
            this.actor.set_position(global.screen_width, this.gridY);
 | 
			
		||||
            this.actor.set_scale(oldScale, oldScale);
 | 
			
		||||
        } else {
 | 
			
		||||
            this.actor.set_position(this.gridX, global.screen_height);
 | 
			
		||||
            this.actor.set_scale(this.scale, this.scale);
 | 
			
		||||
        }
 | 
			
		||||
        Tweener.addTween(this.actor,
 | 
			
		||||
                         { x: this.gridX,
 | 
			
		||||
                           y: this.gridY,
 | 
			
		||||
                           scale_x: this.scale,
 | 
			
		||||
                           scale_y: this.scale,
 | 
			
		||||
                           time: Overview.ANIMATION_TIME,
 | 
			
		||||
                           transition: 'easeOutQuad'
 | 
			
		||||
                         });
 | 
			
		||||
 | 
			
		||||
        this._visible = true;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    // Animates the removal of a workspace
 | 
			
		||||
    slideOut : function(onComplete) {
 | 
			
		||||
        let destX = this.actor.x, destY = this.actor.y;
 | 
			
		||||
 | 
			
		||||
        this._hideAllOverlays();
 | 
			
		||||
 | 
			
		||||
        if (this.gridCol > this.gridRow)
 | 
			
		||||
            destX = global.screen_width;
 | 
			
		||||
        else
 | 
			
		||||
            destY = global.screen_height;
 | 
			
		||||
        Tweener.addTween(this.actor,
 | 
			
		||||
                         { x: destX,
 | 
			
		||||
                           y: destY,
 | 
			
		||||
                           scale_x: this.scale,
 | 
			
		||||
                           scale_y: this.scale,
 | 
			
		||||
                           time: Overview.ANIMATION_TIME,
 | 
			
		||||
                           transition: 'easeOutQuad',
 | 
			
		||||
                           onComplete: onComplete
 | 
			
		||||
                         });
 | 
			
		||||
 | 
			
		||||
        this._visible = false;
 | 
			
		||||
 | 
			
		||||
        // Don't let the user try to select this workspace as it's
 | 
			
		||||
        // making its exit.
 | 
			
		||||
        this._desktop.reactive = false;
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    destroy : function() {
 | 
			
		||||
        this.actor.destroy();
 | 
			
		||||
    },
 | 
			
		||||
@@ -1475,7 +1272,7 @@ Workspace.prototype = {
 | 
			
		||||
        // their parent (this.actor), but we might have a zoomed window
 | 
			
		||||
        // which has been reparented to the stage - _windows[0] holds
 | 
			
		||||
        // the desktop window, which is never reparented
 | 
			
		||||
        for (let w = 1; w < this._windows.length; w++)
 | 
			
		||||
        for (let w = 0; w < this._windows.length; w++)
 | 
			
		||||
            this._windows[w].destroy();
 | 
			
		||||
        this._windows = [];
 | 
			
		||||
    },
 | 
			
		||||
@@ -1506,12 +1303,12 @@ Workspace.prototype = {
 | 
			
		||||
                      Lang.bind(this, this._onCloneSelected));
 | 
			
		||||
        clone.connect('drag-begin',
 | 
			
		||||
                      Lang.bind(this, function(clone) {
 | 
			
		||||
                          this.emit('window-drag-begin', clone.actor);
 | 
			
		||||
                          Main.overview.beginWindowDrag();
 | 
			
		||||
                          overlay.hide();
 | 
			
		||||
                      }));
 | 
			
		||||
        clone.connect('drag-end',
 | 
			
		||||
                      Lang.bind(this, function(clone) {
 | 
			
		||||
                          this.emit('window-drag-end', clone.actor);
 | 
			
		||||
                          Main.overview.endWindowDrag();
 | 
			
		||||
                          overlay.show();
 | 
			
		||||
                      }));
 | 
			
		||||
        clone.connect('zoom-start',
 | 
			
		||||
@@ -1534,7 +1331,7 @@ Workspace.prototype = {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    _onShowOverlayClose: function (windowOverlay) {
 | 
			
		||||
        for (let i = 1; i < this._windowOverlays.length; i++) {
 | 
			
		||||
        for (let i = 0; i < this._windowOverlays.length; i++) {
 | 
			
		||||
            let overlay = this._windowOverlays[i];
 | 
			
		||||
            if (overlay == windowOverlay)
 | 
			
		||||
                continue;
 | 
			
		||||
@@ -1643,11 +1440,11 @@ function _workspaceRelativeModifier(workspace) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return [ { name: 'x',
 | 
			
		||||
               parameters: { workspacePos: workspace.gridX,
 | 
			
		||||
               parameters: { workspacePos: workspace.x,
 | 
			
		||||
                             overviewPos: overviewPosX,
 | 
			
		||||
                             overviewScale: overviewScale } },
 | 
			
		||||
             { name: 'y',
 | 
			
		||||
               parameters: { workspacePos: workspace.gridY,
 | 
			
		||||
               parameters: { workspacePos: workspace.y,
 | 
			
		||||
                             overviewPos: overviewPosY,
 | 
			
		||||
                             overviewScale: overviewScale } }
 | 
			
		||||
           ];
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -15,6 +15,7 @@ js/ui/popupMenu.js
 | 
			
		||||
js/ui/runDialog.js
 | 
			
		||||
js/ui/statusMenu.js
 | 
			
		||||
js/ui/status/accessibility.js
 | 
			
		||||
js/ui/viewSelector.js
 | 
			
		||||
js/ui/windowAttentionHandler.js
 | 
			
		||||
js/ui/workspacesView.js
 | 
			
		||||
src/gvc/gvc-mixer-control.c
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user