Merge branch 'master' into message-tray
This commit is contained in:
commit
3b4e2202f7
@ -17,7 +17,6 @@ dist_images_DATA = \
|
||||
add-workspace.svg \
|
||||
app-well-glow.png \
|
||||
close-black.svg \
|
||||
info.svg \
|
||||
magnifier.svg \
|
||||
remove-workspace.svg
|
||||
|
||||
@ -25,6 +24,7 @@ themedir = $(pkgdatadir)/theme
|
||||
dist_theme_DATA = \
|
||||
theme/gnome-shell.css \
|
||||
theme/close.svg \
|
||||
theme/close-window.svg \
|
||||
theme/scroll-button-down.png \
|
||||
theme/scroll-button-down-hover.png \
|
||||
theme/scroll-button-up.png \
|
||||
|
@ -1,74 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Foreground"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="16px"
|
||||
height="16px"
|
||||
viewBox="0 0 16 16"
|
||||
enable-background="new 0 0 16 16"
|
||||
xml:space="preserve"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.46"
|
||||
sodipodi:docname="info_16.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata
|
||||
id="metadata2389"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs2387"><linearGradient
|
||||
id="linearGradient3710"><stop
|
||||
style="stop-color:#c4c4c4;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3712" /><stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3714" /></linearGradient><inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 8 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="16 : 8 : 1"
|
||||
inkscape:persp3d-origin="8 : 5.3333333 : 1"
|
||||
id="perspective2391" /><linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient3710"
|
||||
id="linearGradient3716"
|
||||
x1="7.9066148"
|
||||
y1="15.937743"
|
||||
x2="7.9377432"
|
||||
y2="0.031128405"
|
||||
gradientUnits="userSpaceOnUse" /></defs><sodipodi:namedview
|
||||
inkscape:window-height="713"
|
||||
inkscape:window-width="722"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="0.0"
|
||||
guidetolerance="10.0"
|
||||
gridtolerance="10.0"
|
||||
objecttolerance="10.0"
|
||||
borderopacity="1.0"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#ffffff"
|
||||
id="base"
|
||||
showgrid="false"
|
||||
inkscape:zoom="32.125"
|
||||
inkscape:cx="8"
|
||||
inkscape:cy="8.154146"
|
||||
inkscape:window-x="20"
|
||||
inkscape:window-y="20"
|
||||
inkscape:current-layer="Foreground" />
|
||||
<path
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M7,3h2v2H7V3z M5.5,12H7V8H5.5V7H9v5h1.5v1h-5V12z M0,8c0-4.418,3.582-8,8-8 s8,3.582,8,8s-3.582,8-8,8S0,12.418,0,8z"
|
||||
id="path2384"
|
||||
style="fill-opacity:1;fill:url(#linearGradient3716)" />
|
||||
</svg>
|
Before Width: | Height: | Size: 2.5 KiB |
76
data/theme/close-window.svg
Normal file
76
data/theme/close-window.svg
Normal file
@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 13.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 14948) -->
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.0"
|
||||
id="Foreground"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="22"
|
||||
height="22"
|
||||
viewBox="0 0 16 16"
|
||||
enable-background="new 0 0 16 16"
|
||||
xml:space="preserve"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.46"
|
||||
sodipodi:docname="close-window.svg"
|
||||
inkscape:output_extension="org.inkscape.output.svg.inkscape"><metadata
|
||||
id="metadata2399"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs2397"><linearGradient
|
||||
id="linearGradient3173"><stop
|
||||
style="stop-color:#c4c4c4;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3175" /><stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3177" /></linearGradient><inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 8 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="16 : 8 : 1"
|
||||
inkscape:persp3d-origin="8 : 5.3333333 : 1"
|
||||
id="perspective2401" /></defs><sodipodi:namedview
|
||||
inkscape:window-height="999"
|
||||
inkscape:window-width="1680"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:pageopacity="1"
|
||||
guidetolerance="10.0"
|
||||
gridtolerance="10.0"
|
||||
objecttolerance="10.0"
|
||||
borderopacity="1.0"
|
||||
bordercolor="#666666"
|
||||
pagecolor="#000000"
|
||||
id="base"
|
||||
showgrid="false"
|
||||
inkscape:zoom="25.648691"
|
||||
inkscape:cx="8.8097603"
|
||||
inkscape:cy="9.0472789"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="26"
|
||||
inkscape:current-layer="Foreground"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true" />
|
||||
|
||||
<g
|
||||
id="g3175"><path
|
||||
sodipodi:nodetypes="csssc"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.59217799;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path2394"
|
||||
d="M 0.83987936,8.0425327 C 0.83987936,4.0805265 4.0712155,0.86823453 8.0567103,0.86823453 C 12.042205,0.86823453 15.273542,4.0805265 15.273542,8.0425327 C 15.273542,12.004539 12.042205,15.216831 8.0567103,15.216831 C 4.0712155,15.216831 0.83987936,12.004539 0.83987936,8.0425327 z"
|
||||
clip-rule="evenodd" /><g
|
||||
id="g3172"><path
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.67127273;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 5.4242673,5.3313047 L 10.515414,10.421272 L 10.714004,10.646491"
|
||||
id="path3152" /></g></g><path
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:1.67127273;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 5.4402527,10.650392 L 10.688082,5.3573033"
|
||||
id="path3154"
|
||||
sodipodi:nodetypes="cc" /></svg>
|
After Width: | Height: | Size: 3.2 KiB |
@ -70,17 +70,76 @@ StTooltip {
|
||||
|
||||
/* Panel */
|
||||
|
||||
#panel {
|
||||
color: #ffffff;
|
||||
font-size: 16px;
|
||||
background-gradient-direction: vertical;
|
||||
background-gradient-start: #161616;
|
||||
background-gradient-end: #000000;
|
||||
}
|
||||
|
||||
#panelLeft, #panelCenter, #panelRight {
|
||||
spacing: 4px;
|
||||
}
|
||||
|
||||
#panelLeft {
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
#panelRight {
|
||||
padding-left: 4px;
|
||||
}
|
||||
|
||||
.panel-button:pressed {
|
||||
background-color: rgba(50,76,111,0.98);
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
#appMenu {
|
||||
spacing: 4px;
|
||||
}
|
||||
|
||||
.app-menu-icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.panel-button {
|
||||
padding: 4px 12px 3px;
|
||||
border-radius: 5px;
|
||||
font: 16px sans-serif;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.panel-button:active, .panel-button:checked {
|
||||
background-color: #314a6c;
|
||||
}
|
||||
|
||||
#panelStatus {
|
||||
spacing: 4px;
|
||||
}
|
||||
|
||||
/* Overlay */
|
||||
|
||||
.workspaces {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.window-caption {
|
||||
background: rgba(0,0,0,0.8);
|
||||
border: 1px solid rgba(128,128,128,0.40);
|
||||
border-radius: 10px;
|
||||
font-size: 12px;
|
||||
padding: 2px 8px;
|
||||
-shell-caption-spacing: 4px;
|
||||
}
|
||||
|
||||
.window-close {
|
||||
background-image: url("close-window.svg");
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
-shell-close-overlap: 16px;
|
||||
}
|
||||
|
||||
/* Dash */
|
||||
|
||||
#dash {
|
||||
@ -119,8 +178,9 @@ StTooltip {
|
||||
|
||||
.section-header {
|
||||
border: 1px solid #262626;
|
||||
-shell-gradient-top: #161616;
|
||||
-shell-gradient-bottom: #000000;
|
||||
background-gradient-direction: vertical;
|
||||
background-gradient-start: #161616;
|
||||
background-gradient-end: #000000;
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
}
|
||||
@ -213,12 +273,56 @@ StTooltip {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* AppIcon */
|
||||
/* Apps */
|
||||
|
||||
.app-icon-label {
|
||||
#dashAppWell {
|
||||
spacing: 2px;
|
||||
-shell-grid-item-size: 74px;
|
||||
}
|
||||
|
||||
.app-well-app {
|
||||
border: 1px solid #080808;
|
||||
border-radius: 2px;
|
||||
padding: 2px;
|
||||
width: 74px;
|
||||
height: 74px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.app-well-app:hover {
|
||||
border: 1px solid #202020;
|
||||
}
|
||||
|
||||
.app-well-app:active {
|
||||
background-color: #1e1e1e;
|
||||
border: 1px solid #5f5f5f;
|
||||
}
|
||||
|
||||
.app-well-app-glow {
|
||||
-shell-glow-extend-vertical: 3px;
|
||||
-shell-glow-shrink-horizontal: 3px;
|
||||
}
|
||||
|
||||
.app-well-menu {
|
||||
border: 1px solid #5f5f5f;
|
||||
border-radius: 4px;
|
||||
padding: 4px;
|
||||
background-color: rgba(0,0,0,0.9);
|
||||
color: #ffffff;
|
||||
-shell-arrow-width: 12px;
|
||||
-shell-menu-spacing: 4px;
|
||||
}
|
||||
|
||||
.app-well-menu-item:hover {
|
||||
background-color: #1e1e1e;
|
||||
}
|
||||
|
||||
.app-well-menu-separator {
|
||||
padding-top: 1px;
|
||||
border-bottom: 1px solid #5f5f5f;
|
||||
height: 1px;
|
||||
}
|
||||
|
||||
/* Places */
|
||||
|
||||
.places-actions {
|
||||
@ -371,9 +475,3 @@ StTooltip {
|
||||
background: rgba(255,255,255,0.33);
|
||||
}
|
||||
|
||||
/* Status Menu */
|
||||
#StatusMenu {
|
||||
spacing: 4px;
|
||||
font: 16px sans-serif;
|
||||
color: white;
|
||||
}
|
||||
|
@ -2,4 +2,5 @@ jsmiscdir = $(pkgdatadir)/js/misc
|
||||
|
||||
dist_jsmisc_DATA = \
|
||||
docInfo.js \
|
||||
format.js
|
||||
format.js \
|
||||
params.js
|
||||
|
33
js/misc/params.js
Normal file
33
js/misc/params.js
Normal file
@ -0,0 +1,33 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
// parse:
|
||||
// @params: caller-provided parameter object, or %null
|
||||
// @default: function-provided defaults object
|
||||
// @allowExtras: whether or not to allow properties not in @default
|
||||
//
|
||||
// Examines @params and fills in default values from @defaults for
|
||||
// any properties in @defaults that don't appear in @params. If
|
||||
// @allowExtras is not %true, it will throw an error if @params
|
||||
// contains any properties that aren't in @defaults.
|
||||
//
|
||||
// If @params is %null, this returns @defaults.
|
||||
//
|
||||
// Return value: the updated params
|
||||
function parse(params, defaults, allowExtras) {
|
||||
if (!params)
|
||||
return defaults;
|
||||
|
||||
if (!allowExtras) {
|
||||
for (let prop in params) {
|
||||
if (!(prop in defaults))
|
||||
throw new Error('Unrecognized parameter "' + prop + '"');
|
||||
}
|
||||
}
|
||||
|
||||
for (let prop in defaults) {
|
||||
if (!(prop in params))
|
||||
params[prop] = defaults[prop];
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
@ -4,8 +4,6 @@ dist_jsui_DATA = \
|
||||
altTab.js \
|
||||
appDisplay.js \
|
||||
appFavorites.js \
|
||||
appIcon.js \
|
||||
button.js \
|
||||
calendar.js \
|
||||
chrome.js \
|
||||
dash.js \
|
||||
|
@ -11,7 +11,6 @@ const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const AppIcon = imports.ui.appIcon;
|
||||
const Main = imports.ui.main;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
@ -438,25 +437,20 @@ SwitcherList.prototype = {
|
||||
},
|
||||
|
||||
addItem : function(item) {
|
||||
// We want the St.Bin's padding to be clickable (since it will
|
||||
// be part of the highlighted background color), so we put the
|
||||
// bin inside the ButtonBox rather than vice versa.
|
||||
let bin = new St.Bin({ style_class: 'item-box' });
|
||||
let bbox = new Shell.ButtonBox({ reactive: true });
|
||||
let bbox = new St.Clickable({ style_class: 'item-box',
|
||||
reactive: true });
|
||||
|
||||
bin.add_actor(item);
|
||||
bbox.append(bin, Big.BoxPackFlags.NONE);
|
||||
bbox.set_child(item);
|
||||
this._list.add_actor(bbox);
|
||||
|
||||
let n = this._items.length;
|
||||
bbox.connect('activate', Lang.bind(this, function () {
|
||||
bbox.connect('clicked', Lang.bind(this, function () {
|
||||
this._itemActivated(n);
|
||||
}));
|
||||
bbox.connect('enter-event', Lang.bind(this, function () {
|
||||
this._itemEntered(n);
|
||||
}));
|
||||
|
||||
bbox._bin = bin;
|
||||
this._items.push(bbox);
|
||||
},
|
||||
|
||||
@ -468,15 +462,15 @@ SwitcherList.prototype = {
|
||||
|
||||
highlight: function(index, justOutline) {
|
||||
if (this._highlighted != -1)
|
||||
this._items[this._highlighted]._bin.style_class = 'item-box';
|
||||
this._items[this._highlighted].style_class = 'item-box';
|
||||
|
||||
this._highlighted = index;
|
||||
|
||||
if (this._highlighted != -1) {
|
||||
if (justOutline)
|
||||
this._items[this._highlighted]._bin.style_class = 'outlined-item-box';
|
||||
this._items[this._highlighted].style_class = 'outlined-item-box';
|
||||
else
|
||||
this._items[this._highlighted]._bin.style_class = 'selected-item-box';
|
||||
this._items[this._highlighted].style_class = 'selected-item-box';
|
||||
}
|
||||
},
|
||||
|
||||
@ -588,6 +582,22 @@ SwitcherList.prototype = {
|
||||
|
||||
Signals.addSignalMethods(SwitcherList.prototype);
|
||||
|
||||
function AppIcon(app) {
|
||||
this._init(app);
|
||||
}
|
||||
|
||||
AppIcon.prototype = {
|
||||
_init: function(app) {
|
||||
this.app = app;
|
||||
this.actor = new St.BoxLayout({ style_class: "alt-tab-app",
|
||||
vertical: true });
|
||||
this._icon = this.app.create_icon_texture(POPUP_APPICON_SIZE);
|
||||
this.actor.add(this._icon, { x_fill: false, y_fill: false });
|
||||
this._label = new St.Label({ text: this.app.get_name() });
|
||||
this.actor.add(this._label, { x_fill: false });
|
||||
}
|
||||
}
|
||||
|
||||
function AppSwitcher(apps) {
|
||||
this._init(apps);
|
||||
}
|
||||
@ -603,8 +613,7 @@ AppSwitcher.prototype = {
|
||||
let workspaceIcons = [];
|
||||
let otherIcons = [];
|
||||
for (let i = 0; i < apps.length; i++) {
|
||||
let appIcon = new AppIcon.AppIcon({ app: apps[i],
|
||||
size: POPUP_APPICON_SIZE });
|
||||
let appIcon = new AppIcon(apps[i]);
|
||||
// Cache the window list now; we don't handle dynamic changes here,
|
||||
// and we don't want to be continually retrieving it
|
||||
appIcon.cachedWindows = appIcon.app.get_windows();
|
||||
@ -681,12 +690,8 @@ AppSwitcher.prototype = {
|
||||
this.icons.push(appIcon);
|
||||
this.addItem(appIcon.actor);
|
||||
|
||||
// SwitcherList creates its own Shell.ButtonBox; we want to
|
||||
// avoid intercepting the events it wants.
|
||||
appIcon.actor.reactive = false;
|
||||
|
||||
let n = this._arrows.length;
|
||||
let arrow = new Shell.DrawingArea();
|
||||
let arrow = new St.DrawingArea();
|
||||
arrow.connect('redraw', Lang.bind(this,
|
||||
function (area, texture) {
|
||||
Shell.draw_box_pointer(texture, Shell.PointerDirection.DOWN,
|
||||
|
@ -9,28 +9,19 @@ const Gtk = imports.gi.Gtk;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Lang = imports.lang;
|
||||
const Signals = imports.signals;
|
||||
const St = imports.gi.St;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const AppFavorites = imports.ui.appFavorites;
|
||||
const AppIcon = imports.ui.appIcon;
|
||||
const DND = imports.ui.dnd;
|
||||
const GenericDisplay = imports.ui.genericDisplay;
|
||||
const Main = imports.ui.main;
|
||||
const Workspaces = imports.ui.workspaces;
|
||||
|
||||
const ENTERED_MENU_COLOR = new Clutter.Color();
|
||||
ENTERED_MENU_COLOR.from_pixel(0x00ff0022);
|
||||
|
||||
const WELL_DEFAULT_COLUMNS = 4;
|
||||
const WELL_ITEM_MIN_HSPACING = 4;
|
||||
const WELL_ITEM_VSPACING = 4;
|
||||
|
||||
const MENU_ARROW_SIZE = 12;
|
||||
const MENU_SPACING = 7;
|
||||
|
||||
const MAX_ITEMS = 30;
|
||||
const APPICON_SIZE = 48;
|
||||
const WELL_MAX_COLUMNS = 8;
|
||||
|
||||
/* This class represents a single display item containing information about an application.
|
||||
*
|
||||
@ -86,79 +77,6 @@ AppDisplayItem.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
const MENU_UNSELECTED = 0;
|
||||
const MENU_SELECTED = 1;
|
||||
const MENU_ENTERED = 2;
|
||||
|
||||
function MenuItem(name, id) {
|
||||
this._init(name, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* MenuItem:
|
||||
* Shows the list of menus in the sidebar.
|
||||
*/
|
||||
MenuItem.prototype = {
|
||||
_init: function(name, id) {
|
||||
this.id = id;
|
||||
|
||||
this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
spacing: 4,
|
||||
corner_radius: 4,
|
||||
padding_right: 4,
|
||||
padding_left: 4,
|
||||
reactive: true });
|
||||
this.actor.connect('button-press-event', Lang.bind(this, function (a, e) {
|
||||
this.setState(MENU_SELECTED);
|
||||
}));
|
||||
|
||||
this._text = new Clutter.Text({ color: GenericDisplay.ITEM_DISPLAY_NAME_COLOR,
|
||||
font_name: "Sans 14px",
|
||||
text: name });
|
||||
|
||||
// We use individual boxes for the label and the arrow to ensure that they
|
||||
// are aligned vertically. Just setting y_align: Big.BoxAlignment.CENTER
|
||||
// on this.actor does not seem to achieve that.
|
||||
let labelBox = new Big.Box({ y_align: Big.BoxAlignment.CENTER,
|
||||
padding: 4 });
|
||||
|
||||
labelBox.append(this._text, Big.BoxPackFlags.NONE);
|
||||
|
||||
this.actor.append(labelBox, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
let arrowBox = new Big.Box({ y_align: Big.BoxAlignment.CENTER });
|
||||
|
||||
this._arrow = new Shell.Arrow({ surface_width: MENU_ARROW_SIZE,
|
||||
surface_height: MENU_ARROW_SIZE,
|
||||
direction: Gtk.ArrowType.RIGHT,
|
||||
opacity: 0 });
|
||||
arrowBox.append(this._arrow, Big.BoxPackFlags.NONE);
|
||||
this.actor.append(arrowBox, Big.BoxPackFlags.NONE);
|
||||
},
|
||||
|
||||
getState: function() {
|
||||
return this._state;
|
||||
},
|
||||
|
||||
setState: function (state) {
|
||||
if (state == this._state)
|
||||
return;
|
||||
this._state = state;
|
||||
if (this._state == MENU_UNSELECTED) {
|
||||
this.actor.background_color = null;
|
||||
this._arrow.set_opacity(0);
|
||||
} else if (this._state == MENU_ENTERED) {
|
||||
this.actor.background_color = ENTERED_MENU_COLOR;
|
||||
this._arrow.set_opacity(0xFF/2);
|
||||
} else {
|
||||
this.actor.background_color = GenericDisplay.ITEM_DISPLAY_SELECTED_BACKGROUND_COLOR;
|
||||
this._arrow.set_opacity(0xFF);
|
||||
}
|
||||
this.emit('state-changed')
|
||||
}
|
||||
}
|
||||
Signals.addSignalMethods(MenuItem.prototype);
|
||||
|
||||
/* This class represents a display containing a collection of application items.
|
||||
* The applications are sorted based on their popularity by default, and based on
|
||||
* their name if some search filter is applied.
|
||||
@ -302,42 +220,203 @@ AppDisplay.prototype = {
|
||||
|
||||
Signals.addSignalMethods(AppDisplay.prototype);
|
||||
|
||||
function BaseWellItem(app, isFavorite, hasMenu) {
|
||||
this._init(app, isFavorite, hasMenu);
|
||||
|
||||
function BaseWellItem(app, isFavorite) {
|
||||
this._init(app, isFavorite);
|
||||
}
|
||||
|
||||
BaseWellItem.prototype = {
|
||||
__proto__: AppIcon.AppIcon.prototype,
|
||||
_init : function(app, isFavorite) {
|
||||
this.app = app;
|
||||
|
||||
_init: function(app, isFavorite) {
|
||||
AppIcon.AppIcon.prototype._init.call(this, { app: app,
|
||||
menuType: AppIcon.MenuType.ON_RIGHT,
|
||||
glow: true });
|
||||
this._glowExtendVertical = 0;
|
||||
this._glowShrinkHorizontal = 0;
|
||||
|
||||
this.isFavorite = isFavorite;
|
||||
this.actor = new St.Clickable({ style_class: 'app-well-app',
|
||||
reactive: true });
|
||||
this.actor._delegate = this;
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
this.actor.connect('notify::mapped', Lang.bind(this, this._onMapped));
|
||||
|
||||
let box = new St.BoxLayout({ vertical: true });
|
||||
this.actor.set_child(box);
|
||||
|
||||
this.actor.connect('clicked', Lang.bind(this, this._onClicked));
|
||||
|
||||
this._menu = null;
|
||||
|
||||
this.icon = this.app.create_icon_texture(APPICON_SIZE);
|
||||
|
||||
box.add(this.icon, { expand: true, x_fill: false, y_fill: false });
|
||||
|
||||
let nameBox = new Shell.GenericContainer();
|
||||
nameBox.connect('get-preferred-width', Lang.bind(this, this._nameBoxGetPreferredWidth));
|
||||
nameBox.connect('get-preferred-height', Lang.bind(this, this._nameBoxGetPreferredHeight));
|
||||
nameBox.connect('allocate', Lang.bind(this, this._nameBoxAllocate));
|
||||
this._nameBox = nameBox;
|
||||
|
||||
this._name = new St.Label({ text: this.app.get_name() });
|
||||
this._name.clutter_text.line_alignment = Pango.Alignment.CENTER;
|
||||
nameBox.add_actor(this._name);
|
||||
this._glowBox = new St.BoxLayout({ style_class: 'app-well-app-glow' });
|
||||
this._glowBox.connect('style-changed', Lang.bind(this, this._onStyleChanged));
|
||||
this._nameBox.add_actor(this._glowBox);
|
||||
this._glowBox.lower(this._name);
|
||||
this._appWindowChangedId = this.app.connect('windows-changed', Lang.bind(this, this._rerenderGlow));
|
||||
this._rerenderGlow();
|
||||
|
||||
box.add(nameBox);
|
||||
|
||||
this._draggable = DND.makeDraggable(this.actor, true);
|
||||
this._dragStartX = null;
|
||||
this._dragStartY = null;
|
||||
|
||||
// Do these as anonymous functions to avoid conflict with handlers in subclasses
|
||||
this.actor.connect('button-press-event', Lang.bind(this, function(actor, event) {
|
||||
let [stageX, stageY] = event.get_coords();
|
||||
this._dragStartX = stageX;
|
||||
this._dragStartY = stageY;
|
||||
return false;
|
||||
}));
|
||||
this.actor.connect('notify::hover', Lang.bind(this, function () {
|
||||
let hover = this.actor.hover;
|
||||
if (!hover) {
|
||||
if (this.actor.pressed && this._dragStartX != null) {
|
||||
this.actor.fake_release();
|
||||
this._draggable.startDrag(this._dragStartX, this._dragStartY,
|
||||
Main.currentTime());
|
||||
} else {
|
||||
this._dragStartX = null;
|
||||
this._dragStartY = null;
|
||||
}
|
||||
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
|
||||
this.actor.connect('notify::hover', Lang.bind(this, this._onHoverChange));
|
||||
},
|
||||
|
||||
_nameBoxGetPreferredWidth: function (nameBox, forHeight, alloc) {
|
||||
let [min, natural] = this._name.get_preferred_width(forHeight);
|
||||
alloc.min_size = min;
|
||||
alloc.natural_size = natural;
|
||||
},
|
||||
|
||||
_nameBoxGetPreferredHeight: function (nameBox, forWidth, alloc) {
|
||||
let [min, natural] = this._name.get_preferred_height(forWidth);
|
||||
alloc.min_size = min + this._glowExtendVertical * 2;
|
||||
alloc.natural_size = natural + this._glowExtendVertical * 2;
|
||||
},
|
||||
|
||||
_nameBoxAllocate: function (nameBox, box, flags) {
|
||||
let childBox = new Clutter.ActorBox();
|
||||
let [minWidth, naturalWidth] = this._name.get_preferred_width(-1);
|
||||
let [minHeight, naturalHeight] = this._name.get_preferred_height(-1);
|
||||
let availWidth = box.x2 - box.x1;
|
||||
let availHeight = box.y2 - box.y1;
|
||||
let targetWidth = availWidth;
|
||||
let xPadding = 0;
|
||||
if (naturalWidth < availWidth) {
|
||||
xPadding = Math.floor((availWidth - naturalWidth) / 2);
|
||||
}
|
||||
childBox.x1 = xPadding;
|
||||
childBox.x2 = availWidth - xPadding;
|
||||
childBox.y1 = this._glowExtendVertical;
|
||||
childBox.y2 = availHeight - this._glowExtendVertical;
|
||||
this._name.allocate(childBox, flags);
|
||||
|
||||
// Now the glow
|
||||
let glowPaddingHoriz = Math.max(0, xPadding - this._glowShrinkHorizontal);
|
||||
glowPaddingHoriz = Math.max(this._glowShrinkHorizontal, glowPaddingHoriz);
|
||||
childBox.x1 = glowPaddingHoriz;
|
||||
childBox.x2 = availWidth - glowPaddingHoriz;
|
||||
childBox.y1 = 0;
|
||||
childBox.y2 = availHeight;
|
||||
this._glowBox.allocate(childBox, flags);
|
||||
},
|
||||
|
||||
_onDestroy: function() {
|
||||
if (this._appWindowChangedId > 0)
|
||||
this.app.disconnect(this._appWindowChangedId);
|
||||
},
|
||||
|
||||
_onMapped: function() {
|
||||
if (!this._queuedGlowRerender)
|
||||
return;
|
||||
this._queuedGlowRerender = false;
|
||||
this._rerenderGlow();
|
||||
},
|
||||
|
||||
_rerenderGlow: function() {
|
||||
if (!this.actor.mapped) {
|
||||
this._queuedGlowRerender = true;
|
||||
return;
|
||||
}
|
||||
this._glowBox.destroy_children();
|
||||
let glowPath = GLib.filename_to_uri(global.imagedir + 'app-well-glow.png', '');
|
||||
let windows = this.app.get_windows();
|
||||
for (let i = 0; i < windows.length && i < 3; i++) {
|
||||
let glow = Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.FOREVER,
|
||||
glowPath, -1, -1);
|
||||
glow.keep_aspect_ratio = false;
|
||||
this._glowBox.add(glow);
|
||||
}
|
||||
},
|
||||
|
||||
_onButtonPress: function(actor, event) {
|
||||
let [stageX, stageY] = event.get_coords();
|
||||
this._dragStartX = stageX;
|
||||
this._dragStartY = stageY;
|
||||
},
|
||||
|
||||
_onHoverChange: function(actor) {
|
||||
let hover = this.actor.hover;
|
||||
if (!hover) {
|
||||
if (this.actor.pressed && this._dragStartX != null) {
|
||||
this.actor.fake_release();
|
||||
this._draggable.startDrag(this._dragStartX, this._dragStartY,
|
||||
Main.currentTime());
|
||||
} else {
|
||||
this._dragStartX = null;
|
||||
this._dragStartY = null;
|
||||
}
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
_onClicked: function(actor, event) {
|
||||
let button = event.get_button();
|
||||
if (button == 1) {
|
||||
this._onActivate(event);
|
||||
} else if (button == 3) {
|
||||
// Don't bind to the right click here; we want left click outside the
|
||||
// area to deactivate as well.
|
||||
this.popupMenu(0);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
_onStyleChanged: function() {
|
||||
let themeNode = this._glowBox.get_theme_node();
|
||||
|
||||
let success, len;
|
||||
[success, len] = themeNode.get_length('-shell-glow-extend-vertical', false);
|
||||
if (success)
|
||||
this._glowExtendVertical = len;
|
||||
[success, len] = themeNode.get_length('-shell-glow-shrink-horizontal', false);
|
||||
if (success)
|
||||
this._glowShrinkHorizontal = len;
|
||||
this.actor.queue_relayout();
|
||||
},
|
||||
|
||||
popupMenu: function(activatingButton) {
|
||||
if (!this._menu) {
|
||||
this._menu = new AppIconMenu(this);
|
||||
this._menu.connect('highlight-window', Lang.bind(this, function (menu, window) {
|
||||
this.highlightWindow(window);
|
||||
}));
|
||||
this._menu.connect('activate-window', Lang.bind(this, function (menu, window) {
|
||||
this.activateWindow(window);
|
||||
}));
|
||||
this._menu.connect('popup', Lang.bind(this, function (menu, isPoppedUp) {
|
||||
if (isPoppedUp) {
|
||||
this._onMenuPoppedUp();
|
||||
} else {
|
||||
this._onMenuPoppedDown();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
this._menu.popup(activatingButton);
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
// Default implementations; AppDisplay.RunningWellItem overrides these
|
||||
highlightWindow: function(window) {
|
||||
this.emit('highlight-window', window);
|
||||
},
|
||||
|
||||
activateWindow: function(window) {
|
||||
this.emit('activate-window', window);
|
||||
},
|
||||
|
||||
shellWorkspaceLaunch : function() {
|
||||
@ -353,7 +432,7 @@ BaseWellItem.prototype = {
|
||||
},
|
||||
|
||||
getDragActor: function() {
|
||||
return this.createDragActor();
|
||||
return this.app.create_icon_texture(APPICON_SIZE);
|
||||
},
|
||||
|
||||
// Returns the original icon that is being used as a source for the cloned texture
|
||||
@ -362,6 +441,305 @@ BaseWellItem.prototype = {
|
||||
return this.actor;
|
||||
}
|
||||
}
|
||||
Signals.addSignalMethods(BaseWellItem.prototype);
|
||||
|
||||
function AppIconMenu(source) {
|
||||
this._init(source);
|
||||
}
|
||||
|
||||
AppIconMenu.prototype = {
|
||||
_init: function(source) {
|
||||
this._source = source;
|
||||
|
||||
this._arrowSize = 4; // CSS default
|
||||
this._spacing = 0; // CSS default
|
||||
|
||||
this._dragStartX = 0;
|
||||
this._dragStartY = 0;
|
||||
|
||||
this.actor = new Shell.GenericContainer({ reactive: true });
|
||||
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
||||
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
||||
|
||||
this._windowContainerBox = new St.Bin({ style_class: 'app-well-menu' });
|
||||
this._windowContainer = new Shell.Menu({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
width: Main.overview._dash.actor.width });
|
||||
this._windowContainerBox.set_child(this._windowContainer);
|
||||
this._windowContainer.connect('unselected', Lang.bind(this, this._onItemUnselected));
|
||||
this._windowContainer.connect('selected', Lang.bind(this, this._onItemSelected));
|
||||
this._windowContainer.connect('cancelled', Lang.bind(this, this._onWindowSelectionCancelled));
|
||||
this._windowContainer.connect('activate', Lang.bind(this, this._onItemActivate));
|
||||
this.actor.add_actor(this._windowContainerBox);
|
||||
|
||||
// Stay popped up on release over application icon
|
||||
this._windowContainer.set_persistent_source(this._source.actor);
|
||||
|
||||
// Intercept events while the menu has the pointer grab to do window-related effects
|
||||
this._windowContainer.connect('enter-event', Lang.bind(this, this._onMenuEnter));
|
||||
this._windowContainer.connect('leave-event', Lang.bind(this, this._onMenuLeave));
|
||||
this._windowContainer.connect('button-release-event', Lang.bind(this, this._onMenuButtonRelease));
|
||||
|
||||
this._borderColor = new Clutter.Color();
|
||||
this._backgroundColor = new Clutter.Color();
|
||||
this._windowContainerBox.connect('style-changed', Lang.bind(this, this._onStyleChanged));
|
||||
|
||||
this._arrow = new St.DrawingArea();
|
||||
this._arrow.connect('redraw', Lang.bind(this, function (area, texture) {
|
||||
Shell.draw_box_pointer(texture,
|
||||
Shell.PointerDirection.LEFT,
|
||||
this._borderColor,
|
||||
this._backgroundColor);
|
||||
}));
|
||||
this.actor.add_actor(this._arrow);
|
||||
|
||||
// Chain our visibility and lifecycle to that of the source
|
||||
source.actor.connect('notify::mapped', Lang.bind(this, function () {
|
||||
if (!source.actor.mapped)
|
||||
this._windowContainer.popdown();
|
||||
}));
|
||||
source.actor.connect('destroy', Lang.bind(this, function () { this.actor.destroy(); }));
|
||||
|
||||
global.stage.add_actor(this.actor);
|
||||
},
|
||||
|
||||
_getPreferredWidth: function(actor, forHeight, alloc) {
|
||||
let [min, natural] = this._windowContainerBox.get_preferred_width(forHeight);
|
||||
min += this._arrowSize;
|
||||
natural += this._arrowSize;
|
||||
alloc.min_size = min;
|
||||
alloc.natural_size = natural;
|
||||
},
|
||||
|
||||
_getPreferredHeight: function(actor, forWidth, alloc) {
|
||||
let [min, natural] = this._windowContainerBox.get_preferred_height(forWidth);
|
||||
alloc.min_size = min;
|
||||
alloc.natural_size = natural;
|
||||
},
|
||||
|
||||
_allocate: function(actor, box, flags) {
|
||||
let childBox = new Clutter.ActorBox();
|
||||
let themeNode = this._windowContainerBox.get_theme_node();
|
||||
|
||||
let width = box.x2 - box.x1;
|
||||
let height = box.y2 - box.y1;
|
||||
|
||||
childBox.x1 = 0;
|
||||
childBox.x2 = this._arrowSize;
|
||||
childBox.y1 = Math.floor((height / 2) - (this._arrowSize / 2));
|
||||
childBox.y2 = childBox.y1 + this._arrowSize;
|
||||
this._arrow.allocate(childBox, flags);
|
||||
|
||||
// Ensure the arrow is above the border area
|
||||
let border = themeNode.get_border_width(St.Side.LEFT);
|
||||
childBox.x1 = this._arrowSize - border;
|
||||
childBox.x2 = width;
|
||||
childBox.y1 = 0;
|
||||
childBox.y2 = height;
|
||||
this._windowContainerBox.allocate(childBox, flags);
|
||||
},
|
||||
|
||||
_redisplay: function() {
|
||||
this._windowContainer.remove_all();
|
||||
|
||||
let windows = this._source.app.get_windows();
|
||||
|
||||
this._windowContainer.show();
|
||||
|
||||
let iconsDiffer = false;
|
||||
let texCache = Shell.TextureCache.get_default();
|
||||
if (windows.length > 0) {
|
||||
let firstIcon = windows[0].mini_icon;
|
||||
for (let i = 1; i < windows.length; i++) {
|
||||
if (!texCache.pixbuf_equal(windows[i].mini_icon, firstIcon)) {
|
||||
iconsDiffer = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Display the app windows menu items and the separator between windows
|
||||
// of the current desktop and other windows.
|
||||
let activeWorkspace = global.screen.get_active_workspace();
|
||||
let separatorShown = windows.length > 0 && windows[0].get_workspace() != activeWorkspace;
|
||||
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
if (!separatorShown && windows[i].get_workspace() != activeWorkspace) {
|
||||
this._appendSeparator();
|
||||
separatorShown = true;
|
||||
}
|
||||
let box = this._appendMenuItem(windows[i].title);
|
||||
box._window = windows[i];
|
||||
}
|
||||
|
||||
if (windows.length > 0)
|
||||
this._appendSeparator();
|
||||
|
||||
let isFavorite = AppFavorites.getAppFavorites().isFavorite(this._source.app.get_id());
|
||||
|
||||
this._newWindowMenuItem = windows.length > 0 ? this._appendMenuItem(_("New Window")) : null;
|
||||
|
||||
if (windows.length > 0)
|
||||
this._appendSeparator();
|
||||
this._toggleFavoriteMenuItem = this._appendMenuItem(isFavorite ? _("Remove from Favorites")
|
||||
: _("Add to Favorites"));
|
||||
|
||||
this._highlightedItem = null;
|
||||
},
|
||||
|
||||
_appendSeparator: function () {
|
||||
let bin = new St.Bin({ style_class: "app-well-menu-separator" });
|
||||
this._windowContainer.append_separator(bin, Big.BoxPackFlags.NONE);
|
||||
},
|
||||
|
||||
_appendMenuItem: function(labelText) {
|
||||
let box = new St.BoxLayout({ style_class: 'app-well-menu-item',
|
||||
reactive: true });
|
||||
let label = new St.Label({ text: labelText });
|
||||
box.add(label);
|
||||
this._windowContainer.append(box, Big.BoxPackFlags.NONE);
|
||||
return box;
|
||||
},
|
||||
|
||||
popup: function(activatingButton) {
|
||||
let [stageX, stageY] = this._source.actor.get_transformed_position();
|
||||
let [stageWidth, stageHeight] = this._source.actor.get_transformed_size();
|
||||
|
||||
this._redisplay();
|
||||
|
||||
this._windowContainer.popup(activatingButton, Main.currentTime());
|
||||
|
||||
this.emit('popup', true);
|
||||
|
||||
let x, y;
|
||||
x = Math.floor(stageX + stageWidth);
|
||||
y = Math.floor(stageY + (stageHeight / 2) - (this.actor.height / 2));
|
||||
|
||||
this.actor.set_position(x, y);
|
||||
this.actor.show();
|
||||
},
|
||||
|
||||
popdown: function() {
|
||||
this._windowContainer.popdown();
|
||||
this.emit('popup', false);
|
||||
this.actor.hide();
|
||||
},
|
||||
|
||||
selectWindow: function(metaWindow) {
|
||||
this._selectMenuItemForWindow(metaWindow);
|
||||
},
|
||||
|
||||
_findMetaWindowForActor: function (actor) {
|
||||
if (actor._delegate instanceof Workspaces.WindowClone)
|
||||
return actor._delegate.metaWindow;
|
||||
else if (actor.get_meta_window)
|
||||
return actor.get_meta_window();
|
||||
return null;
|
||||
},
|
||||
|
||||
// This function is called while the menu has a pointer grab; what we want
|
||||
// to do is see if the mouse was released over a window representation
|
||||
_onMenuButtonRelease: function (actor, event) {
|
||||
let metaWindow = this._findMetaWindowForActor(event.get_source());
|
||||
if (metaWindow) {
|
||||
this.emit('activate-window', metaWindow);
|
||||
}
|
||||
},
|
||||
|
||||
_updateHighlight: function (item) {
|
||||
if (this._highlightedItem) {
|
||||
this._highlightedItem.set_style_pseudo_class(null);
|
||||
this.emit('highlight-window', null);
|
||||
}
|
||||
this._highlightedItem = item;
|
||||
if (this._highlightedItem) {
|
||||
item.set_style_pseudo_class('hover');
|
||||
let window = this._highlightedItem._window;
|
||||
if (window)
|
||||
this.emit('highlight-window', window);
|
||||
}
|
||||
},
|
||||
|
||||
_selectMenuItemForWindow: function (metaWindow) {
|
||||
let children = this._windowContainer.get_children();
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
let child = children[i];
|
||||
let menuMetaWindow = child._window;
|
||||
if (menuMetaWindow == metaWindow)
|
||||
this._updateHighlight(child);
|
||||
}
|
||||
},
|
||||
|
||||
// Called while menu has a pointer grab
|
||||
_onMenuEnter: function (actor, event) {
|
||||
let metaWindow = this._findMetaWindowForActor(event.get_source());
|
||||
if (metaWindow) {
|
||||
this._selectMenuItemForWindow(metaWindow);
|
||||
}
|
||||
},
|
||||
|
||||
// Called while menu has a pointer grab
|
||||
_onMenuLeave: function (actor, event) {
|
||||
let metaWindow = this._findMetaWindowForActor(event.get_source());
|
||||
if (metaWindow) {
|
||||
this._updateHighlight(null);
|
||||
}
|
||||
},
|
||||
|
||||
_onItemUnselected: function (actor, child) {
|
||||
this._updateHighlight(null);
|
||||
},
|
||||
|
||||
_onItemSelected: function (actor, child) {
|
||||
this._updateHighlight(child);
|
||||
},
|
||||
|
||||
_onItemActivate: function (actor, child) {
|
||||
if (child._window) {
|
||||
let metaWindow = child._window;
|
||||
this.emit('activate-window', metaWindow);
|
||||
} else if (child == this._newWindowMenuItem) {
|
||||
this._source.app.launch();
|
||||
this.emit('activate-window', null);
|
||||
} else if (child == this._toggleFavoriteMenuItem) {
|
||||
let favs = AppFavorites.getAppFavorites();
|
||||
let isFavorite = favs.isFavorite(this._source.app.get_id());
|
||||
if (isFavorite)
|
||||
favs.removeFavorite(this._source.app.get_id());
|
||||
else
|
||||
favs.addFavorite(this._source.app.get_id());
|
||||
}
|
||||
this.popdown();
|
||||
},
|
||||
|
||||
_onWindowSelectionCancelled: function () {
|
||||
this.emit('highlight-window', null);
|
||||
this.popdown();
|
||||
},
|
||||
|
||||
_onStyleChanged: function() {
|
||||
let themeNode = this._windowContainerBox.get_theme_node();
|
||||
let [success, len] = themeNode.get_length('-shell-arrow-size', false);
|
||||
if (success) {
|
||||
this._arrowSize = len;
|
||||
this.actor.queue_relayout();
|
||||
}
|
||||
[success, len] = themeNode.get_length('-shell-menu-spacing', false)
|
||||
if (success) {
|
||||
this._windowContainer.spacing = len;
|
||||
}
|
||||
let color = new Clutter.Color();
|
||||
if (themeNode.get_background_color(color)) {
|
||||
this._backgroundColor = color;
|
||||
color = new Clutter.Color();
|
||||
}
|
||||
if (themeNode.get_border_color(St.Side.LEFT, color)) {
|
||||
this._borderColor = color;
|
||||
}
|
||||
this._arrow.emit_redraw();
|
||||
}
|
||||
};
|
||||
Signals.addSignalMethods(AppIconMenu.prototype);
|
||||
|
||||
function RunningWellItem(app, isFavorite) {
|
||||
this._init(app, isFavorite);
|
||||
@ -372,14 +750,9 @@ RunningWellItem.prototype = {
|
||||
|
||||
_init: function(app, isFavorite) {
|
||||
BaseWellItem.prototype._init.call(this, app, isFavorite);
|
||||
|
||||
this._dragStartX = 0;
|
||||
this._dragStartY = 0;
|
||||
|
||||
this.actor.connect('activate', Lang.bind(this, this._onActivate));
|
||||
},
|
||||
|
||||
_onActivate: function (actor, event) {
|
||||
_onActivate: function (event) {
|
||||
let modifiers = Shell.get_event_state(event);
|
||||
|
||||
if (modifiers & Clutter.ModifierType.CONTROL_MASK) {
|
||||
@ -406,11 +779,11 @@ RunningWellItem.prototype = {
|
||||
Main.overview.hide();
|
||||
},
|
||||
|
||||
menuPoppedUp: function() {
|
||||
_onMenuPoppedUp: function() {
|
||||
Main.overview.getWorkspacesForWindow(null).setApplicationWindowSelection(this.app.get_id());
|
||||
},
|
||||
|
||||
menuPoppedDown: function() {
|
||||
_onMenuPoppedDown: function() {
|
||||
if (this._didActivateWindow)
|
||||
return;
|
||||
|
||||
@ -427,25 +800,18 @@ InactiveWellItem.prototype = {
|
||||
|
||||
_init : function(app, isFavorite) {
|
||||
BaseWellItem.prototype._init.call(this, app, isFavorite);
|
||||
|
||||
this.actor.connect('notify::pressed', Lang.bind(this, this._onPressedChanged));
|
||||
this.actor.connect('activate', Lang.bind(this, this._onActivate));
|
||||
},
|
||||
|
||||
_onPressedChanged: function() {
|
||||
this.setHighlight(this.actor.pressed);
|
||||
},
|
||||
|
||||
_onActivate: function() {
|
||||
_onActivate: function(event) {
|
||||
this.app.launch();
|
||||
Main.overview.hide();
|
||||
return true;
|
||||
},
|
||||
|
||||
menuPoppedUp: function() {
|
||||
_onMenuPoppedUp: function() {
|
||||
},
|
||||
|
||||
menuPoppedDown: function() {
|
||||
_onMenuPoppedDown: function() {
|
||||
}
|
||||
};
|
||||
|
||||
@ -455,156 +821,123 @@ function WellGrid() {
|
||||
|
||||
WellGrid.prototype = {
|
||||
_init: function() {
|
||||
this.actor = new Shell.GenericContainer();
|
||||
this.actor = new St.Bin({ name: "dashAppWell" });
|
||||
// Pulled from CSS, but hardcode some defaults here
|
||||
this._spacing = 0;
|
||||
this._item_size = 48;
|
||||
this._grid = new Shell.GenericContainer();
|
||||
this.actor.set_child(this._grid);
|
||||
this.actor.connect('style-changed', Lang.bind(this, this._onStyleChanged));
|
||||
|
||||
this._separator = new Big.Box({ height: 1 });
|
||||
this.actor.add_actor(this._separator);
|
||||
this._separatorIndex = 0;
|
||||
this._cachedSeparatorY = 0;
|
||||
|
||||
this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
||||
this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||
this.actor.connect('allocate', Lang.bind(this, this._allocate));
|
||||
this._grid.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
|
||||
this._grid.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
|
||||
this._grid.connect('allocate', Lang.bind(this, this._allocate));
|
||||
},
|
||||
|
||||
_getPreferredWidth: function (grid, forHeight, alloc) {
|
||||
let [itemMin, itemNatural] = this._getItemPreferredWidth();
|
||||
let children = this._getItemChildren();
|
||||
let nColumns;
|
||||
if (children.length < WELL_DEFAULT_COLUMNS)
|
||||
nColumns = children.length;
|
||||
else
|
||||
nColumns = WELL_DEFAULT_COLUMNS;
|
||||
alloc.min_size = itemMin;
|
||||
alloc.natural_size = itemNatural * nColumns;
|
||||
let children = this._grid.get_children();
|
||||
let nColumns = children.length;
|
||||
let totalSpacing = Math.max(0, nColumns - 1) * this._spacing;
|
||||
// Kind of a lie, but not really an issue right now. If
|
||||
// we wanted to support some sort of hidden/overflow that would
|
||||
// need higher level design
|
||||
alloc.min_size = this._item_size;
|
||||
alloc.natural_size = nColumns * this._item_size + totalSpacing;
|
||||
},
|
||||
|
||||
_getPreferredHeight: function (grid, forWidth, alloc) {
|
||||
let [rows, columns, itemWidth, itemHeight] = this._computeLayout(forWidth);
|
||||
let totalVerticalSpacing = Math.max(rows - 1, 0) * WELL_ITEM_VSPACING;
|
||||
|
||||
let [separatorMin, separatorNatural] = this._separator.get_preferred_height(forWidth);
|
||||
alloc.min_size = alloc.natural_size = rows * itemHeight + totalVerticalSpacing + separatorNatural;
|
||||
let children = this._grid.get_children();
|
||||
let [nColumns, usedWidth] = this._computeLayout(forWidth);
|
||||
let nRows;
|
||||
if (nColumns > 0)
|
||||
nRows = Math.ceil(children.length / nColumns);
|
||||
else
|
||||
nRows = 0;
|
||||
let totalSpacing = Math.max(0, nRows - 1) * this._spacing;
|
||||
let height = nRows * this._item_size + totalSpacing;
|
||||
alloc.min_size = height;
|
||||
alloc.natural_size = height;
|
||||
},
|
||||
|
||||
_allocate: function (grid, box, flags) {
|
||||
let children = this._getItemChildren();
|
||||
let children = this._grid.get_children();
|
||||
let availWidth = box.x2 - box.x1;
|
||||
let availHeight = box.y2 - box.y1;
|
||||
|
||||
let [rows, columns, itemWidth, itemHeight] = this._computeLayout(availWidth);
|
||||
let [nColumns, usedWidth] = this._computeLayout(availWidth);
|
||||
|
||||
let [separatorMin, separatorNatural] = this._separator.get_preferred_height(-1);
|
||||
let overallPaddingX = Math.floor((availWidth - usedWidth) / 2);
|
||||
|
||||
let x = box.x1;
|
||||
let x = box.x1 + overallPaddingX;
|
||||
let y = box.y1;
|
||||
let columnIndex = 0;
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
let [childMinWidth, childNaturalWidth] = children[i].get_preferred_width(-1);
|
||||
let [childMinWidth, childMinHeight, childNaturalWidth, childNaturalHeight]
|
||||
= children[i].get_preferred_size();
|
||||
|
||||
/* Center the item in its allocation horizontally */
|
||||
let width = Math.min(itemWidth, childNaturalWidth);
|
||||
let horizSpacing = (itemWidth - width) / 2;
|
||||
let width = Math.min(this._item_size, childNaturalWidth);
|
||||
let childXSpacing = Math.max(0, width - childNaturalWidth) / 2;
|
||||
let height = Math.min(this._item_size, childNaturalHeight);
|
||||
let childYSpacing = Math.max(0, height - childNaturalHeight) / 2;
|
||||
|
||||
let childBox = new Clutter.ActorBox();
|
||||
childBox.x1 = Math.floor(x + horizSpacing);
|
||||
childBox.y1 = y;
|
||||
childBox.x1 = Math.floor(x + childXSpacing);
|
||||
childBox.y1 = Math.floor(y + childYSpacing);
|
||||
childBox.x2 = childBox.x1 + width;
|
||||
childBox.y2 = childBox.y1 + itemHeight;
|
||||
childBox.y2 = childBox.y1 + height;
|
||||
children[i].allocate(childBox, flags);
|
||||
|
||||
columnIndex++;
|
||||
if (columnIndex == columns) {
|
||||
if (columnIndex == nColumns) {
|
||||
columnIndex = 0;
|
||||
}
|
||||
|
||||
if (columnIndex == 0) {
|
||||
y += itemHeight + WELL_ITEM_VSPACING;
|
||||
x = box.x1;
|
||||
y += this._item_size + this._spacing;
|
||||
x = box.x1 + overallPaddingX;
|
||||
} else {
|
||||
x += itemWidth;
|
||||
x += this._item_size + this._spacing;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
removeAll: function () {
|
||||
let itemChildren = this._getItemChildren();
|
||||
for (let i = 0; i < itemChildren.length; i++) {
|
||||
itemChildren[i].destroy();
|
||||
}
|
||||
},
|
||||
|
||||
_getItemChildren: function () {
|
||||
let children = this.actor.get_children();
|
||||
children.shift();
|
||||
return children;
|
||||
},
|
||||
|
||||
_computeLayout: function (forWidth) {
|
||||
let [itemMinWidth, itemNaturalWidth] = this._getItemPreferredWidth();
|
||||
let columnsNatural;
|
||||
let i;
|
||||
let children = this._getItemChildren();
|
||||
if (children.length == 0)
|
||||
return [0, WELL_DEFAULT_COLUMNS, 0, 0];
|
||||
let children = this._grid.get_children();
|
||||
let nColumns = 0;
|
||||
let usedWidth = 0;
|
||||
// Big.Box will allocate us at 0x0 if we are not visible; this is probably a
|
||||
// Big.Box bug but it can't be fixed because if children are skipped in allocate()
|
||||
// Clutter gets confused (see http://bugzilla.openedhand.com/show_bug.cgi?id=1831)
|
||||
if (forWidth <= 0) {
|
||||
nColumns = WELL_DEFAULT_COLUMNS;
|
||||
} else {
|
||||
while (nColumns < WELL_DEFAULT_COLUMNS &&
|
||||
nColumns < children.length &&
|
||||
usedWidth + itemMinWidth <= forWidth) {
|
||||
// By including WELL_ITEM_MIN_HSPACING in usedWidth, we are ensuring
|
||||
// that the number of columns we end up with will allow the spacing
|
||||
// between the columns to be at least that value.
|
||||
usedWidth += itemMinWidth + WELL_ITEM_MIN_HSPACING;
|
||||
nColumns++;
|
||||
}
|
||||
while (nColumns < WELL_MAX_COLUMNS &&
|
||||
nColumns < children.length &&
|
||||
(usedWidth + this._item_size <= forWidth)) {
|
||||
usedWidth += this._item_size + this._spacing;
|
||||
nColumns += 1;
|
||||
}
|
||||
|
||||
if (nColumns == 0) {
|
||||
log("WellGrid: couldn't fit a column in width " + forWidth);
|
||||
/* FIXME - fall back to smaller icon size */
|
||||
}
|
||||
if (nColumns > 0)
|
||||
usedWidth -= this._spacing;
|
||||
|
||||
let minWidth = itemMinWidth * nColumns;
|
||||
|
||||
let lastColumnIndex = nColumns - 1;
|
||||
let rows = Math.ceil(children.length / nColumns);
|
||||
|
||||
let itemWidth;
|
||||
if (forWidth <= 0) {
|
||||
itemWidth = itemNaturalWidth;
|
||||
} else {
|
||||
itemWidth = Math.floor(forWidth / nColumns);
|
||||
}
|
||||
|
||||
let itemNaturalHeight = 0;
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
let [childMin, childNatural] = children[i].get_preferred_height(itemWidth);
|
||||
if (childNatural > itemNaturalHeight)
|
||||
itemNaturalHeight = childNatural;
|
||||
}
|
||||
|
||||
return [rows, nColumns, itemWidth, itemNaturalHeight];
|
||||
return [nColumns, usedWidth];
|
||||
},
|
||||
|
||||
_getItemPreferredWidth: function () {
|
||||
let children = this._getItemChildren();
|
||||
let minWidth = 0;
|
||||
let naturalWidth = 0;
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
let [childMin, childNatural] = children[i].get_preferred_width(-1);
|
||||
if (childMin > minWidth)
|
||||
minWidth = childMin;
|
||||
if (childNatural > naturalWidth)
|
||||
naturalWidth = childNatural;
|
||||
}
|
||||
return [minWidth, naturalWidth];
|
||||
_onStyleChanged: function() {
|
||||
let themeNode = this.actor.get_theme_node();
|
||||
let [success, len] = themeNode.get_length('spacing', false);
|
||||
if (success)
|
||||
this._spacing = len;
|
||||
[success, len] = themeNode.get_length('-shell-grid-item-size', false);
|
||||
if (success)
|
||||
this._item_size = len;
|
||||
this._grid.queue_relayout();
|
||||
},
|
||||
|
||||
removeAll: function () {
|
||||
this._grid.get_children().forEach(Lang.bind(this, function (child) {
|
||||
child.destroy();
|
||||
}));
|
||||
},
|
||||
|
||||
addItem: function(actor) {
|
||||
this._grid.add_actor(actor);
|
||||
}
|
||||
}
|
||||
|
||||
@ -671,6 +1004,7 @@ AppWell.prototype = {
|
||||
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;
|
||||
@ -679,7 +1013,8 @@ AppWell.prototype = {
|
||||
} else {
|
||||
display = new InactiveWellItem(app, true);
|
||||
}
|
||||
this._grid.actor.add_actor(display.actor);
|
||||
this._grid.addItem(display.actor);
|
||||
nFavorites++;
|
||||
}
|
||||
|
||||
for (let i = 0; i < running.length; i++) {
|
||||
@ -687,14 +1022,12 @@ AppWell.prototype = {
|
||||
if (app.get_id() in favorites)
|
||||
continue;
|
||||
let display = new RunningWellItem(app, false);
|
||||
this._grid.actor.add_actor(display.actor);
|
||||
this._grid.addItem(display.actor);
|
||||
}
|
||||
|
||||
if (this._grid.actor.get_n_children() == 1) {
|
||||
let text = new Clutter.Text({ color: GenericDisplay.ITEM_DISPLAY_NAME_COLOR,
|
||||
font_name: "Sans 14px",
|
||||
text: _("Drag here to add favorites")});
|
||||
this._grid.actor.add_actor(text);
|
||||
if (running.length == 0 && nFavorites == 0) {
|
||||
let text = new St.Label({ text: _("Drag here to add favorites")});
|
||||
this._grid.actor.set_child(text);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -307,7 +307,7 @@ AppIconMenu.prototype = {
|
||||
this._windowContainer.connect('leave-event', Lang.bind(this, this._onMenuLeave));
|
||||
this._windowContainer.connect('button-release-event', Lang.bind(this, this._onMenuButtonRelease));
|
||||
|
||||
this._arrow = new Shell.DrawingArea();
|
||||
this._arrow = new St.DrawingArea();
|
||||
this._arrow.connect('redraw', Lang.bind(this, function (area, texture) {
|
||||
Shell.draw_box_pointer(texture,
|
||||
this._type == MenuType.ON_RIGHT ? Shell.PointerDirection.LEFT : Shell.PointerDirection.UP,
|
||||
|
172
js/ui/button.js
172
js/ui/button.js
@ -1,172 +0,0 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Big = imports.gi.Big;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Shell = imports.gi.Shell;
|
||||
const Signals = imports.signals;
|
||||
const Tweener = imports.ui.tweener;
|
||||
|
||||
const DEFAULT_BUTTON_COLOR = new Clutter.Color();
|
||||
DEFAULT_BUTTON_COLOR.from_pixel(0xeeddcc66);
|
||||
|
||||
const DEFAULT_PRESSED_BUTTON_COLOR = new Clutter.Color();
|
||||
DEFAULT_PRESSED_BUTTON_COLOR.from_pixel(0xccbbaa66);
|
||||
|
||||
const DEFAULT_TEXT_COLOR = new Clutter.Color();
|
||||
DEFAULT_TEXT_COLOR.from_pixel(0x000000ff);
|
||||
|
||||
const DEFAULT_FONT = 'Sans Bold 16px';
|
||||
|
||||
// Padding on the left and right side of the button.
|
||||
const SIDE_PADDING = 14;
|
||||
|
||||
function Button(widget, buttonColor, pressedButtonColor, textColor, font) {
|
||||
this._init(widget, buttonColor, pressedButtonColor, textColor, font);
|
||||
}
|
||||
|
||||
Button.prototype = {
|
||||
_init : function(widgetOrText, buttonColor, pressedButtonColor, textColor, font) {
|
||||
this._buttonColor = buttonColor
|
||||
if (buttonColor == null)
|
||||
this._buttonColor = DEFAULT_BUTTON_COLOR;
|
||||
|
||||
this._pressedButtonColor = pressedButtonColor
|
||||
if (pressedButtonColor == null)
|
||||
this._pressedButtonColor = DEFAULT_PRESSED_BUTTON_COLOR;
|
||||
|
||||
this._textColor = textColor;
|
||||
if (textColor == null)
|
||||
this._textColor = DEFAULT_TEXT_COLOR;
|
||||
|
||||
this._font = font;
|
||||
if (font == null)
|
||||
this._font = DEFAULT_FONT;
|
||||
|
||||
this._isBetweenPressAndRelease = false;
|
||||
this._mouseIsOverButton = false;
|
||||
|
||||
this.actor = new Shell.ButtonBox({ reactive: true,
|
||||
corner_radius: 5,
|
||||
padding_left: SIDE_PADDING,
|
||||
padding_right: SIDE_PADDING,
|
||||
orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
y_align: Big.BoxAlignment.CENTER
|
||||
});
|
||||
if (typeof widgetOrText == 'string') {
|
||||
this._widget = new Clutter.Text({ font_name: this._font,
|
||||
color: this._textColor,
|
||||
text: widgetOrText });
|
||||
} else {
|
||||
this._widget = widgetOrText;
|
||||
}
|
||||
|
||||
this.actor.append(this._widget, Big.BoxPackFlags.EXPAND);
|
||||
|
||||
this.actor.connect('notify::hover', Lang.bind(this, this._updateColors));
|
||||
this.actor.connect('notify::pressed', Lang.bind(this, this._updateColors));
|
||||
this.actor.connect('notify::active', Lang.bind(this, this._updateColors));
|
||||
},
|
||||
|
||||
_updateColors : function() {
|
||||
if (this.actor.active || this.actor.pressed)
|
||||
this.actor.backgroundColor = this._pressedButtonColor;
|
||||
else if (this.actor.hover)
|
||||
this.actor.backgroundColor = this._buttonColor;
|
||||
else
|
||||
this.actor.backgroundColor = null;
|
||||
}
|
||||
};
|
||||
|
||||
Signals.addSignalMethods(Button.prototype);
|
||||
|
||||
/* Delay before the icon should appear, in seconds after the pointer has entered the parent */
|
||||
const ANIMATION_TIME = 0.25;
|
||||
|
||||
/* This is an icon button that fades in/out when mouse enters/leaves the parent.
|
||||
* A delay is used before the fading starts. You can force it to be shown if needed.
|
||||
*
|
||||
* parent -- used to show/hide the button depending on mouse entering/leaving it
|
||||
* size -- size in pixels of both the button and the icon it contains
|
||||
* texture -- optional, must be used if the texture for the icon is already created (else, use setIconFromName)
|
||||
*/
|
||||
function IconButton(parent, size, texture) {
|
||||
this._init(parent, size, texture);
|
||||
}
|
||||
|
||||
IconButton.prototype = {
|
||||
_init : function(parent, size, texture) {
|
||||
this._size = size;
|
||||
if (texture)
|
||||
this.actor = texture;
|
||||
else
|
||||
this.actor = new Clutter.Texture({ width: this._size, height: this._size });
|
||||
this.actor.set_reactive(true);
|
||||
this.actor.set_opacity(0);
|
||||
parent.connect("enter-event", Lang.bind(this, function(actor, event) {
|
||||
this._shouldHide = false;
|
||||
// Nothing to do if the cursor has come back from a child of the parent actor
|
||||
if (actor.get_children().indexOf(event.get_related()) != -1)
|
||||
return;
|
||||
|
||||
this._fadeIn();
|
||||
}));
|
||||
parent.connect("leave-event", Lang.bind(this, function(actor, event) {
|
||||
// Nothing to do if the cursor has merely entered a child of the parent actor
|
||||
if (actor.get_children().indexOf(event.get_related()) != -1)
|
||||
return;
|
||||
|
||||
// Remember that we should not be visible to hide the button if forceShow is unset
|
||||
if (this._forceShow) {
|
||||
this._shouldHide = true;
|
||||
return;
|
||||
}
|
||||
|
||||
this._fadeOut();
|
||||
}));
|
||||
},
|
||||
|
||||
/// Private methods ///
|
||||
|
||||
setIconFromName : function(iconName) {
|
||||
let iconTheme = Gtk.IconTheme.get_default();
|
||||
let iconInfo = iconTheme.lookup_icon(iconName, this._size, 0);
|
||||
if (!iconInfo)
|
||||
return;
|
||||
|
||||
let iconPath = iconInfo.get_filename();
|
||||
this.actor.set_from_file(iconPath);
|
||||
},
|
||||
|
||||
// Useful if we want to show the button immediately,
|
||||
// e.g. in case the mouse is already in the parent when the button is created
|
||||
show : function() {
|
||||
this.actor.set_opacity(255);
|
||||
},
|
||||
|
||||
// If show is true, prevents the button from fading out
|
||||
forceShow : function(show) {
|
||||
this._forceShow = show;
|
||||
// Hide the button if it should have been hidden under normal conditions
|
||||
if (!this._forceShow && this._shouldHide) {
|
||||
this._fadeOut();
|
||||
}
|
||||
},
|
||||
|
||||
/// Private methods ///
|
||||
|
||||
_fadeIn : function() {
|
||||
Tweener.removeTweens(this.actor);
|
||||
Tweener.addTween(this.actor, { opacity: 255,
|
||||
time: ANIMATION_TIME,
|
||||
transition :"easeInQuad" });
|
||||
},
|
||||
|
||||
_fadeOut : function() {
|
||||
Tweener.removeTweens(this.actor);
|
||||
Tweener.addTween(this.actor, { opacity: 0,
|
||||
time: ANIMATION_TIME,
|
||||
transition :"easeOutQuad" });
|
||||
}
|
||||
};
|
138
js/ui/chrome.js
138
js/ui/chrome.js
@ -7,6 +7,7 @@ const Meta = imports.gi.Meta;
|
||||
const Shell = imports.gi.Shell;
|
||||
|
||||
const Main = imports.ui.main;
|
||||
const Params = imports.misc.params;
|
||||
|
||||
// This manages the shell "chrome"; the UI that's visible in the
|
||||
// normal mode (ie, outside the Overview), that surrounds the main
|
||||
@ -54,7 +55,7 @@ Chrome.prototype = {
|
||||
|
||||
// addActor:
|
||||
// @actor: an actor to add to the chrome layer
|
||||
// @shapeActor: optional "shape actor".
|
||||
// @params: (optional) additional params
|
||||
//
|
||||
// Adds @actor to the chrome layer and extends the input region
|
||||
// and window manager struts to include it. (Window manager struts
|
||||
@ -64,59 +65,45 @@ Chrome.prototype = {
|
||||
// in its visibility will affect the input region, but NOT the
|
||||
// struts.
|
||||
//
|
||||
// If @shapeActor is provided, it will be used instead of @actor
|
||||
// for the input region/strut shape. (This lets you have things like
|
||||
// drop shadows in @actor that don't affect the struts.) It must
|
||||
// be a child of @actor. Alternatively, you can pass %null for
|
||||
// @shapeActor to indicate that @actor should not affect the input
|
||||
// region or struts at all.
|
||||
addActor: function(actor, shapeActor) {
|
||||
if (shapeActor === undefined)
|
||||
shapeActor = actor;
|
||||
else if (shapeActor && !this._verifyAncestry(shapeActor, actor))
|
||||
throw new Error('shapeActor is not a descendent of actor');
|
||||
// If %visibleInOverview is %true in @params, @actor will remain
|
||||
// visible when the overview is brought up. Otherwise it will
|
||||
// automatically be hidden. If %affectsStruts or %affectsInputRegion
|
||||
// is %false, the actor will not have the indicated effect.
|
||||
addActor: function(actor, params) {
|
||||
params = Params.parse(params, { visibleInOverview: false,
|
||||
affectsStruts: true,
|
||||
affectsInputRegion: true });
|
||||
|
||||
this.nonOverviewActor.add_actor(actor);
|
||||
|
||||
if (shapeActor)
|
||||
this._trackActor(shapeActor, true, true);
|
||||
},
|
||||
|
||||
// setVisibleInOverview:
|
||||
// @actor: an actor in the chrome layer
|
||||
// @visible: Overview visibility
|
||||
//
|
||||
// By default, actors in the chrome layer are automatically hidden
|
||||
// when the Overview is shown. This can be used to override that
|
||||
// behavior
|
||||
setVisibleInOverview: function(actor, visible) {
|
||||
if (!this._verifyAncestry(actor, this.actor))
|
||||
throw new Error('actor is not a descendent of the chrome layer');
|
||||
|
||||
if (visible)
|
||||
actor.reparent(this.actor);
|
||||
if (params.visibleInOverview)
|
||||
this.actor.add_actor(actor);
|
||||
else
|
||||
actor.reparent(this.nonOverviewActor);
|
||||
this.nonOverviewActor.add_actor(actor);
|
||||
|
||||
this._trackActor(actor, params.affectsInputRegion, params.affectsStruts);
|
||||
},
|
||||
|
||||
// addInputRegionActor:
|
||||
// @actor: an actor to add to the stage input region
|
||||
// trackActor:
|
||||
// @actor: a descendant of the chrome to begin tracking
|
||||
// @params: parameters describing how to track @actor
|
||||
//
|
||||
// Adds @actor to the stage input region, as with addActor(), but
|
||||
// for actors that are already descendants of the chrome layer.
|
||||
addInputRegionActor: function(actor) {
|
||||
// Tells the chrome to track @actor, which must be a descendant
|
||||
// of an actor added via addActor(). This can be used to extend the
|
||||
// struts or input region to cover specific children.
|
||||
trackActor: function(actor, params) {
|
||||
if (!this._verifyAncestry(actor, this.actor))
|
||||
throw new Error('actor is not a descendent of the chrome layer');
|
||||
|
||||
this._trackActor(actor, true, false);
|
||||
params = Params.parse(params, { affectsStruts: true,
|
||||
affectsInputRegion: true });
|
||||
this._trackActor(actor, params.affectsInputRegion, params.affectsStruts);
|
||||
},
|
||||
|
||||
// removeInputRegionActor:
|
||||
// @actor: an actor previously added to the stage input region
|
||||
// untrackActor:
|
||||
// @actor: an actor previously tracked via trackActor()
|
||||
//
|
||||
// Undoes the effect of addInputRegionActor()
|
||||
removeInputRegionActor: function(actor) {
|
||||
this._untrackActor(actor, true, false);
|
||||
// Undoes the effect of trackActor()
|
||||
untrackActor: function(actor) {
|
||||
this._untrackActor(actor);
|
||||
},
|
||||
|
||||
// removeActor:
|
||||
@ -128,7 +115,7 @@ Chrome.prototype = {
|
||||
this.nonOverviewActor.remove_actor(actor);
|
||||
else
|
||||
this.actor.remove_actor(actor);
|
||||
this._untrackActor(actor, true, true);
|
||||
this._untrackActor(actor);
|
||||
},
|
||||
|
||||
_findActor: function(actor) {
|
||||
@ -142,23 +129,13 @@ Chrome.prototype = {
|
||||
|
||||
_trackActor: function(actor, inputRegion, strut) {
|
||||
let actorData;
|
||||
let i = this._findActor(actor);
|
||||
|
||||
if (i != -1) {
|
||||
actorData = this._trackedActors[i];
|
||||
if (inputRegion)
|
||||
actorData.inputRegion++;
|
||||
if (strut)
|
||||
actorData.strut++;
|
||||
if (!inputRegion && !strut)
|
||||
actorData.children++;
|
||||
return;
|
||||
}
|
||||
if (this._findActor(actor) != -1)
|
||||
throw new Error('trying to re-track existing chrome actor');
|
||||
|
||||
actorData = { actor: actor,
|
||||
inputRegion: inputRegion ? 1 : 0,
|
||||
strut: strut ? 1 : 0,
|
||||
children: 0 };
|
||||
inputRegion: inputRegion,
|
||||
strut: strut };
|
||||
|
||||
actorData.visibleId = actor.connect('notify::visible',
|
||||
Lang.bind(this, this._queueUpdateRegions));
|
||||
@ -166,54 +143,31 @@ Chrome.prototype = {
|
||||
Lang.bind(this, this._queueUpdateRegions));
|
||||
actorData.parentSetId = actor.connect('parent-set',
|
||||
Lang.bind(this, this._actorReparented));
|
||||
// Note that destroying actor will unset its parent, so we don't
|
||||
// need to connect to 'destroy' too.
|
||||
|
||||
this._trackedActors.push(actorData);
|
||||
|
||||
actor = actor.get_parent();
|
||||
if (actor != this.actor && actor != this.nonOverviewActor)
|
||||
this._trackActor(actor, false, false);
|
||||
|
||||
if (inputRegion || strut)
|
||||
this._queueUpdateRegions();
|
||||
this._queueUpdateRegions();
|
||||
},
|
||||
|
||||
_untrackActor: function(actor, inputRegion, strut) {
|
||||
_untrackActor: function(actor) {
|
||||
let i = this._findActor(actor);
|
||||
|
||||
if (i == -1)
|
||||
return;
|
||||
let actorData = this._trackedActors[i];
|
||||
|
||||
if (inputRegion)
|
||||
actorData.inputRegion--;
|
||||
if (strut)
|
||||
actorData.strut--;
|
||||
if (!inputRegion && !strut)
|
||||
actorData.children--;
|
||||
this._trackedActors.splice(i, 1);
|
||||
actor.disconnect(actorData.visibleId);
|
||||
actor.disconnect(actorData.allocationId);
|
||||
actor.disconnect(actorData.parentSetId);
|
||||
|
||||
if (actorData.inputRegion <= 0 && actorData.strut <= 0 && actorData.children <= 0) {
|
||||
this._trackedActors.splice(i, 1);
|
||||
actor.disconnect(actorData.visibleId);
|
||||
actor.disconnect(actorData.allocationId);
|
||||
actor.disconnect(actorData.parentSetId);
|
||||
|
||||
actor = actor.get_parent();
|
||||
if (actor && actor != this.actor && actor != this.nonOverviewActor)
|
||||
this._untrackActor(actor, false, false);
|
||||
}
|
||||
|
||||
if (inputRegion || strut)
|
||||
this._queueUpdateRegions();
|
||||
this._queueUpdateRegions();
|
||||
},
|
||||
|
||||
_actorReparented: function(actor, oldParent) {
|
||||
if (this._verifyAncestry(actor, this.actor)) {
|
||||
let newParent = actor.get_parent();
|
||||
if (newParent != this.actor && newParent != this.nonOverviewActor)
|
||||
this._trackActor(newParent, false, false);
|
||||
}
|
||||
if (oldParent != this.actor && oldParent != this.nonOverviewActor)
|
||||
this._untrackActor(oldParent, false, false);
|
||||
if (!this._verifyAncestry(actor, this.actor))
|
||||
this._untrackActor(actor);
|
||||
},
|
||||
|
||||
_overviewShowing: function() {
|
||||
|
@ -16,7 +16,6 @@ const AppDisplay = imports.ui.appDisplay;
|
||||
const DocDisplay = imports.ui.docDisplay;
|
||||
const PlaceDisplay = imports.ui.placeDisplay;
|
||||
const GenericDisplay = imports.ui.genericDisplay;
|
||||
const Button = imports.ui.button;
|
||||
const Main = imports.ui.main;
|
||||
|
||||
const DEFAULT_PADDING = 4;
|
||||
@ -390,14 +389,6 @@ SectionHeader.prototype = {
|
||||
this._innerBox = new St.BoxLayout({ style_class: "section-header-inner" });
|
||||
this.actor.set_child(this._innerBox);
|
||||
|
||||
this._backgroundGradient = null;
|
||||
this.actor.connect('style-changed', Lang.bind(this, this._onStyleChanged));
|
||||
this.actor.connect('notify::allocation', Lang.bind(this, function (actor) {
|
||||
if (!this._backgroundGradient)
|
||||
return;
|
||||
this._onStyleChanged();
|
||||
}));
|
||||
|
||||
this.backLink = new BackLink();
|
||||
this._innerBox.add(this.backLink.actor);
|
||||
this.backLink.actor.hide();
|
||||
@ -422,33 +413,6 @@ SectionHeader.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_onStyleChanged: function () {
|
||||
if (this._backgroundGradient) {
|
||||
this._backgroundGradient.destroy();
|
||||
}
|
||||
// Manually implement the gradient
|
||||
let themeNode = this.actor.get_theme_node();
|
||||
let gradientTopColor = new Clutter.Color();
|
||||
if (!themeNode.get_color("-shell-gradient-top", false, gradientTopColor))
|
||||
return;
|
||||
let gradientBottomColor = new Clutter.Color();
|
||||
if (!themeNode.get_color("-shell-gradient-bottom", false, gradientBottomColor))
|
||||
return;
|
||||
this._backgroundGradient = Shell.create_vertical_gradient(gradientTopColor,
|
||||
gradientBottomColor);
|
||||
let box = this.actor.allocation;
|
||||
let contentBox = new Clutter.ActorBox();
|
||||
themeNode.get_content_box(box, contentBox);
|
||||
let width = contentBox.x2 - contentBox.x1;
|
||||
let height = contentBox.y2 - contentBox.y1;
|
||||
this._backgroundGradient.set_size(width, height);
|
||||
// This will set a fixed position, which puts us outside of the normal box layout
|
||||
this._backgroundGradient.set_position(0, 0);
|
||||
|
||||
this._innerBox.add_actor(this._backgroundGradient);
|
||||
this._backgroundGradient.lower_bottom();
|
||||
},
|
||||
|
||||
setTitle : function(title) {
|
||||
this.text.text = title;
|
||||
},
|
||||
|
@ -13,7 +13,6 @@ const Signals = imports.signals;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
|
||||
const Button = imports.ui.button;
|
||||
const DND = imports.ui.dnd;
|
||||
const Link = imports.ui.link;
|
||||
const Main = imports.ui.main;
|
||||
@ -43,8 +42,6 @@ const PREVIEW_BOX_CORNER_RADIUS = 10;
|
||||
const PREVIEW_PLACING = 3/4;
|
||||
const PREVIEW_DETAILS_MIN_WIDTH = PREVIEW_ICON_SIZE * 2;
|
||||
|
||||
const INFORMATION_BUTTON_SIZE = 16;
|
||||
|
||||
/* This is a virtual class that represents a single display item containing
|
||||
* a name, a description, and an icon. It allows selecting an item and represents
|
||||
* it by highlighting it with a different background color than the default.
|
||||
@ -68,44 +65,14 @@ GenericDisplayItem.prototype = {
|
||||
}));
|
||||
|
||||
let draggable = DND.makeDraggable(this.actor);
|
||||
draggable.connect('drag-begin', Lang.bind(this, this._onDragBegin));
|
||||
|
||||
this._iconBin = new St.Bin();
|
||||
this.actor.add(this._iconBin);
|
||||
|
||||
this._infoText = new St.BoxLayout({ style_class: "generic-display-item-text",
|
||||
this._infoText = new St.BoxLayout({ style_class: 'generic-display-item-text',
|
||||
vertical: true });
|
||||
this.actor.add(this._infoText, { expand: true, y_fill: false });
|
||||
|
||||
let infoIconUri = "file://" + global.imagedir + "info.svg";
|
||||
let infoIcon = Shell.TextureCache.get_default().load_uri_sync(Shell.TextureCachePolicy.FOREVER,
|
||||
infoIconUri,
|
||||
INFORMATION_BUTTON_SIZE,
|
||||
INFORMATION_BUTTON_SIZE);
|
||||
this._informationButton = new Button.IconButton(this.actor, INFORMATION_BUTTON_SIZE, infoIcon);
|
||||
let buttonBox = new Big.Box({ width: INFORMATION_BUTTON_SIZE + 2 * DEFAULT_PADDING,
|
||||
height: INFORMATION_BUTTON_SIZE,
|
||||
padding_left: DEFAULT_PADDING, padding_right: DEFAULT_PADDING,
|
||||
y_align: Big.BoxAlignment.CENTER });
|
||||
buttonBox.append(this._informationButton.actor, Big.BoxPackFlags.NONE);
|
||||
this.actor.add(buttonBox, { x_fill: false, x_align: St.Align.END });
|
||||
|
||||
// Connecting to the button-press-event for the information button ensures that the actor,
|
||||
// which is a draggable actor, does not get the button-press-event and doesn't initiate
|
||||
// the dragging, which then prevents us from getting the button-release-event for the button.
|
||||
this._informationButton.actor.connect('button-press-event',
|
||||
Lang.bind(this,
|
||||
function() {
|
||||
return true;
|
||||
}));
|
||||
this._informationButton.actor.connect('button-release-event',
|
||||
Lang.bind(this,
|
||||
function() {
|
||||
// Selects the item by highlighting it and displaying its details
|
||||
this.emit('show-details');
|
||||
return true;
|
||||
}));
|
||||
|
||||
this._name = null;
|
||||
this._description = null;
|
||||
this._icon = null;
|
||||
@ -136,16 +103,10 @@ GenericDisplayItem.prototype = {
|
||||
|
||||
//// Public methods ////
|
||||
|
||||
// Shows the information button when the item was drawn under the mouse pointer.
|
||||
onDrawnUnderPointer: function() {
|
||||
this._informationButton.show();
|
||||
},
|
||||
|
||||
// Highlights the item by setting a different background color than the default
|
||||
// if isSelected is true, removes the highlighting otherwise.
|
||||
markSelected: function(isSelected) {
|
||||
this.actor.set_style_pseudo_class(isSelected ? "selected" : null);
|
||||
this._informationButton.forceShow(isSelected)
|
||||
},
|
||||
|
||||
/*
|
||||
@ -271,16 +232,9 @@ GenericDisplayItem.prototype = {
|
||||
// Returns a preview icon for the item.
|
||||
_createPreviewIcon: function() {
|
||||
throw new Error("Not implemented");
|
||||
},
|
||||
}
|
||||
|
||||
//// Private methods ////
|
||||
|
||||
// Hides the information button once the item starts being dragged.
|
||||
_onDragBegin : function (draggable, time) {
|
||||
// For some reason, we are not getting leave-event signal when we are dragging an item,
|
||||
// so we should remove the link manually.
|
||||
this._informationButton.actor.hide();
|
||||
}
|
||||
};
|
||||
|
||||
Signals.addSignalMethods(GenericDisplayItem.prototype);
|
||||
@ -637,28 +591,9 @@ GenericDisplay.prototype = {
|
||||
this.selectFirstItem();
|
||||
}
|
||||
|
||||
Mainloop.idle_add(Lang.bind(this, this._checkInformationIcon),
|
||||
Meta.PRIORITY_BEFORE_REDRAW);
|
||||
|
||||
this.emit('redisplayed');
|
||||
},
|
||||
|
||||
// Check if the pointer is over one of the items and display the information button if it is.
|
||||
// We want to do this between finishing our changes to the display and the point where
|
||||
// the display is redrawn.
|
||||
_checkInformationIcon: function() {
|
||||
let [child, x, y, mask] = Gdk.Screen.get_default().get_root_window().get_pointer();
|
||||
let actor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE,
|
||||
x, y);
|
||||
if (actor != null) {
|
||||
let item = this._findDisplayedByActor(actor);
|
||||
if (item != null) {
|
||||
item.onDrawnUnderPointer();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
//// Pure virtual protected methods ////
|
||||
|
||||
// Performs the steps needed to have the latest information about the items.
|
||||
|
177
js/ui/panel.js
177
js/ui/panel.js
@ -13,42 +13,16 @@ const Signals = imports.signals;
|
||||
const Gettext = imports.gettext.domain('gnome-shell');
|
||||
const _ = Gettext.gettext;
|
||||
|
||||
const Button = imports.ui.button;
|
||||
const Calendar = imports.ui.calendar;
|
||||
const Main = imports.ui.main;
|
||||
const StatusMenu = imports.ui.statusMenu;
|
||||
|
||||
const PANEL_HEIGHT = 26;
|
||||
const TRAY_HEIGHT = PANEL_HEIGHT - 1;
|
||||
|
||||
const DEFAULT_PADDING = 4;
|
||||
|
||||
const PANEL_ICON_SIZE = 24;
|
||||
|
||||
const BACKGROUND_TOP = new Clutter.Color();
|
||||
BACKGROUND_TOP.from_pixel(0x161616ff);
|
||||
const BACKGROUND_BOTTOM = new Clutter.Color();
|
||||
BACKGROUND_BOTTOM.from_pixel(0x000000ff);
|
||||
|
||||
const PANEL_FOREGROUND_COLOR = new Clutter.Color();
|
||||
PANEL_FOREGROUND_COLOR.from_pixel(0xffffffff);
|
||||
const SN_BACKGROUND_COLOR = new Clutter.Color();
|
||||
SN_BACKGROUND_COLOR.from_pixel(0xffff00a0);
|
||||
|
||||
const TRANSPARENT_COLOR = new Clutter.Color();
|
||||
TRANSPARENT_COLOR.from_pixel(0x00000000);
|
||||
|
||||
// Don't make the mouse hover effect visible to the user for a menu feel.
|
||||
const PANEL_BUTTON_COLOR = new Clutter.Color();
|
||||
PANEL_BUTTON_COLOR.from_pixel(0x00000000);
|
||||
|
||||
// Lighten pressed buttons; darkening has no effect on a black background.
|
||||
const PRESSED_BUTTON_BACKGROUND_COLOR = new Clutter.Color();
|
||||
PRESSED_BUTTON_BACKGROUND_COLOR.from_pixel(0x324c6ffa);
|
||||
|
||||
const DEFAULT_FONT = 'Sans 16px';
|
||||
|
||||
const TRAY_PADDING = 0;
|
||||
// See comments around _recomputeTraySize
|
||||
const TRAY_SPACING = 14;
|
||||
const TRAY_SPACING_MIN = 8;
|
||||
@ -84,24 +58,14 @@ AppPanelMenu.prototype = {
|
||||
this._activeSequence = null;
|
||||
this._startupSequences = {};
|
||||
|
||||
this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
spacing: DEFAULT_PADDING,
|
||||
y_align: Big.BoxAlignment.CENTER });
|
||||
this._iconBox = new Big.Box({ width: PANEL_ICON_SIZE, height: PANEL_ICON_SIZE,
|
||||
x_align: Big.BoxAlignment.CENTER,
|
||||
y_align: Big.BoxAlignment.CENTER });
|
||||
this.actor.append(this._iconBox, Big.BoxPackFlags.NONE);
|
||||
let labelBox = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
y_align: Big.BoxAlignment.CENTER });
|
||||
this._label = new Clutter.Text({ font_name: DEFAULT_FONT,
|
||||
color: PANEL_FOREGROUND_COLOR,
|
||||
text: "" });
|
||||
labelBox.append(this._label, Big.BoxPackFlags.EXPAND);
|
||||
this.actor.append(labelBox, Big.BoxPackFlags.NONE);
|
||||
this.actor = new St.BoxLayout({ name: 'appMenu' });
|
||||
this._iconBox = new St.Bin({ name: 'appMenuIcon' });
|
||||
this.actor.add(this._iconBox);
|
||||
this._label = new St.Label();
|
||||
this.actor.add(this._label, { expand: true, y_fill: false });
|
||||
|
||||
this._startupBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
y_align: Big.BoxAlignment.CENTER });
|
||||
this.actor.append(this._startupBox, Big.BoxPackFlags.NONE);
|
||||
this._startupBox = new St.BoxLayout();
|
||||
this.actor.add(this._startupBox);
|
||||
|
||||
Main.overview.connect('hiding', Lang.bind(this, function () {
|
||||
this.actor.opacity = 255;
|
||||
@ -145,19 +109,20 @@ AppPanelMenu.prototype = {
|
||||
this._focusedApp = focusedApp;
|
||||
this._activeSequence = lastSequence;
|
||||
|
||||
this._iconBox.remove_all();
|
||||
if (this._iconBox.child != null)
|
||||
this._iconBox.child.destroy();
|
||||
this._iconBox.hide();
|
||||
this._label.set_text('');
|
||||
if (this._focusedApp != null) {
|
||||
let icon = this._focusedApp.create_icon_texture(PANEL_ICON_SIZE);
|
||||
this._iconBox.append(icon, Big.BoxPackFlags.NONE);
|
||||
this._iconBox.set_child(icon);
|
||||
this._iconBox.show();
|
||||
let appName = this._focusedApp.get_name();
|
||||
// Use _set_text to work around http://bugzilla.openedhand.com/show_bug.cgi?id=1851
|
||||
this._label.set_text(appName);
|
||||
} else if (this._activeSequence != null) {
|
||||
let icon = this._activeSequence.create_icon(PANEL_ICON_SIZE);
|
||||
this._iconBox.append(icon, Big.BoxPackFlags.NONE);
|
||||
this._iconBox.set_child(icon);
|
||||
this._iconBox.show();
|
||||
this._label.set_text(this._activeSequence.get_name());
|
||||
}
|
||||
@ -175,32 +140,17 @@ function Panel() {
|
||||
Panel.prototype = {
|
||||
_init : function() {
|
||||
|
||||
this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL
|
||||
});
|
||||
this.actor = new St.BoxLayout({ name: 'panel' });
|
||||
this.actor._delegate = this;
|
||||
|
||||
let backgroundGradient = Shell.create_vertical_gradient(BACKGROUND_TOP,
|
||||
BACKGROUND_BOTTOM);
|
||||
this.actor.connect('notify::allocation', Lang.bind(this, function () {
|
||||
let [width, height] = this.actor.get_size();
|
||||
backgroundGradient.set_size(width, height);
|
||||
}));
|
||||
this.actor.add_actor(backgroundGradient);
|
||||
|
||||
this._leftBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
y_align: Big.BoxAlignment.CENTER,
|
||||
spacing: DEFAULT_PADDING,
|
||||
padding_right: DEFAULT_PADDING });
|
||||
this._centerBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
y_align: Big.BoxAlignment.CENTER });
|
||||
this._rightBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
y_align: Big.BoxAlignment.CENTER,
|
||||
padding_left: DEFAULT_PADDING });
|
||||
this._leftBox = new St.BoxLayout({ name: 'panelLeft' });
|
||||
this._centerBox = new St.BoxLayout({ name: 'panelCenter' });
|
||||
this._rightBox = new St.BoxLayout({ name: 'panelRight' });
|
||||
|
||||
/* This box container ensures that the centerBox is positioned in the *absolute*
|
||||
* center, but can be pushed aside if necessary. */
|
||||
this._boxContainer = new Shell.GenericContainer();
|
||||
this.actor.append(this._boxContainer, Big.BoxPackFlags.EXPAND);
|
||||
this.actor.add(this._boxContainer, { expand: true });
|
||||
this._boxContainer.add_actor(this._leftBox);
|
||||
this._boxContainer.add_actor(this._centerBox);
|
||||
this._boxContainer.add_actor(this._rightBox);
|
||||
@ -274,11 +224,14 @@ Panel.prototype = {
|
||||
|
||||
/* Button on the left side of the panel. */
|
||||
/* Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview". */
|
||||
this.button = new Button.Button(_("Activities"), PANEL_BUTTON_COLOR, PRESSED_BUTTON_BACKGROUND_COLOR,
|
||||
PANEL_FOREGROUND_COLOR, DEFAULT_FONT);
|
||||
this.button.actor.height = PANEL_HEIGHT;
|
||||
let label = new St.Label({ text: _("Activities") });
|
||||
this.button = new St.Clickable({ name: 'panelActivities',
|
||||
style_class: 'panel-button',
|
||||
reactive: true });
|
||||
this.button.set_child(label);
|
||||
this.button.height = PANEL_HEIGHT;
|
||||
|
||||
this._leftBox.append(this.button.actor, Big.BoxPackFlags.NONE);
|
||||
this._leftBox.add(this.button);
|
||||
|
||||
// We use this flag to mark the case where the user has entered the
|
||||
// hot corner and has not left both the hot corner and a surrounding
|
||||
@ -286,12 +239,16 @@ Panel.prototype = {
|
||||
// multiple times due to an accidental jitter.
|
||||
this._hotCornerEntered = false;
|
||||
|
||||
this._hotCornerEnvirons = new Clutter.Rectangle({ width: 3,
|
||||
this._hotCornerEnvirons = new Clutter.Rectangle({ x: 0,
|
||||
y: 0,
|
||||
width: 3,
|
||||
height: 3,
|
||||
opacity: 0,
|
||||
reactive: true });
|
||||
|
||||
this._hotCorner = new Clutter.Rectangle({ width: 1,
|
||||
this._hotCorner = new Clutter.Rectangle({ x: 0,
|
||||
y: 0,
|
||||
width: 1,
|
||||
height: 1,
|
||||
opacity: 0,
|
||||
reactive: true });
|
||||
@ -315,23 +272,23 @@ Panel.prototype = {
|
||||
this._hotCorner.connect('leave-event',
|
||||
Lang.bind(this, this._onHotCornerLeft));
|
||||
|
||||
this._leftBox.append(this._hotCornerEnvirons, Big.BoxPackFlags.FIXED);
|
||||
this._leftBox.append(this._hotCorner, Big.BoxPackFlags.FIXED);
|
||||
this._leftBox.add(this._hotCornerEnvirons);
|
||||
this._leftBox.add(this._hotCorner);
|
||||
|
||||
let appMenu = new AppPanelMenu();
|
||||
this._leftBox.append(appMenu.actor, Big.BoxPackFlags.NONE);
|
||||
this._leftBox.add(appMenu.actor);
|
||||
|
||||
/* center */
|
||||
|
||||
let clockButton = new St.Button({ style_class: "panel-button",
|
||||
toggle_mode: true });
|
||||
this._centerBox.append(clockButton, Big.BoxPackFlags.NONE);
|
||||
toggle_mode: true,
|
||||
x_fill: true,
|
||||
y_fill: true });
|
||||
this._centerBox.add(clockButton, { y_fill: false });
|
||||
clockButton.connect('clicked', Lang.bind(this, this._toggleCalendar));
|
||||
|
||||
this._clock = new Clutter.Text({ font_name: DEFAULT_FONT,
|
||||
color: PANEL_FOREGROUND_COLOR,
|
||||
text: "" });
|
||||
clockButton.add_actor(this._clock);
|
||||
this._clock = new St.Label();
|
||||
clockButton.set_child(this._clock);
|
||||
|
||||
this._calendarPopup = null;
|
||||
|
||||
@ -340,11 +297,10 @@ Panel.prototype = {
|
||||
// The tray icons live in trayBox within trayContainer.
|
||||
// The trayBox is hidden when there are no tray icons.
|
||||
let trayContainer = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
|
||||
y_align: Big.BoxAlignment.START });
|
||||
this._rightBox.append(trayContainer, Big.BoxPackFlags.NONE);
|
||||
y_align: Big.BoxAlignment.CENTER });
|
||||
this._rightBox.add(trayContainer);
|
||||
let trayBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
|
||||
height: TRAY_HEIGHT,
|
||||
padding: TRAY_PADDING,
|
||||
height: PANEL_ICON_SIZE,
|
||||
spacing: TRAY_SPACING });
|
||||
this._trayBox = trayBox;
|
||||
|
||||
@ -373,37 +329,31 @@ Panel.prototype = {
|
||||
}));
|
||||
this._traymanager.manage_stage(global.stage);
|
||||
|
||||
let statusbox = new Big.Box();
|
||||
let statusmenu = this._statusmenu = new StatusMenu.StatusMenu();
|
||||
statusbox.append(this._statusmenu.actor, Big.BoxPackFlags.NONE);
|
||||
let statusbutton = new Button.Button(statusbox,
|
||||
PANEL_BUTTON_COLOR,
|
||||
PRESSED_BUTTON_BACKGROUND_COLOR,
|
||||
PANEL_FOREGROUND_COLOR);
|
||||
statusbutton.actor.height = PANEL_HEIGHT;
|
||||
statusbutton.actor.connect('button-press-event', function (b, e) {
|
||||
if (e.get_button() == 1 && e.get_click_count() == 1) {
|
||||
statusmenu.toggle(e);
|
||||
// The statusmenu might not pop up if it couldn't get a pointer grab
|
||||
if (statusmenu.isActive())
|
||||
statusbutton.actor.active = true;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
let statusbutton = new St.Clickable({ name: 'panelStatus',
|
||||
style_class: 'panel-button',
|
||||
reactive: true });
|
||||
statusbutton.set_child(statusmenu.actor);
|
||||
statusbutton.height = PANEL_HEIGHT;
|
||||
statusbutton.connect('clicked', function (b, event) {
|
||||
statusmenu.toggle(event);
|
||||
// The statusmenu might not pop up if it couldn't get a pointer grab
|
||||
if (statusmenu.isActive())
|
||||
statusbutton.active = true;
|
||||
return true;
|
||||
});
|
||||
this._rightBox.append(statusbutton.actor, Big.BoxPackFlags.NONE);
|
||||
this._rightBox.add(statusbutton);
|
||||
// We get a deactivated event when the popup disappears
|
||||
this._statusmenu.connect('deactivated', function (sm) {
|
||||
statusbutton.actor.active = false;
|
||||
statusbutton.active = false;
|
||||
});
|
||||
|
||||
// TODO: decide what to do with the rest of the panel in the Overview mode (make it fade-out, become non-reactive, etc.)
|
||||
// We get into the Overview mode on button-press-event as opposed to button-release-event because eventually we'll probably
|
||||
// have the Overview act like a menu that allows the user to release the mouse on the activity the user wants
|
||||
// to switch to.
|
||||
this.button.actor.connect('button-press-event', Lang.bind(this, function(b, e) {
|
||||
if (e.get_button() == 1 && e.get_click_count() == 1 && !Main.overview.animationInProgress) {
|
||||
this.button.connect('clicked', Lang.bind(this, function(b, event) {
|
||||
if (!Main.overview.animationInProgress) {
|
||||
this._maybeToggleOverviewOnClick();
|
||||
return true;
|
||||
} else {
|
||||
@ -414,14 +364,13 @@ Panel.prototype = {
|
||||
// pressing the System key, Alt+F1 or Esc. We want the button to be pressed in when the Overview is entered
|
||||
// and to be released when it is exited regardless of how it was triggered.
|
||||
Main.overview.connect('showing', Lang.bind(this, function() {
|
||||
this.button.actor.active = true;
|
||||
this.button.active = true;
|
||||
}));
|
||||
Main.overview.connect('hiding', Lang.bind(this, function() {
|
||||
this.button.actor.active = false;
|
||||
this.button.active = false;
|
||||
}));
|
||||
|
||||
Main.chrome.addActor(this.actor);
|
||||
Main.chrome.setVisibleInOverview(this.actor, true);
|
||||
Main.chrome.addActor(this.actor, { visibleInOverview: true });
|
||||
|
||||
// Start the clock
|
||||
this._updateClock();
|
||||
@ -558,12 +507,8 @@ CalendarPopup.prototype = {
|
||||
this.calendar = new Calendar.Calendar();
|
||||
this.actor.add(this.calendar.actor);
|
||||
|
||||
// Directly adding the actor to Main.chrome.actor is a hack to
|
||||
// work around the fact that there is no way to add an actor that
|
||||
// affects the input region but not the shape.
|
||||
// See: https://bugzilla.gnome.org/show_bug.cgi?id=597044
|
||||
Main.chrome.actor.add_actor(this.actor);
|
||||
Main.chrome.addInputRegionActor(this.actor);
|
||||
Main.chrome.addActor(this.actor, { visibleInOverview: true,
|
||||
affectsStruts: false });
|
||||
this.actor.y = (panelActor.y + panelActor.height - this.actor.height);
|
||||
},
|
||||
|
||||
|
@ -206,7 +206,7 @@ RunDialog.prototype = {
|
||||
this._commandError = false;
|
||||
|
||||
this._group.hide();
|
||||
this._entry.text = '';
|
||||
this._entry.set_text('');
|
||||
|
||||
Main.popModal(this._group);
|
||||
}
|
||||
|
@ -331,7 +331,7 @@ WidgetBox.prototype = {
|
||||
onCompleteScope: this });
|
||||
this.state = this._widget.state = Widget.STATE_POPPING_OUT;
|
||||
|
||||
Main.chrome.addInputRegionActor(this._hbox);
|
||||
Main.chrome.trackActor(this._hbox, { affectsStruts: false });
|
||||
},
|
||||
|
||||
_popOutComplete: function() {
|
||||
@ -370,7 +370,7 @@ WidgetBox.prototype = {
|
||||
this._egroup.hide();
|
||||
this._ebox.x = 0;
|
||||
|
||||
Main.chrome.removeInputRegionActor(this._hbox);
|
||||
Main.chrome.untrackActor(this._hbox);
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
|
@ -3,12 +3,14 @@
|
||||
const Big = imports.gi.Big;
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const GdkPixbuf = imports.gi.GdkPixbuf;
|
||||
const Gdk = imports.gi.Gdk;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Lang = imports.lang;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Pango = imports.gi.Pango;
|
||||
const Shell = imports.gi.Shell;
|
||||
const St = imports.gi.St;
|
||||
const Signals = imports.signals;
|
||||
|
||||
const DND = imports.ui.dnd;
|
||||
@ -20,10 +22,6 @@ const Tweener = imports.ui.tweener;
|
||||
|
||||
const FOCUS_ANIMATION_TIME = 0.15;
|
||||
|
||||
const WINDOWCLONE_BG_COLOR = new Clutter.Color();
|
||||
WINDOWCLONE_BG_COLOR.from_pixel(0x000000f0);
|
||||
const WINDOWCLONE_TITLE_COLOR = new Clutter.Color();
|
||||
WINDOWCLONE_TITLE_COLOR.from_pixel(0xffffffff);
|
||||
const FRAME_COLOR = new Clutter.Color();
|
||||
FRAME_COLOR.from_pixel(0xffffffff);
|
||||
|
||||
@ -113,8 +111,6 @@ WindowClone.prototype = {
|
||||
|
||||
this._stackAbove = null;
|
||||
|
||||
this._title = null;
|
||||
|
||||
this.actor.connect('button-release-event',
|
||||
Lang.bind(this, this._onButtonRelease));
|
||||
|
||||
@ -135,18 +131,6 @@ WindowClone.prototype = {
|
||||
this._zooming = false;
|
||||
},
|
||||
|
||||
setVisibleWithChrome: function(visible) {
|
||||
if (visible) {
|
||||
this.actor.show();
|
||||
if (this._title)
|
||||
this._title.show();
|
||||
} else {
|
||||
this.actor.hide();
|
||||
if (this._title)
|
||||
this._title.hide();
|
||||
}
|
||||
},
|
||||
|
||||
setStackAbove: function (actor) {
|
||||
this._stackAbove = actor;
|
||||
if (this._inDrag || this._zooming)
|
||||
@ -157,8 +141,6 @@ WindowClone.prototype = {
|
||||
|
||||
destroy: function () {
|
||||
this.actor.destroy();
|
||||
if (this._title)
|
||||
this._title.destroy();
|
||||
},
|
||||
|
||||
_onEnter: function (actor, event) {
|
||||
@ -168,8 +150,6 @@ WindowClone.prototype = {
|
||||
return;
|
||||
|
||||
this._havePointer = true;
|
||||
|
||||
this._updateTitle();
|
||||
},
|
||||
|
||||
_onLeave: function (actor, event) {
|
||||
@ -179,7 +159,6 @@ WindowClone.prototype = {
|
||||
return;
|
||||
|
||||
this._havePointer = false;
|
||||
this._updateTitle();
|
||||
|
||||
if (this._zoomStep)
|
||||
this._zoomEnd();
|
||||
@ -218,6 +197,7 @@ WindowClone.prototype = {
|
||||
|
||||
_zoomStart : function () {
|
||||
this._zooming = true;
|
||||
this.emit('zoom-start');
|
||||
|
||||
this._zoomLightbox = new Lightbox.Lightbox(global.stage);
|
||||
|
||||
@ -246,6 +226,7 @@ WindowClone.prototype = {
|
||||
|
||||
_zoomEnd : function () {
|
||||
this._zooming = false;
|
||||
this.emit('zoom-end');
|
||||
|
||||
this.actor.reparent(this._origParent);
|
||||
this.actor.raise(this._stackAbove);
|
||||
@ -253,8 +234,6 @@ WindowClone.prototype = {
|
||||
[this.actor.x, this.actor.y] = this._zoomLocalOrig.getPosition();
|
||||
[this.actor.scale_x, this.actor.scale_y] = this._zoomLocalOrig.getScale();
|
||||
|
||||
this._adjustTitle();
|
||||
|
||||
this._zoomLightbox.destroy();
|
||||
Main.overview.disconnect(this._hideEventId);
|
||||
|
||||
@ -273,7 +252,6 @@ WindowClone.prototype = {
|
||||
|
||||
_onDragBegin : function (draggable, time) {
|
||||
this._inDrag = true;
|
||||
this._updateTitle();
|
||||
this.emit('drag-begin');
|
||||
},
|
||||
|
||||
@ -295,86 +273,6 @@ WindowClone.prototype = {
|
||||
this.actor.raise(this._stackAbove);
|
||||
|
||||
this.emit('drag-end');
|
||||
},
|
||||
|
||||
// Called by Tweener
|
||||
onAnimationStart : function () {
|
||||
this._updateTitle();
|
||||
},
|
||||
|
||||
// Called by Tweener
|
||||
onAnimationComplete : function () {
|
||||
this._updateTitle();
|
||||
},
|
||||
|
||||
_createTitle : function () {
|
||||
let window = this.realWindow;
|
||||
|
||||
let box = new Big.Box({ background_color : WINDOWCLONE_BG_COLOR,
|
||||
y_align: Big.BoxAlignment.CENTER,
|
||||
corner_radius: 5,
|
||||
padding: 4,
|
||||
spacing: 4,
|
||||
orientation: Big.BoxOrientation.HORIZONTAL });
|
||||
|
||||
let title = new Clutter.Text({ color: WINDOWCLONE_TITLE_COLOR,
|
||||
font_name: "Sans 12",
|
||||
text: this.metaWindow.title,
|
||||
ellipsize: Pango.EllipsizeMode.END
|
||||
});
|
||||
box.append(title, Big.BoxPackFlags.EXPAND);
|
||||
// Get and cache the expected width (just the icon), with spacing, plus title
|
||||
box.fullWidth = box.width;
|
||||
box.hide(); // Hidden by default, show on mouseover
|
||||
this._title = box;
|
||||
|
||||
// Make the title a sibling of the window
|
||||
this.actor.get_parent().add_actor(box);
|
||||
},
|
||||
|
||||
_adjustTitle : function () {
|
||||
let title = this._title;
|
||||
if (!title)
|
||||
return;
|
||||
|
||||
let [cloneScreenWidth, cloneScreenHeight] = this.actor.get_transformed_size();
|
||||
let [titleScreenWidth, titleScreenHeight] = title.get_transformed_size();
|
||||
|
||||
// Titles are supposed to be "full-size", so adjust its
|
||||
// scale to counteract the scaling of its ancestor actors.
|
||||
title.set_scale(title.width / titleScreenWidth * title.scale_x,
|
||||
title.height / titleScreenHeight * title.scale_y);
|
||||
|
||||
title.width = Math.min(title.fullWidth, cloneScreenWidth);
|
||||
let xoff = ((cloneScreenWidth - title.width) / 2) * title.scale_x;
|
||||
title.set_position(this.actor.x + xoff, this.actor.y);
|
||||
},
|
||||
|
||||
_showTitle : function () {
|
||||
if (!this._title)
|
||||
this._createTitle();
|
||||
|
||||
this._adjustTitle();
|
||||
this._title.show();
|
||||
this._title.raise(this.actor);
|
||||
},
|
||||
|
||||
_hideTitle : function () {
|
||||
if (!this._title)
|
||||
return;
|
||||
|
||||
this._title.hide();
|
||||
},
|
||||
|
||||
_updateTitle : function () {
|
||||
let shouldShow = (this._havePointer &&
|
||||
!this._inDrag &&
|
||||
!Tweener.isTweening(this.actor));
|
||||
|
||||
if (shouldShow)
|
||||
this._showTitle();
|
||||
else
|
||||
this._hideTitle();
|
||||
}
|
||||
};
|
||||
|
||||
@ -409,6 +307,207 @@ DesktopClone.prototype = {
|
||||
Signals.addSignalMethods(DesktopClone.prototype);
|
||||
|
||||
|
||||
/**
|
||||
* @windowClone: Corresponding window clone
|
||||
* @parentActor: The actor which will be the parent of all overlay items
|
||||
* such as app icon and window caption
|
||||
*/
|
||||
function WindowOverlay(windowClone, parentActor) {
|
||||
this._init(windowClone, parentActor);
|
||||
}
|
||||
|
||||
WindowOverlay.prototype = {
|
||||
_init : function(windowClone, parentActor) {
|
||||
let metaWindow = windowClone.metaWindow;
|
||||
|
||||
this._windowClone = windowClone;
|
||||
this._parentActor = parentActor;
|
||||
|
||||
let title = new St.Label({ style_class: "window-caption",
|
||||
text : metaWindow.title });
|
||||
title.connect('style-changed',
|
||||
Lang.bind(this, this._onStyleChanged));
|
||||
title.clutter_text.ellipsize = Pango.EllipsizeMode.END;
|
||||
title._spacing = 0;
|
||||
|
||||
let button = new St.Bin({ style_class: "window-close",
|
||||
reactive: true });
|
||||
button.connect('style-changed',
|
||||
Lang.bind(this, this._onStyleChanged));
|
||||
button._overlap = 0;
|
||||
|
||||
windowClone.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
windowClone.actor.connect('notify::allocation',
|
||||
Lang.bind(this, this._positionItems));
|
||||
windowClone.actor.connect('enter-event',
|
||||
Lang.bind(this, this._onEnter));
|
||||
windowClone.actor.connect('leave-event',
|
||||
Lang.bind(this, this._onLeave));
|
||||
|
||||
this._idleToggleCloseId = 0;
|
||||
button.connect('button-release-event',
|
||||
Lang.bind(this, this._closeWindow));
|
||||
|
||||
this._windowAddedId = 0;
|
||||
windowClone.connect('zoom-start', Lang.bind(this, this.hide));
|
||||
windowClone.connect('zoom-end', Lang.bind(this, this.show));
|
||||
|
||||
button.hide();
|
||||
|
||||
this.title = title;
|
||||
this.closeButton = button;
|
||||
|
||||
parentActor.add_actor(this.title);
|
||||
parentActor.add_actor(this.closeButton);
|
||||
},
|
||||
|
||||
hide: function() {
|
||||
this.closeButton.hide();
|
||||
this.title.hide();
|
||||
},
|
||||
|
||||
show: function() {
|
||||
let [child, x, y, mask] = Gdk.Screen.get_default().get_root_window().get_pointer();
|
||||
let actor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE,
|
||||
x, y);
|
||||
if (actor == this._windowClone.actor) {
|
||||
this.closeButton.show();
|
||||
}
|
||||
this.title.show();
|
||||
},
|
||||
|
||||
fadeIn: function() {
|
||||
this.title.opacity = 0;
|
||||
this.title.show();
|
||||
this.title.raise_top();
|
||||
Tweener.addTween(this.title,
|
||||
{ opacity: 255,
|
||||
time: Overview.ANIMATION_TIME,
|
||||
transition: "easeOutQuad" });
|
||||
},
|
||||
|
||||
chromeWidth: function () {
|
||||
return this.closeButton.width - this.closeButton._overlap;
|
||||
},
|
||||
|
||||
chromeHeight: function () {
|
||||
return this.closeButton.height - this.closeButton._overlap +
|
||||
this.title.height + this.title._spacing;
|
||||
},
|
||||
|
||||
_positionItems: function(win) {
|
||||
let button = this.closeButton;
|
||||
let title = this.title;
|
||||
|
||||
let [x, y] = win.get_transformed_position();
|
||||
let [w, h] = win.get_transformed_size();
|
||||
|
||||
let buttonX = x + w - button._overlap;
|
||||
let buttonY = y - button.height + button._overlap;
|
||||
button.set_position(Math.floor(buttonX), Math.floor(buttonY));
|
||||
|
||||
if (!title.fullWidth)
|
||||
title.fullWidth = title.width;
|
||||
title.width = Math.min(title.fullWidth, w);
|
||||
|
||||
let titleX = x + (w - title.width) / 2;
|
||||
let titleY = y + h + title._spacing;
|
||||
title.set_position(Math.floor(titleX), Math.floor(titleY));
|
||||
},
|
||||
|
||||
_closeWindow: function(actor, event) {
|
||||
let metaWindow = this._windowClone.metaWindow;
|
||||
this._workspace = metaWindow.get_workspace();
|
||||
|
||||
this._windowAddedId = this._workspace.connect('window-added',
|
||||
Lang.bind(this,
|
||||
this._onWindowAdded));
|
||||
|
||||
metaWindow.delete(event.get_time());
|
||||
},
|
||||
|
||||
_onWindowAdded: function(workspace, win) {
|
||||
let metaWindow = this._windowClone.metaWindow;
|
||||
|
||||
if (win.get_transient_for() == metaWindow) {
|
||||
workspace.disconnect(this._windowAddedId);
|
||||
this._windowAddedId = 0;
|
||||
|
||||
// use an idle handler to avoid mapping problems -
|
||||
// see comment in Workspace._windowAdded
|
||||
Mainloop.idle_add(Lang.bind(this,
|
||||
function() {
|
||||
this._windowClone.emit('selected');
|
||||
return false;
|
||||
}));
|
||||
}
|
||||
},
|
||||
|
||||
_onDestroy: function() {
|
||||
if (this._windowAddedId > 0) {
|
||||
this._workspace.disconnect(this._windowAddedId);
|
||||
this._windowAddedId = 0;
|
||||
}
|
||||
if (this._idleToggleCloseId > 0) {
|
||||
Mainloop.source_remove(this._idleToggleCloseId);
|
||||
this._idleToggleCloseId = 0;
|
||||
}
|
||||
this.title.destroy();
|
||||
this.closeButton.destroy();
|
||||
},
|
||||
|
||||
_onEnter: function() {
|
||||
this.closeButton.raise_top();
|
||||
this.closeButton.show();
|
||||
this.emit('show-close-button');
|
||||
},
|
||||
|
||||
_onLeave: function() {
|
||||
if (this._idleToggleCloseId == 0)
|
||||
this._idleToggleCloseId = Mainloop.timeout_add(750, Lang.bind(this, this._idleToggleCloseButton));
|
||||
},
|
||||
|
||||
_idleToggleCloseButton: function() {
|
||||
this._idleToggleCloseId = 0;
|
||||
let [child, x, y, mask] = Gdk.Screen.get_default().get_root_window().get_pointer();
|
||||
let actor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE,
|
||||
x, y);
|
||||
if (actor != this._windowClone.actor && actor != this.closeButton) {
|
||||
this.closeButton.hide();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
hideCloseButton: function() {
|
||||
if (this._idleToggleCloseId > 0) {
|
||||
Mainloop.source_remove(this._idleToggleCloseId);
|
||||
this._idleToggleCloseId = 0;
|
||||
}
|
||||
this.closeButton.hide();
|
||||
},
|
||||
|
||||
_onStyleChanged: function() {
|
||||
let titleNode = this.title.get_theme_node();
|
||||
|
||||
let [success, len] = titleNode.get_length('-shell-caption-spacing',
|
||||
false);
|
||||
if (success)
|
||||
this.title._spacing = len;
|
||||
|
||||
let closeNode = this.closeButton.get_theme_node();
|
||||
|
||||
let [success, len] = closeNode.get_length('-shell-close-overlap',
|
||||
false);
|
||||
if (success)
|
||||
this.closeButton._overlap = len;
|
||||
|
||||
this._parentActor.queue_relayout();
|
||||
}
|
||||
};
|
||||
|
||||
Signals.addSignalMethods(WindowOverlay.prototype);
|
||||
|
||||
|
||||
/**
|
||||
* @workspaceNum: Workspace index
|
||||
* @parentActor: The actor which will be the parent of this workspace;
|
||||
@ -460,7 +559,7 @@ Workspace.prototype = {
|
||||
// Create clones for remaining windows that should be
|
||||
// visible in the Overview
|
||||
this._windows = [this._desktop];
|
||||
this._windowIcons = [ null ];
|
||||
this._windowOverlays = [ null ];
|
||||
for (let i = 0; i < windows.length; i++) {
|
||||
if (this._isOverviewWindow(windows[i])) {
|
||||
this._addWindowClone(windows[i]);
|
||||
@ -676,13 +775,13 @@ Workspace.prototype = {
|
||||
_resetCloneVisibility: function () {
|
||||
for (let i = 1; i < this._windows.length; i++) {
|
||||
let clone = this._windows[i];
|
||||
let icon = this._windowIcons[i];
|
||||
let overlay = this._windowOverlays[i];
|
||||
|
||||
if (!this._isCloneVisible(clone)) {
|
||||
clone.setVisibleWithChrome(false);
|
||||
icon.hide();
|
||||
clone.actor.hide();
|
||||
overlay.hide();
|
||||
} else {
|
||||
clone.setVisibleWithChrome(true);
|
||||
clone.actor.show();
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -888,14 +987,17 @@ Workspace.prototype = {
|
||||
let rect = new Meta.Rectangle();
|
||||
metaWindow.get_outer_rect(rect);
|
||||
|
||||
let desiredWidth = global.screen_width * fraction;
|
||||
let desiredHeight = global.screen_height * fraction;
|
||||
let scale = Math.min(desiredWidth / rect.width,
|
||||
desiredHeight / rect.height,
|
||||
let chromeHeight = this._windowOverlays[1].chromeHeight() / this.scale;
|
||||
let chromeWidth = this._windowOverlays[1].chromeWidth() / this.scale;
|
||||
|
||||
let desiredWidth = (global.screen_width - chromeWidth) * fraction;
|
||||
let desiredHeight = (global.screen_height - chromeHeight) * fraction;
|
||||
let scale = Math.min(desiredWidth / (rect.width + chromeWidth),
|
||||
desiredHeight / (rect.height + chromeHeight),
|
||||
1.0 / this.scale);
|
||||
|
||||
let x = xCenter - 0.5 * scale * rect.width;
|
||||
let y = yCenter - 0.5 * scale * rect.height;
|
||||
let x = xCenter - 0.5 * scale * (rect.width + chromeWidth);
|
||||
let y = yCenter - 0.5 * scale * (rect.height + chromeHeight);
|
||||
|
||||
return [x, y, scale];
|
||||
},
|
||||
@ -918,11 +1020,11 @@ Workspace.prototype = {
|
||||
let metaWindow = visibleWindows[i];
|
||||
let mainIndex = this._lookupIndex(metaWindow);
|
||||
let clone = metaWindow._delegate;
|
||||
let icon = this._windowIcons[mainIndex];
|
||||
let overlay = this._windowOverlays[mainIndex];
|
||||
|
||||
let [x, y, scale] = this._computeWindowRelativeLayout(metaWindow, slot);
|
||||
|
||||
icon.hide();
|
||||
overlay.hide();
|
||||
Tweener.addTween(clone.actor,
|
||||
{ x: x,
|
||||
y: y,
|
||||
@ -932,7 +1034,7 @@ Workspace.prototype = {
|
||||
time: Overview.ANIMATION_TIME,
|
||||
transition: "easeOutQuad",
|
||||
onComplete: Lang.bind(this, function() {
|
||||
this._fadeInWindowIcon(clone, icon);
|
||||
overlay.fadeIn();
|
||||
})
|
||||
});
|
||||
}
|
||||
@ -956,49 +1058,20 @@ Workspace.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_fadeInWindowIcon: function (clone, icon) {
|
||||
icon.opacity = 0;
|
||||
icon.show();
|
||||
// This is a little messy and complicated because when we
|
||||
// start the fade-in we may not have done the final positioning
|
||||
// of the workspaces. (Tweener doesn't necessarily finish
|
||||
// all animations before calling onComplete callbacks.)
|
||||
// So we need to manually compute where the window will
|
||||
// be after the workspace animation finishes.
|
||||
let [parentX, parentY] = icon.get_parent().get_position();
|
||||
let [cloneX, cloneY] = clone.actor.get_position();
|
||||
let [cloneWidth, cloneHeight] = clone.actor.get_size();
|
||||
cloneX = this.gridX + this.scale * cloneX;
|
||||
cloneY = this.gridY + this.scale * cloneY;
|
||||
cloneWidth = this.scale * clone.actor.scale_x * cloneWidth;
|
||||
cloneHeight = this.scale * clone.actor.scale_y * cloneHeight;
|
||||
// Note we only round the first part, because we're still going to be
|
||||
// positioned relative to the parent. By subtracting a possibly
|
||||
// non-integral parent X/Y we cancel it out.
|
||||
let x = Math.round(cloneX + cloneWidth - icon.width) - parentX;
|
||||
let y = Math.round(cloneY + cloneHeight - icon.height) - parentY;
|
||||
icon.set_position(x, y);
|
||||
icon.raise(this.actor);
|
||||
Tweener.addTween(icon,
|
||||
{ opacity: 255,
|
||||
time: Overview.ANIMATION_TIME,
|
||||
transition: "easeOutQuad" });
|
||||
},
|
||||
|
||||
_fadeInAllIcons: function () {
|
||||
_fadeInAllOverlays: function() {
|
||||
for (let i = 1; i < this._windows.length; i++) {
|
||||
let clone = this._windows[i];
|
||||
let icon = this._windowIcons[i];
|
||||
let overlay = this._windowOverlays[i];
|
||||
if (this._showOnlyWindows != null && !(clone.metaWindow in this._showOnlyWindows))
|
||||
continue;
|
||||
this._fadeInWindowIcon(clone, icon);
|
||||
overlay.fadeIn();
|
||||
}
|
||||
},
|
||||
|
||||
_hideAllIcons: function () {
|
||||
for (let i = 1; i < this._windows.length; i++) {
|
||||
let icon = this._windowIcons[i];
|
||||
icon.hide();
|
||||
_hideAllOverlays: function() {
|
||||
for (let i = 1; i< this._windows.length; i++) {
|
||||
let overlay = this._windowOverlays[i];
|
||||
overlay.hide();
|
||||
}
|
||||
},
|
||||
|
||||
@ -1012,10 +1085,9 @@ Workspace.prototype = {
|
||||
return;
|
||||
|
||||
let clone = this._windows[index];
|
||||
let icon = this._windowIcons[index];
|
||||
|
||||
this._windows.splice(index, 1);
|
||||
this._windowIcons.splice(index, 1);
|
||||
this._windowOverlays.splice(index, 1);
|
||||
|
||||
// If metaWin.get_compositor_private() returned non-NULL, that
|
||||
// means the window still exists (and is just being moved to
|
||||
@ -1033,7 +1105,6 @@ Workspace.prototype = {
|
||||
};
|
||||
}
|
||||
clone.destroy();
|
||||
icon.destroy();
|
||||
|
||||
this.positionWindows(false);
|
||||
this.updateRemovable();
|
||||
@ -1103,7 +1174,7 @@ Workspace.prototype = {
|
||||
zoomFromOverview : function() {
|
||||
this.leavingOverview = true;
|
||||
|
||||
this._hideAllIcons();
|
||||
this._hideAllOverlays();
|
||||
|
||||
Main.overview.connect('hidden', Lang.bind(this,
|
||||
this._doneLeavingOverview));
|
||||
@ -1140,7 +1211,7 @@ Workspace.prototype = {
|
||||
// Animates grid shrinking/expanding when a row or column
|
||||
// of workspaces is added or removed
|
||||
resizeToGrid : function (oldScale) {
|
||||
this._hideAllIcons();
|
||||
this._hideAllOverlays();
|
||||
Tweener.addTween(this.actor,
|
||||
{ x: this.gridX,
|
||||
y: this.gridY,
|
||||
@ -1148,7 +1219,7 @@ Workspace.prototype = {
|
||||
scale_y: this.scale,
|
||||
time: Overview.ANIMATION_TIME,
|
||||
transition: "easeOutQuad",
|
||||
onComplete: Lang.bind(this, this._fadeInAllIcons)
|
||||
onComplete: Lang.bind(this, this._fadeInAllOverlays)
|
||||
});
|
||||
},
|
||||
|
||||
@ -1177,7 +1248,7 @@ Workspace.prototype = {
|
||||
slideOut : function(onComplete) {
|
||||
let destX = this.actor.x, destY = this.actor.y;
|
||||
|
||||
this._hideAllIcons();
|
||||
this._hideAllOverlays();
|
||||
|
||||
if (this.gridCol > this.gridRow)
|
||||
destX = global.screen_width;
|
||||
@ -1226,50 +1297,41 @@ Workspace.prototype = {
|
||||
return tracker.is_window_interesting(win.get_meta_window());
|
||||
},
|
||||
|
||||
_createWindowIcon: function(window) {
|
||||
let tracker = Shell.WindowTracker.get_default()
|
||||
let app = tracker.get_window_app(window.metaWindow);
|
||||
let iconTexture = null;
|
||||
// The design is application based, so prefer the application
|
||||
// icon here if we have it. FIXME - should move this fallback code
|
||||
// into ShellAppMonitor.
|
||||
if (app) {
|
||||
iconTexture = app.create_icon_texture(48);
|
||||
} else {
|
||||
let icon = window.metaWindow.icon;
|
||||
iconTexture = new Clutter.Texture({ width: 48,
|
||||
height: 48,
|
||||
keep_aspect_ratio: true });
|
||||
Shell.clutter_texture_set_from_pixbuf(iconTexture, icon);
|
||||
}
|
||||
return iconTexture;
|
||||
},
|
||||
|
||||
// Create a clone of a (non-desktop) window and add it to the window list
|
||||
_addWindowClone : function(win) {
|
||||
let icon = this._createWindowIcon(win);
|
||||
this.parentActor.add_actor(icon);
|
||||
|
||||
let clone = new WindowClone(win);
|
||||
let overlay = new WindowOverlay(clone, this.parentActor);
|
||||
|
||||
clone.connect('selected',
|
||||
Lang.bind(this, this._onCloneSelected));
|
||||
clone.connect('drag-begin',
|
||||
Lang.bind(this, function() {
|
||||
icon.hide();
|
||||
overlay.hide();
|
||||
}));
|
||||
clone.connect('drag-end',
|
||||
Lang.bind(this, function() {
|
||||
icon.show();
|
||||
overlay.show();
|
||||
}));
|
||||
|
||||
this.actor.add_actor(clone.actor);
|
||||
|
||||
overlay.connect('show-close-button', Lang.bind(this, this._onShowOverlayClose));
|
||||
|
||||
this._windows.push(clone);
|
||||
this._windowIcons.push(icon);
|
||||
this._windowOverlays.push(overlay);
|
||||
|
||||
return clone;
|
||||
},
|
||||
|
||||
_onShowOverlayClose: function (windowOverlay) {
|
||||
for (let i = 1; i < this._windowOverlays.length; i++) {
|
||||
let overlay = this._windowOverlays[i];
|
||||
if (overlay == windowOverlay)
|
||||
continue;
|
||||
overlay.hideCloseButton();
|
||||
}
|
||||
},
|
||||
|
||||
_computeWindowSlot : function(windowIndex, numberOfWindows) {
|
||||
if (numberOfWindows in POSITIONS)
|
||||
return POSITIONS[numberOfWindows][windowIndex];
|
||||
@ -1345,7 +1407,10 @@ function Workspaces(width, height, x, y) {
|
||||
|
||||
Workspaces.prototype = {
|
||||
_init : function(width, height, x, y) {
|
||||
this.actor = new Clutter.Group();
|
||||
this.actor = new St.Bin({ style_class: "workspaces" });
|
||||
this._actor = new Clutter.Group();
|
||||
|
||||
this.actor.add_actor(this._actor);
|
||||
|
||||
this._width = width;
|
||||
this._height = height;
|
||||
@ -1654,9 +1719,9 @@ Workspaces.prototype = {
|
||||
},
|
||||
|
||||
_addWorkspaceActor : function(workspaceNum) {
|
||||
let workspace = new Workspace(workspaceNum, this.actor);
|
||||
let workspace = new Workspace(workspaceNum, this._actor);
|
||||
this._workspaces[workspaceNum] = workspace;
|
||||
this.actor.add_actor(workspace.actor);
|
||||
this._actor.add_actor(workspace.actor);
|
||||
},
|
||||
|
||||
_onRestacked: function() {
|
||||
|
104
po/pt_BR.po
104
po/pt_BR.po
@ -7,10 +7,11 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2009-09-21 08:39-0300\n"
|
||||
"PO-Revision-Date: 2009-09-20 08:41-0300\n"
|
||||
"Last-Translator: Rodrigo Flores <mail@rodrigoflores.org>\n"
|
||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
|
||||
"shell&component=general\n"
|
||||
"POT-Creation-Date: 2009-11-12 21:33+0000\n"
|
||||
"PO-Revision-Date: 2009-11-14 11:53-0200\n"
|
||||
"Last-Translator: Amanda Magalhães <amandinhakee@gmail.com>\n"
|
||||
"Language-Team: Brazilian Portuguese <gnome-pt_br-list@gnome.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@ -25,84 +26,115 @@ msgstr "GNOME Shell"
|
||||
msgid "Window management and application launching"
|
||||
msgstr "Gerenciamento de janelas e lançador de aplicações"
|
||||
|
||||
#. left side
|
||||
#: ../js/ui/panel.js:269
|
||||
msgid "Activities"
|
||||
msgstr "Atividades"
|
||||
#: ../js/ui/appDisplay.js:696
|
||||
msgid "Drag here to add favorites"
|
||||
msgstr "Arraste até aqui para adicionar aos favoritos"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:452
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %l:%M %p"
|
||||
#: ../js/ui/appIcon.js:425
|
||||
msgid "New Window"
|
||||
msgstr "Nova janela"
|
||||
|
||||
#: ../js/ui/dash.js:283
|
||||
#: ../js/ui/appIcon.js:429
|
||||
msgid "Remove from Favorites"
|
||||
msgstr "Remover dos Favoritos"
|
||||
|
||||
#: ../js/ui/appIcon.js:430
|
||||
msgid "Add to Favorites"
|
||||
msgstr "Adicionar aos Favoritos"
|
||||
|
||||
#: ../js/ui/dash.js:237
|
||||
msgid "Find..."
|
||||
msgstr "Encontre..."
|
||||
|
||||
#: ../js/ui/dash.js:400
|
||||
msgid "Browse"
|
||||
msgstr "Navegar"
|
||||
|
||||
#: ../js/ui/dash.js:536
|
||||
msgid "(see all)"
|
||||
msgstr "(veja todos)"
|
||||
msgstr "Procurar..."
|
||||
|
||||
#. **** Applications ****
|
||||
#: ../js/ui/dash.js:753 ../js/ui/dash.js:809
|
||||
#: ../js/ui/dash.js:656 ../js/ui/dash.js:718
|
||||
msgid "APPLICATIONS"
|
||||
msgstr "APLICATIVOS"
|
||||
|
||||
#. **** Places ****
|
||||
#. Translators: This is in the sense of locations for documents,
|
||||
#. network locations, etc.
|
||||
#: ../js/ui/dash.js:773
|
||||
#: ../js/ui/dash.js:676 ../js/ui/dash.js:733
|
||||
msgid "PLACES"
|
||||
msgstr "LOCAIS"
|
||||
|
||||
#. **** Documents ****
|
||||
#: ../js/ui/dash.js:780 ../js/ui/dash.js:819
|
||||
#: ../js/ui/dash.js:683 ../js/ui/dash.js:728
|
||||
msgid "RECENT DOCUMENTS"
|
||||
msgstr "DOCUMENTOS RECENTES"
|
||||
|
||||
#. **** Search Results ****
|
||||
#: ../js/ui/dash.js:799 ../js/ui/dash.js:931
|
||||
#: ../js/ui/dash.js:708 ../js/ui/dash.js:898
|
||||
msgid "SEARCH RESULTS"
|
||||
msgstr "RESULTADOS DA BUSCA"
|
||||
|
||||
#: ../js/ui/dash.js:814
|
||||
#: ../js/ui/dash.js:723
|
||||
msgid "PREFERENCES"
|
||||
msgstr "PREFERÊNCIAS"
|
||||
|
||||
#: ../js/ui/runDialog.js:101
|
||||
#. Button on the left side of the panel.
|
||||
#. Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview".
|
||||
#: ../js/ui/panel.js:274
|
||||
msgid "Activities"
|
||||
msgstr "Atividades"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/panel.js:491
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %l:%M %p"
|
||||
|
||||
#: ../js/ui/placeDisplay.js:84
|
||||
msgid "Connect to..."
|
||||
msgstr "Conectar ao..."
|
||||
|
||||
#: ../js/ui/runDialog.js:96
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Por favor digite um comando:"
|
||||
|
||||
#: ../src/shell-global.c:799
|
||||
#: ../js/ui/runDialog.js:173
|
||||
#, c-format
|
||||
msgid "Execution of '%s' failed:"
|
||||
msgstr "A execução de \"%s\" falhou:"
|
||||
|
||||
#. Translators: This is a time format.
|
||||
#: ../js/ui/widget.js:163
|
||||
msgid "%H:%M"
|
||||
msgstr "%H:%M"
|
||||
|
||||
#: ../js/ui/widget.js:317
|
||||
msgid "Applications"
|
||||
msgstr "Aplicações"
|
||||
|
||||
#: ../js/ui/widget.js:339
|
||||
msgid "Recent Documents"
|
||||
msgstr "Documentos Recentes"
|
||||
|
||||
#: ../src/shell-global.c:821
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Menos de um minuto atrás"
|
||||
|
||||
#: ../src/shell-global.c:802
|
||||
#: ../src/shell-global.c:824
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "%d minuto atrás"
|
||||
msgstr[1] "%d minutos atrás"
|
||||
|
||||
#: ../src/shell-global.c:805
|
||||
#: ../src/shell-global.c:827
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "%d hora atrás"
|
||||
msgstr[1] "%d horas atrás"
|
||||
|
||||
#: ../src/shell-global.c:808
|
||||
#: ../src/shell-global.c:830
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "%d dia atrás"
|
||||
msgstr[1] "%d dias atrás"
|
||||
|
||||
#: ../src/shell-global.c:811
|
||||
#: ../src/shell-global.c:833
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
@ -183,6 +215,12 @@ msgstr "Procurar"
|
||||
msgid "%1$s: %2$s"
|
||||
msgstr "%1$s: %2$s"
|
||||
|
||||
#~ msgid "Browse"
|
||||
#~ msgstr "Navegar"
|
||||
|
||||
#~ msgid "(see all)"
|
||||
#~ msgstr "(veja todos)"
|
||||
|
||||
#~ msgid "Find apps or documents"
|
||||
#~ msgstr "Localizar aplicativos ou documentos"
|
||||
|
||||
|
@ -72,7 +72,9 @@ st_source_h = \
|
||||
st/st-box-layout.h \
|
||||
st/st-box-layout-child.h \
|
||||
st/st-button.h \
|
||||
st/st-clickable.h \
|
||||
st/st-clipboard.h \
|
||||
st/st-drawing-area.h \
|
||||
st/st-entry.h \
|
||||
st/st-im-text.h \
|
||||
st/st-label.h \
|
||||
@ -108,7 +110,9 @@ st_source_c = \
|
||||
st/st-box-layout.c \
|
||||
st/st-box-layout-child.c \
|
||||
st/st-button.c \
|
||||
st/st-clickable.c \
|
||||
st/st-clipboard.c \
|
||||
st/st-drawing-area.c \
|
||||
st/st-entry.c \
|
||||
st/st-im-text.c \
|
||||
st/st-label.c \
|
||||
|
@ -63,12 +63,8 @@ libgnome_shell_la_SOURCES = \
|
||||
shell-app-usage.h \
|
||||
shell-arrow.c \
|
||||
shell-arrow.h \
|
||||
shell-button-box.c \
|
||||
shell-button-box.h \
|
||||
shell-drawing.c \
|
||||
shell-drawing.h \
|
||||
shell-drawing-area.c \
|
||||
shell-drawing-area.h \
|
||||
shell-embedded-window.c \
|
||||
shell-embedded-window.h \
|
||||
shell-embedded-window-private.h \
|
||||
|
@ -23,6 +23,8 @@
|
||||
* 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#define MUTTER_BUILDING_PLUGIN 1
|
||||
#include <mutter-plugin.h>
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "shell-app-system.h"
|
||||
#include <string.h>
|
||||
|
||||
|
@ -1,4 +1,7 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@ -62,7 +65,7 @@
|
||||
*/
|
||||
|
||||
/* How often we save internally app data, in seconds */
|
||||
#define SAVE_APPS_TIMEOUT_SECONDS 5 /* leave this low for testing, we can bump later if need be */
|
||||
#define SAVE_APPS_TIMEOUT_SECONDS (5 * 60)
|
||||
|
||||
/* With this value, an app goes from bottom to top of the
|
||||
* usage list in 50 hours of use */
|
||||
@ -711,7 +714,7 @@ idle_save_application_usage (gpointer data)
|
||||
|
||||
out:
|
||||
if (!error)
|
||||
g_output_stream_close (G_OUTPUT_STREAM(data_output), NULL, &error);
|
||||
g_output_stream_close_async (G_OUTPUT_STREAM (data_output), 0, NULL, NULL, NULL);
|
||||
g_object_unref (data_output);
|
||||
if (error)
|
||||
{
|
||||
|
@ -1,5 +1,7 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "shell-app-private.h"
|
||||
#include "shell-global.h"
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "shell-arrow.h"
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
|
@ -1,317 +0,0 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/**
|
||||
* SECTION:shell-button-box
|
||||
* @short_description: A box with properties useful for implementing buttons
|
||||
*
|
||||
* A #BigBox subclass which translates lower-level Clutter button events
|
||||
* into higher level properties which are useful for implementing "button-like"
|
||||
* actors.
|
||||
*/
|
||||
|
||||
#include "shell-button-box.h"
|
||||
|
||||
G_DEFINE_TYPE(ShellButtonBox, shell_button_box, BIG_TYPE_BOX);
|
||||
|
||||
struct _ShellButtonBoxPrivate {
|
||||
gboolean active;
|
||||
gboolean held;
|
||||
gboolean hover;
|
||||
gboolean pressed;
|
||||
};
|
||||
|
||||
/* Signals */
|
||||
enum
|
||||
{
|
||||
ACTIVATE,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
|
||||
PROP_ACTIVE,
|
||||
PROP_HOVER,
|
||||
PROP_PRESSED,
|
||||
};
|
||||
|
||||
static guint shell_button_box_signals [LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void
|
||||
set_active (ShellButtonBox *box,
|
||||
gboolean active)
|
||||
{
|
||||
if (box->priv->active == active)
|
||||
return;
|
||||
box->priv->active = active;
|
||||
g_object_notify (G_OBJECT (box), "active");
|
||||
}
|
||||
|
||||
static void
|
||||
set_hover (ShellButtonBox *box,
|
||||
gboolean hover)
|
||||
{
|
||||
if (box->priv->hover == hover)
|
||||
return;
|
||||
box->priv->hover = hover;
|
||||
g_object_notify (G_OBJECT (box), "hover");
|
||||
}
|
||||
|
||||
static void
|
||||
set_pressed (ShellButtonBox *box,
|
||||
gboolean pressed)
|
||||
{
|
||||
if (box->priv->pressed == pressed)
|
||||
return;
|
||||
box->priv->pressed = pressed;
|
||||
g_object_notify (G_OBJECT (box), "pressed");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
shell_button_box_contains (ShellButtonBox *box,
|
||||
ClutterActor *actor)
|
||||
{
|
||||
while (actor != NULL && actor != (ClutterActor*)box)
|
||||
{
|
||||
actor = clutter_actor_get_parent (actor);
|
||||
}
|
||||
return actor != NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
shell_button_box_enter_event (ClutterActor *actor,
|
||||
ClutterCrossingEvent *event)
|
||||
{
|
||||
ShellButtonBox *box = SHELL_BUTTON_BOX (actor);
|
||||
|
||||
if (shell_button_box_contains (box, event->related))
|
||||
return TRUE;
|
||||
if (!shell_button_box_contains (box, event->source))
|
||||
return TRUE;
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (actor));
|
||||
|
||||
if (box->priv->held)
|
||||
set_pressed (box, TRUE);
|
||||
set_hover (box, TRUE);
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (actor));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
shell_button_box_leave_event (ClutterActor *actor,
|
||||
ClutterCrossingEvent *event)
|
||||
{
|
||||
ShellButtonBox *box = SHELL_BUTTON_BOX (actor);
|
||||
|
||||
if (shell_button_box_contains (box, event->related))
|
||||
return TRUE;
|
||||
|
||||
set_hover (box, FALSE);
|
||||
set_pressed (box, FALSE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
shell_button_box_button_press_event (ClutterActor *actor,
|
||||
ClutterButtonEvent *event)
|
||||
{
|
||||
ShellButtonBox *box = SHELL_BUTTON_BOX (actor);
|
||||
|
||||
if (event->button != 1 || event->click_count != 1)
|
||||
return FALSE;
|
||||
|
||||
if (box->priv->held)
|
||||
return TRUE;
|
||||
|
||||
if (!shell_button_box_contains (box, event->source))
|
||||
return FALSE;
|
||||
|
||||
box->priv->held = TRUE;
|
||||
clutter_grab_pointer (CLUTTER_ACTOR (box));
|
||||
|
||||
set_pressed (box, TRUE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
shell_button_box_button_release_event (ClutterActor *actor,
|
||||
ClutterButtonEvent *event)
|
||||
{
|
||||
ShellButtonBox *box = SHELL_BUTTON_BOX (actor);
|
||||
|
||||
if (event->button != 1 || event->click_count != 1)
|
||||
return FALSE;
|
||||
|
||||
if (!box->priv->held)
|
||||
return TRUE;
|
||||
|
||||
box->priv->held = FALSE;
|
||||
clutter_ungrab_pointer ();
|
||||
|
||||
if (!shell_button_box_contains (box, event->source))
|
||||
return FALSE;
|
||||
|
||||
set_pressed (box, FALSE);
|
||||
|
||||
g_signal_emit (G_OBJECT (box), shell_button_box_signals[ACTIVATE], 0, event);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_button_box_fake_release:
|
||||
* @box:
|
||||
*
|
||||
* If this button box is holding a pointer grab, this function will
|
||||
* will ungrab it, and reset the pressed state. The effect is
|
||||
* similar to if the user had released the mouse button, but without
|
||||
* emitting the activate signal.
|
||||
*
|
||||
* This function is useful if for example you want to do something after the user
|
||||
* is holding the mouse button for a given period of time, breaking the
|
||||
* grab.
|
||||
*/
|
||||
void
|
||||
shell_button_box_fake_release (ShellButtonBox *box)
|
||||
{
|
||||
if (!box->priv->held)
|
||||
return;
|
||||
|
||||
box->priv->held = FALSE;
|
||||
clutter_ungrab_pointer ();
|
||||
|
||||
set_pressed (box, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
shell_button_box_set_property(GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ShellButtonBox *box = SHELL_BUTTON_BOX (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ACTIVE:
|
||||
set_active (box, g_value_get_boolean (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
shell_button_box_get_property(GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ShellButtonBox *box = SHELL_BUTTON_BOX (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ACTIVE:
|
||||
g_value_set_boolean (value, box->priv->active);
|
||||
break;
|
||||
case PROP_PRESSED:
|
||||
g_value_set_boolean (value, box->priv->pressed);
|
||||
break;
|
||||
case PROP_HOVER:
|
||||
g_value_set_boolean (value, box->priv->hover);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
shell_button_box_class_init (ShellButtonBoxClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
||||
|
||||
gobject_class->get_property = shell_button_box_get_property;
|
||||
gobject_class->set_property = shell_button_box_set_property;
|
||||
|
||||
actor_class->enter_event = shell_button_box_enter_event;
|
||||
actor_class->leave_event = shell_button_box_leave_event;
|
||||
actor_class->button_press_event = shell_button_box_button_press_event;
|
||||
actor_class->button_release_event = shell_button_box_button_release_event;
|
||||
|
||||
/**
|
||||
* ShellButtonBox::activate
|
||||
* @box: The #ShellButtonBox
|
||||
* @event: Release event which triggered the activation
|
||||
*
|
||||
* This signal is emitted when the button should take the action
|
||||
* associated with button click+release.
|
||||
*/
|
||||
shell_button_box_signals[ACTIVATE] =
|
||||
g_signal_new ("activate",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 1, CLUTTER_TYPE_EVENT);
|
||||
|
||||
/**
|
||||
* ShellButtonBox:active
|
||||
*
|
||||
* The property allows the button to be used as a "toggle button"; it's up to the
|
||||
* application to update the active property in response to the activate signal;
|
||||
* it doesn't happen automatically.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_ACTIVE,
|
||||
g_param_spec_boolean ("active",
|
||||
"Active",
|
||||
"Whether the button persistently active",
|
||||
FALSE,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* ShellButtonBox:hover
|
||||
*
|
||||
* This property tracks whether the mouse is over the button; note this
|
||||
* state is independent of whether the button is pressed.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_HOVER,
|
||||
g_param_spec_boolean ("hover",
|
||||
"Hovering state",
|
||||
"Whether the mouse is over the button",
|
||||
FALSE,
|
||||
G_PARAM_READABLE));
|
||||
|
||||
/**
|
||||
* ShellButtonBox:pressed
|
||||
*
|
||||
* This property tracks whether the button should have a "pressed in"
|
||||
* effect.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_PRESSED,
|
||||
g_param_spec_boolean ("pressed",
|
||||
"Pressed state",
|
||||
"Whether the button is currently pressed",
|
||||
FALSE,
|
||||
G_PARAM_READABLE));
|
||||
|
||||
g_type_class_add_private (gobject_class, sizeof (ShellButtonBoxPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
shell_button_box_init (ShellButtonBox *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, SHELL_TYPE_BUTTON_BOX,
|
||||
ShellButtonBoxPrivate);
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
#ifndef __SHELL_BUTTON_BOX_H__
|
||||
#define __SHELL_BUTTON_BOX_H__
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include "big/box.h"
|
||||
|
||||
#define SHELL_TYPE_BUTTON_BOX (shell_button_box_get_type ())
|
||||
#define SHELL_BUTTON_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_BUTTON_BOX, ShellButtonBox))
|
||||
#define SHELL_BUTTON_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_BUTTON_BOX, ShellButtonBoxClass))
|
||||
#define SHELL_IS_BUTTON_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_TYPE_BUTTON_BOX))
|
||||
#define SHELL_IS_BUTTON_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_BUTTON_BOX))
|
||||
#define SHELL_BUTTON_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_BUTTON_BOX, ShellButtonBoxClass))
|
||||
|
||||
typedef struct _ShellButtonBox ShellButtonBox;
|
||||
typedef struct _ShellButtonBoxClass ShellButtonBoxClass;
|
||||
|
||||
typedef struct _ShellButtonBoxPrivate ShellButtonBoxPrivate;
|
||||
|
||||
struct _ShellButtonBox
|
||||
{
|
||||
BigBox parent;
|
||||
|
||||
ShellButtonBoxPrivate *priv;
|
||||
};
|
||||
|
||||
struct _ShellButtonBoxClass
|
||||
{
|
||||
BigBoxClass parent_class;
|
||||
};
|
||||
|
||||
GType shell_button_box_get_type (void) G_GNUC_CONST;
|
||||
|
||||
void shell_button_box_fake_release (ShellButtonBox *box);
|
||||
|
||||
#endif /* __SHELL_BUTTON_BOX_H__ */
|
@ -1,102 +0,0 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/**
|
||||
* SECTION:shell-drawing-area
|
||||
* @short_description: A dynamically-sized Cairo drawing area
|
||||
*
|
||||
* #ShellDrawingArea is similar to #ClutterCairoTexture in that
|
||||
* it allows drawing via Cairo; the primary difference is that
|
||||
* it is dynamically sized. To use, connect to the @redraw
|
||||
* signal, and inside the signal handler, call
|
||||
* clutter_cairo_texture_create() to begin drawing.
|
||||
*/
|
||||
|
||||
#include "shell-drawing-area.h"
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include <gtk/gtk.h>
|
||||
#include <cairo.h>
|
||||
|
||||
G_DEFINE_TYPE(ShellDrawingArea, shell_drawing_area, CLUTTER_TYPE_GROUP);
|
||||
|
||||
struct _ShellDrawingAreaPrivate {
|
||||
ClutterCairoTexture *texture;
|
||||
};
|
||||
|
||||
/* Signals */
|
||||
enum
|
||||
{
|
||||
REDRAW,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint shell_drawing_area_signals [LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void
|
||||
shell_drawing_area_allocate (ClutterActor *self,
|
||||
const ClutterActorBox *box,
|
||||
ClutterAllocationFlags flags)
|
||||
{
|
||||
ShellDrawingArea *area = SHELL_DRAWING_AREA (self);
|
||||
int width = box->x2 - box->x1;
|
||||
int height = box->y2 - box->y1;
|
||||
ClutterActorBox child_box;
|
||||
|
||||
/* Chain up directly to ClutterActor to set actor->allocation. We explicitly skip our parent class
|
||||
* ClutterGroup here because we want to override the allocate function. */
|
||||
(CLUTTER_ACTOR_CLASS (g_type_class_peek (clutter_actor_get_type ())))->allocate (self, box, flags);
|
||||
|
||||
child_box.x1 = 0;
|
||||
child_box.x2 = width;
|
||||
child_box.y1 = 0;
|
||||
child_box.y2 = height;
|
||||
|
||||
clutter_actor_allocate (CLUTTER_ACTOR (area->priv->texture), &child_box, flags);
|
||||
if (width > 0 && height > 0)
|
||||
{
|
||||
clutter_cairo_texture_set_surface_size (area->priv->texture,
|
||||
width, height);
|
||||
g_signal_emit (G_OBJECT (self), shell_drawing_area_signals[REDRAW], 0,
|
||||
area->priv->texture);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
shell_drawing_area_class_init (ShellDrawingAreaClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
||||
|
||||
actor_class->allocate = shell_drawing_area_allocate;
|
||||
|
||||
shell_drawing_area_signals[REDRAW] =
|
||||
g_signal_new ("redraw",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (ShellDrawingAreaClass, redraw),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1, G_TYPE_OBJECT);
|
||||
|
||||
g_type_class_add_private (gobject_class, sizeof (ShellDrawingAreaPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
shell_drawing_area_init (ShellDrawingArea *area)
|
||||
{
|
||||
area->priv = G_TYPE_INSTANCE_GET_PRIVATE (area, SHELL_TYPE_DRAWING_AREA,
|
||||
ShellDrawingAreaPrivate);
|
||||
area->priv->texture = CLUTTER_CAIRO_TEXTURE (clutter_cairo_texture_new (1, 1));
|
||||
clutter_container_add_actor (CLUTTER_CONTAINER (area), CLUTTER_ACTOR (area->priv->texture));
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_drawing_area_get_texture:
|
||||
*
|
||||
* Return Value: (transfer none):
|
||||
*/
|
||||
ClutterCairoTexture *
|
||||
shell_drawing_area_get_texture (ShellDrawingArea *area)
|
||||
{
|
||||
return area->priv->texture;
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
#ifndef __SHELL_DRAWING_AREA_H__
|
||||
#define __SHELL_DRAWING_AREA_H__
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#define SHELL_TYPE_DRAWING_AREA (shell_drawing_area_get_type ())
|
||||
#define SHELL_DRAWING_AREA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_DRAWING_AREA, ShellDrawingArea))
|
||||
#define SHELL_DRAWING_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_DRAWING_AREA, ShellDrawingAreaClass))
|
||||
#define SHELL_IS_DRAWING_AREA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_TYPE_DRAWING_AREA))
|
||||
#define SHELL_IS_DRAWING_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_DRAWING_AREA))
|
||||
#define SHELL_DRAWING_AREA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_DRAWING_AREA, ShellDrawingAreaClass))
|
||||
|
||||
typedef struct _ShellDrawingArea ShellDrawingArea;
|
||||
typedef struct _ShellDrawingAreaClass ShellDrawingAreaClass;
|
||||
|
||||
typedef struct _ShellDrawingAreaPrivate ShellDrawingAreaPrivate;
|
||||
|
||||
struct _ShellDrawingArea
|
||||
{
|
||||
ClutterGroup parent;
|
||||
|
||||
ShellDrawingAreaPrivate *priv;
|
||||
};
|
||||
|
||||
struct _ShellDrawingAreaClass
|
||||
{
|
||||
ClutterGroupClass parent_class;
|
||||
|
||||
void (*redraw) (ShellDrawingArea *area, ClutterCairoTexture *texture);
|
||||
};
|
||||
|
||||
GType shell_drawing_area_get_type (void) G_GNUC_CONST;
|
||||
|
||||
ClutterCairoTexture *shell_drawing_area_get_texture (ShellDrawingArea *area);
|
||||
|
||||
#endif /* __SHELL_DRAWING_AREA_H__ */
|
@ -1,104 +1,10 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "shell-drawing.h"
|
||||
#include <math.h>
|
||||
|
||||
/**
|
||||
* shell_create_vertical_gradient:
|
||||
* @top: the color at the top
|
||||
* @bottom: the color at the bottom
|
||||
*
|
||||
* Creates a vertical gradient actor.
|
||||
*
|
||||
* Return value: (transfer none): a #ClutterCairoTexture actor with the
|
||||
* gradient. The texture actor is floating, hence (transfer none).
|
||||
*/
|
||||
ClutterCairoTexture *
|
||||
shell_create_vertical_gradient (ClutterColor *top,
|
||||
ClutterColor *bottom)
|
||||
{
|
||||
ClutterCairoTexture *texture;
|
||||
cairo_t *cr;
|
||||
cairo_pattern_t *pattern;
|
||||
|
||||
/* Draw the gradient on an 8x8 pixel texture. Because the gradient is drawn
|
||||
* from the uppermost to the lowermost row, after stretching 1/16 of the
|
||||
* texture height has the top color and 1/16 has the bottom color. The 8
|
||||
* pixel width is chosen for reasons related to graphics hardware internals.
|
||||
*/
|
||||
texture = CLUTTER_CAIRO_TEXTURE (clutter_cairo_texture_new (8, 8));
|
||||
cr = clutter_cairo_texture_create (texture);
|
||||
|
||||
pattern = cairo_pattern_create_linear (0, 0, 0, 8);
|
||||
cairo_pattern_add_color_stop_rgba (pattern, 0,
|
||||
top->red / 255.,
|
||||
top->green / 255.,
|
||||
top->blue / 255.,
|
||||
top->alpha / 255.);
|
||||
cairo_pattern_add_color_stop_rgba (pattern, 1,
|
||||
bottom->red / 255.,
|
||||
bottom->green / 255.,
|
||||
bottom->blue / 255.,
|
||||
bottom->alpha / 255.);
|
||||
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_pattern_destroy (pattern);
|
||||
cairo_destroy (cr);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
/**
|
||||
* shell_create_horizontal_gradient:
|
||||
* @left: the color on the left
|
||||
* @right: the color on the right
|
||||
*
|
||||
* Creates a horizontal gradient actor.
|
||||
*
|
||||
* Return value: (transfer none): a #ClutterCairoTexture actor with the
|
||||
* gradient. The texture actor is floating, hence (transfer none).
|
||||
*/
|
||||
ClutterCairoTexture *
|
||||
shell_create_horizontal_gradient (ClutterColor *left,
|
||||
ClutterColor *right)
|
||||
{
|
||||
ClutterCairoTexture *texture;
|
||||
cairo_t *cr;
|
||||
cairo_pattern_t *pattern;
|
||||
|
||||
/* Draw the gradient on an 8x1 pixel texture. Because the gradient is drawn
|
||||
* from the left to the right column, after stretching 1/16 of the
|
||||
* texture width has the left side color and 1/16 has the right side color.
|
||||
* There is no reason to use the 8 pixel height that would be similar to the
|
||||
* reason we are using the 8 pixel width for the vertical gradient, so we
|
||||
* are just using the 1 pixel height instead.
|
||||
*/
|
||||
texture = CLUTTER_CAIRO_TEXTURE (clutter_cairo_texture_new (8, 1));
|
||||
cr = clutter_cairo_texture_create (texture);
|
||||
|
||||
pattern = cairo_pattern_create_linear (0, 0, 8, 0);
|
||||
cairo_pattern_add_color_stop_rgba (pattern, 0,
|
||||
left->red / 255.,
|
||||
left->green / 255.,
|
||||
left->blue / 255.,
|
||||
left->alpha / 255.);
|
||||
cairo_pattern_add_color_stop_rgba (pattern, 1,
|
||||
right->red / 255.,
|
||||
right->green / 255.,
|
||||
right->blue / 255.,
|
||||
right->alpha / 255.);
|
||||
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_pattern_destroy (pattern);
|
||||
cairo_destroy (cr);
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
||||
void
|
||||
shell_draw_clock (ClutterCairoTexture *texture,
|
||||
int hour,
|
||||
|
@ -7,12 +7,6 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
ClutterCairoTexture *shell_create_vertical_gradient (ClutterColor *top,
|
||||
ClutterColor *bottom);
|
||||
|
||||
ClutterCairoTexture *shell_create_horizontal_gradient (ClutterColor *left,
|
||||
ClutterColor *right);
|
||||
|
||||
typedef enum {
|
||||
SHELL_POINTER_UP,
|
||||
SHELL_POINTER_DOWN,
|
||||
|
@ -1,5 +1,7 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gdk/gdkx.h>
|
||||
#include <clutter/x11/clutter-x11.h>
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "shell-gconf.h"
|
||||
|
||||
#include <gconf/gconf-client.h>
|
||||
|
@ -94,6 +94,8 @@ function runTestFixedBox() {
|
||||
}
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "shell-generic-container.h"
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
|
@ -1,5 +1,7 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "shell-global-private.h"
|
||||
#include "shell-wm.h"
|
||||
|
||||
@ -19,6 +21,9 @@
|
||||
#include <math.h>
|
||||
#include <X11/extensions/Xfixes.h>
|
||||
#include <gjs/gjs.h>
|
||||
#ifdef HAVE_SYS_RESOURCE_H
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
#define SHELL_DBUS_SERVICE "org.gnome.Shell"
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "shell-embedded-window-private.h"
|
||||
|
||||
#include <clutter/glx/clutter-glx.h>
|
||||
|
@ -8,6 +8,8 @@
|
||||
* popup-menu like actors.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "shell-menu.h"
|
||||
|
||||
G_DEFINE_TYPE(ShellMenu, shell_menu, BIG_TYPE_BOX);
|
||||
|
@ -1,5 +1,7 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "shell-overflow-list.h"
|
||||
|
||||
G_DEFINE_TYPE (ShellOverflowList,
|
||||
|
@ -1,5 +1,7 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "shell-process.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
|
@ -1,5 +1,7 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <gst/base/gstpushsrc.h>
|
||||
|
||||
#include "shell-recorder-src.h"
|
||||
|
@ -1,5 +1,7 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
@ -12,6 +12,8 @@
|
||||
* size, even if that would overflow the size allocated to the stack.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "shell-stack.h"
|
||||
|
||||
G_DEFINE_TYPE (ShellStack,
|
||||
|
@ -1,5 +1,7 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "shell-texture-cache.h"
|
||||
#include "shell-global.h"
|
||||
#include <gtk/gtk.h>
|
||||
|
@ -1,5 +1,7 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include <clutter/x11/clutter-x11.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
@ -1,7 +1,9 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "shell-uri-util.h"
|
||||
#include <glib/gi18n.h>
|
||||
#include <glib/gi18n-lib.h>
|
||||
#include <gconf/gconf-client.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
|
@ -1,4 +1,7 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "shell-wm.h"
|
||||
|
330
src/st/st-clickable.c
Normal file
330
src/st/st-clickable.c
Normal file
@ -0,0 +1,330 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/**
|
||||
* SECTION:st-clickable
|
||||
* @short_description: A bin with methods and properties useful for implementing buttons
|
||||
*
|
||||
* A #StBin subclass which translates lower-level Clutter button events
|
||||
* into higher level properties which are useful for implementing "button-like"
|
||||
* actors.
|
||||
*/
|
||||
|
||||
#include "st-clickable.h"
|
||||
|
||||
G_DEFINE_TYPE (StClickable, st_clickable, ST_TYPE_BIN);
|
||||
|
||||
struct _StClickablePrivate {
|
||||
gboolean active;
|
||||
gboolean held;
|
||||
gboolean hover;
|
||||
gboolean pressed;
|
||||
|
||||
guint initiating_button;
|
||||
};
|
||||
|
||||
/* Signals */
|
||||
enum
|
||||
{
|
||||
CLICKED,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
|
||||
PROP_ACTIVE,
|
||||
PROP_HOVER,
|
||||
PROP_PRESSED,
|
||||
};
|
||||
|
||||
static guint st_clickable_signals [LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void
|
||||
sync_pseudo_class (StClickable *self)
|
||||
{
|
||||
st_widget_set_style_pseudo_class (ST_WIDGET (self),
|
||||
(self->priv->pressed || self->priv->active) ? "pressed" :
|
||||
(self->priv->hover ? "hover" : NULL));
|
||||
}
|
||||
|
||||
static void
|
||||
set_active (StClickable *self,
|
||||
gboolean active)
|
||||
{
|
||||
if (self->priv->active == active)
|
||||
return;
|
||||
self->priv->active = active;
|
||||
sync_pseudo_class (self);
|
||||
g_object_notify (G_OBJECT (self), "active");
|
||||
}
|
||||
|
||||
static void
|
||||
set_hover (StClickable *self,
|
||||
gboolean hover)
|
||||
{
|
||||
if (self->priv->hover == hover)
|
||||
return;
|
||||
self->priv->hover = hover;
|
||||
sync_pseudo_class (self);
|
||||
g_object_notify (G_OBJECT (self), "hover");
|
||||
}
|
||||
|
||||
static void
|
||||
set_pressed (StClickable *self,
|
||||
gboolean pressed)
|
||||
{
|
||||
if (self->priv->pressed == pressed)
|
||||
return;
|
||||
self->priv->pressed = pressed;
|
||||
sync_pseudo_class (self);
|
||||
g_object_notify (G_OBJECT (self), "pressed");
|
||||
}
|
||||
|
||||
static gboolean
|
||||
st_clickable_contains (StClickable *self,
|
||||
ClutterActor *actor)
|
||||
{
|
||||
while (actor != NULL && actor != (ClutterActor*)self)
|
||||
{
|
||||
actor = clutter_actor_get_parent (actor);
|
||||
}
|
||||
return actor != NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
st_clickable_enter_event (ClutterActor *actor,
|
||||
ClutterCrossingEvent *event)
|
||||
{
|
||||
StClickable *self = ST_CLICKABLE (actor);
|
||||
|
||||
if (st_clickable_contains (self, event->related))
|
||||
return TRUE;
|
||||
if (!st_clickable_contains (self, event->source))
|
||||
return TRUE;
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (actor));
|
||||
|
||||
if (self->priv->held)
|
||||
set_pressed (self, TRUE);
|
||||
set_hover (self, TRUE);
|
||||
|
||||
g_object_thaw_notify (G_OBJECT (actor));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
st_clickable_leave_event (ClutterActor *actor,
|
||||
ClutterCrossingEvent *event)
|
||||
{
|
||||
StClickable *self = ST_CLICKABLE (actor);
|
||||
|
||||
if (st_clickable_contains (self, event->related))
|
||||
return TRUE;
|
||||
|
||||
set_hover (self, FALSE);
|
||||
set_pressed (self, FALSE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
st_clickable_button_press_event (ClutterActor *actor,
|
||||
ClutterButtonEvent *event)
|
||||
{
|
||||
StClickable *self = ST_CLICKABLE (actor);
|
||||
|
||||
if (event->click_count != 1)
|
||||
return FALSE;
|
||||
|
||||
if (self->priv->held)
|
||||
return TRUE;
|
||||
|
||||
if (!st_clickable_contains (self, event->source))
|
||||
return FALSE;
|
||||
|
||||
self->priv->held = TRUE;
|
||||
self->priv->initiating_button = event->button;
|
||||
clutter_grab_pointer (CLUTTER_ACTOR (self));
|
||||
|
||||
set_pressed (self, TRUE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
st_clickable_button_release_event (ClutterActor *actor,
|
||||
ClutterButtonEvent *event)
|
||||
{
|
||||
StClickable *self = ST_CLICKABLE (actor);
|
||||
|
||||
if (event->button != self->priv->initiating_button || event->click_count != 1)
|
||||
return FALSE;
|
||||
|
||||
if (!self->priv->held)
|
||||
return TRUE;
|
||||
|
||||
self->priv->held = FALSE;
|
||||
clutter_ungrab_pointer ();
|
||||
|
||||
if (!st_clickable_contains (self, event->source))
|
||||
return FALSE;
|
||||
|
||||
set_pressed (self, FALSE);
|
||||
|
||||
g_signal_emit (G_OBJECT (self), st_clickable_signals[CLICKED], 0, event);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_clickable_fake_release:
|
||||
* @box:
|
||||
*
|
||||
* If this widget is holding a pointer grab, this function will
|
||||
* will ungrab it, and reset the pressed state. The effect is
|
||||
* similar to if the user had released the mouse button, but without
|
||||
* emitting the clicked signal.
|
||||
*
|
||||
* This function is useful if for example you want to do something after the user
|
||||
* is holding the mouse button for a given period of time, breaking the
|
||||
* grab.
|
||||
*/
|
||||
void
|
||||
st_clickable_fake_release (StClickable *self)
|
||||
{
|
||||
if (!self->priv->held)
|
||||
return;
|
||||
|
||||
self->priv->held = FALSE;
|
||||
clutter_ungrab_pointer ();
|
||||
|
||||
set_pressed (self, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
st_clickable_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StClickable *self = ST_CLICKABLE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ACTIVE:
|
||||
set_active (self, g_value_get_boolean (value));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_clickable_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
StClickable *self = ST_CLICKABLE (object);
|
||||
|
||||
switch (prop_id)
|
||||
{
|
||||
case PROP_ACTIVE:
|
||||
g_value_set_boolean (value, self->priv->active);
|
||||
break;
|
||||
case PROP_PRESSED:
|
||||
g_value_set_boolean (value, self->priv->pressed);
|
||||
break;
|
||||
case PROP_HOVER:
|
||||
g_value_set_boolean (value, self->priv->hover);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_clickable_class_init (StClickableClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
||||
|
||||
gobject_class->get_property = st_clickable_get_property;
|
||||
gobject_class->set_property = st_clickable_set_property;
|
||||
|
||||
actor_class->enter_event = st_clickable_enter_event;
|
||||
actor_class->leave_event = st_clickable_leave_event;
|
||||
actor_class->button_press_event = st_clickable_button_press_event;
|
||||
actor_class->button_release_event = st_clickable_button_release_event;
|
||||
|
||||
/**
|
||||
* StClickable::clicked
|
||||
* @box: The #StClickable
|
||||
*
|
||||
* This signal is emitted when the button should take the action
|
||||
* associated with button click+release.
|
||||
*/
|
||||
st_clickable_signals[CLICKED] =
|
||||
g_signal_new ("clicked",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0,
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__BOXED,
|
||||
G_TYPE_NONE, 1, CLUTTER_TYPE_EVENT);
|
||||
|
||||
/**
|
||||
* StClickable:active
|
||||
*
|
||||
* The property allows the button to be used as a "toggle button"; it's up to the
|
||||
* application to update the active property in response to the activate signal;
|
||||
* it doesn't happen automatically.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_ACTIVE,
|
||||
g_param_spec_boolean ("active",
|
||||
"Active",
|
||||
"Whether the button persistently active",
|
||||
FALSE,
|
||||
G_PARAM_READWRITE));
|
||||
|
||||
/**
|
||||
* StClickable:hover
|
||||
*
|
||||
* This property tracks whether the mouse is over the button; note this
|
||||
* state is independent of whether the button is pressed.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_HOVER,
|
||||
g_param_spec_boolean ("hover",
|
||||
"Hovering state",
|
||||
"Whether the mouse is over the button",
|
||||
FALSE,
|
||||
G_PARAM_READABLE));
|
||||
|
||||
/**
|
||||
* StClickable:pressed
|
||||
*
|
||||
* This property tracks whether the button should have a "pressed in"
|
||||
* effect.
|
||||
*/
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_PRESSED,
|
||||
g_param_spec_boolean ("pressed",
|
||||
"Pressed state",
|
||||
"Whether the button is currently pressed",
|
||||
FALSE,
|
||||
G_PARAM_READABLE));
|
||||
|
||||
g_type_class_add_private (gobject_class, sizeof (StClickablePrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
st_clickable_init (StClickable *self)
|
||||
{
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, ST_TYPE_CLICKABLE,
|
||||
StClickablePrivate);
|
||||
}
|
35
src/st/st-clickable.h
Normal file
35
src/st/st-clickable.h
Normal file
@ -0,0 +1,35 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
#ifndef __ST_CLICKABLE_H__
|
||||
#define __ST_CLICKABLE_H__
|
||||
|
||||
#include "st-bin.h"
|
||||
|
||||
#define ST_TYPE_CLICKABLE (st_clickable_get_type ())
|
||||
#define ST_CLICKABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ST_TYPE_CLICKABLE, StClickable))
|
||||
#define ST_CLICKABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ST_TYPE_CLICKABLE, StClickableClass))
|
||||
#define ST_IS_CLICKABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ST_TYPE_CLICKABLE))
|
||||
#define ST_IS_CLICKABLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ST_TYPE_CLICKABLE))
|
||||
#define ST_CLICKABLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ST_TYPE_CLICKABLE, StClickableClass))
|
||||
|
||||
typedef struct _StClickable StClickable;
|
||||
typedef struct _StClickableClass StClickableClass;
|
||||
|
||||
typedef struct _StClickablePrivate StClickablePrivate;
|
||||
|
||||
struct _StClickable
|
||||
{
|
||||
StBin parent;
|
||||
|
||||
StClickablePrivate *priv;
|
||||
};
|
||||
|
||||
struct _StClickableClass
|
||||
{
|
||||
StBinClass parent_class;
|
||||
};
|
||||
|
||||
GType st_clickable_get_type (void) G_GNUC_CONST;
|
||||
|
||||
void st_clickable_fake_release (StClickable *box);
|
||||
|
||||
#endif /* __ST_CLICKABLE_H__ */
|
125
src/st/st-drawing-area.c
Normal file
125
src/st/st-drawing-area.c
Normal file
@ -0,0 +1,125 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
|
||||
/**
|
||||
* SECTION:st-drawing-area
|
||||
* @short_description: A dynamically-sized Cairo drawing area
|
||||
*
|
||||
* #StDrawingArea is similar to #ClutterCairoTexture in that
|
||||
* it allows drawing via Cairo; the primary difference is that
|
||||
* it is dynamically sized. To use, connect to the #StDrawingArea::redraw
|
||||
* signal, and inside the signal handler, call
|
||||
* clutter_cairo_texture_create() to begin drawing. The
|
||||
* #StDrawingArea::redraw signal will be emitted by default when the area is
|
||||
* resized or the CSS style changes; you can use the
|
||||
* st_drawing_area_emit_redraw() as well.
|
||||
*/
|
||||
|
||||
#include "st-drawing-area.h"
|
||||
|
||||
#include <cairo.h>
|
||||
|
||||
G_DEFINE_TYPE(StDrawingArea, st_drawing_area, ST_TYPE_BIN);
|
||||
|
||||
struct _StDrawingAreaPrivate {
|
||||
ClutterCairoTexture *texture;
|
||||
};
|
||||
|
||||
/* Signals */
|
||||
enum
|
||||
{
|
||||
REDRAW,
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint st_drawing_area_signals [LAST_SIGNAL] = { 0 };
|
||||
|
||||
static void
|
||||
st_drawing_area_allocate (ClutterActor *self,
|
||||
const ClutterActorBox *box,
|
||||
ClutterAllocationFlags flags)
|
||||
{
|
||||
StThemeNode *theme_node;
|
||||
ClutterActorBox content_box;
|
||||
StDrawingArea *area = ST_DRAWING_AREA (self);
|
||||
int width = box->x2 - box->x1;
|
||||
int height = box->y2 - box->y1;
|
||||
|
||||
(CLUTTER_ACTOR_CLASS (st_drawing_area_parent_class))->allocate (self, box, flags);
|
||||
|
||||
theme_node = st_widget_get_theme_node (ST_WIDGET (self));
|
||||
|
||||
st_theme_node_get_content_box (theme_node, box, &content_box);
|
||||
|
||||
if (width > 0 && height > 0)
|
||||
{
|
||||
clutter_cairo_texture_set_surface_size (area->priv->texture,
|
||||
content_box.x2 - content_box.x1,
|
||||
content_box.y2 - content_box.y1);
|
||||
g_signal_emit (G_OBJECT (self), st_drawing_area_signals[REDRAW], 0,
|
||||
area->priv->texture);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
st_drawing_area_style_changed (StWidget *self)
|
||||
{
|
||||
(ST_WIDGET_CLASS (st_drawing_area_parent_class))->style_changed (self);
|
||||
|
||||
st_drawing_area_emit_redraw (ST_DRAWING_AREA (self));
|
||||
}
|
||||
|
||||
static void
|
||||
st_drawing_area_class_init (StDrawingAreaClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
||||
StWidgetClass *widget_class = ST_WIDGET_CLASS (klass);
|
||||
|
||||
actor_class->allocate = st_drawing_area_allocate;
|
||||
widget_class->style_changed = st_drawing_area_style_changed;
|
||||
|
||||
st_drawing_area_signals[REDRAW] =
|
||||
g_signal_new ("redraw",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (StDrawingAreaClass, redraw),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1, CLUTTER_TYPE_CAIRO_TEXTURE);
|
||||
|
||||
g_type_class_add_private (gobject_class, sizeof (StDrawingAreaPrivate));
|
||||
}
|
||||
|
||||
static void
|
||||
st_drawing_area_init (StDrawingArea *area)
|
||||
{
|
||||
area->priv = G_TYPE_INSTANCE_GET_PRIVATE (area, ST_TYPE_DRAWING_AREA,
|
||||
StDrawingAreaPrivate);
|
||||
area->priv->texture = CLUTTER_CAIRO_TEXTURE (clutter_cairo_texture_new (1, 1));
|
||||
clutter_container_add_actor (CLUTTER_CONTAINER (area), CLUTTER_ACTOR (area->priv->texture));
|
||||
}
|
||||
|
||||
/**
|
||||
* st_drawing_area_get_texture:
|
||||
*
|
||||
* Return Value: (transfer none):
|
||||
*/
|
||||
ClutterCairoTexture *
|
||||
st_drawing_area_get_texture (StDrawingArea *area)
|
||||
{
|
||||
return area->priv->texture;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_drawing_area_emit_redraw:
|
||||
* @area: A #StDrawingArea
|
||||
*
|
||||
* Immediately emit a redraw signal. Useful if
|
||||
* some parameters for the area being drawn other
|
||||
* than the size or style have changed.
|
||||
*/
|
||||
void
|
||||
st_drawing_area_emit_redraw (StDrawingArea *area)
|
||||
{
|
||||
g_signal_emit ((GObject*)area, st_drawing_area_signals[REDRAW], 0, area->priv->texture);
|
||||
}
|
39
src/st/st-drawing-area.h
Normal file
39
src/st/st-drawing-area.h
Normal file
@ -0,0 +1,39 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
#ifndef __ST_DRAWING_AREA_H__
|
||||
#define __ST_DRAWING_AREA_H__
|
||||
|
||||
#include "st-bin.h"
|
||||
|
||||
#define ST_TYPE_DRAWING_AREA (st_drawing_area_get_type ())
|
||||
#define ST_DRAWING_AREA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ST_TYPE_DRAWING_AREA, StDrawingArea))
|
||||
#define ST_DRAWING_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ST_TYPE_DRAWING_AREA, StDrawingAreaClass))
|
||||
#define ST_IS_DRAWING_AREA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ST_TYPE_DRAWING_AREA))
|
||||
#define ST_IS_DRAWING_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ST_TYPE_DRAWING_AREA))
|
||||
#define ST_DRAWING_AREA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ST_TYPE_DRAWING_AREA, StDrawingAreaClass))
|
||||
|
||||
typedef struct _StDrawingArea StDrawingArea;
|
||||
typedef struct _StDrawingAreaClass StDrawingAreaClass;
|
||||
|
||||
typedef struct _StDrawingAreaPrivate StDrawingAreaPrivate;
|
||||
|
||||
struct _StDrawingArea
|
||||
{
|
||||
StBin parent;
|
||||
|
||||
StDrawingAreaPrivate *priv;
|
||||
};
|
||||
|
||||
struct _StDrawingAreaClass
|
||||
{
|
||||
StBinClass parent_class;
|
||||
|
||||
void (*redraw) (StDrawingArea *area, ClutterCairoTexture *texture);
|
||||
};
|
||||
|
||||
GType st_drawing_area_get_type (void) G_GNUC_CONST;
|
||||
|
||||
ClutterCairoTexture *st_drawing_area_get_texture (StDrawingArea *area);
|
||||
|
||||
void st_drawing_area_emit_redraw (StDrawingArea *area);
|
||||
|
||||
#endif /* __ST_DRAWING_AREA_H__ */
|
@ -21,8 +21,13 @@ struct _StThemeNode {
|
||||
PangoFontDescription *font_desc;
|
||||
|
||||
ClutterColor background_color;
|
||||
/* If gradient is set, then background_color is the gradient start */
|
||||
StGradientType background_gradient_type;
|
||||
ClutterColor background_gradient_end;
|
||||
|
||||
ClutterColor foreground_color;
|
||||
ClutterColor border_color[4];
|
||||
|
||||
double border_width[4];
|
||||
double border_radius[4];
|
||||
guint padding[4];
|
||||
@ -513,7 +518,7 @@ st_theme_node_get_color (StThemeNode *node,
|
||||
* parent's parent, and so forth. Note that if the property has a
|
||||
* value of 'inherit' it will be inherited even if %FALSE is passed
|
||||
* in for @inherit; this only affects the default behavior for inheritance.
|
||||
* @value: location to store the value that was determined.
|
||||
* @value: (out): location to store the value that was determined.
|
||||
* If the property is not found, the value in this location
|
||||
* will not be changed.
|
||||
*
|
||||
@ -740,7 +745,7 @@ get_length_internal (StThemeNode *node,
|
||||
* parent's parent, and so forth. Note that if the property has a
|
||||
* value of 'inherit' it will be inherited even if %FALSE is passed
|
||||
* in for @inherit; this only affects the default behavior for inheritance.
|
||||
* @length: location to store the length that was determined.
|
||||
* @length: (out): location to store the length that was determined.
|
||||
* If the property is not found, the value in this location
|
||||
* will not be changed. The returned length is resolved
|
||||
* to pixels.
|
||||
@ -1236,6 +1241,7 @@ ensure_background (StThemeNode *node)
|
||||
|
||||
node->background_computed = TRUE;
|
||||
node->background_color = TRANSPARENT_COLOR;
|
||||
node->background_gradient_type = ST_GRADIENT_NONE;
|
||||
|
||||
ensure_properties (node);
|
||||
|
||||
@ -1331,6 +1337,31 @@ ensure_background (StThemeNode *node)
|
||||
node->background_image = NULL;
|
||||
}
|
||||
}
|
||||
else if (strcmp (property_name, "-gradient-direction") == 0)
|
||||
{
|
||||
CRTerm *term = decl->value;
|
||||
if (strcmp (term->content.str->stryng->str, "vertical") == 0)
|
||||
{
|
||||
node->background_gradient_type = ST_GRADIENT_VERTICAL;
|
||||
}
|
||||
else if (strcmp (term->content.str->stryng->str, "horizontal") == 0)
|
||||
{
|
||||
node->background_gradient_type = ST_GRADIENT_HORIZONTAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Unrecognized background-gradient-direction \"%s\"",
|
||||
term->content.str->stryng->str);
|
||||
}
|
||||
}
|
||||
else if (strcmp (property_name, "-gradient-start") == 0)
|
||||
{
|
||||
get_color_from_term (node, decl->value, &node->background_color);
|
||||
}
|
||||
else if (strcmp (property_name, "-gradient-end") == 0)
|
||||
{
|
||||
get_color_from_term (node, decl->value, &node->background_gradient_end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1393,6 +1424,34 @@ st_theme_node_get_foreground_color (StThemeNode *node,
|
||||
*color = node->foreground_color;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* st_theme_node_get_background_gradient:
|
||||
* @node: A #StThemeNode
|
||||
* @type: (out): Type of gradient
|
||||
* @start: Color at start of gradient
|
||||
* @end: Color at end of gradient
|
||||
*
|
||||
* The @start and @end arguments will only be set if @type is not #ST_GRADIENT_NONE.
|
||||
*/
|
||||
void
|
||||
st_theme_node_get_background_gradient (StThemeNode *node,
|
||||
StGradientType *type,
|
||||
ClutterColor *start,
|
||||
ClutterColor *end)
|
||||
{
|
||||
g_return_if_fail (ST_IS_THEME_NODE (node));
|
||||
|
||||
ensure_background (node);
|
||||
|
||||
*type = node->background_gradient_type;
|
||||
if (*type != ST_GRADIENT_NONE)
|
||||
{
|
||||
*start = node->background_color;
|
||||
*end = node->background_gradient_end;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
st_theme_node_get_border_color (StThemeNode *node,
|
||||
StSide side,
|
||||
|
@ -57,6 +57,12 @@ typedef enum {
|
||||
ST_TEXT_DECORATION_BLINK = 1 << 3
|
||||
} StTextDecoration;
|
||||
|
||||
typedef enum {
|
||||
ST_GRADIENT_NONE,
|
||||
ST_GRADIENT_VERTICAL,
|
||||
ST_GRADIENT_HORIZONTAL
|
||||
} StGradientType;
|
||||
|
||||
GType st_theme_node_get_type (void) G_GNUC_CONST;
|
||||
|
||||
StThemeNode *st_theme_node_new (StThemeContext *context,
|
||||
@ -103,6 +109,10 @@ void st_theme_node_get_background_color (StThemeNode *node,
|
||||
ClutterColor *color);
|
||||
void st_theme_node_get_foreground_color (StThemeNode *node,
|
||||
ClutterColor *color);
|
||||
void st_theme_node_get_background_gradient (StThemeNode *node,
|
||||
StGradientType *type,
|
||||
ClutterColor *start,
|
||||
ClutterColor *end);
|
||||
|
||||
const char *st_theme_node_get_background_image (StThemeNode *node);
|
||||
|
||||
|
@ -59,6 +59,9 @@ struct _StWidgetPrivate
|
||||
ClutterActor *background_image;
|
||||
ClutterColor bg_color;
|
||||
|
||||
StGradientType bg_gradient_type;
|
||||
ClutterColor bg_gradient_end;
|
||||
|
||||
gboolean is_stylable : 1;
|
||||
gboolean has_tooltip : 1;
|
||||
gboolean is_style_dirty : 1;
|
||||
@ -111,6 +114,7 @@ G_DEFINE_ABSTRACT_TYPE (StWidget, st_widget, CLUTTER_TYPE_ACTOR);
|
||||
|
||||
static void st_widget_recompute_style (StWidget *widget,
|
||||
StThemeNode *old_theme_node);
|
||||
static void st_widget_redraw_gradient (StWidget *widget);
|
||||
|
||||
static void
|
||||
st_widget_set_property (GObject *gobject,
|
||||
@ -258,10 +262,13 @@ st_widget_allocate (ClutterActor *actor,
|
||||
ClutterAllocationFlags flags)
|
||||
{
|
||||
StWidgetPrivate *priv = ST_WIDGET (actor)->priv;
|
||||
StThemeNode *theme_node;
|
||||
ClutterActorClass *klass;
|
||||
ClutterGeometry area;
|
||||
ClutterVertex in_v, out_v;
|
||||
|
||||
theme_node = st_widget_get_theme_node ((StWidget*) actor);
|
||||
|
||||
klass = CLUTTER_ACTOR_CLASS (st_widget_parent_class);
|
||||
klass->allocate (actor, box, flags);
|
||||
|
||||
@ -298,7 +305,7 @@ st_widget_allocate (ClutterActor *actor,
|
||||
flags);
|
||||
}
|
||||
|
||||
if (priv->background_image)
|
||||
if (priv->background_image && priv->bg_gradient_type == ST_GRADIENT_NONE)
|
||||
{
|
||||
ClutterActorBox frame_box = {
|
||||
0, 0, box->x2 - box->x1, box->y2 - box->y1
|
||||
@ -353,6 +360,27 @@ st_widget_allocate (ClutterActor *actor,
|
||||
&frame_box,
|
||||
flags);
|
||||
}
|
||||
else if (priv->bg_gradient_type != ST_GRADIENT_NONE)
|
||||
{
|
||||
float width, height;
|
||||
ClutterActorBox frame_box, content_box;
|
||||
|
||||
width = box->x2 - box->x1;
|
||||
height = box->y2 - box->y1;
|
||||
frame_box.x1 = frame_box.y1 = 0;
|
||||
frame_box.x2 = width;
|
||||
frame_box.y2 = height;
|
||||
|
||||
st_theme_node_get_content_box (theme_node, &frame_box, &content_box);
|
||||
|
||||
if (width > 0 && height > 0)
|
||||
clutter_cairo_texture_set_surface_size (CLUTTER_CAIRO_TEXTURE (priv->background_image),
|
||||
width, height);
|
||||
st_widget_redraw_gradient ((StWidget*) actor);
|
||||
clutter_actor_allocate (CLUTTER_ACTOR (priv->background_image),
|
||||
&content_box,
|
||||
flags);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -526,6 +554,84 @@ st_widget_unmap (ClutterActor *actor)
|
||||
clutter_actor_unmap ((ClutterActor *) priv->tooltip);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_vertical_gradient (ClutterCairoTexture *texture,
|
||||
ClutterColor *start,
|
||||
ClutterColor *end)
|
||||
{
|
||||
guint width, height;
|
||||
cairo_t *cr;
|
||||
cairo_pattern_t *pattern;
|
||||
|
||||
clutter_cairo_texture_get_surface_size (texture, &width, &height);
|
||||
clutter_cairo_texture_clear (texture);
|
||||
cr = clutter_cairo_texture_create (texture);
|
||||
|
||||
pattern = cairo_pattern_create_linear (0, 0, 0, height);
|
||||
cairo_pattern_add_color_stop_rgba (pattern, 0,
|
||||
start->red / 255.,
|
||||
start->green / 255.,
|
||||
start->blue / 255.,
|
||||
start->alpha / 255.);
|
||||
cairo_pattern_add_color_stop_rgba (pattern, 1,
|
||||
end->red / 255.,
|
||||
end->green / 255.,
|
||||
end->blue / 255.,
|
||||
end->alpha / 255.);
|
||||
|
||||
cairo_rectangle (cr, 0, 0, width, height);
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_pattern_destroy (pattern);
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_horizontal_gradient (ClutterCairoTexture *texture,
|
||||
ClutterColor *start,
|
||||
ClutterColor *end)
|
||||
{
|
||||
guint width, height;
|
||||
cairo_t *cr;
|
||||
cairo_pattern_t *pattern;
|
||||
|
||||
clutter_cairo_texture_get_surface_size (texture, &width, &height);
|
||||
clutter_cairo_texture_clear (texture);
|
||||
cr = clutter_cairo_texture_create (texture);
|
||||
|
||||
pattern = cairo_pattern_create_linear (0, 0, width, 0);
|
||||
cairo_pattern_add_color_stop_rgba (pattern, 0,
|
||||
start->red / 255.,
|
||||
start->green / 255.,
|
||||
start->blue / 255.,
|
||||
start->alpha / 255.);
|
||||
cairo_pattern_add_color_stop_rgba (pattern, 1,
|
||||
end->red / 255.,
|
||||
end->green / 255.,
|
||||
end->blue / 255.,
|
||||
end->alpha / 255.);
|
||||
cairo_rectangle (cr, 0, 0, width, height);
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_pattern_destroy (pattern);
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
|
||||
static void
|
||||
st_widget_redraw_gradient (StWidget *widget)
|
||||
{
|
||||
if (widget->priv->bg_gradient_type == ST_GRADIENT_VERTICAL)
|
||||
draw_vertical_gradient ((ClutterCairoTexture*) widget->priv->background_image,
|
||||
&widget->priv->bg_color,
|
||||
&widget->priv->bg_gradient_end);
|
||||
else if (widget->priv->bg_gradient_type == ST_GRADIENT_HORIZONTAL)
|
||||
draw_horizontal_gradient ((ClutterCairoTexture*) widget->priv->background_image,
|
||||
&widget->priv->bg_color,
|
||||
&widget->priv->bg_gradient_end);
|
||||
}
|
||||
|
||||
static void notify_children_of_style_change (ClutterContainer *container);
|
||||
|
||||
static void
|
||||
@ -562,6 +668,8 @@ st_widget_real_style_changed (StWidget *self)
|
||||
guint border_width = 0;
|
||||
guint border_radius = 0;
|
||||
ClutterColor border_color = { 0, };
|
||||
StGradientType gradient;
|
||||
ClutterColor gradient_end;
|
||||
StSide side;
|
||||
StCorner corner;
|
||||
gboolean uniform_border_width;
|
||||
@ -572,11 +680,29 @@ st_widget_real_style_changed (StWidget *self)
|
||||
|
||||
theme_node = st_widget_get_theme_node (self);
|
||||
|
||||
st_theme_node_get_background_color (theme_node, &color);
|
||||
if (!clutter_color_equal (&color, &priv->bg_color))
|
||||
st_theme_node_get_background_gradient (theme_node, &gradient, &color, &gradient_end);
|
||||
|
||||
if (gradient == ST_GRADIENT_NONE)
|
||||
{
|
||||
if (gradient != priv->bg_gradient_type)
|
||||
has_changed = TRUE;
|
||||
priv->bg_gradient_type = gradient;
|
||||
st_theme_node_get_background_color (theme_node, &color);
|
||||
if (!clutter_color_equal (&color, &priv->bg_color))
|
||||
{
|
||||
priv->bg_color = color;
|
||||
priv->draw_bg_color = color.alpha != 0;
|
||||
has_changed = TRUE;
|
||||
}
|
||||
}
|
||||
else if (gradient != priv->bg_gradient_type ||
|
||||
!clutter_color_equal (&color, &priv->bg_color) ||
|
||||
!clutter_color_equal (&gradient_end, &priv->bg_gradient_end))
|
||||
{
|
||||
priv->bg_gradient_type = gradient;
|
||||
priv->bg_color = color;
|
||||
priv->draw_bg_color = color.alpha != 0;
|
||||
priv->bg_gradient_end = gradient_end;
|
||||
priv->draw_bg_color = TRUE;
|
||||
has_changed = TRUE;
|
||||
}
|
||||
|
||||
@ -741,6 +867,15 @@ st_widget_real_style_changed (StWidget *self)
|
||||
has_changed = TRUE;
|
||||
relayout_needed = TRUE;
|
||||
}
|
||||
else if (priv->bg_gradient_type != ST_GRADIENT_NONE)
|
||||
{
|
||||
texture = g_object_new (CLUTTER_TYPE_CAIRO_TEXTURE, NULL);
|
||||
priv->background_image = CLUTTER_ACTOR (texture);
|
||||
clutter_actor_set_parent (priv->background_image,
|
||||
CLUTTER_ACTOR (self));
|
||||
has_changed = TRUE;
|
||||
relayout_needed = TRUE;
|
||||
}
|
||||
|
||||
/* If there are any properties above that need to cause a relayout thay
|
||||
* should set this flag.
|
||||
@ -1248,12 +1383,22 @@ static void
|
||||
st_widget_recompute_style (StWidget *widget,
|
||||
StThemeNode *old_theme_node)
|
||||
{
|
||||
ClutterActorBox allocation_box;
|
||||
StThemeNode *new_theme_node = st_widget_get_theme_node (widget);
|
||||
|
||||
clutter_actor_get_allocation_box ((ClutterActor *) widget, &allocation_box);
|
||||
|
||||
if (!old_theme_node ||
|
||||
!st_theme_node_geometry_equal (old_theme_node, new_theme_node))
|
||||
clutter_actor_queue_relayout ((ClutterActor *) widget);
|
||||
|
||||
/* Could compare gradient values here if we hit a performance issue.
|
||||
* Also, only redraw if we've been allocated.
|
||||
*/
|
||||
if (allocation_box.x2 - allocation_box.x1 > 0 &&
|
||||
allocation_box.y2 - allocation_box.y1 > 0)
|
||||
st_widget_redraw_gradient (widget);
|
||||
|
||||
g_signal_emit (widget, signals[STYLE_CHANGED], 0);
|
||||
widget->priv->is_style_dirty = FALSE;
|
||||
}
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
#include "na-tray-child.h"
|
||||
|
||||
#include <glib/gi18n.h>
|
||||
#include <glib/gi18n-lib.h>
|
||||
#include <gdk/gdk.h>
|
||||
#include <gdk/gdkx.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
@ -27,7 +27,7 @@
|
||||
#include "na-tray-manager.h"
|
||||
|
||||
#include <gdkconfig.h>
|
||||
#include <glib/gi18n.h>
|
||||
#include <glib/gi18n-lib.h>
|
||||
#if defined (GDK_WINDOWING_X11)
|
||||
#include <gdk/gdkx.h>
|
||||
#include <X11/Xatom.h>
|
||||
|
Loading…
Reference in New Issue
Block a user