Merge branch 'master' into datetime
This commit is contained in:
commit
50c5591ec2
@ -101,11 +101,13 @@
|
||||
take care of its own output - this might be used to send the output
|
||||
to an icecast server via shout2send or similar. When unset or set
|
||||
to an empty value, the default pipeline will be used. This is currently
|
||||
'videorate ! theoraenc ! oggmux' and records to Ogg Theora.
|
||||
'videorate ! vp8enc quality=10 speed=2 threads=%T ! queue ! webmmux'
|
||||
and records to WEBM using the VP8 codec. %T is used as a placeholder
|
||||
for a guess at the optimal thread count on the system.
|
||||
</_description>
|
||||
</key>
|
||||
<key name="file-extension" type="s">
|
||||
<default>'ogv'</default>
|
||||
<default>'webm'</default>
|
||||
<_summary>File extension used for storing the screencast</_summary>
|
||||
<_description>
|
||||
The filename for recorded screencasts will be a unique filename
|
||||
|
@ -313,7 +313,7 @@ StTooltip StLabel {
|
||||
background-image: url("close-window.svg");
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
-st-shadow: -2px 2px 6px rgba(0,0,0,0.5);
|
||||
-st-background-image-shadow: -2px 2px 6px rgba(0,0,0,0.5);
|
||||
-shell-close-overlap: 16px;
|
||||
}
|
||||
|
||||
@ -374,7 +374,7 @@ StTooltip StLabel {
|
||||
background-gradient-direction: vertical;
|
||||
color: rgb(64, 64, 64);
|
||||
font-weight: bold;
|
||||
-st-shadow: 0px 0px 6px 2px rgba(255,255,255,0.9);
|
||||
box-shadow: 0px 0px 6px 2px rgba(255,255,255,0.9);
|
||||
transition-duration: 0;
|
||||
}
|
||||
|
||||
@ -391,6 +391,10 @@ StTooltip StLabel {
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
.view-tab-title:hover {
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
.view-tab-title:selected {
|
||||
color: #000000;
|
||||
background-color: #c2c7cd;
|
||||
@ -506,7 +510,7 @@ StTooltip StLabel {
|
||||
|
||||
.remove-favorite-icon:hover {
|
||||
color: white;
|
||||
-st-shadow: black 0px 2px 2px;
|
||||
icon-shadow: black 0px 2px 2px;
|
||||
}
|
||||
|
||||
.app-well-app > .overview-icon,
|
||||
@ -1004,7 +1008,7 @@ StTooltip StLabel {
|
||||
color: #545454;
|
||||
background-color: #e8e8e8;
|
||||
caret-color: #545454;
|
||||
-st-shadow: 0px 0px 6px 2px rgba(255,255,255,0.9);
|
||||
box-shadow: 0px 0px 6px 2px rgba(255,255,255,0.9);
|
||||
}
|
||||
|
||||
/* The spacing and padding on the summary is tricky; we want to keep
|
||||
|
@ -15,6 +15,8 @@ const POPUP_APPICON_SIZE = 96;
|
||||
const POPUP_SCROLL_TIME = 0.10; // seconds
|
||||
const POPUP_FADE_TIME = 0.1; // seconds
|
||||
|
||||
const APP_ICON_HOVER_TIMEOUT = 750; // milliseconds
|
||||
|
||||
const DISABLE_HOVER_TIMEOUT = 500; // milliseconds
|
||||
|
||||
const THUMBNAIL_DEFAULT_SIZE = 256;
|
||||
@ -50,6 +52,8 @@ AltTabPopup.prototype = {
|
||||
this._thumbnailTimeoutId = 0;
|
||||
this._motionTimeoutId = 0;
|
||||
|
||||
this.thumbnailsVisible = false;
|
||||
|
||||
// Initially disable hover so we ignore the enter-event if
|
||||
// the switcher appears underneath the current pointer location
|
||||
this._disableHover();
|
||||
@ -133,7 +137,7 @@ AltTabPopup.prototype = {
|
||||
this.actor.connect('button-press-event', Lang.bind(this, this._clickedOutside));
|
||||
this.actor.connect('scroll-event', Lang.bind(this, this._onScroll));
|
||||
|
||||
this._appSwitcher = new AppSwitcher(apps);
|
||||
this._appSwitcher = new AppSwitcher(apps, this);
|
||||
this.actor.add_actor(this._appSwitcher.actor);
|
||||
this._appSwitcher.connect('item-activated', Lang.bind(this, this._appActivated));
|
||||
this._appSwitcher.connect('item-entered', Lang.bind(this, this._appEntered));
|
||||
@ -457,11 +461,15 @@ AltTabPopup.prototype = {
|
||||
},
|
||||
|
||||
_destroyThumbnails : function() {
|
||||
Tweener.addTween(this._thumbnails.actor,
|
||||
let thumbnailsActor = this._thumbnails.actor;
|
||||
Tweener.addTween(thumbnailsActor,
|
||||
{ opacity: 0,
|
||||
time: THUMBNAIL_FADE_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: function() { this.destroy(); }
|
||||
onComplete: Lang.bind(this, function() {
|
||||
thumbnailsActor.destroy();
|
||||
this.thumbnailsVisible = false;
|
||||
})
|
||||
});
|
||||
this._thumbnails = null;
|
||||
},
|
||||
@ -477,7 +485,8 @@ AltTabPopup.prototype = {
|
||||
Tweener.addTween(this._thumbnails.actor,
|
||||
{ opacity: 255,
|
||||
time: THUMBNAIL_FADE_TIME,
|
||||
transition: 'easeOutQuad'
|
||||
transition: 'easeOutQuad',
|
||||
onComplete: Lang.bind(this, function () { this.thumbnailsVisible = true; })
|
||||
});
|
||||
}
|
||||
};
|
||||
@ -591,16 +600,20 @@ SwitcherList.prototype = {
|
||||
this._list.add_actor(bbox);
|
||||
|
||||
let n = this._items.length;
|
||||
bbox.connect('clicked', Lang.bind(this, function () {
|
||||
this._itemActivated(n);
|
||||
}));
|
||||
bbox.connect('enter-event', Lang.bind(this, function () {
|
||||
this._itemEntered(n);
|
||||
}));
|
||||
bbox.connect('clicked', Lang.bind(this, function() { this._onItemClicked(n); }));
|
||||
bbox.connect('enter-event', Lang.bind(this, function() { this._onItemEnter(n); }));
|
||||
|
||||
this._items.push(bbox);
|
||||
},
|
||||
|
||||
_onItemClicked: function (index) {
|
||||
this._itemActivated(index);
|
||||
},
|
||||
|
||||
_onItemEnter: function (index) {
|
||||
this._itemEntered(index);
|
||||
},
|
||||
|
||||
addSeparator: function () {
|
||||
let box = new St.Bin({ style_class: 'separator' });
|
||||
this._separator = box;
|
||||
@ -819,14 +832,14 @@ AppIcon.prototype = {
|
||||
}
|
||||
};
|
||||
|
||||
function AppSwitcher(apps) {
|
||||
this._init(apps);
|
||||
function AppSwitcher(apps, altTabPopup) {
|
||||
this._init(apps, altTabPopup);
|
||||
}
|
||||
|
||||
AppSwitcher.prototype = {
|
||||
__proto__ : SwitcherList.prototype,
|
||||
|
||||
_init : function(apps) {
|
||||
_init : function(apps, altTabPopup) {
|
||||
SwitcherList.prototype._init.call(this, true);
|
||||
|
||||
// Construct the AppIcons, sort by time, add to the popup
|
||||
@ -858,6 +871,8 @@ AppSwitcher.prototype = {
|
||||
|
||||
this._curApp = -1;
|
||||
this._iconSize = 0;
|
||||
this._altTabPopup = altTabPopup;
|
||||
this._mouseTimeOutId = 0;
|
||||
},
|
||||
|
||||
_getPreferredHeight: function (actor, forWidth, alloc) {
|
||||
@ -922,6 +937,27 @@ AppSwitcher.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
// We override SwitcherList's _onItemEnter method to delay
|
||||
// activation when the thumbnail list is open
|
||||
_onItemEnter: function (index) {
|
||||
if (this._mouseTimeOutId != 0)
|
||||
Mainloop.source_remove(this._mouseTimeOutId);
|
||||
if (this._altTabPopup.thumbnailsVisible) {
|
||||
this._mouseTimeOutId = Mainloop.timeout_add(APP_ICON_HOVER_TIMEOUT,
|
||||
Lang.bind(this, function () {
|
||||
this._enterItem(index);
|
||||
}));
|
||||
} else
|
||||
this._itemEntered(index);
|
||||
},
|
||||
|
||||
_enterItem: function(index) {
|
||||
let [x, y, mask] = global.get_pointer();
|
||||
let pickedActor = global.stage.get_actor_at_pos(Clutter.PickMode.ALL, x, y);
|
||||
if (this._items[index].contains(pickedActor))
|
||||
this._itemEntered(index);
|
||||
},
|
||||
|
||||
// We override SwitcherList's highlight() method to also deal with
|
||||
// the AppSwitcher->ThumbnailList arrows. Apps with only 1 window
|
||||
// will hide their arrows by default, but show them when their
|
||||
|
@ -40,9 +40,18 @@ AlphabeticalView.prototype = {
|
||||
this.actor = new St.ScrollView({ x_fill: true,
|
||||
y_fill: false,
|
||||
y_align: St.Align.START,
|
||||
vshadows: true });
|
||||
vfade: true });
|
||||
this.actor.add_actor(box);
|
||||
this.actor.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
|
||||
this.actor.connect('notify::mapped', Lang.bind(this,
|
||||
function() {
|
||||
if (!this.actor.mapped)
|
||||
return;
|
||||
|
||||
let adjustment = this.actor.vscroll.adjustment;
|
||||
let direction = Overview.SwipeScrollDirection.VERTICAL;
|
||||
Main.overview.setScrollAdjustment(adjustment, direction);
|
||||
}));
|
||||
},
|
||||
|
||||
_removeAll: function() {
|
||||
|
@ -386,7 +386,7 @@ Notification.prototype = {
|
||||
this._scrollArea = new St.ScrollView({ name: 'notification-scrollview',
|
||||
vscrollbar_policy: Gtk.PolicyType.AUTOMATIC,
|
||||
hscrollbar_policy: Gtk.PolicyType.NEVER,
|
||||
vshadows: true });
|
||||
vfade: true });
|
||||
this.actor.add(this._scrollArea, { row: 1,
|
||||
col: 1 });
|
||||
this._contentArea = new St.BoxLayout({ name: 'notification-body',
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
|
||||
const Clutter = imports.gi.Clutter;
|
||||
const Gtk = imports.gi.Gtk;
|
||||
const Meta = imports.gi.Meta;
|
||||
const Mainloop = imports.mainloop;
|
||||
const Signals = imports.signals;
|
||||
@ -32,6 +33,18 @@ const DASH_SPLIT_FRACTION = 0.1;
|
||||
|
||||
const DND_WINDOW_SWITCH_TIMEOUT = 1250;
|
||||
|
||||
const SwipeScrollDirection = {
|
||||
NONE: 0,
|
||||
HORIZONTAL: 1,
|
||||
VERTICAL: 2
|
||||
};
|
||||
|
||||
const SwipeScrollResult = {
|
||||
CANCEL: 0,
|
||||
SWIPE: 1,
|
||||
CLICK: 2
|
||||
};
|
||||
|
||||
function ShellInfo() {
|
||||
this._init();
|
||||
}
|
||||
@ -98,7 +111,8 @@ Overview.prototype = {
|
||||
|
||||
this._spacing = 0;
|
||||
|
||||
this._group = new St.Group({ name: 'overview' });
|
||||
this._group = new St.Group({ name: 'overview',
|
||||
reactive: true });
|
||||
this._group._delegate = this;
|
||||
this._group.connect('style-changed',
|
||||
Lang.bind(this, function() {
|
||||
@ -110,6 +124,11 @@ Overview.prototype = {
|
||||
}
|
||||
}));
|
||||
|
||||
this._scrollDirection = SwipeScrollDirection.NONE;
|
||||
this._scrollAdjustment = null;
|
||||
this._capturedEventId = 0;
|
||||
this._buttonPressId = 0;
|
||||
|
||||
this.shellInfo = new ShellInfo();
|
||||
|
||||
this._workspacesDisplay = null;
|
||||
@ -154,7 +173,7 @@ Overview.prototype = {
|
||||
this._dash.actor.add_constraint(this.viewSelector.constrainY);
|
||||
this._dash.actor.add_constraint(this.viewSelector.constrainHeight);
|
||||
|
||||
this._coverPane.lower_bottom();
|
||||
this._coverPane.hide();
|
||||
|
||||
// XDND
|
||||
this._dragMonitor = {
|
||||
@ -233,6 +252,149 @@ Overview.prototype = {
|
||||
return DND.DragMotionResult.CONTINUE;
|
||||
},
|
||||
|
||||
setScrollAdjustment: function(adjustment, direction) {
|
||||
this._scrollAdjustment = adjustment;
|
||||
if (this._scrollAdjustment == null)
|
||||
this._scrollDirection = SwipeScrollDirection.NONE;
|
||||
else
|
||||
this._scrollDirection = direction;
|
||||
},
|
||||
|
||||
_onButtonPress: function(actor, event) {
|
||||
if (this._scrollDirection == SwipeScrollDirection.NONE)
|
||||
return;
|
||||
|
||||
let [stageX, stageY] = event.get_coords();
|
||||
this._dragStartX = this._dragX = stageX;
|
||||
this._dragStartY = this._dragY = stageY;
|
||||
this._dragStartValue = this._scrollAdjustment.value;
|
||||
this._lastMotionTime = -1; // used to track "stopping" while swipe-scrolling
|
||||
this._capturedEventId = global.stage.connect('captured-event',
|
||||
Lang.bind(this, this._onCapturedEvent));
|
||||
this.emit('swipe-scroll-begin');
|
||||
},
|
||||
|
||||
_onCapturedEvent: function(actor, event) {
|
||||
let stageX, stageY;
|
||||
switch(event.type()) {
|
||||
case Clutter.EventType.BUTTON_RELEASE:
|
||||
[stageX, stageY] = event.get_coords();
|
||||
|
||||
// default to snapping back to the original value
|
||||
let newValue = this._dragStartValue;
|
||||
|
||||
let minValue = this._scrollAdjustment.lower;
|
||||
let maxValue = this._scrollAdjustment.upper - this._scrollAdjustment.page_size;
|
||||
|
||||
let direction;
|
||||
if (this._scrollDirection == SwipeScrollDirection.HORIZONTAL) {
|
||||
direction = stageX > this._dragStartX ? -1 : 1;
|
||||
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
|
||||
direction *= -1;
|
||||
} else {
|
||||
direction = stageY > this._dragStartY ? -1 : 1;
|
||||
}
|
||||
|
||||
// We default to scroll a full page size; both the first
|
||||
// and the last page may be smaller though, so we need to
|
||||
// adjust difference in those cases.
|
||||
let difference = direction * this._scrollAdjustment.page_size;
|
||||
if (this._dragStartValue + difference > maxValue)
|
||||
difference = maxValue - this._dragStartValue;
|
||||
else if (this._dragStartValue + difference < minValue)
|
||||
difference = minValue - this._dragStartValue;
|
||||
|
||||
// If the user has moved more than half the scroll
|
||||
// difference, we want to "settle" to the new value
|
||||
// even if the user stops dragging rather "throws" by
|
||||
// releasing during the drag.
|
||||
let distance = this._dragStartValue - this._scrollAdjustment.value;
|
||||
let noStop = Math.abs(distance / difference) > 0.5;
|
||||
|
||||
// We detect if the user is stopped by comparing the
|
||||
// timestamp of the button release with the timestamp of
|
||||
// the last motion. Experimentally, a difference of 0 or 1
|
||||
// millisecond indicates that the mouse is in motion, a
|
||||
// larger difference indicates that the mouse is stopped.
|
||||
if ((this._lastMotionTime > 0 &&
|
||||
this._lastMotionTime > event.get_time() - 2) ||
|
||||
noStop) {
|
||||
if (this._dragStartValue + difference >= minValue &&
|
||||
this._dragStartValue + difference <= maxValue)
|
||||
newValue += difference;
|
||||
}
|
||||
|
||||
// See if the user has moved the mouse enough to trigger
|
||||
// a drag
|
||||
let threshold = Gtk.Settings.get_default().gtk_dnd_drag_threshold;
|
||||
if (Math.abs(stageX - this._dragStartX) < threshold &&
|
||||
Math.abs(stageY - this._dragStartY) < threshold) {
|
||||
// no motion? It's a click!
|
||||
this.emit('swipe-scroll-end', SwipeScrollResult.CLICK);
|
||||
} else {
|
||||
let result;
|
||||
|
||||
if (newValue == this._dragStartValue)
|
||||
result = SwipeScrollResult.CANCEL;
|
||||
else
|
||||
result = SwipeScrollResult.SWIPE;
|
||||
|
||||
// The event capture handler is disconnected
|
||||
// while scrolling to the final position, so
|
||||
// to avoid undesired prelights we raise
|
||||
// the cover pane.
|
||||
this._coverPane.raise_top();
|
||||
this._coverPane.show();
|
||||
|
||||
Tweener.addTween(this._scrollAdjustment,
|
||||
{ value: newValue,
|
||||
time: ANIMATION_TIME,
|
||||
transition: 'easeOutQuad',
|
||||
onCompleteScope: this,
|
||||
onComplete: function() {
|
||||
this._coverPane.hide();
|
||||
this.emit('swipe-scroll-end',
|
||||
result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
global.stage.disconnect(this._capturedEventId);
|
||||
this._capturedEventId = 0;
|
||||
|
||||
return true;
|
||||
|
||||
case Clutter.EventType.MOTION:
|
||||
[stageX, stageY] = event.get_coords();
|
||||
let dx = this._dragX - stageX;
|
||||
let dy = this._dragY - stageY;
|
||||
let primary = global.get_primary_monitor();
|
||||
|
||||
if (this._scrollDirection == SwipeScrollDirection.HORIZONTAL) {
|
||||
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
|
||||
this._scrollAdjustment.value -= (dx / primary.width) * this._scrollAdjustment.page_size;
|
||||
else
|
||||
this._scrollAdjustment.value += (dx / primary.width) * this._scrollAdjustment.page_size;
|
||||
} else {
|
||||
this._scrollAdjustment.value += (dy / primary.height) * this._scrollAdjustment.page_size;
|
||||
}
|
||||
|
||||
this._dragX = stageX;
|
||||
this._dragY = stageY;
|
||||
this._lastMotionTime = event.get_time();
|
||||
|
||||
return true;
|
||||
|
||||
// Block enter/leave events to avoid prelights
|
||||
// during swipe-scroll
|
||||
case Clutter.EventType.ENTER:
|
||||
case Clutter.EventType.LEAVE:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_getDesktopClone: function() {
|
||||
let windows = global.get_window_actors().filter(function(w) {
|
||||
return w.meta_window.get_window_type() == Meta.WindowType.DESKTOP;
|
||||
@ -335,6 +497,9 @@ Overview.prototype = {
|
||||
this._modal = true;
|
||||
this._animateVisible();
|
||||
this._shown = true;
|
||||
|
||||
this._buttonPressId = this._group.connect('button-press-event',
|
||||
Lang.bind(this, this._onButtonPress));
|
||||
},
|
||||
|
||||
_animateVisible: function() {
|
||||
@ -402,6 +567,7 @@ Overview.prototype = {
|
||||
});
|
||||
|
||||
this._coverPane.raise_top();
|
||||
this._coverPane.show();
|
||||
this.emit('showing');
|
||||
},
|
||||
|
||||
@ -432,6 +598,10 @@ Overview.prototype = {
|
||||
|
||||
this._shown = false;
|
||||
this._syncInputMode();
|
||||
|
||||
if (this._buttonPressId > 0)
|
||||
this._group.disconnect(this._buttonPressId);
|
||||
this._buttonPressId = 0;
|
||||
},
|
||||
|
||||
// hideTemporarily:
|
||||
@ -541,13 +711,14 @@ Overview.prototype = {
|
||||
});
|
||||
|
||||
this._coverPane.raise_top();
|
||||
this._coverPane.show();
|
||||
this.emit('hiding');
|
||||
},
|
||||
|
||||
_showDone: function() {
|
||||
this.animationInProgress = false;
|
||||
this._desktopFade.hide();
|
||||
this._coverPane.lower_bottom();
|
||||
this._coverPane.hide();
|
||||
|
||||
this.emit('shown');
|
||||
// Handle any calls to hide* while we were showing
|
||||
@ -575,7 +746,7 @@ Overview.prototype = {
|
||||
this.animationInProgress = false;
|
||||
this._hideInProgress = false;
|
||||
|
||||
this._coverPane.lower_bottom();
|
||||
this._coverPane.hide();
|
||||
|
||||
this.emit('hidden');
|
||||
// Handle any calls to show* while we were hiding
|
||||
|
@ -44,6 +44,10 @@ const STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION = {
|
||||
if (Config.HAVE_BLUETOOTH)
|
||||
STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION['bluetooth'] = imports.ui.status.bluetooth.Indicator;
|
||||
|
||||
const STANDARD_TRAY_INDICATOR_FACTORIES = [
|
||||
imports.ui.status.keyboard.ModifierIndicatorFactory
|
||||
];
|
||||
|
||||
// in org.gnome.desktop.interface
|
||||
const CLOCK_FORMAT_KEY = 'clock-format';
|
||||
|
||||
@ -695,17 +699,18 @@ Panel.prototype = {
|
||||
|
||||
/* right */
|
||||
|
||||
// System status applets live in statusBox, while legacy tray icons
|
||||
// On-off indicators (for keyboard leds and accessx) are in indicatorBox
|
||||
// System status applets live in statusBox, and legacy tray icons
|
||||
// live in trayBox
|
||||
// The trayBox is hidden when there are no tray icons.
|
||||
let statusBox = new St.BoxLayout({ name: 'statusTray' });
|
||||
let trayBox = new St.BoxLayout({ name: 'legacyTray' });
|
||||
this._trayBox = trayBox;
|
||||
this._statusBox = statusBox;
|
||||
this._indicatorBox = new St.BoxLayout({ name: 'indicatorBox' });
|
||||
this._trayBox = new St.BoxLayout({ name: 'legacyTray' });
|
||||
this._statusBox = new St.BoxLayout({ name: 'statusTray' });
|
||||
|
||||
trayBox.hide();
|
||||
this._rightBox.add(trayBox);
|
||||
this._rightBox.add(statusBox);
|
||||
this._trayBox.hide();
|
||||
this._rightBox.add(this._indicatorBox);
|
||||
this._rightBox.add(this._trayBox);
|
||||
this._rightBox.add(this._statusBox);
|
||||
|
||||
Main.statusIconDispatcher.connect('status-icon-added', Lang.bind(this, this._onTrayIconAdded));
|
||||
Main.statusIconDispatcher.connect('status-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
|
||||
@ -755,6 +760,13 @@ Panel.prototype = {
|
||||
},
|
||||
|
||||
startStatusArea: function() {
|
||||
for (let i = 0; i < STANDARD_TRAY_INDICATOR_FACTORIES.length; i++) {
|
||||
let factory = new STANDARD_TRAY_INDICATOR_FACTORIES[i];
|
||||
let indicators = factory.getIndicators();
|
||||
for (let j = 0; j < indicators.length; j++)
|
||||
this._indicatorBox.add(indicators[j]);
|
||||
}
|
||||
|
||||
for (let i = 0; i < STANDARD_TRAY_ICON_ORDER.length; i++) {
|
||||
let role = STANDARD_TRAY_ICON_ORDER[i];
|
||||
let constructor = STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION[role];
|
||||
|
@ -10,6 +10,7 @@ const St = imports.gi.St;
|
||||
const DND = imports.ui.dnd;
|
||||
const IconGrid = imports.ui.iconGrid;
|
||||
const Main = imports.ui.main;
|
||||
const Overview = imports.ui.overview;
|
||||
const Search = imports.ui.search;
|
||||
|
||||
const MAX_SEARCH_RESULTS_ROWS = 2;
|
||||
@ -166,7 +167,7 @@ SearchResults.prototype = {
|
||||
|
||||
let scrollView = new St.ScrollView({ x_fill: true,
|
||||
y_fill: false,
|
||||
vshadows: true });
|
||||
vfade: true });
|
||||
scrollView.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
|
||||
scrollView.add_actor(this._content);
|
||||
|
||||
@ -175,6 +176,15 @@ SearchResults.prototype = {
|
||||
expand: true,
|
||||
x_align: St.Align.START,
|
||||
y_align: St.Align.START });
|
||||
this.actor.connect('notify::mapped', Lang.bind(this,
|
||||
function() {
|
||||
if (!this.actor.mapped)
|
||||
return;
|
||||
|
||||
let adjustment = scrollView.vscroll.adjustment;
|
||||
let direction = Overview.SwipeScrollDirection.VERTICAL;
|
||||
Main.overview.setScrollAdjustment(adjustment, direction);
|
||||
}));
|
||||
|
||||
this._statusText = new St.Label({ style_class: 'search-statustext' });
|
||||
this._content.add(this._statusText);
|
||||
|
@ -42,7 +42,7 @@ LayoutMenuItem.prototype = {
|
||||
};
|
||||
|
||||
function XKBIndicator() {
|
||||
this._init.apply(this, arguments);
|
||||
this._init.call(this);
|
||||
}
|
||||
|
||||
XKBIndicator.prototype = {
|
||||
@ -75,7 +75,7 @@ XKBIndicator.prototype = {
|
||||
this._sync_config();
|
||||
|
||||
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
||||
this.menu.addAction(_("Keyboard Settings"), function() {
|
||||
this.menu.addAction(_("Localization Settings"), function() {
|
||||
GLib.spawn_command_line_async('gnome-control-center region');
|
||||
});
|
||||
},
|
||||
@ -203,4 +203,53 @@ XKBIndicator.prototype = {
|
||||
for (let i = 0; i < this._labelActors.length; i++)
|
||||
this._labelActors[i].allocate_align_fill(box, 0.5, 0, false, false, flags);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
function ModifierIndicatorFactory() {
|
||||
this._init.call(this);
|
||||
}
|
||||
|
||||
ModifierIndicatorFactory.prototype = {
|
||||
_init: function() {
|
||||
this._settings = new Gio.Settings({ schema: INDICATOR_SCHEMA });
|
||||
this._settings.connect('changed::show-keyboard-leds-indicator', Lang.bind(this, this._changed));
|
||||
|
||||
this._config = Gkbd.Configuration.get();
|
||||
this._config.connect('indicators-changed', Lang.bind(this, this._changed));
|
||||
|
||||
this._scrollLock = new St.Icon({ icon_name: 'kbdled-scroll-lock', icon_type: St.IconType.SYMBOLIC, style_class: 'system-status-icon' });
|
||||
this._numLock = new St.Icon({ icon_name: 'kbdled-num-lock', icon_type: St.IconType.SYMBOLIC, style_class: 'system-status-icon' });
|
||||
this._capsLock = new St.Icon({ icon_name: 'kbdled-caps-lock', icon_type: St.IconType.SYMBOLIC, style_class: 'system-status-icon' });
|
||||
|
||||
this._changed();
|
||||
},
|
||||
|
||||
getIndicators: function() {
|
||||
return [this._scrollLock, this._numLock, this._capsLock];
|
||||
},
|
||||
|
||||
_changed: function() {
|
||||
let enable = this._settings.get_boolean('show-keyboard-leds-indicator');
|
||||
|
||||
if (enable) {
|
||||
if (this._config.get_scroll_lock_state())
|
||||
this._scrollLock.show();
|
||||
else
|
||||
this._scrollLock.hide();
|
||||
|
||||
if (this._config.get_num_lock_state())
|
||||
this._numLock.show();
|
||||
else
|
||||
this._numLock.hide();
|
||||
|
||||
if (this._config.get_caps_lock_state())
|
||||
this._capsLock.show();
|
||||
else
|
||||
this._capsLock.hide();
|
||||
} else {
|
||||
this._scrollLock.hide();
|
||||
this._numLock.hide();
|
||||
this._capsLock.hide();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -517,20 +517,10 @@ Workspace.prototype = {
|
||||
// Without this the drop area will be overlapped.
|
||||
this._windowOverlaysGroup.set_size(0, 0);
|
||||
|
||||
this.actor = new Clutter.Group({ reactive: true });
|
||||
this.actor = new Clutter.Group();
|
||||
this.actor._delegate = this;
|
||||
|
||||
this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
|
||||
this.actor.connect('button-release-event', Lang.bind(this,
|
||||
function(actor, event) {
|
||||
// Only switch to the workspace when there's no application
|
||||
// windows open. The problem is that it's too easy to miss
|
||||
// an app window and get the wrong one focused.
|
||||
if (this._windows.length == 0) {
|
||||
this.metaWorkspace.activate(event.get_time());
|
||||
Main.overview.hide();
|
||||
}
|
||||
}));
|
||||
|
||||
// Items in _windowOverlaysGroup should not be scaled, so we don't
|
||||
// add them to this.actor, but to its parent whenever it changes
|
||||
@ -605,6 +595,10 @@ Workspace.prototype = {
|
||||
return this._lookupIndex(metaWindow) >= 0;
|
||||
},
|
||||
|
||||
isEmpty: function() {
|
||||
return this._windows.length == 0;
|
||||
},
|
||||
|
||||
setShowOnlyWindows: function(showOnlyWindows, reposition) {
|
||||
this._showOnlyWindows = showOnlyWindows;
|
||||
this._resetCloneVisibility();
|
||||
|
@ -45,6 +45,8 @@ WorkspacesView.prototype = {
|
||||
this._spacing = node.get_length('spacing');
|
||||
this._computeWorkspacePositions();
|
||||
}));
|
||||
this.actor.connect('notify::mapped',
|
||||
Lang.bind(this, this._onMappedChanged));
|
||||
|
||||
this._width = width;
|
||||
this._height = height;
|
||||
@ -55,10 +57,9 @@ WorkspacesView.prototype = {
|
||||
this._activeWorkspaceY = 0; // y offset of active ws while dragging
|
||||
this._lostWorkspaces = [];
|
||||
this._animating = false; // tweening
|
||||
this._scrolling = false; // dragging desktop
|
||||
this._scrolling = false; // swipe-scrolling
|
||||
this._animatingScroll = false; // programatically updating the adjustment
|
||||
this._inDrag = false; // dragging a window
|
||||
this._lastMotionTime = -1; // used to track "stopping" while dragging workspaces
|
||||
|
||||
let activeWorkspaceIndex = global.screen.get_active_workspace_index();
|
||||
this._workspaces = workspaces;
|
||||
@ -89,10 +90,6 @@ WorkspacesView.prototype = {
|
||||
this._scrollAdjustment.connect('notify::value',
|
||||
Lang.bind(this, this._onScroll));
|
||||
|
||||
this._dragIndex = -1;
|
||||
|
||||
this._buttonPressId = 0;
|
||||
this._capturedEventId = 0;
|
||||
this._timeoutId = 0;
|
||||
|
||||
this._windowSelectionAppId = null;
|
||||
@ -113,6 +110,8 @@ WorkspacesView.prototype = {
|
||||
Lang.bind(this, this._dragBegin));
|
||||
this._windowDragEndId = Main.overview.connect('window-drag-end',
|
||||
Lang.bind(this, this._dragEnd));
|
||||
this._swipeScrollBeginId = 0;
|
||||
this._swipeScrollEndId = 0;
|
||||
},
|
||||
|
||||
_lookupWorkspaceForMetaWindow: function (metaWindow) {
|
||||
@ -290,8 +289,6 @@ WorkspacesView.prototype = {
|
||||
if (this._inDrag)
|
||||
scale *= WORKSPACE_DRAGGING_SCALE;
|
||||
|
||||
this._setWorkspaceDraggable(active, true);
|
||||
|
||||
let _width = this._workspaces[0].actor.width * scale;
|
||||
let _height = this._workspaces[0].actor.height * scale;
|
||||
|
||||
@ -323,128 +320,6 @@ WorkspacesView.prototype = {
|
||||
this._updateScrollAdjustment(active, showAnimation);
|
||||
},
|
||||
|
||||
// _setWorkspaceDraggable:
|
||||
// @index: workspace index
|
||||
// @draggable: whether workspace @index should be draggable
|
||||
//
|
||||
// If @draggable is %true, set up workspace @index to allow switching
|
||||
// workspaces by dragging the desktop - if a draggable workspace has
|
||||
// been set up before, it will be reset before the new one is made
|
||||
// draggable.
|
||||
// If @draggable is %false, workspace @index is reset to no longer allow
|
||||
// dragging.
|
||||
_setWorkspaceDraggable: function(index, draggable) {
|
||||
if (index < 0 || index >= global.n_workspaces)
|
||||
return;
|
||||
|
||||
let dragActor = this._workspaces[index].actor;
|
||||
|
||||
if (draggable) {
|
||||
this._workspaces[index].actor.reactive = true;
|
||||
|
||||
// reset old draggable workspace
|
||||
if (this._dragIndex > -1)
|
||||
this._setWorkspaceDraggable(this._dragIndex, false);
|
||||
|
||||
this._dragIndex = index;
|
||||
this._buttonPressId = dragActor.connect('button-press-event',
|
||||
Lang.bind(this, this._onButtonPress));
|
||||
} else {
|
||||
this._dragIndex = -1;
|
||||
|
||||
if (this._buttonPressId > 0) {
|
||||
if (dragActor.get_stage())
|
||||
dragActor.disconnect(this._buttonPressId);
|
||||
this._buttonPressId = 0;
|
||||
}
|
||||
|
||||
if (this._capturedEventId > 0) {
|
||||
global.stage.disconnect(this._capturedEventId);
|
||||
this._capturedEventId = 0;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// start dragging the active workspace
|
||||
_onButtonPress: function(actor, event) {
|
||||
if (actor != event.get_source())
|
||||
return;
|
||||
|
||||
if (this._dragIndex == -1)
|
||||
return;
|
||||
|
||||
let [stageX, stageY] = event.get_coords();
|
||||
this._dragStartX = this._dragX = stageX;
|
||||
this._scrolling = true;
|
||||
this._capturedEventId = global.stage.connect('captured-event',
|
||||
Lang.bind(this, this._onCapturedEvent));
|
||||
},
|
||||
|
||||
// handle captured events while dragging a workspace
|
||||
_onCapturedEvent: function(actor, event) {
|
||||
let active = global.screen.get_active_workspace_index();
|
||||
let stageX, stageY;
|
||||
|
||||
switch (event.type()) {
|
||||
case Clutter.EventType.BUTTON_RELEASE:
|
||||
this._scrolling = false;
|
||||
|
||||
[stageX, stageY] = event.get_coords();
|
||||
|
||||
// default to snapping back to the original workspace
|
||||
let activate = this._dragIndex;
|
||||
let last = global.screen.n_workspaces - 1;
|
||||
|
||||
// If the user has moved more than half a workspace, we want to "settle"
|
||||
// to the new workspace even if the user stops dragging rather "throws"
|
||||
// by releasing during the drag.
|
||||
let noStop = Math.abs(activate - this._scrollAdjustment.value) > 0.5;
|
||||
|
||||
let difference = stageX > this._dragStartX ? -1 : 1;
|
||||
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
|
||||
difference *= -1;
|
||||
|
||||
// We detect if the user is stopped by comparing the timestamp of the button
|
||||
// release with the timestamp of the last motion. Experimentally, a difference
|
||||
// of 0 or 1 millisecond indicates that the mouse is in motion, a larger
|
||||
// difference indicates that the mouse is stopped.
|
||||
if ((this._lastMotionTime > 0 && this._lastMotionTime > event.get_time() - 2) || noStop) {
|
||||
if (activate + difference >= 0 &&
|
||||
activate + difference <= last)
|
||||
activate += difference;
|
||||
}
|
||||
|
||||
if (activate != active) {
|
||||
let workspace = this._workspaces[activate].metaWorkspace;
|
||||
workspace.activate(global.get_current_time());
|
||||
} else {
|
||||
this._scrollToActive(true);
|
||||
}
|
||||
|
||||
if (stageX == this._dragStartX)
|
||||
// no motion? It's a click!
|
||||
return false;
|
||||
|
||||
return true;
|
||||
|
||||
case Clutter.EventType.MOTION:
|
||||
[stageX, stageY] = event.get_coords();
|
||||
let dx = this._dragX - stageX;
|
||||
let primary = global.get_primary_monitor();
|
||||
|
||||
if (St.Widget.get_default_direction() == St.TextDirection.RTL)
|
||||
this._scrollAdjustment.value -= (dx / primary.width);
|
||||
else
|
||||
this._scrollAdjustment.value += (dx / primary.width);
|
||||
this._dragX = stageX;
|
||||
this._lastMotionTime = event.get_time();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
// Update workspace actors parameters to the values calculated in
|
||||
// _computeWorkspacePositions()
|
||||
// @showAnimation: iff %true, transition between states
|
||||
@ -454,7 +329,6 @@ WorkspacesView.prototype = {
|
||||
let targetWorkspaceCurrentX = this._workspaces[active].x;
|
||||
let dx = targetWorkspaceNewX - targetWorkspaceCurrentX;
|
||||
|
||||
this._setWorkspaceDraggable(active, true);
|
||||
this._animating = showAnimation;
|
||||
|
||||
for (let w = 0; w < this._workspaces.length; w++) {
|
||||
@ -606,7 +480,6 @@ WorkspacesView.prototype = {
|
||||
global.window_manager.disconnect(this._switchWorkspaceNotifyId);
|
||||
global.screen.disconnect(this._restackedNotifyId);
|
||||
|
||||
this._setWorkspaceDraggable(this._dragIndex, false);
|
||||
if (this._timeoutId) {
|
||||
Mainloop.source_remove(this._timeoutId);
|
||||
this._timeoutId = 0;
|
||||
@ -629,6 +502,21 @@ WorkspacesView.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
_onMappedChanged: function() {
|
||||
if (this.actor.mapped) {
|
||||
let direction = Overview.SwipeScrollDirection.HORIZONTAL;
|
||||
Main.overview.setScrollAdjustment(this._scrollAdjustment,
|
||||
direction);
|
||||
this._swipeScrollBeginId = Main.overview.connect('swipe-scroll-begin',
|
||||
Lang.bind(this, this._swipeScrollBegin));
|
||||
this._swipeScrollEndId = Main.overview.connect('swipe-scroll-end',
|
||||
Lang.bind(this, this._swipeScrollEnd));
|
||||
} else {
|
||||
Main.overview.disconnect(this._swipeScrollBeginId);
|
||||
Main.overview.disconnect(this._swipeScrollEndId);
|
||||
}
|
||||
},
|
||||
|
||||
_dragBegin: function() {
|
||||
if (this._scrolling)
|
||||
return;
|
||||
@ -736,6 +624,37 @@ WorkspacesView.prototype = {
|
||||
this._workspaces[i].setReservedSlot(null);
|
||||
},
|
||||
|
||||
_swipeScrollBegin: function() {
|
||||
this._scrolling = true;
|
||||
},
|
||||
|
||||
_swipeScrollEnd: function(overview, result) {
|
||||
this._scrolling = false;
|
||||
|
||||
if (result == Overview.SwipeScrollResult.CLICK) {
|
||||
let [x, y, mod] = global.get_pointer();
|
||||
let actor = global.stage.get_actor_at_pos(Clutter.PickMode.ALL,
|
||||
x, y);
|
||||
|
||||
// Only switch to the workspace when there's no application
|
||||
// windows open. The problem is that it's too easy to miss
|
||||
// an app window and get the wrong one focused.
|
||||
let active = global.screen.get_active_workspace_index();
|
||||
if (this._workspaces[active].isEmpty() &&
|
||||
this.actor.contains(actor))
|
||||
Main.overview.hide();
|
||||
}
|
||||
|
||||
if (result == Overview.SwipeScrollResult.SWIPE)
|
||||
// The active workspace has changed; while swipe-scrolling
|
||||
// has already taken care of the positioning, the cached
|
||||
// positions need to be updated
|
||||
this._computeWorkspacePositions();
|
||||
|
||||
// Make sure title captions etc are shown as necessary
|
||||
this._updateVisibility();
|
||||
},
|
||||
|
||||
// sync the workspaces' positions to the value of the scroll adjustment
|
||||
// and change the active workspace if appropriate
|
||||
_onScroll: function(adj) {
|
||||
|
63
po/ar.po
63
po/ar.po
@ -6,8 +6,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: HEAD\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-01-19 22:47+0200\n"
|
||||
"PO-Revision-Date: 2011-01-19 22:47+0300\n"
|
||||
"POT-Creation-Date: 2011-01-23 13:29+0200\n"
|
||||
"PO-Revision-Date: 2011-01-23 13:29+0300\n"
|
||||
"Last-Translator: Khaled Hosny <khaledhosny@eglug.org>\n"
|
||||
"Language-Team: Arabic <doc@arabeyes.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@ -70,7 +70,8 @@ msgstr ""
|
||||
msgid "List of desktop file IDs for favorite applications"
|
||||
msgstr ""
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:11
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:12
|
||||
#, no-c-format
|
||||
msgid ""
|
||||
"Sets the GStreamer pipeline used to encode recordings. It follows the syntax "
|
||||
"used for gst-launch. The pipeline should have an unconnected sink pad where "
|
||||
@ -79,45 +80,47 @@ msgid ""
|
||||
"pipeline can also take care of its own output - this might be used to send "
|
||||
"the output to an icecast server via shout2send or similar. When unset or set "
|
||||
"to an empty value, the default pipeline will be used. This is currently "
|
||||
"'videorate ! theoraenc ! oggmux' and records to Ogg Theora."
|
||||
msgstr ""
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:12
|
||||
msgid "Show date in clock"
|
||||
"'videorate ! vp8enc quality=10 speed=2 threads=%T ! queue ! webmmux' and "
|
||||
"records to WEBM using the VP8 codec. %T is used as a placeholder for a guess "
|
||||
"at the optimal thread count on the system."
|
||||
msgstr ""
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:13
|
||||
msgid "Show the week date in the calendar"
|
||||
msgid "Show date in clock"
|
||||
msgstr ""
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:14
|
||||
msgid "Show time with seconds"
|
||||
msgid "Show the week date in the calendar"
|
||||
msgstr ""
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:15
|
||||
msgid "Show time with seconds"
|
||||
msgstr ""
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:16
|
||||
msgid ""
|
||||
"The applications corresponding to these identifiers will be displayed in the "
|
||||
"favorites area."
|
||||
msgstr ""
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:16
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:17
|
||||
msgid ""
|
||||
"The filename for recorded screencasts will be a unique filename based on the "
|
||||
"current date, and use this extension. It should be changed when recording to "
|
||||
"a different container format."
|
||||
msgstr ""
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:17
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:18
|
||||
msgid ""
|
||||
"The framerate of the resulting screencast recordered by GNOME Shell's "
|
||||
"screencast recorder in frames-per-second."
|
||||
msgstr ""
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:18
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:19
|
||||
msgid "The gstreamer pipeline used to encode the screencast"
|
||||
msgstr ""
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:19
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:20
|
||||
msgid ""
|
||||
"The shell normally monitors active applications in order to present the most "
|
||||
"used ones (e.g. in launchers). While this data will be kept private, you may "
|
||||
@ -125,15 +128,15 @@ msgid ""
|
||||
"remove already saved data."
|
||||
msgstr ""
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:20
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:21
|
||||
msgid "Uuids of extensions to disable"
|
||||
msgstr ""
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:21
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:22
|
||||
msgid "Whether to collect stats about applications usage"
|
||||
msgstr ""
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:22
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:23
|
||||
msgid "disabled OpenSearch providers"
|
||||
msgstr ""
|
||||
|
||||
@ -436,54 +439,54 @@ msgid "Applications"
|
||||
msgstr "التطبيقات"
|
||||
|
||||
#. TODO - _quit() doesn't really work on apps in state STARTING yet
|
||||
#: ../js/ui/panel.js:479
|
||||
#: ../js/ui/panel.js:483
|
||||
#, c-format
|
||||
msgid "Quit %s"
|
||||
msgstr "أغلق %s"
|
||||
|
||||
#. Translators: This is the time format with date used
|
||||
#. in 24-hour mode.
|
||||
#: ../js/ui/panel.js:564
|
||||
#: ../js/ui/panel.js:568
|
||||
msgid "%a %b %e, %R:%S"
|
||||
msgstr "%A %e %B، %R:%S"
|
||||
|
||||
#: ../js/ui/panel.js:565
|
||||
#: ../js/ui/panel.js:569
|
||||
msgid "%a %b %e, %R"
|
||||
msgstr "%A %e %B، %R"
|
||||
|
||||
#. Translators: This is the time format without date used
|
||||
#. in 24-hour mode.
|
||||
#: ../js/ui/panel.js:569
|
||||
#: ../js/ui/panel.js:573
|
||||
msgid "%a %R:%S"
|
||||
msgstr "%A %R:%S"
|
||||
|
||||
#: ../js/ui/panel.js:570
|
||||
#: ../js/ui/panel.js:574
|
||||
msgid "%a %R"
|
||||
msgstr "%A %R"
|
||||
|
||||
#. Translators: This is a time format with date used
|
||||
#. for AM/PM.
|
||||
#: ../js/ui/panel.js:577
|
||||
#: ../js/ui/panel.js:581
|
||||
msgid "%a %b %e, %l:%M:%S %p"
|
||||
msgstr "%A %e %B، %l:%M:%S %p"
|
||||
|
||||
#: ../js/ui/panel.js:578
|
||||
#: ../js/ui/panel.js:582
|
||||
msgid "%a %b %e, %l:%M %p"
|
||||
msgstr "%A %e %B، %l:%M %p"
|
||||
|
||||
#. Translators: This is a time format without date used
|
||||
#. for AM/PM.
|
||||
#: ../js/ui/panel.js:582
|
||||
#: ../js/ui/panel.js:586
|
||||
msgid "%a %l:%M:%S %p"
|
||||
msgstr "%A %l:%M:%S %p"
|
||||
|
||||
#: ../js/ui/panel.js:583
|
||||
#: ../js/ui/panel.js:587
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%A %Ol:%OM %p"
|
||||
|
||||
#. 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:728
|
||||
#: ../js/ui/panel.js:732
|
||||
msgid "Activities"
|
||||
msgstr "الأنشطة"
|
||||
|
||||
@ -638,7 +641,7 @@ msgstr "عطل أثناء تصفّح الجهاز"
|
||||
msgid "The requested device cannot be browsed, error is '%s'"
|
||||
msgstr "تعذّر تصفح الجهاز، رسالة العطل '%s'"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:251 ../js/ui/status/keyboard.js:78
|
||||
#: ../js/ui/status/bluetooth.js:251
|
||||
msgid "Keyboard Settings"
|
||||
msgstr "إعدادات لوحة المفاتيح"
|
||||
|
||||
@ -713,6 +716,10 @@ msgstr "من فضلك أدخل الرقم المذكور على الجهاز."
|
||||
msgid "OK"
|
||||
msgstr "حسنا"
|
||||
|
||||
#: ../js/ui/status/keyboard.js:78
|
||||
msgid "Localization Settings"
|
||||
msgstr "إعدادات اللغة"
|
||||
|
||||
#: ../js/ui/status/power.js:85
|
||||
msgid "Power Settings"
|
||||
msgstr "إعدادات الطاقة"
|
||||
|
120
po/es.po
120
po/es.po
@ -1,17 +1,17 @@
|
||||
# Spanish translation of gnome-shell.
|
||||
# Copyright (C) 2009 gnome-shell's COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the gnome-shell package.
|
||||
# Jorge González <jorgegonz@svn.gnome.org>, 2009, 2010.
|
||||
# Daniel Mustieles <daniel.mustieles@gmail.com>, 2010, 2011.
|
||||
# Jorge González <jorgegonz@svn.gnome.org>, 2009, 2010, 2011.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell.master\n"
|
||||
"Report-Msgid-Bugs-To: http://bugzilla.gnome.org/enter_bug.cgi?product=gnome-"
|
||||
"shell&component=general\n"
|
||||
"POT-Creation-Date: 2011-01-17 21:45+0000\n"
|
||||
"PO-Revision-Date: 2011-01-19 16:17+0100\n"
|
||||
"Last-Translator: Daniel Mustieles <daniel.mustieles@gmail.com>\n"
|
||||
"POT-Creation-Date: 2011-01-21 18:46+0000\n"
|
||||
"PO-Revision-Date: 2011-01-22 16:34+0100\n"
|
||||
"Last-Translator: Jorge González <jorgegonz@svn.gnome.org>\n"
|
||||
"Language-Team: Español <gnome-es-list@gnome.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
@ -76,7 +76,18 @@ msgstr "Si es cierta muestra la fecha de semana ISO en el calendario."
|
||||
msgid "List of desktop file IDs for favorite applications"
|
||||
msgstr "Lista de ID de archivos de escritorio para las aplicaciones favoritas"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:11
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:12
|
||||
#, no-c-format
|
||||
#| msgid ""
|
||||
#| "Sets the GStreamer pipeline used to encode recordings. It follows the "
|
||||
#| "syntax used for gst-launch. The pipeline should have an unconnected sink "
|
||||
#| "pad where the recorded video is recorded. It will normally have a "
|
||||
#| "unconnected source pad; output from that pad will be written into the "
|
||||
#| "output file. However the pipeline can also take care of its own output - "
|
||||
#| "this might be used to send the output to an icecast server via shout2send "
|
||||
#| "or similar. When unset or set to an empty value, the default pipeline "
|
||||
#| "will be used. This is currently 'videorate ! theoraenc ! oggmux' and "
|
||||
#| "records to Ogg Theora."
|
||||
msgid ""
|
||||
"Sets the GStreamer pipeline used to encode recordings. It follows the syntax "
|
||||
"used for gst-launch. The pipeline should have an unconnected sink pad where "
|
||||
@ -85,32 +96,35 @@ msgid ""
|
||||
"pipeline can also take care of its own output - this might be used to send "
|
||||
"the output to an icecast server via shout2send or similar. When unset or set "
|
||||
"to an empty value, the default pipeline will be used. This is currently "
|
||||
"'videorate ! theoraenc ! oggmux' and records to Ogg Theora."
|
||||
"'videorate ! vp8enc quality=10 speed=2 threads=%T ! queue ! webmmux' and "
|
||||
"records to WEBM using the VP8 codec. %T is used as a placeholder for a guess "
|
||||
"at the optimal thread count on the system."
|
||||
msgstr ""
|
||||
"Establece la tubería GStreamer usada para codificar grabaciones. Sigue la "
|
||||
"sintaxis usada para gst-launch. La tubería debería tener un sumidero («sink») "
|
||||
"de ensamblaje/sesensamblaje donde el vídeo que se está grabando se graba. "
|
||||
"Generalmente tendrá un origen de ensamblado/desensamblado; la salida de ese "
|
||||
"punto se escibirá en el archivo de salida. No obstante la tubería también "
|
||||
"puede tomar parte en su propia salida; esto se puede usar para enviar la "
|
||||
"salida a un servidor «icecast» a través de shout2send o similar. Cuando no "
|
||||
"está establecido o lo está a un valor vacío, se usará la tubería "
|
||||
"predeterminada. Actualmente es «videorate ! theoraenc ! oggmux» y greba en "
|
||||
"Ogg Theora."
|
||||
"sintaxis usada para gst-launch. La tubería debería tener un sumidero "
|
||||
"(«sink») de ensamblaje/sesensamblaje donde el vídeo que se está grabando se "
|
||||
"graba. Generalmente tendrá un origen de ensamblado/desensamblado; la salida "
|
||||
"de ese punto se escibirá en el archivo de salida. No obstante la tubería "
|
||||
"también puede tomar parte en su propia salida; esto se puede usar para "
|
||||
"enviar la salida a un servidor «icecast» a través de shout2send o similar. "
|
||||
"Cuando no está establecido o lo está a un valor vacío, se usará la tubería "
|
||||
"predeterminada. Actualmente es «videorate ! vp8enc quality=10 speed=2 "
|
||||
"threads=%T ! queue ! webmmux» y greba en WEBM usando el códec VP8. Se usa %T "
|
||||
"como suposición para el número de hilos óptimos en el sistema."
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:12
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:13
|
||||
msgid "Show date in clock"
|
||||
msgstr "Mostrar la fecha en el reloj"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:13
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:14
|
||||
msgid "Show the week date in the calendar"
|
||||
msgstr "Mostrar la fecha de la semana en el calendario"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:14
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:15
|
||||
msgid "Show time with seconds"
|
||||
msgstr "Mostrar la hora con segundos"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:15
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:16
|
||||
msgid ""
|
||||
"The applications corresponding to these identifiers will be displayed in the "
|
||||
"favorites area."
|
||||
@ -118,7 +132,7 @@ msgstr ""
|
||||
"Las aplicaciones correspondientes con esos identificadores se mostrarán en "
|
||||
"el área de favoritos."
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:16
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:17
|
||||
msgid ""
|
||||
"The filename for recorded screencasts will be a unique filename based on the "
|
||||
"current date, and use this extension. It should be changed when recording to "
|
||||
@ -128,7 +142,7 @@ msgstr ""
|
||||
"basado en la fecha actual y usará esta extensión. Se debería cambiar al "
|
||||
"grabar en otro formato contenedor diferente."
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:17
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:18
|
||||
msgid ""
|
||||
"The framerate of the resulting screencast recordered by GNOME Shell's "
|
||||
"screencast recorder in frames-per-second."
|
||||
@ -136,11 +150,11 @@ msgstr ""
|
||||
"La tasa de fotogramas de la grabación resultante grabada por el grabador de "
|
||||
"«screencast» de GNOME Shell, en fotogramas por segundo."
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:18
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:19
|
||||
msgid "The gstreamer pipeline used to encode the screencast"
|
||||
msgstr "La tubería de gstreamer usada para codificar el «screencast»"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:19
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:20
|
||||
msgid ""
|
||||
"The shell normally monitors active applications in order to present the most "
|
||||
"used ones (e.g. in launchers). While this data will be kept private, you may "
|
||||
@ -152,16 +166,16 @@ msgstr ""
|
||||
"mantienen de forma privada, puede querer desactivarlo por razones de "
|
||||
"privacidad. Note que haciéndolo no eliminará los datos ya guardados."
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:20
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:21
|
||||
msgid "Uuids of extensions to disable"
|
||||
msgstr "Uuid de las extensiones que desactivar"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:21
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:22
|
||||
msgid "Whether to collect stats about applications usage"
|
||||
msgstr ""
|
||||
"Indica si se deben recolectar estadísticas acerca del uso de las aplicaciones"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:22
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:23
|
||||
msgid "disabled OpenSearch providers"
|
||||
msgstr "proveedores OpenSearch desactivados"
|
||||
|
||||
@ -482,7 +496,7 @@ msgstr "Ver fuente"
|
||||
msgid "Web Page"
|
||||
msgstr "Página web"
|
||||
|
||||
#: ../js/ui/messageTray.js:1748
|
||||
#: ../js/ui/messageTray.js:1765
|
||||
msgid "System Information"
|
||||
msgstr "Información del sistema"
|
||||
|
||||
@ -499,54 +513,54 @@ msgid "Applications"
|
||||
msgstr "Aplicaciones"
|
||||
|
||||
#. TODO - _quit() doesn't really work on apps in state STARTING yet
|
||||
#: ../js/ui/panel.js:479
|
||||
#: ../js/ui/panel.js:483
|
||||
#, c-format
|
||||
msgid "Quit %s"
|
||||
msgstr "Salir de %s"
|
||||
|
||||
#. Translators: This is the time format with date used
|
||||
#. in 24-hour mode.
|
||||
#: ../js/ui/panel.js:564
|
||||
#: ../js/ui/panel.js:568
|
||||
msgid "%a %b %e, %R:%S"
|
||||
msgstr "%a %e de %b, %R:%S"
|
||||
|
||||
#: ../js/ui/panel.js:565
|
||||
#: ../js/ui/panel.js:569
|
||||
msgid "%a %b %e, %R"
|
||||
msgstr "%a %e de %b, %R"
|
||||
|
||||
#. Translators: This is the time format without date used
|
||||
#. in 24-hour mode.
|
||||
#: ../js/ui/panel.js:569
|
||||
#: ../js/ui/panel.js:573
|
||||
msgid "%a %R:%S"
|
||||
msgstr "%a %R:%S"
|
||||
|
||||
#: ../js/ui/panel.js:570
|
||||
#: ../js/ui/panel.js:574
|
||||
msgid "%a %R"
|
||||
msgstr "%a %R"
|
||||
|
||||
#. Translators: This is a time format with date used
|
||||
#. for AM/PM.
|
||||
#: ../js/ui/panel.js:577
|
||||
#: ../js/ui/panel.js:581
|
||||
msgid "%a %b %e, %l:%M:%S %p"
|
||||
msgstr "%a %e de %b, %H:%M:%S"
|
||||
|
||||
#: ../js/ui/panel.js:578
|
||||
#: ../js/ui/panel.js:582
|
||||
msgid "%a %b %e, %l:%M %p"
|
||||
msgstr "%a %e de %b, %H:%M"
|
||||
|
||||
#. Translators: This is a time format without date used
|
||||
#. for AM/PM.
|
||||
#: ../js/ui/panel.js:582
|
||||
#: ../js/ui/panel.js:586
|
||||
msgid "%a %l:%M:%S %p"
|
||||
msgstr "%a %H:%M:%S"
|
||||
|
||||
#: ../js/ui/panel.js:583
|
||||
#: ../js/ui/panel.js:587
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %H:%M"
|
||||
|
||||
#. 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:728
|
||||
#: ../js/ui/panel.js:732
|
||||
msgid "Activities"
|
||||
msgstr "Actividades"
|
||||
|
||||
@ -701,7 +715,7 @@ msgstr "Error al examinar el dispositivo"
|
||||
msgid "The requested device cannot be browsed, error is '%s'"
|
||||
msgstr "No se puede examinar el dispositivo solicitado, el error es «%s»"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:251 ../js/ui/status/keyboard.js:78
|
||||
#: ../js/ui/status/bluetooth.js:251
|
||||
msgid "Keyboard Settings"
|
||||
msgstr "Configuración del teclado"
|
||||
|
||||
@ -776,6 +790,11 @@ msgstr "Introduzca el PIN mencionado en el dispositivo."
|
||||
msgid "OK"
|
||||
msgstr "Aceptar"
|
||||
|
||||
#: ../js/ui/status/keyboard.js:78
|
||||
#| msgid "Sound Settings"
|
||||
msgid "Localization Settings"
|
||||
msgstr "Configuración regional"
|
||||
|
||||
#: ../js/ui/status/power.js:85
|
||||
msgid "Power Settings"
|
||||
msgstr "Configuración de energía"
|
||||
@ -1015,8 +1034,8 @@ msgstr "%1$s: %2$s"
|
||||
#~ "If true and format is either \"12-hour\" or \"24-hour\", display seconds "
|
||||
#~ "in time."
|
||||
#~ msgstr ""
|
||||
#~ "Si es cierta y el formato es «12-horas» o «24-horas», muestra los segundos "
|
||||
#~ "en la hora."
|
||||
#~ "Si es cierta y el formato es «12-horas» o «24-horas», muestra los "
|
||||
#~ "segundos en la hora."
|
||||
|
||||
#~ msgid ""
|
||||
#~ "This key specifies the format used by the panel clock when the format key "
|
||||
@ -1033,18 +1052,19 @@ msgstr "%1$s: %2$s"
|
||||
#~ msgid ""
|
||||
#~ "This key specifies the hour format used by the panel clock. Possible "
|
||||
#~ "values are \"12-hour\", \"24-hour\", \"unix\" and \"custom\". If set to "
|
||||
#~ "\"unix\", the clock will display time in seconds since Epoch, i.e. 1970-"
|
||||
#~ "01-01. If set to \"custom\", the clock will display time according to the "
|
||||
#~ "format specified in the custom_format key. Note that if set to either "
|
||||
#~ "\"unix\" or \"custom\", the show_date and show_seconds keys are ignored."
|
||||
#~ "\"unix\", the clock will display time in seconds since Epoch, i.e. "
|
||||
#~ "1970-01-01. If set to \"custom\", the clock will display time according "
|
||||
#~ "to the format specified in the custom_format key. Note that if set to "
|
||||
#~ "either \"unix\" or \"custom\", the show_date and show_seconds keys are "
|
||||
#~ "ignored."
|
||||
#~ msgstr ""
|
||||
#~ "Esta clave especifica el formato de la hora especificado por el reloj del "
|
||||
#~ "panel. Los valores posibles son «12-hour» (12 horas), «24-hour» (24 horas), "
|
||||
#~ "«unix» y «custom» (personalizado).Si se establece a «unix» el reloj mostrará "
|
||||
#~ "la hora en segundos desde la época (1 de enero de 1970). Si se establece "
|
||||
#~ "a «custom» el reloj mostrará la hora según el formato especificado en la "
|
||||
#~ "clave «custom_format». Note que si se establece a «unix» o «custom» se "
|
||||
#~ "ignoran las claves «show_date» y «show_seconds»."
|
||||
#~ "panel. Los valores posibles son «12-hour» (12 horas), «24-hour» (24 "
|
||||
#~ "horas), «unix» y «custom» (personalizado).Si se establece a «unix» el "
|
||||
#~ "reloj mostrará la hora en segundos desde la época (1 de enero de 1970). "
|
||||
#~ "Si se establece a «custom» el reloj mostrará la hora según el formato "
|
||||
#~ "especificado en la clave «custom_format». Note que si se establece a "
|
||||
#~ "«unix» o «custom» se ignoran las claves «show_date» y «show_seconds»."
|
||||
|
||||
#~ msgid "Clock Format"
|
||||
#~ msgstr "Formato del reloj"
|
||||
|
87
po/he.po
87
po/he.po
@ -8,8 +8,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell master\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-01-18 13:02+0200\n"
|
||||
"PO-Revision-Date: 2011-01-18 13:05+0200\n"
|
||||
"POT-Creation-Date: 2011-01-23 02:42+0200\n"
|
||||
"PO-Revision-Date: 2011-01-23 02:43+0200\n"
|
||||
"Last-Translator: Yaron Shahrabani <sh.yaron@gmail.com>\n"
|
||||
"Language-Team: Hebrew <he@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@ -73,7 +73,8 @@ msgstr "If true, display the ISO week date in the calendar."
|
||||
msgid "List of desktop file IDs for favorite applications"
|
||||
msgstr "List of desktop file IDs for favorite applications"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:11
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:12
|
||||
#, no-c-format
|
||||
msgid ""
|
||||
"Sets the GStreamer pipeline used to encode recordings. It follows the syntax "
|
||||
"used for gst-launch. The pipeline should have an unconnected sink pad where "
|
||||
@ -82,7 +83,9 @@ msgid ""
|
||||
"pipeline can also take care of its own output - this might be used to send "
|
||||
"the output to an icecast server via shout2send or similar. When unset or set "
|
||||
"to an empty value, the default pipeline will be used. This is currently "
|
||||
"'videorate ! theoraenc ! oggmux' and records to Ogg Theora."
|
||||
"'videorate ! vp8enc quality=10 speed=2 threads=%T ! queue ! webmmux' and "
|
||||
"records to WEBM using the VP8 codec. %T is used as a placeholder for a guess "
|
||||
"at the optimal thread count on the system."
|
||||
msgstr ""
|
||||
"Sets the GStreamer pipeline used to encode recordings. It follows the syntax "
|
||||
"used for gst-launch. The pipeline should have an unconnected sink pad where "
|
||||
@ -91,51 +94,53 @@ msgstr ""
|
||||
"pipeline can also take care of its own output - this might be used to send "
|
||||
"the output to an icecast server via shout2send or similar. When unset or set "
|
||||
"to an empty value, the default pipeline will be used. This is currently "
|
||||
"'videorate ! theoraenc ! oggmux' and records to Ogg Theora."
|
||||
"'videorate ! vp8enc quality=10 speed=2 threads=%T ! queue ! webmmux' and "
|
||||
"records to WEBM using the VP8 codec. %T is used as a placeholder for a guess "
|
||||
"at the optimal thread count on the system."
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:12
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:13
|
||||
msgid "Show date in clock"
|
||||
msgstr "Show date in clock"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:13
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:14
|
||||
msgid "Show the week date in the calendar"
|
||||
msgstr "Show the week date in the calendar"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:14
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:15
|
||||
msgid "Show time with seconds"
|
||||
msgstr "Show time with seconds"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:15
|
||||
msgid ""
|
||||
"The applications corresponding to these identifiers will be displayed in the "
|
||||
"favorites area."
|
||||
msgstr ""
|
||||
"The applications corresponding to these identifiers will be displayed in the "
|
||||
"favorites area."
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:16
|
||||
msgid ""
|
||||
"The filename for recorded screencasts will be a unique filename based on the "
|
||||
"current date, and use this extension. It should be changed when recording to "
|
||||
"a different container format."
|
||||
"The applications corresponding to these identifiers will be displayed in the "
|
||||
"favorites area."
|
||||
msgstr ""
|
||||
"The filename for recorded screencasts will be a unique filename based on the "
|
||||
"current date, and use this extension. It should be changed when recording to "
|
||||
"a different container format."
|
||||
"The applications corresponding to these identifiers will be displayed in the "
|
||||
"favorites area."
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:17
|
||||
msgid ""
|
||||
"The filename for recorded screencasts will be a unique filename based on the "
|
||||
"current date, and use this extension. It should be changed when recording to "
|
||||
"a different container format."
|
||||
msgstr ""
|
||||
"The filename for recorded screencasts will be a unique filename based on the "
|
||||
"current date, and use this extension. It should be changed when recording to "
|
||||
"a different container format."
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:18
|
||||
msgid ""
|
||||
"The framerate of the resulting screencast recordered by GNOME Shell's "
|
||||
"screencast recorder in frames-per-second."
|
||||
msgstr ""
|
||||
"The framerate of the resulting screencast recordered by GNOME Shell's "
|
||||
"screencast recorder in frames-per-second."
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:18
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:19
|
||||
msgid "The gstreamer pipeline used to encode the screencast"
|
||||
msgstr "The gstreamer pipeline used to encode the screencast"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:19
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:20
|
||||
msgid ""
|
||||
"The shell normally monitors active applications in order to present the most "
|
||||
"used ones (e.g. in launchers). While this data will be kept private, you may "
|
||||
@ -147,15 +152,15 @@ msgstr ""
|
||||
"want to disable this for privacy reasons. Please note that doing so won't "
|
||||
"remove already saved data."
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:20
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:21
|
||||
msgid "Uuids of extensions to disable"
|
||||
msgstr "Uuids of extensions to disable"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:21
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:22
|
||||
msgid "Whether to collect stats about applications usage"
|
||||
msgstr "Whether to collect stats about applications usage"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:22
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:23
|
||||
msgid "disabled OpenSearch providers"
|
||||
msgstr "disabled OpenSearch providers"
|
||||
|
||||
@ -471,7 +476,7 @@ msgstr "צפייה במקור"
|
||||
msgid "Web Page"
|
||||
msgstr "דף אינטרנט"
|
||||
|
||||
#: ../js/ui/messageTray.js:1748
|
||||
#: ../js/ui/messageTray.js:1765
|
||||
msgid "System Information"
|
||||
msgstr "פרטי המערכת"
|
||||
|
||||
@ -488,54 +493,54 @@ msgid "Applications"
|
||||
msgstr "יישומים"
|
||||
|
||||
#. TODO - _quit() doesn't really work on apps in state STARTING yet
|
||||
#: ../js/ui/panel.js:479
|
||||
#: ../js/ui/panel.js:483
|
||||
#, c-format
|
||||
msgid "Quit %s"
|
||||
msgstr "יציאה מ־%s"
|
||||
|
||||
#. Translators: This is the time format with date used
|
||||
#. in 24-hour mode.
|
||||
#: ../js/ui/panel.js:564
|
||||
#: ../js/ui/panel.js:568
|
||||
msgid "%a %b %e, %R:%S"
|
||||
msgstr "%a %b %e, %R:%S"
|
||||
|
||||
#: ../js/ui/panel.js:565
|
||||
#: ../js/ui/panel.js:569
|
||||
msgid "%a %b %e, %R"
|
||||
msgstr "%a %b %e, %R"
|
||||
|
||||
#. Translators: This is the time format without date used
|
||||
#. in 24-hour mode.
|
||||
#: ../js/ui/panel.js:569
|
||||
#: ../js/ui/panel.js:573
|
||||
msgid "%a %R:%S"
|
||||
msgstr "%a %R:%S"
|
||||
|
||||
#: ../js/ui/panel.js:570
|
||||
#: ../js/ui/panel.js:574
|
||||
msgid "%a %R"
|
||||
msgstr "%a %R"
|
||||
|
||||
#. Translators: This is a time format with date used
|
||||
#. for AM/PM.
|
||||
#: ../js/ui/panel.js:577
|
||||
#: ../js/ui/panel.js:581
|
||||
msgid "%a %b %e, %l:%M:%S %p"
|
||||
msgstr "%a %b %e, %l:%M:%S %p"
|
||||
|
||||
#: ../js/ui/panel.js:578
|
||||
#: ../js/ui/panel.js:582
|
||||
msgid "%a %b %e, %l:%M %p"
|
||||
msgstr "%a %b %e, %l:%M %p"
|
||||
|
||||
#. Translators: This is a time format without date used
|
||||
#. for AM/PM.
|
||||
#: ../js/ui/panel.js:582
|
||||
#: ../js/ui/panel.js:586
|
||||
msgid "%a %l:%M:%S %p"
|
||||
msgstr "%a %l:%M:%S %p"
|
||||
|
||||
#: ../js/ui/panel.js:583
|
||||
#: ../js/ui/panel.js:587
|
||||
msgid "%a %l:%M %p"
|
||||
msgstr "%a %l:%M %p"
|
||||
|
||||
#. 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:728
|
||||
#: ../js/ui/panel.js:732
|
||||
msgid "Activities"
|
||||
msgstr "פעילויות"
|
||||
|
||||
@ -690,7 +695,7 @@ msgstr "שגיאה בעיון בהתקן"
|
||||
msgid "The requested device cannot be browsed, error is '%s'"
|
||||
msgstr "לא ניתן לעיין בהתקן הנבחר, השגיאה היא '%s'"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:251 ../js/ui/status/keyboard.js:78
|
||||
#: ../js/ui/status/bluetooth.js:251
|
||||
msgid "Keyboard Settings"
|
||||
msgstr "הגדרות מקלדת"
|
||||
|
||||
@ -765,6 +770,10 @@ msgstr "נא להזין את קוד ה־PIN המוזכר בהתקן."
|
||||
msgid "OK"
|
||||
msgstr "אישור"
|
||||
|
||||
#: ../js/ui/status/keyboard.js:78
|
||||
msgid "Localization Settings"
|
||||
msgstr "הגדרות אוזריות"
|
||||
|
||||
#: ../js/ui/status/power.js:85
|
||||
msgid "Power Settings"
|
||||
msgstr "הגדרות צריכת החשמל"
|
||||
|
102
po/it.po
102
po/it.po
@ -8,14 +8,14 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnome-shell\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2011-01-15 01:10+0100\n"
|
||||
"POT-Creation-Date: 2011-01-21 01:16+0100\n"
|
||||
"PO-Revision-Date: 2011-01-15 01:19+0100\n"
|
||||
"Last-Translator: Luca Ferretti <lferrett@gnome.org>\n"
|
||||
"Language-Team: Italian <tp@lists.linux.it>\n"
|
||||
"Language: it\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Language: it\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: ../data/gnome-shell.desktop.in.in.h:1
|
||||
@ -161,6 +161,10 @@ msgid "Whether to collect stats about applications usage"
|
||||
msgstr ""
|
||||
"Indica se raccogliere statistiche riguardo l'utilizzo delle applicazioni"
|
||||
|
||||
#: ../data/org.gnome.shell.gschema.xml.in.h:22
|
||||
msgid "disabled OpenSearch providers"
|
||||
msgstr ""
|
||||
|
||||
#: ../data/org.gnome.accessibility.magnifier.gschema.xml.in.h:1
|
||||
msgid "Clip the crosshairs at the center"
|
||||
msgstr ""
|
||||
@ -296,7 +300,7 @@ msgstr "Impossibile analizzare il comando:"
|
||||
msgid "No such application"
|
||||
msgstr "Applicazione inesistente"
|
||||
|
||||
#: ../js/misc/util.js:143 ../js/ui/runDialog.js:364
|
||||
#: ../js/misc/util.js:143 ../js/ui/runDialog.js:351
|
||||
#, c-format
|
||||
msgid "Execution of '%s' failed:"
|
||||
msgstr "Esecuzione di «%s» non riuscita:"
|
||||
@ -344,7 +348,7 @@ msgstr "Rimuovi"
|
||||
|
||||
#: ../js/ui/docDisplay.js:18
|
||||
msgid "RECENT ITEMS"
|
||||
msgstr "Elementi recenti"
|
||||
msgstr "ELEMENTI RECENTI"
|
||||
|
||||
#: ../js/ui/endSessionDialog.js:63
|
||||
#, c-format
|
||||
@ -358,7 +362,9 @@ msgstr "Termina sessione"
|
||||
# oddio... abbandonare il sistema sembra la nave che affonda... (LF)
|
||||
#: ../js/ui/endSessionDialog.js:65
|
||||
msgid "Click Log Out to quit these applications and log out of the system."
|
||||
msgstr "Fare clic su «Termina sessione» per chiudere queste applicazioni e abbandonare il sistema."
|
||||
msgstr ""
|
||||
"Fare clic su «Termina sessione» per chiudere queste applicazioni e "
|
||||
"abbandonare il sistema."
|
||||
|
||||
#: ../js/ui/endSessionDialog.js:66
|
||||
#, c-format
|
||||
@ -381,7 +387,9 @@ msgstr "Arresta"
|
||||
# usato un termine diverso, magari si capisce meglio (LF)
|
||||
#: ../js/ui/endSessionDialog.js:75
|
||||
msgid "Click Shut Down to quit these applications and shut down the system."
|
||||
msgstr "Fare clic su «Arresta» per chiudere queste applicazioni e spegnere il sistema."
|
||||
msgstr ""
|
||||
"Fare clic su «Arresta» per chiudere queste applicazioni e spegnere il "
|
||||
"sistema."
|
||||
|
||||
#: ../js/ui/endSessionDialog.js:76
|
||||
#, c-format
|
||||
@ -398,7 +406,9 @@ msgstr "Riavvia"
|
||||
|
||||
#: ../js/ui/endSessionDialog.js:85
|
||||
msgid "Click Restart to quit these applications and restart the system."
|
||||
msgstr "Fare clic su «Riavvia» per chiudere queste applicazioni e riavviare il sistema."
|
||||
msgstr ""
|
||||
"Fare clic su «Riavvia» per chiudere queste applicazioni e riavviare il "
|
||||
"sistema."
|
||||
|
||||
#: ../js/ui/endSessionDialog.js:86
|
||||
#, c-format
|
||||
@ -413,7 +423,7 @@ msgstr "Riavvio del sistema."
|
||||
msgid "Confirm"
|
||||
msgstr "Conferma"
|
||||
|
||||
#: ../js/ui/endSessionDialog.js:400 ../js/ui/status/bluetooth.js:469
|
||||
#: ../js/ui/endSessionDialog.js:400 ../js/ui/status/bluetooth.js:470
|
||||
msgid "Cancel"
|
||||
msgstr "Annulla"
|
||||
|
||||
@ -449,7 +459,7 @@ msgstr "Visualizza sorgente"
|
||||
msgid "Web Page"
|
||||
msgstr "Pagina web"
|
||||
|
||||
#: ../js/ui/messageTray.js:1748
|
||||
#: ../js/ui/messageTray.js:1765
|
||||
msgid "System Information"
|
||||
msgstr "Informazione di sistema"
|
||||
|
||||
@ -519,22 +529,22 @@ msgid "Activities"
|
||||
msgstr "Attività"
|
||||
|
||||
# (ndt) libera, ma unmount non si può proprio vedere...
|
||||
#: ../js/ui/placeDisplay.js:112
|
||||
#: ../js/ui/placeDisplay.js:106
|
||||
#, c-format
|
||||
msgid "Failed to unmount '%s'"
|
||||
msgstr "Impossibile scollegare «%s»"
|
||||
|
||||
#: ../js/ui/placeDisplay.js:115
|
||||
#: ../js/ui/placeDisplay.js:109
|
||||
msgid "Retry"
|
||||
msgstr "Riprova"
|
||||
|
||||
#: ../js/ui/placeDisplay.js:160
|
||||
#: ../js/ui/placeDisplay.js:150
|
||||
msgid "Connect to..."
|
||||
msgstr "Connetti a..."
|
||||
|
||||
#: ../js/ui/placeDisplay.js:559
|
||||
#: ../js/ui/placeDisplay.js:386
|
||||
msgid "PLACES & DEVICES"
|
||||
msgstr "Risorse e dispositivi"
|
||||
msgstr "RISORSE E DISPOSITIVI"
|
||||
|
||||
#. Translators: this MUST be either "toggle-switch-us"
|
||||
#. (for toggle switches containing the English words
|
||||
@ -545,7 +555,7 @@ msgstr "Risorse e dispositivi"
|
||||
msgid "toggle-switch-us"
|
||||
msgstr "toggle-switch-intl"
|
||||
|
||||
#: ../js/ui/runDialog.js:222
|
||||
#: ../js/ui/runDialog.js:209
|
||||
msgid "Please enter a command:"
|
||||
msgstr "Inserire un comando:"
|
||||
|
||||
@ -629,7 +639,7 @@ msgstr "Contrasto elevato"
|
||||
msgid "Large Text"
|
||||
msgstr "Caratteri grandi"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:42 ../js/ui/status/bluetooth.js:240
|
||||
#: ../js/ui/status/bluetooth.js:42 ../js/ui/status/bluetooth.js:241
|
||||
msgid "Bluetooth"
|
||||
msgstr "Bluetooth"
|
||||
|
||||
@ -646,105 +656,105 @@ msgstr "Invia file al dispositivo..."
|
||||
msgid "Setup a New Device..."
|
||||
msgstr "Imposta un nuovo dispositivo..."
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:94
|
||||
#: ../js/ui/status/bluetooth.js:95
|
||||
msgid "Bluetooth Settings"
|
||||
msgstr "Impostazioni Bluetooth"
|
||||
|
||||
# indica lo stato del device BT, per esempio gli auricolari
|
||||
# credo sia meglio l'aggettivo che il sostantivo
|
||||
#: ../js/ui/status/bluetooth.js:191
|
||||
#: ../js/ui/status/bluetooth.js:192
|
||||
msgid "Connection"
|
||||
msgstr "Collegato"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:227
|
||||
#: ../js/ui/status/bluetooth.js:228
|
||||
msgid "Send Files..."
|
||||
msgstr "Invia file..."
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:232
|
||||
#: ../js/ui/status/bluetooth.js:233
|
||||
msgid "Browse Files..."
|
||||
msgstr "Esplora file..."
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:241
|
||||
#: ../js/ui/status/bluetooth.js:242
|
||||
msgid "Error browsing device"
|
||||
msgstr "Errore nell'esplorare il dispositivo"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:242
|
||||
#: ../js/ui/status/bluetooth.js:243
|
||||
#, c-format
|
||||
msgid "The requested device cannot be browsed, error is '%s'"
|
||||
msgstr "Non è possibile esplorare il dispositivo richiesto, l'errore è «%s»"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:250 ../js/ui/status/keyboard.js:78
|
||||
#: ../js/ui/status/bluetooth.js:251 ../js/ui/status/keyboard.js:78
|
||||
msgid "Keyboard Settings"
|
||||
msgstr "Impostazioni tastiera"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:255
|
||||
#: ../js/ui/status/bluetooth.js:256
|
||||
msgid "Mouse Settings"
|
||||
msgstr "Impostazioni mouse"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:262 ../js/ui/status/volume.js:63
|
||||
#: ../js/ui/status/bluetooth.js:263 ../js/ui/status/volume.js:63
|
||||
msgid "Sound Settings"
|
||||
msgstr "Impostazioni audio"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:336 ../js/ui/status/bluetooth.js:370
|
||||
#: ../js/ui/status/bluetooth.js:410 ../js/ui/status/bluetooth.js:443
|
||||
#: ../js/ui/status/bluetooth.js:337 ../js/ui/status/bluetooth.js:371
|
||||
#: ../js/ui/status/bluetooth.js:411 ../js/ui/status/bluetooth.js:444
|
||||
msgid "Bluetooth Agent"
|
||||
msgstr ""
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:371
|
||||
#: ../js/ui/status/bluetooth.js:372
|
||||
#, c-format
|
||||
msgid "Authorization request from %s"
|
||||
msgstr "Richesta autorizzazione da %s"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:377
|
||||
#: ../js/ui/status/bluetooth.js:378
|
||||
#, c-format
|
||||
msgid "Device %s wants access to the service '%s'"
|
||||
msgstr "Il dispositivo %s vuole accedere al servizio «%s»"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:379
|
||||
#: ../js/ui/status/bluetooth.js:380
|
||||
msgid "Always grant access"
|
||||
msgstr "Consenti sempre accesso"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:380
|
||||
#: ../js/ui/status/bluetooth.js:381
|
||||
msgid "Grant this time only"
|
||||
msgstr "Consenti solo stavolta"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:381
|
||||
#: ../js/ui/status/bluetooth.js:382
|
||||
msgid "Reject"
|
||||
msgstr "Rifiuta"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:411
|
||||
#: ../js/ui/status/bluetooth.js:412
|
||||
#, c-format
|
||||
msgid "Pairing confirmation for %s"
|
||||
msgstr "Conferma associazione per %s"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:417 ../js/ui/status/bluetooth.js:451
|
||||
#: ../js/ui/status/bluetooth.js:418 ../js/ui/status/bluetooth.js:452
|
||||
#, c-format
|
||||
msgid "Device %s wants to pair with this computer"
|
||||
msgstr "Il dispositivo %s vuole associarsi con questo computer"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:418
|
||||
#: ../js/ui/status/bluetooth.js:419
|
||||
#, c-format
|
||||
msgid "Please confirm whether the PIN '%s' matches the one on the device."
|
||||
msgstr "Confermare la corrispondenza del PIN «%s» con quello sul dispositivo."
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:420
|
||||
#: ../js/ui/status/bluetooth.js:421
|
||||
msgid "Matches"
|
||||
msgstr "Corrisponde"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:421
|
||||
#: ../js/ui/status/bluetooth.js:422
|
||||
msgid "Does not match"
|
||||
msgstr "Non corrisponde"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:444
|
||||
#: ../js/ui/status/bluetooth.js:445
|
||||
#, c-format
|
||||
msgid "Pairing request for %s"
|
||||
msgstr "Richiesta associazione per %s"
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:452
|
||||
#: ../js/ui/status/bluetooth.js:453
|
||||
msgid "Please enter the PIN mentioned on the device."
|
||||
msgstr "Inserire il PIN indicato sul dispositivo."
|
||||
|
||||
#: ../js/ui/status/bluetooth.js:468
|
||||
#: ../js/ui/status/bluetooth.js:469
|
||||
msgid "OK"
|
||||
msgstr "OK"
|
||||
|
||||
@ -867,7 +877,7 @@ msgstr "%s non è disponibile."
|
||||
#: ../js/ui/telepathyClient.js:666
|
||||
#, no-c-format
|
||||
msgid "Sent at %X on %A"
|
||||
msgstr "Inviato alle %-H.%M.%S di %A"
|
||||
msgstr "Inviato alle %-H.%M di %A"
|
||||
|
||||
# FIXME ma ha senso in inglese???
|
||||
#: ../js/ui/viewSelector.js:26
|
||||
@ -919,32 +929,32 @@ msgstr[1] "%u ingressi"
|
||||
msgid "System Sounds"
|
||||
msgstr "Audio di sistema"
|
||||
|
||||
#: ../src/shell-global.c:1233
|
||||
#: ../src/shell-global.c:1366
|
||||
msgid "Less than a minute ago"
|
||||
msgstr "Meno di un minuto fa"
|
||||
|
||||
#: ../src/shell-global.c:1237
|
||||
#: ../src/shell-global.c:1370
|
||||
#, c-format
|
||||
msgid "%d minute ago"
|
||||
msgid_plural "%d minutes ago"
|
||||
msgstr[0] "%d minuto fa"
|
||||
msgstr[1] "%d minuti fa"
|
||||
|
||||
#: ../src/shell-global.c:1242
|
||||
#: ../src/shell-global.c:1375
|
||||
#, c-format
|
||||
msgid "%d hour ago"
|
||||
msgid_plural "%d hours ago"
|
||||
msgstr[0] "%d ora fa"
|
||||
msgstr[1] "%d ore fa"
|
||||
|
||||
#: ../src/shell-global.c:1247
|
||||
#: ../src/shell-global.c:1380
|
||||
#, c-format
|
||||
msgid "%d day ago"
|
||||
msgid_plural "%d days ago"
|
||||
msgstr[0] "%d giorno fa"
|
||||
msgstr[1] "%d giorni fa"
|
||||
|
||||
#: ../src/shell-global.c:1252
|
||||
#: ../src/shell-global.c:1385
|
||||
#, c-format
|
||||
msgid "%d week ago"
|
||||
msgid_plural "%d weeks ago"
|
||||
|
@ -159,11 +159,17 @@ st_source_c = \
|
||||
st/st-widget.c \
|
||||
$(NULL)
|
||||
|
||||
st_non_gir_sources = \
|
||||
st/st-scroll-view-fade.c \
|
||||
st/st-scroll-view-fade.h \
|
||||
$(NULL)
|
||||
|
||||
noinst_LTLIBRARIES += libst-1.0.la
|
||||
|
||||
libst_1_0_la_LIBADD = -lm $(ST_LIBS)
|
||||
libst_1_0_la_SOURCES = \
|
||||
$(st_source_c) \
|
||||
$(st_source_c) \
|
||||
$(st_non_gir_sources) \
|
||||
$(st_source_private_h) \
|
||||
$(st_source_private_c) \
|
||||
$(st_source_h) \
|
||||
|
@ -262,7 +262,7 @@ St-1.0.gir: $(mutter) $(G_IR_SCANNER) libst-1.0.la Makefile
|
||||
--libtool="$(LIBTOOL)" \
|
||||
--library=libst-1.0.la \
|
||||
-DST_COMPILATION \
|
||||
$(filter-out %-private.h, $(addprefix $(srcdir)/,$(st_source_h))) \
|
||||
$(filter-out %-private.h $(st_non_gir_sources), $(addprefix $(srcdir)/,$(st_source_h))) \
|
||||
$(addprefix $(srcdir)/,$(st_source_c)) \
|
||||
$(srcdir)/st-enum-types.h \
|
||||
$(st_cflags) \
|
||||
|
@ -1020,13 +1020,10 @@ on_get_unix_user_finished (DBusGProxy *proxy,
|
||||
DBusGProxyCall *call,
|
||||
GdmUserManagerNewSession *new_session)
|
||||
{
|
||||
GdmUserManager *manager;
|
||||
GError *error;
|
||||
guint uid;
|
||||
gboolean res;
|
||||
|
||||
manager = new_session->manager;
|
||||
|
||||
g_assert (new_session->get_unix_user_call == call);
|
||||
|
||||
error = NULL;
|
||||
@ -1550,11 +1547,9 @@ static void
|
||||
get_accounts_proxy (GdmUserManager *manager)
|
||||
{
|
||||
DBusGProxy *proxy;
|
||||
GError *error;
|
||||
|
||||
g_assert (manager->priv->accounts_proxy == NULL);
|
||||
|
||||
error = NULL;
|
||||
proxy = dbus_g_proxy_new_for_name (manager->priv->connection,
|
||||
ACCOUNTS_NAME,
|
||||
ACCOUNTS_PATH,
|
||||
@ -2554,8 +2549,6 @@ reload_shells (GdmUserManager *manager)
|
||||
static void
|
||||
load_users_manually (GdmUserManager *manager)
|
||||
{
|
||||
gboolean res;
|
||||
|
||||
manager->priv->shells = g_hash_table_new_full (g_str_hash,
|
||||
g_str_equal,
|
||||
g_free,
|
||||
@ -2564,7 +2557,7 @@ load_users_manually (GdmUserManager *manager)
|
||||
|
||||
load_sessions (manager);
|
||||
|
||||
res = load_ck_history (manager);
|
||||
load_ck_history (manager);
|
||||
schedule_reload_passwd (manager);
|
||||
}
|
||||
|
||||
@ -2605,10 +2598,8 @@ load_seat_incrementally (GdmUserManager *manager)
|
||||
}
|
||||
|
||||
if (manager->priv->seat.state == GDM_USER_MANAGER_SEAT_STATE_LOADED) {
|
||||
gboolean res;
|
||||
|
||||
load_sessions (manager);
|
||||
res = load_ck_history (manager);
|
||||
load_ck_history (manager);
|
||||
}
|
||||
|
||||
maybe_set_is_loaded (manager);
|
||||
|
@ -151,10 +151,6 @@ gdm_user_set_property (GObject *object,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GdmUser *user;
|
||||
|
||||
user = GDM_USER (object);
|
||||
|
||||
switch (prop_id) {
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
|
@ -59,13 +59,10 @@ update_settings (GvcMixerEventRole *role,
|
||||
gpointer *op)
|
||||
{
|
||||
pa_operation *o;
|
||||
guint index;
|
||||
const GvcChannelMap *map;
|
||||
pa_context *context;
|
||||
pa_ext_stream_restore_info info;
|
||||
|
||||
index = gvc_mixer_stream_get_index (GVC_MIXER_STREAM (role));
|
||||
|
||||
map = gvc_mixer_stream_get_channel_map (GVC_MIXER_STREAM(role));
|
||||
|
||||
info.volume = *gvc_channel_map_get_cvolume(map);
|
||||
@ -165,12 +162,9 @@ gvc_mixer_event_role_constructor (GType type,
|
||||
GObjectConstructParam *construct_params)
|
||||
{
|
||||
GObject *object;
|
||||
GvcMixerEventRole *self;
|
||||
|
||||
object = G_OBJECT_CLASS (gvc_mixer_event_role_parent_class)->constructor (type, n_construct_properties, construct_params);
|
||||
|
||||
self = GVC_MIXER_EVENT_ROLE (object);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
|
@ -55,12 +55,10 @@ gvc_mixer_sink_input_push_volume (GvcMixerStream *stream, gpointer *op)
|
||||
const GvcChannelMap *map;
|
||||
pa_context *context;
|
||||
const pa_cvolume *cv;
|
||||
guint num_channels;
|
||||
|
||||
index = gvc_mixer_stream_get_index (stream);
|
||||
|
||||
map = gvc_mixer_stream_get_channel_map (stream);
|
||||
num_channels = gvc_channel_map_get_num_channels (map);
|
||||
|
||||
cv = gvc_channel_map_get_cvolume(map);
|
||||
|
||||
@ -115,12 +113,9 @@ gvc_mixer_sink_input_constructor (GType type,
|
||||
GObjectConstructParam *construct_params)
|
||||
{
|
||||
GObject *object;
|
||||
GvcMixerSinkInput *self;
|
||||
|
||||
object = G_OBJECT_CLASS (gvc_mixer_sink_input_parent_class)->constructor (type, n_construct_properties, construct_params);
|
||||
|
||||
self = GVC_MIXER_SINK_INPUT (object);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
@ -149,13 +144,9 @@ gvc_mixer_sink_input_init (GvcMixerSinkInput *sink_input)
|
||||
static void
|
||||
gvc_mixer_sink_input_dispose (GObject *object)
|
||||
{
|
||||
GvcMixerSinkInput *mixer_sink_input;
|
||||
|
||||
g_return_if_fail (object != NULL);
|
||||
g_return_if_fail (GVC_IS_MIXER_SINK_INPUT (object));
|
||||
|
||||
mixer_sink_input = GVC_MIXER_SINK_INPUT (object);
|
||||
|
||||
G_OBJECT_CLASS (gvc_mixer_sink_input_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
|
@ -145,12 +145,9 @@ gvc_mixer_sink_constructor (GType type,
|
||||
GObjectConstructParam *construct_params)
|
||||
{
|
||||
GObject *object;
|
||||
GvcMixerSink *self;
|
||||
|
||||
object = G_OBJECT_CLASS (gvc_mixer_sink_parent_class)->constructor (type, n_construct_properties, construct_params);
|
||||
|
||||
self = GVC_MIXER_SINK (object);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
@ -180,13 +177,9 @@ gvc_mixer_sink_init (GvcMixerSink *sink)
|
||||
static void
|
||||
gvc_mixer_sink_dispose (GObject *object)
|
||||
{
|
||||
GvcMixerSink *mixer_sink;
|
||||
|
||||
g_return_if_fail (object != NULL);
|
||||
g_return_if_fail (GVC_IS_MIXER_SINK (object));
|
||||
|
||||
mixer_sink = GVC_MIXER_SINK (object);
|
||||
|
||||
G_OBJECT_CLASS (gvc_mixer_sink_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
|
@ -66,12 +66,9 @@ gvc_mixer_source_output_constructor (GType type,
|
||||
GObjectConstructParam *construct_params)
|
||||
{
|
||||
GObject *object;
|
||||
GvcMixerSourceOutput *self;
|
||||
|
||||
object = G_OBJECT_CLASS (gvc_mixer_source_output_parent_class)->constructor (type, n_construct_properties, construct_params);
|
||||
|
||||
self = GVC_MIXER_SOURCE_OUTPUT (object);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
|
@ -145,12 +145,9 @@ gvc_mixer_source_constructor (GType type,
|
||||
GObjectConstructParam *construct_params)
|
||||
{
|
||||
GObject *object;
|
||||
GvcMixerSource *self;
|
||||
|
||||
object = G_OBJECT_CLASS (gvc_mixer_source_parent_class)->constructor (type, n_construct_properties, construct_params);
|
||||
|
||||
self = GVC_MIXER_SOURCE (object);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
@ -180,13 +177,9 @@ gvc_mixer_source_init (GvcMixerSource *source)
|
||||
static void
|
||||
gvc_mixer_source_dispose (GObject *object)
|
||||
{
|
||||
GvcMixerSource *mixer_source;
|
||||
|
||||
g_return_if_fail (object != NULL);
|
||||
g_return_if_fail (GVC_IS_MIXER_SOURCE (object));
|
||||
|
||||
mixer_source = GVC_MIXER_SOURCE (object);
|
||||
|
||||
G_OBJECT_CLASS (gvc_mixer_source_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
|
@ -1317,7 +1317,6 @@ shell_app_info_launch_full (ShellAppInfo *info,
|
||||
gboolean ret;
|
||||
ShellGlobal *global;
|
||||
MetaScreen *screen;
|
||||
MetaDisplay *display;
|
||||
|
||||
if (startup_id)
|
||||
*startup_id = NULL;
|
||||
@ -1353,7 +1352,6 @@ shell_app_info_launch_full (ShellAppInfo *info,
|
||||
|
||||
global = shell_global_get ();
|
||||
screen = shell_global_get_screen (global);
|
||||
display = meta_screen_get_display (screen);
|
||||
|
||||
if (timestamp == 0)
|
||||
timestamp = clutter_get_current_event_time ();
|
||||
|
@ -324,7 +324,8 @@ on_app_state_changed (ShellWindowTracker *tracker,
|
||||
|
||||
running = shell_app_get_state (app) == SHELL_APP_STATE_RUNNING;
|
||||
|
||||
usage->last_seen = get_time ();
|
||||
if (running)
|
||||
usage->last_seen = get_time ();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -285,7 +285,8 @@ shell_doc_system_open (ShellDocSystem *system,
|
||||
app_exec_quoted = g_regex_replace (regex, app_exec, -1, 0, "%%", 0, NULL);
|
||||
g_regex_unref (regex);
|
||||
|
||||
app_info = g_app_info_create_from_commandline (app_exec, NULL, 0, NULL);
|
||||
app_info = g_app_info_create_from_commandline (app_exec_quoted, NULL, 0, NULL);
|
||||
g_free (app_exec_quoted);
|
||||
|
||||
/* The point of passing an app launch context to
|
||||
launch() is mostly to get startup notification and
|
||||
|
@ -885,7 +885,6 @@ shell_global_add_extension_importer (ShellGlobal *global,
|
||||
GError **error)
|
||||
{
|
||||
jsval target_object;
|
||||
JSObject *importer;
|
||||
JSContext *context = gjs_context_get_native_context (global->js_context);
|
||||
char *search_path[2] = { 0, 0 };
|
||||
|
||||
@ -920,7 +919,7 @@ shell_global_add_extension_importer (ShellGlobal *global,
|
||||
}
|
||||
|
||||
search_path[0] = (char*)directory;
|
||||
importer = gjs_define_importer (context, JSVAL_TO_OBJECT (target_object), target_property, (const char **)search_path, FALSE);
|
||||
gjs_define_importer (context, JSVAL_TO_OBJECT (target_object), target_property, (const char **)search_path, FALSE);
|
||||
JS_EndRequest (context);
|
||||
return TRUE;
|
||||
out_error:
|
||||
|
@ -83,6 +83,7 @@ struct _ShellRecorder {
|
||||
guint redraw_idle;
|
||||
guint update_memory_used_timeout;
|
||||
guint update_pointer_timeout;
|
||||
guint repaint_hook_id;
|
||||
};
|
||||
|
||||
struct _RecorderPipeline
|
||||
@ -146,11 +147,11 @@ G_DEFINE_TYPE(ShellRecorder, shell_recorder, G_TYPE_OBJECT);
|
||||
* (Theora does have some support for frames at non-uniform times, but
|
||||
* things seem to break down if there are large gaps.)
|
||||
*/
|
||||
#define DEFAULT_PIPELINE "videorate ! theoraenc ! oggmux"
|
||||
#define DEFAULT_PIPELINE "videorate ! vp8enc quality=10 speed=2 threads=%T ! queue ! webmmux"
|
||||
|
||||
/* The default filename pattern. Example shell-20090311b-2.ogg
|
||||
/* The default filename pattern. Example shell-20090311b-2.webm
|
||||
*/
|
||||
#define DEFAULT_FILENAME "shell-%d%u-%c.ogg"
|
||||
#define DEFAULT_FILENAME "shell-%d%u-%c.webm"
|
||||
|
||||
/* If we can find the amount of memory on the machine, we use half
|
||||
* of that for memory_target, otherwise, we use this value, in kB.
|
||||
@ -239,6 +240,22 @@ get_memory_target (void)
|
||||
return DEFAULT_MEMORY_TARGET;
|
||||
}
|
||||
|
||||
/*
|
||||
* Used to force full stage redraws during recording to avoid artifacts
|
||||
*
|
||||
* Note: That this will cause the stage to be repainted on
|
||||
* every animation frame even if the frame wouldn't normally cause any new
|
||||
* drawing
|
||||
*/
|
||||
static gboolean
|
||||
recorder_repaint_hook (gpointer data)
|
||||
{
|
||||
ClutterActor *stage = data;
|
||||
clutter_actor_queue_redraw (stage);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
shell_recorder_init (ShellRecorder *recorder)
|
||||
{
|
||||
@ -1476,11 +1493,47 @@ recorder_pipeline_closed (RecorderPipeline *pipeline)
|
||||
recorder_pipeline_free (pipeline);
|
||||
}
|
||||
|
||||
/*
|
||||
* Replaces '%T' in the passed pipeline with the thread count,
|
||||
* the maximum possible value is 64 (limit of what vp8enc supports)
|
||||
*
|
||||
* It is assumes that %T occurs only once.
|
||||
*/
|
||||
static char*
|
||||
substitute_thread_count (const char *pipeline)
|
||||
{
|
||||
char *tmp;
|
||||
int n_threads;
|
||||
GString *result;
|
||||
|
||||
tmp = strstr (pipeline, "%T");
|
||||
|
||||
if (!tmp)
|
||||
return g_strdup (pipeline);
|
||||
|
||||
#ifdef _SC_NPROCESSORS_ONLN
|
||||
{
|
||||
int n_processors = sysconf (_SC_NPROCESSORS_ONLN); /* includes hyper-threading */
|
||||
n_threads = MIN (MAX (1, n_processors - 1), 64);
|
||||
}
|
||||
#else
|
||||
n_threads = 3;
|
||||
#endif
|
||||
|
||||
result = g_string_new (NULL);
|
||||
g_string_append_len (result, pipeline, tmp - pipeline);
|
||||
g_string_append_printf (result, "%d", n_threads);
|
||||
g_string_append (result, tmp + 2);
|
||||
|
||||
return g_string_free (result, FALSE);;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
recorder_open_pipeline (ShellRecorder *recorder)
|
||||
{
|
||||
RecorderPipeline *pipeline;
|
||||
const char *pipeline_description;
|
||||
char *parsed_pipeline;
|
||||
GError *error = NULL;
|
||||
GstBus *bus;
|
||||
|
||||
@ -1492,9 +1545,12 @@ recorder_open_pipeline (ShellRecorder *recorder)
|
||||
if (!pipeline_description)
|
||||
pipeline_description = DEFAULT_PIPELINE;
|
||||
|
||||
pipeline->pipeline = gst_parse_launch_full (pipeline_description, NULL,
|
||||
parsed_pipeline = substitute_thread_count (pipeline_description);
|
||||
|
||||
pipeline->pipeline = gst_parse_launch_full (parsed_pipeline, NULL,
|
||||
GST_PARSE_FLAG_FATAL_ERRORS,
|
||||
&error);
|
||||
g_free (parsed_pipeline);
|
||||
|
||||
if (pipeline->pipeline == NULL)
|
||||
{
|
||||
@ -1682,6 +1738,9 @@ shell_recorder_record (ShellRecorder *recorder)
|
||||
recorder->state = RECORDER_STATE_RECORDING;
|
||||
recorder_add_update_pointer_timeout (recorder);
|
||||
|
||||
/* Set up repaint hook */
|
||||
recorder->repaint_hook_id = clutter_threads_add_repaint_func(recorder_repaint_hook, recorder->stage, NULL);
|
||||
|
||||
/* Record an initial frame and also redraw with the indicator */
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (recorder->stage));
|
||||
|
||||
@ -1723,6 +1782,12 @@ shell_recorder_pause (ShellRecorder *recorder)
|
||||
|
||||
/* Queue a redraw to remove the recording indicator */
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (recorder->stage));
|
||||
|
||||
if (recorder->repaint_hook_id != 0)
|
||||
{
|
||||
clutter_threads_remove_repaint_func (recorder->repaint_hook_id);
|
||||
recorder->repaint_hook_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -825,12 +825,9 @@ on_focus_window_changed (MetaDisplay *display,
|
||||
GParamSpec *spec,
|
||||
ShellWindowTracker *tracker)
|
||||
{
|
||||
MetaScreen *screen;
|
||||
MetaWindow *new_focus_win;
|
||||
ShellApp *new_focus_app;
|
||||
|
||||
screen = shell_global_get_screen (shell_global_get ());
|
||||
|
||||
new_focus_win = meta_display_get_focus_window (display);
|
||||
new_focus_app = new_focus_win ? g_hash_table_lookup (tracker->window_to_app, new_focus_win) : NULL;
|
||||
|
||||
|
@ -62,6 +62,7 @@ struct _StIconPrivate
|
||||
CoglHandle shadow_material;
|
||||
float shadow_width;
|
||||
float shadow_height;
|
||||
StShadow *shadow_spec;
|
||||
};
|
||||
|
||||
static void st_icon_update (StIcon *icon);
|
||||
@ -164,6 +165,12 @@ st_icon_dispose (GObject *gobject)
|
||||
priv->shadow_material = COGL_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (priv->shadow_spec)
|
||||
{
|
||||
st_shadow_unref (priv->shadow_spec);
|
||||
priv->shadow_spec = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (st_icon_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
@ -249,8 +256,6 @@ st_icon_paint (ClutterActor *actor)
|
||||
{
|
||||
if (priv->shadow_material)
|
||||
{
|
||||
StThemeNode *node = st_widget_get_theme_node (ST_WIDGET (actor));
|
||||
StShadow *shadow_spec = st_theme_node_get_shadow (node);
|
||||
ClutterActorBox allocation;
|
||||
float width, height;
|
||||
|
||||
@ -262,7 +267,7 @@ st_icon_paint (ClutterActor *actor)
|
||||
allocation.x2 = allocation.x1 + priv->shadow_width;
|
||||
allocation.y2 = allocation.y1 + priv->shadow_height;
|
||||
|
||||
_st_paint_shadow_with_opacity (shadow_spec,
|
||||
_st_paint_shadow_with_opacity (priv->shadow_spec,
|
||||
priv->shadow_material,
|
||||
&allocation,
|
||||
clutter_actor_get_paint_opacity (priv->icon_texture));
|
||||
@ -279,6 +284,13 @@ st_icon_style_changed (StWidget *widget)
|
||||
StThemeNode *theme_node = st_widget_get_theme_node (widget);
|
||||
StIconPrivate *priv = self->priv;
|
||||
|
||||
if (priv->shadow_spec)
|
||||
{
|
||||
st_shadow_unref (priv->shadow_spec);
|
||||
priv->shadow_spec = NULL;
|
||||
}
|
||||
priv->shadow_spec = st_theme_node_get_shadow (theme_node, "icon-shadow");
|
||||
|
||||
priv->theme_icon_size = (int)(0.5 + st_theme_node_get_length (theme_node, "icon-size"));
|
||||
st_icon_update_icon_size (self);
|
||||
st_icon_update (self);
|
||||
@ -353,8 +365,6 @@ static void
|
||||
st_icon_update_shadow_material (StIcon *icon)
|
||||
{
|
||||
StIconPrivate *priv = icon->priv;
|
||||
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (icon));
|
||||
StShadow *shadow_spec = st_theme_node_get_shadow (theme_node);
|
||||
|
||||
if (priv->shadow_material)
|
||||
{
|
||||
@ -362,14 +372,15 @@ st_icon_update_shadow_material (StIcon *icon)
|
||||
priv->shadow_material = COGL_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (shadow_spec)
|
||||
if (priv->shadow_spec)
|
||||
{
|
||||
CoglHandle material;
|
||||
gint width, height;
|
||||
|
||||
clutter_texture_get_base_size (CLUTTER_TEXTURE (priv->icon_texture),
|
||||
&width, &height);
|
||||
material = _st_create_shadow_material_from_actor (shadow_spec,
|
||||
|
||||
material = _st_create_shadow_material_from_actor (priv->shadow_spec,
|
||||
priv->icon_texture);
|
||||
priv->shadow_material = material;
|
||||
priv->shadow_width = width;
|
||||
|
@ -250,7 +250,7 @@ st_overflow_box_allocate (ClutterActor *actor,
|
||||
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
|
||||
ClutterActorBox content_box;
|
||||
gfloat position;
|
||||
float avail_width, avail_height;
|
||||
float avail_width;
|
||||
GList *l, *children;
|
||||
int i;
|
||||
gboolean done_non_fixed;
|
||||
@ -265,7 +265,6 @@ st_overflow_box_allocate (ClutterActor *actor,
|
||||
st_theme_node_get_content_box (theme_node, box, &content_box);
|
||||
|
||||
avail_width = content_box.x2 - content_box.x1;
|
||||
avail_height = content_box.y2 - content_box.y1;
|
||||
|
||||
position = content_box.y1;
|
||||
priv->n_visible = 0;
|
||||
|
@ -49,7 +49,7 @@ _st_actor_get_preferred_width (ClutterActor *actor,
|
||||
ClutterRequestMode mode;
|
||||
gfloat natural_height;
|
||||
|
||||
g_object_get (G_OBJECT (actor), "request-mode", &mode, NULL);
|
||||
mode = clutter_actor_get_request_mode (actor);
|
||||
if (mode == CLUTTER_REQUEST_WIDTH_FOR_HEIGHT)
|
||||
{
|
||||
clutter_actor_get_preferred_height (actor, -1, NULL, &natural_height);
|
||||
@ -86,7 +86,7 @@ _st_actor_get_preferred_height (ClutterActor *actor,
|
||||
ClutterRequestMode mode;
|
||||
gfloat natural_width;
|
||||
|
||||
g_object_get (G_OBJECT (actor), "request-mode", &mode, NULL);
|
||||
mode = clutter_actor_get_request_mode (actor);
|
||||
if (mode == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
|
||||
{
|
||||
clutter_actor_get_preferred_width (actor, -1, NULL, &natural_width);
|
||||
@ -173,8 +173,7 @@ _st_allocate_fill (StWidget *parent,
|
||||
* modified to cope with the fact that the available size may be
|
||||
* less than the preferred size.
|
||||
*/
|
||||
request = CLUTTER_REQUEST_HEIGHT_FOR_WIDTH;
|
||||
g_object_get (G_OBJECT (child), "request-mode", &request, NULL);
|
||||
request = clutter_actor_get_request_mode (child);
|
||||
|
||||
if (request == CLUTTER_REQUEST_HEIGHT_FOR_WIDTH)
|
||||
{
|
||||
@ -423,44 +422,31 @@ calculate_gaussian_kernel (gdouble sigma,
|
||||
return ret;
|
||||
}
|
||||
|
||||
CoglHandle
|
||||
_st_create_shadow_material (StShadow *shadow_spec,
|
||||
CoglHandle src_texture)
|
||||
static guchar *
|
||||
blur_pixels (guchar *pixels_in,
|
||||
gint width_in,
|
||||
gint height_in,
|
||||
gint rowstride_in,
|
||||
gdouble blur,
|
||||
gint *width_out,
|
||||
gint *height_out,
|
||||
gint *rowstride_out)
|
||||
{
|
||||
static CoglHandle shadow_material_template = COGL_INVALID_HANDLE;
|
||||
|
||||
CoglHandle material;
|
||||
CoglHandle texture;
|
||||
guchar *pixels_in, *pixels_out;
|
||||
gint width_in, height_in, rowstride_in;
|
||||
gint width_out, height_out, rowstride_out;
|
||||
float sigma;
|
||||
|
||||
g_return_val_if_fail (shadow_spec != NULL, COGL_INVALID_HANDLE);
|
||||
g_return_val_if_fail (src_texture != COGL_INVALID_HANDLE,
|
||||
COGL_INVALID_HANDLE);
|
||||
guchar *pixels_out;
|
||||
float sigma;
|
||||
|
||||
/* we use an approximation of the sigma - blur radius relationship used
|
||||
in Firefox for doing SVG blurs; see
|
||||
http://mxr.mozilla.org/mozilla-central/source/gfx/thebes/src/gfxBlur.cpp#280
|
||||
*/
|
||||
sigma = shadow_spec->blur / 1.9;
|
||||
sigma = blur / 1.9;
|
||||
|
||||
width_in = cogl_texture_get_width (src_texture);
|
||||
height_in = cogl_texture_get_height (src_texture);
|
||||
rowstride_in = (width_in + 3) & ~3;
|
||||
|
||||
pixels_in = g_malloc0 (rowstride_in * height_in);
|
||||
|
||||
cogl_texture_get_data (src_texture, COGL_PIXEL_FORMAT_A_8,
|
||||
rowstride_in, pixels_in);
|
||||
|
||||
if ((guint) shadow_spec->blur == 0)
|
||||
if ((guint) blur == 0)
|
||||
{
|
||||
width_out = width_in;
|
||||
height_out = height_in;
|
||||
rowstride_out = rowstride_in;
|
||||
pixels_out = g_memdup (pixels_in, rowstride_out * height_out);
|
||||
*width_out = width_in;
|
||||
*height_out = height_in;
|
||||
*rowstride_out = rowstride_in;
|
||||
pixels_out = g_memdup (pixels_in, *rowstride_out * *height_out);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -472,18 +458,18 @@ _st_create_shadow_material (StShadow *shadow_spec,
|
||||
n_values = (gint) 5 * sigma;
|
||||
half = n_values / 2;
|
||||
|
||||
width_out = width_in + 2 * half;
|
||||
height_out = height_in + 2 * half;
|
||||
rowstride_out = (width_out + 3) & ~3;
|
||||
*width_out = width_in + 2 * half;
|
||||
*height_out = height_in + 2 * half;
|
||||
*rowstride_out = (*width_out + 3) & ~3;
|
||||
|
||||
pixels_out = g_malloc0 (rowstride_out * height_out);
|
||||
line = g_malloc0 (rowstride_out);
|
||||
pixels_out = g_malloc0 (*rowstride_out * *height_out);
|
||||
line = g_malloc0 (*rowstride_out);
|
||||
|
||||
kernel = calculate_gaussian_kernel (sigma, n_values);
|
||||
|
||||
/* vertical blur */
|
||||
for (x_in = 0; x_in < width_in; x_in++)
|
||||
for (y_out = 0; y_out < height_out; y_out++)
|
||||
for (y_out = 0; y_out < *height_out; y_out++)
|
||||
{
|
||||
guchar *pixel_in, *pixel_out;
|
||||
gint i0, i1;
|
||||
@ -497,7 +483,7 @@ _st_create_shadow_material (StShadow *shadow_spec,
|
||||
i1 = MIN (height_in + half - y_in, n_values);
|
||||
|
||||
pixel_in = pixels_in + (y_in + i0 - half) * rowstride_in + x_in;
|
||||
pixel_out = pixels_out + y_out * rowstride_out + (x_in + half);
|
||||
pixel_out = pixels_out + y_out * *rowstride_out + (x_in + half);
|
||||
|
||||
for (i = i0; i < i1; i++)
|
||||
{
|
||||
@ -507,11 +493,11 @@ _st_create_shadow_material (StShadow *shadow_spec,
|
||||
}
|
||||
|
||||
/* horizontal blur */
|
||||
for (y_out = 0; y_out < height_out; y_out++)
|
||||
for (y_out = 0; y_out < *height_out; y_out++)
|
||||
{
|
||||
memcpy (line, pixels_out + y_out * rowstride_out, rowstride_out);
|
||||
memcpy (line, pixels_out + y_out * *rowstride_out, *rowstride_out);
|
||||
|
||||
for (x_out = 0; x_out < width_out; x_out++)
|
||||
for (x_out = 0; x_out < *width_out; x_out++)
|
||||
{
|
||||
gint i0, i1;
|
||||
guchar *pixel_out, *pixel_in;
|
||||
@ -520,10 +506,10 @@ _st_create_shadow_material (StShadow *shadow_spec,
|
||||
* full i range [0, n_values) so that x is in [0, width_out).
|
||||
*/
|
||||
i0 = MAX (half - x_out, 0);
|
||||
i1 = MIN (width_out + half - x_out, n_values);
|
||||
i1 = MIN (*width_out + half - x_out, n_values);
|
||||
|
||||
pixel_in = line + x_out + i0 - half;
|
||||
pixel_out = pixels_out + rowstride_out * y_out + x_out;
|
||||
pixel_out = pixels_out + *rowstride_out * y_out + x_out;
|
||||
|
||||
*pixel_out = 0;
|
||||
for (i = i0; i < i1; i++)
|
||||
@ -537,6 +523,39 @@ _st_create_shadow_material (StShadow *shadow_spec,
|
||||
g_free (line);
|
||||
}
|
||||
|
||||
return pixels_out;
|
||||
}
|
||||
|
||||
CoglHandle
|
||||
_st_create_shadow_material (StShadow *shadow_spec,
|
||||
CoglHandle src_texture)
|
||||
{
|
||||
static CoglHandle shadow_material_template = COGL_INVALID_HANDLE;
|
||||
|
||||
CoglHandle material;
|
||||
CoglHandle texture;
|
||||
guchar *pixels_in, *pixels_out;
|
||||
gint width_in, height_in, rowstride_in;
|
||||
gint width_out, height_out, rowstride_out;
|
||||
|
||||
g_return_val_if_fail (shadow_spec != NULL, COGL_INVALID_HANDLE);
|
||||
g_return_val_if_fail (src_texture != COGL_INVALID_HANDLE,
|
||||
COGL_INVALID_HANDLE);
|
||||
|
||||
width_in = cogl_texture_get_width (src_texture);
|
||||
height_in = cogl_texture_get_height (src_texture);
|
||||
rowstride_in = (width_in + 3) & ~3;
|
||||
|
||||
pixels_in = g_malloc0 (rowstride_in * height_in);
|
||||
|
||||
cogl_texture_get_data (src_texture, COGL_PIXEL_FORMAT_A_8,
|
||||
rowstride_in, pixels_in);
|
||||
|
||||
pixels_out = blur_pixels (pixels_in, width_in, height_in, rowstride_in,
|
||||
shadow_spec->blur,
|
||||
&width_out, &height_out, &rowstride_out);
|
||||
g_free (pixels_in);
|
||||
|
||||
texture = cogl_texture_new_from_data (width_out,
|
||||
height_out,
|
||||
COGL_TEXTURE_NONE,
|
||||
@ -545,7 +564,6 @@ _st_create_shadow_material (StShadow *shadow_spec,
|
||||
rowstride_out,
|
||||
pixels_out);
|
||||
|
||||
g_free (pixels_in);
|
||||
g_free (pixels_out);
|
||||
|
||||
if (G_UNLIKELY (shadow_material_template == COGL_INVALID_HANDLE))
|
||||
@ -618,6 +636,103 @@ _st_create_shadow_material_from_actor (StShadow *shadow_spec,
|
||||
return shadow_material;
|
||||
}
|
||||
|
||||
cairo_pattern_t *
|
||||
_st_create_shadow_cairo_pattern (StShadow *shadow_spec,
|
||||
cairo_pattern_t *src_pattern)
|
||||
{
|
||||
cairo_t *cr;
|
||||
cairo_surface_t *src_surface;
|
||||
cairo_surface_t *surface_in;
|
||||
cairo_surface_t *surface_out;
|
||||
cairo_pattern_t *dst_pattern;
|
||||
guchar *pixels_in, *pixels_out;
|
||||
gint width_in, height_in, rowstride_in;
|
||||
gint width_out, height_out, rowstride_out;
|
||||
cairo_matrix_t shadow_matrix;
|
||||
|
||||
g_return_val_if_fail (shadow_spec != NULL, NULL);
|
||||
g_return_val_if_fail (src_pattern != NULL, NULL);
|
||||
|
||||
cairo_pattern_get_surface (src_pattern, &src_surface);
|
||||
|
||||
width_in = cairo_image_surface_get_width (src_surface);
|
||||
height_in = cairo_image_surface_get_height (src_surface);
|
||||
|
||||
/* We want the output to be a color agnostic alpha mask,
|
||||
* so we need to strip the color channels from the input
|
||||
*/
|
||||
if (cairo_image_surface_get_format (src_surface) != CAIRO_FORMAT_A8)
|
||||
{
|
||||
surface_in = cairo_image_surface_create (CAIRO_FORMAT_A8,
|
||||
width_in, height_in);
|
||||
|
||||
cr = cairo_create (surface_in);
|
||||
cairo_set_source_surface (cr, src_surface, 0, 0);
|
||||
cairo_paint (cr);
|
||||
cairo_destroy (cr);
|
||||
}
|
||||
else
|
||||
{
|
||||
surface_in = cairo_surface_reference (src_surface);
|
||||
}
|
||||
|
||||
pixels_in = cairo_image_surface_get_data (surface_in);
|
||||
rowstride_in = cairo_image_surface_get_stride (surface_in);
|
||||
|
||||
pixels_out = blur_pixels (pixels_in, width_in, height_in, rowstride_in,
|
||||
shadow_spec->blur,
|
||||
&width_out, &height_out, &rowstride_out);
|
||||
cairo_surface_destroy (surface_in);
|
||||
|
||||
surface_out = cairo_image_surface_create_for_data (pixels_out,
|
||||
CAIRO_FORMAT_A8,
|
||||
width_out,
|
||||
height_out,
|
||||
rowstride_out);
|
||||
|
||||
dst_pattern = cairo_pattern_create_for_surface (surface_out);
|
||||
cairo_surface_destroy (surface_out);
|
||||
|
||||
cairo_pattern_get_matrix (src_pattern, &shadow_matrix);
|
||||
|
||||
/* Read all the code from the cairo_pattern_set_matrix call
|
||||
* at the end of this function to here from bottom to top,
|
||||
* because each new affine transformation is applied in
|
||||
* front of all the previous ones */
|
||||
|
||||
/* 6. Invert the matrix back */
|
||||
cairo_matrix_invert (&shadow_matrix);
|
||||
|
||||
/* 5. Adjust based on specified offsets */
|
||||
cairo_matrix_translate (&shadow_matrix,
|
||||
shadow_spec->xoffset,
|
||||
shadow_spec->yoffset);
|
||||
|
||||
/* 4. Recenter the newly scaled image */
|
||||
cairo_matrix_translate (&shadow_matrix,
|
||||
- shadow_spec->spread,
|
||||
- shadow_spec->spread);
|
||||
|
||||
/* 3. Scale up the blurred image to fill the spread */
|
||||
cairo_matrix_scale (&shadow_matrix,
|
||||
(width_in + 2.0 * shadow_spec->spread) / width_in,
|
||||
(height_in + 2.0 * shadow_spec->spread) / height_in);
|
||||
|
||||
/* 2. Shift the blurred image left, so that it aligns centered
|
||||
* under the unblurred one */
|
||||
cairo_matrix_translate (&shadow_matrix,
|
||||
- (width_out - width_in) / 2.0,
|
||||
- (height_out - height_in) / 2.0);
|
||||
|
||||
/* 1. Invert the matrix so we can work with it in pattern space
|
||||
*/
|
||||
cairo_matrix_invert (&shadow_matrix);
|
||||
|
||||
cairo_pattern_set_matrix (dst_pattern, &shadow_matrix);
|
||||
|
||||
return dst_pattern;
|
||||
}
|
||||
|
||||
void
|
||||
_st_paint_shadow_with_opacity (StShadow *shadow_spec,
|
||||
CoglHandle shadow_material,
|
||||
|
@ -24,6 +24,7 @@
|
||||
#define __ST_PRIVATE_H__
|
||||
|
||||
#include <glib.h>
|
||||
#include <cairo.h>
|
||||
#include "st-widget.h"
|
||||
#include "st-bin.h"
|
||||
#include "st-shadow.h"
|
||||
@ -79,6 +80,9 @@ CoglHandle _st_create_shadow_material (StShadow *shadow_spec,
|
||||
CoglHandle src_texture);
|
||||
CoglHandle _st_create_shadow_material_from_actor (StShadow *shadow_spec,
|
||||
ClutterActor *actor);
|
||||
cairo_pattern_t *_st_create_shadow_cairo_pattern (StShadow *shadow_spec,
|
||||
cairo_pattern_t *src_pattern);
|
||||
|
||||
void _st_paint_shadow_with_opacity (StShadow *shadow_spec,
|
||||
CoglHandle shadow_material,
|
||||
ClutterActorBox *box,
|
||||
|
@ -643,13 +643,11 @@ st_scroll_bar_constructor (GType type,
|
||||
GObjectClass *gobject_class;
|
||||
GObject *obj;
|
||||
StScrollBar *bar;
|
||||
StScrollBarPrivate *priv;
|
||||
|
||||
gobject_class = G_OBJECT_CLASS (st_scroll_bar_parent_class);
|
||||
obj = gobject_class->constructor (type, n_properties, properties);
|
||||
|
||||
bar = ST_SCROLL_BAR (obj);
|
||||
priv = ST_SCROLL_BAR_GET_PRIVATE (bar);
|
||||
|
||||
g_signal_connect (bar, "notify::reactive",
|
||||
G_CALLBACK (bar_reactive_notify_cb), NULL);
|
||||
|
348
src/st/st-scroll-view-fade.c
Normal file
348
src/st/st-scroll-view-fade.c
Normal file
@ -0,0 +1,348 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
/*
|
||||
* st-scroll-view-fade.h: Edge fade effect for StScrollView
|
||||
*
|
||||
* Copyright 2010 Intel Corporation.
|
||||
* Copyright 2011 Adel Gadllah
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU Lesser General Public License,
|
||||
* version 2.1, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#define ST_SCROLL_VIEW_FADE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), ST_TYPE_SCROLL_VIEW_FADE, StScrollViewFadeClass))
|
||||
#define ST_IS_SCROLL_VIEW_FADE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), ST_TYPE_SCROLL_VIEW_FADE))
|
||||
#define ST_SCROLL_VIEW_FADE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), ST_TYPE_SCROLL_VIEW_FADE, StScrollViewFadeClass))
|
||||
|
||||
#include "st-scroll-view-fade.h"
|
||||
#include "st-scroll-view.h"
|
||||
#include "st-scroll-bar.h"
|
||||
#include "st-scrollable.h"
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
#include <cogl/cogl.h>
|
||||
|
||||
typedef struct _StScrollViewFadeClass StScrollViewFadeClass;
|
||||
|
||||
#define FADE_OFFSET 68.0f
|
||||
|
||||
static const gchar *fade_glsl_shader =
|
||||
"uniform sampler2D tex;\n"
|
||||
"uniform float height;\n"
|
||||
"uniform float width;\n"
|
||||
"uniform float scrollbar_width;\n"
|
||||
"uniform float offset_bottom;\n"
|
||||
"uniform float offset_top;\n"
|
||||
"\n"
|
||||
"void main ()\n"
|
||||
"{\n"
|
||||
" vec4 color = cogl_color_in * texture2D (tex, vec2 (cogl_tex_coord_in[0].xy));\n"
|
||||
" float y = height * cogl_tex_coord_in[0].y;\n"
|
||||
" float x = width * cogl_tex_coord_in[0].x;\n"
|
||||
" float ratio = 0.0;\n"
|
||||
" float fade_bottom_start = height - offset_bottom;\n"
|
||||
" \n"
|
||||
" if (offset_top != 0.0 && y < offset_top && x < (width - scrollbar_width)) {\n"
|
||||
" ratio = y / offset_top;\n"
|
||||
" cogl_color_out = color * ratio;\n"
|
||||
" }\n"
|
||||
" else if (offset_bottom != 0.0 && y > fade_bottom_start && x < (width - scrollbar_width)) {\n"
|
||||
" ratio = (height - y)/(height - fade_bottom_start);\n"
|
||||
" cogl_color_out = color * ratio;\n"
|
||||
" }\n"
|
||||
" else { \n"
|
||||
" cogl_color_out = color;\n"
|
||||
" }\n"
|
||||
"}\n";
|
||||
|
||||
struct _StScrollViewFade
|
||||
{
|
||||
ClutterOffscreenEffect parent_instance;
|
||||
|
||||
/* a back pointer to our actor, so that we can query it */
|
||||
ClutterActor *actor;
|
||||
|
||||
CoglHandle shader;
|
||||
CoglHandle program;
|
||||
|
||||
gint tex_uniform;
|
||||
gint height_uniform;
|
||||
gint width_uniform;
|
||||
gint scrollbar_width_uniform;
|
||||
gint offset_top_uniform;
|
||||
gint offset_bottom_uniform;
|
||||
|
||||
StAdjustment *vadjustment;
|
||||
|
||||
guint is_attached : 1;
|
||||
};
|
||||
|
||||
struct _StScrollViewFadeClass
|
||||
{
|
||||
ClutterOffscreenEffectClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (StScrollViewFade,
|
||||
st_scroll_view_fade,
|
||||
CLUTTER_TYPE_OFFSCREEN_EFFECT);
|
||||
|
||||
static gboolean
|
||||
st_scroll_view_fade_pre_paint (ClutterEffect *effect)
|
||||
{
|
||||
StScrollViewFade *self = ST_SCROLL_VIEW_FADE (effect);
|
||||
ClutterEffectClass *parent_class;
|
||||
|
||||
if (self->shader == COGL_INVALID_HANDLE)
|
||||
return FALSE;
|
||||
|
||||
if (!clutter_actor_meta_get_enabled (CLUTTER_ACTOR_META (effect)))
|
||||
return FALSE;
|
||||
|
||||
if (self->actor == NULL)
|
||||
return FALSE;
|
||||
|
||||
if (self->program == COGL_INVALID_HANDLE)
|
||||
self->program = cogl_create_program ();
|
||||
|
||||
if (!self->is_attached)
|
||||
{
|
||||
g_assert (self->shader != COGL_INVALID_HANDLE);
|
||||
g_assert (self->program != COGL_INVALID_HANDLE);
|
||||
|
||||
cogl_program_attach_shader (self->program, self->shader);
|
||||
cogl_program_link (self->program);
|
||||
|
||||
cogl_handle_unref (self->shader);
|
||||
|
||||
self->is_attached = TRUE;
|
||||
|
||||
self->tex_uniform =
|
||||
cogl_program_get_uniform_location (self->program, "tex");
|
||||
self->height_uniform =
|
||||
cogl_program_get_uniform_location (self->program, "height");
|
||||
self->width_uniform =
|
||||
cogl_program_get_uniform_location (self->program, "width");
|
||||
self->scrollbar_width_uniform =
|
||||
cogl_program_get_uniform_location (self->program, "scrollbar_width");
|
||||
self->offset_top_uniform =
|
||||
cogl_program_get_uniform_location (self->program, "offset_top");
|
||||
self->offset_bottom_uniform =
|
||||
cogl_program_get_uniform_location (self->program, "offset_bottom");
|
||||
}
|
||||
|
||||
parent_class = CLUTTER_EFFECT_CLASS (st_scroll_view_fade_parent_class);
|
||||
return parent_class->pre_paint (effect);
|
||||
}
|
||||
|
||||
static CoglHandle
|
||||
st_scroll_view_fade_create_texture (ClutterOffscreenEffect *effect,
|
||||
gfloat min_width,
|
||||
gfloat min_height)
|
||||
{
|
||||
return cogl_texture_new_with_size (min_width,
|
||||
min_height,
|
||||
COGL_TEXTURE_NO_SLICING,
|
||||
COGL_PIXEL_FORMAT_RGBA_8888_PRE);
|
||||
}
|
||||
|
||||
static void
|
||||
st_scroll_view_fade_paint_target (ClutterOffscreenEffect *effect)
|
||||
{
|
||||
StScrollViewFade *self = ST_SCROLL_VIEW_FADE (effect);
|
||||
ClutterOffscreenEffectClass *parent;
|
||||
CoglHandle material;
|
||||
|
||||
gdouble value, lower, upper, page_size;
|
||||
ClutterActor *vscroll = st_scroll_view_get_vscroll_bar (ST_SCROLL_VIEW (self->actor));
|
||||
|
||||
if (self->program == COGL_INVALID_HANDLE)
|
||||
goto out;
|
||||
|
||||
st_adjustment_get_values (self->vadjustment, &value, &lower, &upper, NULL, NULL, &page_size);
|
||||
|
||||
if (self->offset_top_uniform > -1) {
|
||||
if (value > lower + 0.1)
|
||||
cogl_program_set_uniform_1f (self->program, self->offset_top_uniform, FADE_OFFSET);
|
||||
else
|
||||
cogl_program_set_uniform_1f (self->program, self->offset_top_uniform, 0.0f);
|
||||
}
|
||||
|
||||
if (self->offset_bottom_uniform > -1) {
|
||||
if (value < upper - page_size - 0.1)
|
||||
cogl_program_set_uniform_1f (self->program, self->offset_bottom_uniform, FADE_OFFSET);
|
||||
else
|
||||
cogl_program_set_uniform_1f (self->program, self->offset_bottom_uniform, 0.0f);
|
||||
}
|
||||
|
||||
if (self->tex_uniform > -1)
|
||||
cogl_program_set_uniform_1i (self->program, self->tex_uniform, 0);
|
||||
if (self->height_uniform > -1)
|
||||
cogl_program_set_uniform_1f (self->program, self->height_uniform, clutter_actor_get_height (self->actor));
|
||||
if (self->width_uniform > -1)
|
||||
cogl_program_set_uniform_1f (self->program, self->width_uniform, clutter_actor_get_width (self->actor));
|
||||
if (self->scrollbar_width_uniform > -1)
|
||||
cogl_program_set_uniform_1f (self->program, self->scrollbar_width_uniform, clutter_actor_get_width (vscroll));
|
||||
|
||||
material = clutter_offscreen_effect_get_target (effect);
|
||||
cogl_material_set_user_program (material, self->program);
|
||||
|
||||
out:
|
||||
parent = CLUTTER_OFFSCREEN_EFFECT_CLASS (st_scroll_view_fade_parent_class);
|
||||
parent->paint_target (effect);
|
||||
}
|
||||
|
||||
static void
|
||||
on_vadjustment_changed (StAdjustment *adjustment,
|
||||
ClutterEffect *effect)
|
||||
{
|
||||
gdouble value, lower, upper, page_size;
|
||||
gboolean needs_fade;
|
||||
|
||||
st_adjustment_get_values (adjustment, &value, &lower, &upper, NULL, NULL, &page_size);
|
||||
needs_fade = (value > lower + 0.1) || (value < upper - page_size - 0.1);
|
||||
|
||||
clutter_actor_meta_set_enabled (CLUTTER_ACTOR_META (effect), needs_fade);
|
||||
}
|
||||
|
||||
static void
|
||||
st_scroll_view_fade_set_actor (ClutterActorMeta *meta,
|
||||
ClutterActor *actor)
|
||||
{
|
||||
StScrollViewFade *self = ST_SCROLL_VIEW_FADE (meta);
|
||||
ClutterActorMetaClass *parent;
|
||||
|
||||
g_return_if_fail (actor == NULL || ST_IS_SCROLL_VIEW (actor));
|
||||
|
||||
if (self->shader == COGL_INVALID_HANDLE)
|
||||
{
|
||||
clutter_actor_meta_set_enabled (meta, FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (self->vadjustment)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (self->vadjustment,
|
||||
(gpointer)on_vadjustment_changed,
|
||||
self);
|
||||
self->vadjustment = NULL;
|
||||
}
|
||||
|
||||
if (actor)
|
||||
{
|
||||
StScrollView *scroll_view = ST_SCROLL_VIEW (actor);
|
||||
StScrollBar *vscroll = ST_SCROLL_BAR (st_scroll_view_get_vscroll_bar (scroll_view));
|
||||
self->vadjustment = ST_ADJUSTMENT (st_scroll_bar_get_adjustment (vscroll));
|
||||
|
||||
g_signal_connect (self->vadjustment, "changed",
|
||||
G_CALLBACK (on_vadjustment_changed),
|
||||
self);
|
||||
|
||||
on_vadjustment_changed (self->vadjustment, CLUTTER_EFFECT (self));
|
||||
}
|
||||
|
||||
parent = CLUTTER_ACTOR_META_CLASS (st_scroll_view_fade_parent_class);
|
||||
parent->set_actor (meta, actor);
|
||||
|
||||
/* we keep a back pointer here, to avoid going through the ActorMeta */
|
||||
self->actor = clutter_actor_meta_get_actor (meta);
|
||||
}
|
||||
|
||||
static void
|
||||
st_scroll_view_fade_dispose (GObject *gobject)
|
||||
{
|
||||
StScrollViewFade *self = ST_SCROLL_VIEW_FADE (gobject);
|
||||
|
||||
if (self->program != COGL_INVALID_HANDLE)
|
||||
{
|
||||
cogl_handle_unref (self->program);
|
||||
|
||||
self->program = COGL_INVALID_HANDLE;
|
||||
self->shader = COGL_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (self->vadjustment)
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func (self->vadjustment,
|
||||
(gpointer)on_vadjustment_changed,
|
||||
self);
|
||||
self->vadjustment = NULL;
|
||||
}
|
||||
|
||||
self->actor = NULL;
|
||||
|
||||
G_OBJECT_CLASS (st_scroll_view_fade_parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
st_scroll_view_fade_class_init (StScrollViewFadeClass *klass)
|
||||
{
|
||||
ClutterEffectClass *effect_class = CLUTTER_EFFECT_CLASS (klass);
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||||
ClutterOffscreenEffectClass *offscreen_class;
|
||||
ClutterActorMetaClass *meta_class = CLUTTER_ACTOR_META_CLASS (klass);
|
||||
|
||||
gobject_class->dispose = st_scroll_view_fade_dispose;
|
||||
|
||||
meta_class->set_actor = st_scroll_view_fade_set_actor;
|
||||
|
||||
effect_class->pre_paint = st_scroll_view_fade_pre_paint;
|
||||
|
||||
offscreen_class = CLUTTER_OFFSCREEN_EFFECT_CLASS (klass);
|
||||
offscreen_class->create_texture = st_scroll_view_fade_create_texture;
|
||||
offscreen_class->paint_target = st_scroll_view_fade_paint_target;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
st_scroll_view_fade_init (StScrollViewFade *self)
|
||||
{
|
||||
static CoglHandle shader = COGL_INVALID_HANDLE;
|
||||
|
||||
if (shader == COGL_INVALID_HANDLE)
|
||||
{
|
||||
if (clutter_feature_available (CLUTTER_FEATURE_SHADERS_GLSL))
|
||||
{
|
||||
shader = cogl_create_shader (COGL_SHADER_TYPE_FRAGMENT);
|
||||
cogl_shader_source (shader, fade_glsl_shader);
|
||||
cogl_shader_compile (shader);
|
||||
if (!cogl_shader_is_compiled (shader))
|
||||
{
|
||||
gchar *log_buf = cogl_shader_get_info_log (shader);
|
||||
|
||||
g_warning (G_STRLOC ": Unable to compile the fade shader: %s",
|
||||
log_buf);
|
||||
g_free (log_buf);
|
||||
|
||||
cogl_handle_unref (shader);
|
||||
shader = COGL_INVALID_HANDLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self->shader = shader;
|
||||
self->is_attached = FALSE;
|
||||
self->tex_uniform = -1;
|
||||
self->height_uniform = -1;
|
||||
self->width_uniform = -1;
|
||||
self->scrollbar_width_uniform = -1;
|
||||
self->offset_top_uniform = -1;
|
||||
self->offset_bottom_uniform = -1;
|
||||
|
||||
if (shader != COGL_INVALID_HANDLE)
|
||||
cogl_handle_ref (self->shader);
|
||||
}
|
||||
|
||||
ClutterEffect *
|
||||
st_scroll_view_fade_new (void)
|
||||
{
|
||||
return g_object_new (ST_TYPE_SCROLL_VIEW_FADE, NULL);
|
||||
}
|
40
src/st/st-scroll-view-fade.h
Normal file
40
src/st/st-scroll-view-fade.h
Normal file
@ -0,0 +1,40 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
|
||||
/*
|
||||
* st-scroll-view-fade.h: Edge fade effect for StScrollView
|
||||
*
|
||||
* Copyright 2010 Intel Corporation.
|
||||
* Copyright 2011 Adel Gadllah
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU Lesser General Public License,
|
||||
* version 2.1, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __ST_SCROLL_VIEW_FADE_H__
|
||||
#define __ST_SCROLL_VIEW_FADE_H__
|
||||
|
||||
#include <clutter/clutter.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define ST_TYPE_SCROLL_VIEW_FADE (st_scroll_view_fade_get_type ())
|
||||
#define ST_SCROLL_VIEW_FADE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), ST_TYPE_SCROLL_VIEW_FADE, StScrollViewFade))
|
||||
#define ST_IS_SCROLL_VIEW_FADE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), ST_TYPE_SCROLL_VIEW_FADE))
|
||||
|
||||
typedef struct _StScrollViewFade StScrollViewFade;
|
||||
|
||||
GType st_scroll_view_fade_get_type (void) G_GNUC_CONST;
|
||||
|
||||
ClutterEffect *st_scroll_view_fade_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __ST_SCROLL_VIEW_FADE_H__ */
|
@ -62,6 +62,7 @@
|
||||
#include "st-marshal.h"
|
||||
#include "st-scroll-bar.h"
|
||||
#include "st-scrollable.h"
|
||||
#include "st-scroll-view-fade.h"
|
||||
#include <clutter/clutter.h>
|
||||
#include <math.h>
|
||||
|
||||
@ -93,20 +94,17 @@ struct _StScrollViewPrivate
|
||||
GtkPolicyType hscrollbar_policy;
|
||||
GtkPolicyType vscrollbar_policy;
|
||||
|
||||
ClutterActor *top_shadow;
|
||||
ClutterActor *bottom_shadow;
|
||||
|
||||
gfloat row_size;
|
||||
gfloat column_size;
|
||||
|
||||
gboolean vshadows;
|
||||
gboolean vfade;
|
||||
StScrollViewFade *vfade_effect;
|
||||
|
||||
gboolean row_size_set : 1;
|
||||
gboolean column_size_set : 1;
|
||||
guint mouse_scroll : 1;
|
||||
guint hscrollbar_visible : 1;
|
||||
guint vscrollbar_visible : 1;
|
||||
guint top_shadow_visible : 1;
|
||||
guint bottom_shadow_visible : 1;
|
||||
};
|
||||
|
||||
enum {
|
||||
@ -117,7 +115,7 @@ enum {
|
||||
PROP_HSCROLLBAR_POLICY,
|
||||
PROP_VSCROLLBAR_POLICY,
|
||||
PROP_MOUSE_SCROLL,
|
||||
PROP_VSHADOWS
|
||||
PROP_VFADE
|
||||
};
|
||||
|
||||
static void
|
||||
@ -145,80 +143,50 @@ st_scroll_view_get_property (GObject *object,
|
||||
case PROP_MOUSE_SCROLL:
|
||||
g_value_set_boolean (value, priv->mouse_scroll);
|
||||
break;
|
||||
case PROP_VSHADOWS:
|
||||
g_value_set_boolean (value, priv->vshadows);
|
||||
case PROP_VFADE:
|
||||
g_value_set_boolean (value, priv->vfade);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
update_shadow_visibility (StScrollView *scroll)
|
||||
{
|
||||
StScrollViewPrivate *priv = scroll->priv;
|
||||
|
||||
if (priv->vshadows)
|
||||
{
|
||||
gdouble value, lower, upper, page_size;
|
||||
|
||||
st_adjustment_get_values (priv->vadjustment, &value, &lower, &upper, NULL, NULL, &page_size);
|
||||
|
||||
priv->top_shadow_visible = value > lower + 0.1;
|
||||
priv->bottom_shadow_visible = value < upper - page_size - 0.1;
|
||||
}
|
||||
else
|
||||
{
|
||||
priv->top_shadow_visible = FALSE;
|
||||
priv->bottom_shadow_visible = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* st_scroll_view_set_vshadows:
|
||||
* st_scroll_view_set_vfade:
|
||||
* @self: a #StScrollView
|
||||
* @vshadows: Whether to enable vertical shadows
|
||||
* @vfade: Whether to enable the vertical fade effect
|
||||
*
|
||||
* Sets whether to show shadows at the top and bottom of the area. Shadows
|
||||
* are omitted when fully scrolled to that edge.
|
||||
* Sets whether to fade the content at the top and bottom of the area when not
|
||||
* fully scrolled to that edge.
|
||||
*/
|
||||
void
|
||||
st_scroll_view_set_vshadows (StScrollView *self,
|
||||
gboolean vshadows)
|
||||
st_scroll_view_set_vfade (StScrollView *self,
|
||||
gboolean vfade)
|
||||
{
|
||||
StScrollViewPrivate *priv = ST_SCROLL_VIEW (self)->priv;
|
||||
|
||||
vshadows = vshadows != FALSE;
|
||||
if (priv->vshadows == vshadows)
|
||||
vfade = vfade != FALSE;
|
||||
if (priv->vfade == vfade)
|
||||
return;
|
||||
|
||||
priv->vshadows = vshadows;
|
||||
priv->vfade = vfade;
|
||||
|
||||
if (vshadows)
|
||||
if (vfade)
|
||||
{
|
||||
if (priv->top_shadow)
|
||||
{
|
||||
clutter_actor_show (priv->top_shadow);
|
||||
clutter_actor_show (priv->bottom_shadow);
|
||||
}
|
||||
else
|
||||
{
|
||||
priv->top_shadow = g_object_new (ST_TYPE_BIN, "style-class", "top-shadow", NULL);
|
||||
priv->bottom_shadow = g_object_new (ST_TYPE_BIN, "style-class", "bottom-shadow", NULL);
|
||||
if (priv->vfade_effect == NULL)
|
||||
priv->vfade_effect = g_object_new (ST_TYPE_SCROLL_VIEW_FADE, NULL);
|
||||
|
||||
clutter_actor_set_parent (priv->bottom_shadow, CLUTTER_ACTOR (self));
|
||||
clutter_actor_set_parent (priv->top_shadow, CLUTTER_ACTOR (self));
|
||||
}
|
||||
clutter_actor_add_effect (CLUTTER_ACTOR (self), CLUTTER_EFFECT (priv->vfade_effect));
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
clutter_actor_hide (priv->top_shadow);
|
||||
clutter_actor_hide (priv->bottom_shadow);
|
||||
clutter_actor_remove_effect (CLUTTER_ACTOR (self), CLUTTER_EFFECT (priv->vfade_effect));
|
||||
priv->vfade_effect = NULL;
|
||||
}
|
||||
|
||||
update_shadow_visibility (self);
|
||||
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
|
||||
|
||||
g_object_notify (G_OBJECT (self), "vshadows");
|
||||
g_object_notify (G_OBJECT (self), "vfade");
|
||||
}
|
||||
|
||||
static void
|
||||
@ -232,8 +200,8 @@ st_scroll_view_set_property (GObject *object,
|
||||
|
||||
switch (property_id)
|
||||
{
|
||||
case PROP_VSHADOWS:
|
||||
st_scroll_view_set_vshadows (self, g_value_get_boolean (value));
|
||||
case PROP_VFADE:
|
||||
st_scroll_view_set_vfade (self, g_value_get_boolean (value));
|
||||
break;
|
||||
case PROP_MOUSE_SCROLL:
|
||||
st_scroll_view_set_mouse_scrolling (self,
|
||||
@ -259,6 +227,12 @@ st_scroll_view_dispose (GObject *object)
|
||||
{
|
||||
StScrollViewPrivate *priv = ST_SCROLL_VIEW (object)->priv;
|
||||
|
||||
if (priv->vfade_effect)
|
||||
{
|
||||
clutter_actor_remove_effect (CLUTTER_ACTOR (object), CLUTTER_EFFECT (priv->vfade_effect));
|
||||
priv->vfade_effect = NULL;
|
||||
}
|
||||
|
||||
if (priv->vscroll)
|
||||
clutter_actor_destroy (priv->vscroll);
|
||||
|
||||
@ -284,20 +258,6 @@ st_scroll_view_dispose (GObject *object)
|
||||
priv->vadjustment = NULL;
|
||||
}
|
||||
|
||||
/* since it's impossible to get a handle to these actors, we can
|
||||
* just directly unparent them and not go through destroy/remove */
|
||||
if (priv->top_shadow)
|
||||
{
|
||||
clutter_actor_unparent (priv->top_shadow);
|
||||
priv->top_shadow = NULL;
|
||||
}
|
||||
|
||||
if (priv->bottom_shadow)
|
||||
{
|
||||
clutter_actor_unparent (priv->bottom_shadow);
|
||||
priv->bottom_shadow = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (st_scroll_view_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
@ -314,11 +274,6 @@ st_scroll_view_paint (ClutterActor *actor)
|
||||
clutter_actor_paint (priv->hscroll);
|
||||
if (priv->vscrollbar_visible && CLUTTER_ACTOR_IS_VISIBLE (priv->vscroll))
|
||||
clutter_actor_paint (priv->vscroll);
|
||||
|
||||
if (priv->top_shadow_visible)
|
||||
clutter_actor_paint (priv->top_shadow);
|
||||
if (priv->bottom_shadow_visible)
|
||||
clutter_actor_paint (priv->bottom_shadow);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -532,18 +487,6 @@ st_scroll_view_get_preferred_height (ClutterActor *actor,
|
||||
st_theme_node_adjust_preferred_height (theme_node, min_height_p, natural_height_p);
|
||||
}
|
||||
|
||||
static gfloat
|
||||
get_shadow_height (ClutterActor *shadow)
|
||||
{
|
||||
gfloat natural_height;
|
||||
|
||||
/* The shadows are empty StBin and have no height-for-width behavior */
|
||||
|
||||
clutter_actor_get_preferred_height (shadow, -1, NULL, &natural_height);
|
||||
|
||||
return natural_height;
|
||||
}
|
||||
|
||||
static void
|
||||
st_scroll_view_allocate (ClutterActor *actor,
|
||||
const ClutterActorBox *box,
|
||||
@ -688,25 +631,6 @@ st_scroll_view_allocate (ClutterActor *actor,
|
||||
if (priv->child)
|
||||
clutter_actor_allocate (priv->child, &child_box, flags);
|
||||
|
||||
/* Shadows */
|
||||
if (priv->top_shadow && CLUTTER_ACTOR_IS_VISIBLE (priv->top_shadow))
|
||||
{
|
||||
child_box.x1 = content_box.x1;
|
||||
child_box.y1 = content_box.y1;
|
||||
child_box.x2 = MAX (child_box.x1, content_box.x2 - sb_width);
|
||||
child_box.y2 = content_box.y1 + get_shadow_height (priv->top_shadow);
|
||||
clutter_actor_allocate (priv->top_shadow, &child_box, flags);
|
||||
}
|
||||
|
||||
if (priv->bottom_shadow && CLUTTER_ACTOR_IS_VISIBLE (priv->bottom_shadow))
|
||||
{
|
||||
child_box.x1 = content_box.x1;
|
||||
child_box.y1 = content_box.y2 - sb_height - get_shadow_height (priv->bottom_shadow);
|
||||
child_box.x2 = MAX (content_box.x1, content_box.x2 - sb_width);
|
||||
child_box.y2 = content_box.y2 - sb_height;
|
||||
clutter_actor_allocate (priv->bottom_shadow, &child_box, flags);
|
||||
}
|
||||
|
||||
priv->hscrollbar_visible = hscrollbar_visible;
|
||||
priv->vscrollbar_visible = vscrollbar_visible;
|
||||
}
|
||||
@ -719,12 +643,6 @@ st_scroll_view_style_changed (StWidget *widget)
|
||||
st_widget_style_changed (ST_WIDGET (priv->hscroll));
|
||||
st_widget_style_changed (ST_WIDGET (priv->vscroll));
|
||||
|
||||
if (priv->top_shadow)
|
||||
{
|
||||
st_widget_style_changed (ST_WIDGET (priv->top_shadow));
|
||||
st_widget_style_changed (ST_WIDGET (priv->bottom_shadow));
|
||||
}
|
||||
|
||||
ST_WIDGET_CLASS (st_scroll_view_parent_class)->style_changed (widget);
|
||||
}
|
||||
|
||||
@ -857,31 +775,16 @@ st_scroll_view_class_init (StScrollViewClass *klass)
|
||||
PROP_MOUSE_SCROLL,
|
||||
pspec);
|
||||
|
||||
pspec = g_param_spec_boolean ("vshadows",
|
||||
pspec = g_param_spec_boolean ("vfade",
|
||||
"Vertical Shadows",
|
||||
"Show shadows at the top and and bottom of the area unless fully scrolled to that edge",
|
||||
"Fade the content at the top and and bottom of the area unless fully scrolled to that edge",
|
||||
FALSE,
|
||||
G_PARAM_READWRITE);
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_VSHADOWS,
|
||||
PROP_VFADE,
|
||||
pspec);
|
||||
}
|
||||
|
||||
static void
|
||||
child_adjustment_changed_cb (StAdjustment *adjustment,
|
||||
StScrollView *scroll)
|
||||
{
|
||||
update_shadow_visibility (scroll);
|
||||
}
|
||||
|
||||
static void
|
||||
child_adjustment_notify_value (GObject *gobject,
|
||||
GParamSpec *pspec,
|
||||
StScrollView *scroll)
|
||||
{
|
||||
update_shadow_visibility (scroll);
|
||||
}
|
||||
|
||||
static void
|
||||
st_scroll_view_init (StScrollView *self)
|
||||
{
|
||||
@ -897,10 +800,6 @@ st_scroll_view_init (StScrollView *self)
|
||||
NULL);
|
||||
|
||||
priv->vadjustment = g_object_new (ST_TYPE_ADJUSTMENT, NULL);
|
||||
g_signal_connect (priv->vadjustment, "changed",
|
||||
G_CALLBACK (child_adjustment_changed_cb), self);
|
||||
g_signal_connect (priv->vadjustment, "notify::value",
|
||||
G_CALLBACK (child_adjustment_notify_value), self);
|
||||
priv->vscroll = g_object_new (ST_TYPE_SCROLL_BAR,
|
||||
"adjustment", priv->vadjustment,
|
||||
"vertical", TRUE,
|
||||
@ -988,12 +887,6 @@ st_scroll_view_foreach_with_internals (ClutterContainer *container,
|
||||
|
||||
if (priv->vscroll != NULL)
|
||||
callback (priv->vscroll, user_data);
|
||||
|
||||
if (priv->top_shadow)
|
||||
{
|
||||
callback (priv->top_shadow, user_data);
|
||||
callback (priv->bottom_shadow, user_data);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -84,8 +84,8 @@ void st_scroll_view_set_policy (StScrollView *scroll,
|
||||
GtkPolicyType hscroll,
|
||||
GtkPolicyType vscroll);
|
||||
|
||||
void st_scroll_view_set_vshadows (StScrollView *self,
|
||||
gboolean vshadows);
|
||||
void st_scroll_view_set_vfade (StScrollView *self,
|
||||
gboolean vfade);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
@ -315,12 +315,12 @@ st_table_calculate_col_widths (StTable *table,
|
||||
|
||||
for (list = children; list; list = list->next)
|
||||
{
|
||||
gint row, col;
|
||||
gint col;
|
||||
gfloat w_min, w_pref;
|
||||
gboolean x_expand;
|
||||
StTableChild *meta;
|
||||
ClutterActor *child;
|
||||
gint col_span, row_span;
|
||||
gint col_span;
|
||||
|
||||
child = CLUTTER_ACTOR (list->data);
|
||||
|
||||
@ -331,10 +331,8 @@ st_table_calculate_col_widths (StTable *table,
|
||||
|
||||
/* get child properties */
|
||||
col = meta->col;
|
||||
row = meta->row;
|
||||
x_expand = meta->x_expand;
|
||||
col_span = meta->col_span;
|
||||
row_span = meta->row_span;
|
||||
|
||||
if (x_expand)
|
||||
is_expand_col[col] = TRUE;
|
||||
@ -428,7 +426,7 @@ st_table_calculate_row_heights (StTable *table,
|
||||
{
|
||||
gint row, col, cell_width;
|
||||
gfloat h_min, h_pref;
|
||||
gboolean x_expand, y_expand;
|
||||
gboolean y_expand;
|
||||
StTableChild *meta;
|
||||
ClutterActor *child;
|
||||
gint col_span, row_span;
|
||||
@ -443,7 +441,6 @@ st_table_calculate_row_heights (StTable *table,
|
||||
/* get child properties */
|
||||
col = meta->col;
|
||||
row = meta->row;
|
||||
x_expand = meta->x_expand;
|
||||
y_expand = meta->y_expand;
|
||||
col_span = meta->col_span;
|
||||
row_span = meta->row_span;
|
||||
|
@ -30,6 +30,7 @@
|
||||
|
||||
#define CACHE_PREFIX_GICON "gicon:"
|
||||
#define CACHE_PREFIX_URI "uri:"
|
||||
#define CACHE_PREFIX_URI_FOR_CAIRO "uri-for-cairo:"
|
||||
#define CACHE_PREFIX_THUMBNAIL_URI "thumbnail-uri:"
|
||||
#define CACHE_PREFIX_RAW_CHECKSUM "raw-checksum:"
|
||||
#define CACHE_PREFIX_COMPRESSED_CHECKSUM "compressed-checksum:"
|
||||
@ -798,6 +799,27 @@ pixbuf_to_cogl_handle (GdkPixbuf *pixbuf)
|
||||
gdk_pixbuf_get_pixels (pixbuf));
|
||||
}
|
||||
|
||||
static cairo_surface_t *
|
||||
pixbuf_to_cairo_surface (GdkPixbuf *pixbuf)
|
||||
{
|
||||
cairo_surface_t *dummy_surface;
|
||||
cairo_pattern_t *pattern;
|
||||
cairo_surface_t *surface;
|
||||
cairo_t *cr;
|
||||
|
||||
dummy_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 1, 1);
|
||||
|
||||
cr = cairo_create (dummy_surface);
|
||||
gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
|
||||
pattern = cairo_get_source (cr);
|
||||
cairo_pattern_get_surface (pattern, &surface);
|
||||
cairo_surface_reference (surface);
|
||||
cairo_destroy (cr);
|
||||
cairo_surface_destroy (dummy_surface);
|
||||
|
||||
return surface;
|
||||
}
|
||||
|
||||
static GdkPixbuf *
|
||||
load_pixbuf_fallback(AsyncTextureLoadData *data)
|
||||
{
|
||||
@ -1504,6 +1526,45 @@ out:
|
||||
return texdata;
|
||||
}
|
||||
|
||||
static cairo_surface_t *
|
||||
st_texture_cache_load_uri_sync_to_cairo_surface (StTextureCache *cache,
|
||||
StTextureCachePolicy policy,
|
||||
const gchar *uri,
|
||||
int available_width,
|
||||
int available_height,
|
||||
GError **error)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
GdkPixbuf *pixbuf;
|
||||
char *key;
|
||||
|
||||
key = g_strconcat (CACHE_PREFIX_URI_FOR_CAIRO, uri, NULL);
|
||||
|
||||
surface = g_hash_table_lookup (cache->priv->keyed_cache, key);
|
||||
|
||||
if (surface == NULL)
|
||||
{
|
||||
pixbuf = impl_load_pixbuf_file (uri, available_width, available_height, error);
|
||||
if (!pixbuf)
|
||||
goto out;
|
||||
|
||||
surface = pixbuf_to_cairo_surface (pixbuf);
|
||||
g_object_unref (pixbuf);
|
||||
|
||||
if (policy == ST_TEXTURE_CACHE_POLICY_FOREVER)
|
||||
{
|
||||
cairo_surface_reference (surface);
|
||||
g_hash_table_insert (cache->priv->keyed_cache, g_strdup (key), surface);
|
||||
}
|
||||
}
|
||||
else
|
||||
cairo_surface_reference (surface);
|
||||
|
||||
out:
|
||||
g_free (key);
|
||||
return surface;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_texture_cache_load_uri_sync:
|
||||
*
|
||||
@ -1582,6 +1643,43 @@ st_texture_cache_load_file_to_cogl_texture (StTextureCache *cache,
|
||||
return texture;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_texture_cache_load_file_to_cairo_surface:
|
||||
* @cache: A #StTextureCache
|
||||
* @file_path: Path to a file in supported image format
|
||||
*
|
||||
* This function synchronously loads the given file path
|
||||
* into a cairo surface. On error, a warning is emitted
|
||||
* and %NULL is returned.
|
||||
*
|
||||
* Returns: (transfer full): a new #cairo_surface_t *
|
||||
*/
|
||||
cairo_surface_t *
|
||||
st_texture_cache_load_file_to_cairo_surface (StTextureCache *cache,
|
||||
const gchar *file_path)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
GFile *file;
|
||||
char *uri;
|
||||
GError *error = NULL;
|
||||
|
||||
file = g_file_new_for_path (file_path);
|
||||
uri = g_file_get_uri (file);
|
||||
|
||||
surface = st_texture_cache_load_uri_sync_to_cairo_surface (cache, ST_TEXTURE_CACHE_POLICY_FOREVER,
|
||||
uri, -1, -1, &error);
|
||||
g_object_unref (file);
|
||||
g_free (uri);
|
||||
|
||||
if (surface == NULL)
|
||||
{
|
||||
g_warning ("Failed to load %s: %s", file_path, error->message);
|
||||
g_clear_error (&error);
|
||||
return NULL;
|
||||
}
|
||||
return surface;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_texture_cache_load_file_simple:
|
||||
* @cache: A #StTextureCache
|
||||
|
@ -119,6 +119,9 @@ ClutterActor *st_texture_cache_load_uri_sync (StTextureCache *cache,
|
||||
CoglHandle st_texture_cache_load_file_to_cogl_texture (StTextureCache *cache,
|
||||
const gchar *file_path);
|
||||
|
||||
cairo_surface_t *st_texture_cache_load_file_to_cairo_surface (StTextureCache *cache,
|
||||
const gchar *file_path);
|
||||
|
||||
ClutterActor *st_texture_cache_load_file_simple (StTextureCache *cache,
|
||||
const gchar *file_path);
|
||||
|
||||
|
@ -427,37 +427,37 @@ get_arbitrary_border_color (StThemeNode *node,
|
||||
st_theme_node_get_border_color (node, ST_SIDE_TOP, color);
|
||||
}
|
||||
|
||||
static CoglHandle
|
||||
st_theme_node_render_gradient (StThemeNode *node)
|
||||
static gboolean
|
||||
st_theme_node_has_visible_outline (StThemeNode *node)
|
||||
{
|
||||
if (node->background_color.alpha > 0)
|
||||
return TRUE;
|
||||
|
||||
if (node->background_gradient_end.alpha > 0)
|
||||
return TRUE;
|
||||
|
||||
if (node->border_radius[ST_CORNER_TOPLEFT] > 0 ||
|
||||
node->border_radius[ST_CORNER_TOPRIGHT] > 0 ||
|
||||
node->border_radius[ST_CORNER_BOTTOMLEFT] > 0 ||
|
||||
node->border_radius[ST_CORNER_BOTTOMRIGHT] > 0)
|
||||
return TRUE;
|
||||
|
||||
if (node->border_width[ST_SIDE_TOP] > 0 ||
|
||||
node->border_width[ST_SIDE_LEFT] > 0 ||
|
||||
node->border_width[ST_SIDE_RIGHT] > 0 ||
|
||||
node->border_width[ST_SIDE_BOTTOM] > 0)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static cairo_pattern_t *
|
||||
create_cairo_pattern_of_background_gradient (StThemeNode *node)
|
||||
{
|
||||
CoglHandle texture;
|
||||
int radius[4], i;
|
||||
cairo_t *cr;
|
||||
cairo_surface_t *surface;
|
||||
cairo_pattern_t *pattern;
|
||||
ClutterColor border_color;
|
||||
int border_width[4];
|
||||
guint rowstride;
|
||||
guchar *data;
|
||||
|
||||
rowstride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32, node->alloc_width);
|
||||
data = g_new0 (guchar, node->alloc_height * rowstride);
|
||||
surface = cairo_image_surface_create_for_data (data,
|
||||
CAIRO_FORMAT_ARGB32,
|
||||
node->alloc_width,
|
||||
node->alloc_height,
|
||||
rowstride);
|
||||
cr = cairo_create (surface);
|
||||
|
||||
/* TODO - support non-uniform border colors */
|
||||
get_arbitrary_border_color (node, &border_color);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
border_width[i] = st_theme_node_get_border_width (node, i);
|
||||
|
||||
radius[i] = st_theme_node_get_border_radius (node, i);
|
||||
}
|
||||
g_return_val_if_fail (node->background_gradient_type != ST_GRADIENT_NONE,
|
||||
NULL);
|
||||
|
||||
if (node->background_gradient_type == ST_GRADIENT_VERTICAL)
|
||||
pattern = cairo_pattern_create_linear (0, 0, 0, node->alloc_height);
|
||||
@ -482,45 +482,374 @@ st_theme_node_render_gradient (StThemeNode *node)
|
||||
node->background_gradient_end.green / 255.,
|
||||
node->background_gradient_end.blue / 255.,
|
||||
node->background_gradient_end.alpha / 255.);
|
||||
return pattern;
|
||||
}
|
||||
|
||||
static cairo_pattern_t *
|
||||
create_cairo_pattern_of_background_image (StThemeNode *node,
|
||||
gboolean *needs_background_fill)
|
||||
{
|
||||
cairo_surface_t *surface;
|
||||
cairo_pattern_t *pattern;
|
||||
cairo_content_t content;
|
||||
cairo_matrix_t matrix;
|
||||
const char *file;
|
||||
double height_ratio, width_ratio;
|
||||
int file_width;
|
||||
int file_height;
|
||||
|
||||
StTextureCache *texture_cache;
|
||||
|
||||
file = st_theme_node_get_background_image (node);
|
||||
|
||||
texture_cache = st_texture_cache_get_default ();
|
||||
|
||||
surface = st_texture_cache_load_file_to_cairo_surface (texture_cache, file);
|
||||
|
||||
if (surface == NULL)
|
||||
return NULL;
|
||||
|
||||
g_assert (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE);
|
||||
|
||||
content = cairo_surface_get_content (surface);
|
||||
pattern = cairo_pattern_create_for_surface (surface);
|
||||
|
||||
file_width = cairo_image_surface_get_width (surface);
|
||||
file_height = cairo_image_surface_get_height (surface);
|
||||
|
||||
height_ratio = file_height / node->alloc_height;
|
||||
width_ratio = file_width / node->alloc_width;
|
||||
|
||||
*needs_background_fill = TRUE;
|
||||
if ((file_width > node->alloc_width || file_height > node->alloc_height)
|
||||
&& !node->background_position_set)
|
||||
{
|
||||
double scale_factor;
|
||||
double x_offset, y_offset;
|
||||
|
||||
if (width_ratio > height_ratio)
|
||||
{
|
||||
double scaled_height;
|
||||
|
||||
/* center vertically */
|
||||
|
||||
scale_factor = width_ratio;
|
||||
scaled_height = file_height / scale_factor;
|
||||
|
||||
x_offset = 0.;
|
||||
y_offset = - (node->alloc_height / 2. - scaled_height / 2.);
|
||||
}
|
||||
else
|
||||
{
|
||||
double scaled_width;
|
||||
|
||||
/* center horizontally */
|
||||
|
||||
scale_factor = height_ratio;
|
||||
scaled_width = file_width / scale_factor;
|
||||
|
||||
y_offset = 0.;
|
||||
x_offset = - (node->alloc_width / 2. - scaled_width / 2.);
|
||||
}
|
||||
|
||||
cairo_matrix_init_translate (&matrix, x_offset, y_offset);
|
||||
cairo_matrix_scale (&matrix, scale_factor, scale_factor);
|
||||
|
||||
cairo_pattern_set_matrix (pattern, &matrix);
|
||||
|
||||
/* If it's opaque, and when scaled, fills up the entire allocated
|
||||
* area, then don't bother doing a background fill first
|
||||
*/
|
||||
if (content != CAIRO_CONTENT_COLOR_ALPHA && width_ratio == height_ratio)
|
||||
*needs_background_fill = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
double x_offset, y_offset;
|
||||
|
||||
if (node->background_position_set)
|
||||
{
|
||||
x_offset = -node->background_position_x;
|
||||
y_offset = -node->background_position_y;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (node->alloc_width > file_width)
|
||||
x_offset = - (node->alloc_width / 2.0 - file_width / 2.0);
|
||||
else
|
||||
x_offset = - (file_width / 2.0 - node->alloc_width / 2.0);
|
||||
|
||||
if (node->alloc_height > file_height)
|
||||
y_offset = - (node->alloc_height / 2.0 - file_height / 2.0);
|
||||
else
|
||||
y_offset = - (file_height / 2.0 - node->alloc_height / 2.0);
|
||||
}
|
||||
|
||||
/* If it's opaque, and when translated, fills up the entire allocated
|
||||
* area, then don't bother doing a background fill first
|
||||
*/
|
||||
if (content != CAIRO_CONTENT_COLOR_ALPHA
|
||||
&& -x_offset <= 0
|
||||
&& -x_offset + file_width >= node->alloc_width
|
||||
&& -y_offset <= 0
|
||||
&& -y_offset + file_height >= node->alloc_height)
|
||||
*needs_background_fill = FALSE;
|
||||
|
||||
cairo_matrix_init_translate (&matrix, x_offset, y_offset);
|
||||
cairo_pattern_set_matrix (pattern, &matrix);
|
||||
}
|
||||
|
||||
return pattern;
|
||||
}
|
||||
|
||||
static void
|
||||
paint_background_image_shadow_to_cairo_context (StThemeNode *node,
|
||||
StShadow *shadow_spec,
|
||||
cairo_pattern_t *pattern,
|
||||
cairo_t *cr,
|
||||
cairo_path_t *interior_path,
|
||||
cairo_path_t *outline_path,
|
||||
int x,
|
||||
int y,
|
||||
int width,
|
||||
int height)
|
||||
{
|
||||
cairo_pattern_t *shadow_pattern;
|
||||
|
||||
g_assert (shadow_spec != NULL);
|
||||
g_assert (pattern != NULL);
|
||||
|
||||
if (outline_path != NULL)
|
||||
{
|
||||
cairo_surface_t *clipped_surface;
|
||||
cairo_pattern_t *clipped_pattern;
|
||||
cairo_t *temp_cr;
|
||||
|
||||
/* Prerender the pattern to a temporary surface,
|
||||
* so it's properly clipped before we create a shadow from it
|
||||
*/
|
||||
clipped_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
|
||||
temp_cr = cairo_create (clipped_surface);
|
||||
|
||||
cairo_set_operator (temp_cr, CAIRO_OPERATOR_CLEAR);
|
||||
cairo_paint (temp_cr);
|
||||
cairo_set_operator (temp_cr, CAIRO_OPERATOR_SOURCE);
|
||||
|
||||
if (interior_path != NULL)
|
||||
{
|
||||
cairo_append_path (temp_cr, interior_path);
|
||||
cairo_clip (temp_cr);
|
||||
}
|
||||
|
||||
cairo_append_path (temp_cr, outline_path);
|
||||
cairo_translate (temp_cr, x, y);
|
||||
cairo_set_source (temp_cr, pattern);
|
||||
cairo_clip (temp_cr);
|
||||
cairo_paint (temp_cr);
|
||||
cairo_destroy (temp_cr);
|
||||
|
||||
clipped_pattern = cairo_pattern_create_for_surface (clipped_surface);
|
||||
cairo_surface_destroy (clipped_surface);
|
||||
|
||||
shadow_pattern = _st_create_shadow_cairo_pattern (shadow_spec,
|
||||
clipped_pattern);
|
||||
cairo_pattern_destroy (clipped_pattern);
|
||||
}
|
||||
else
|
||||
{
|
||||
shadow_pattern = _st_create_shadow_cairo_pattern (shadow_spec,
|
||||
pattern);
|
||||
}
|
||||
|
||||
/* Stamp the shadow pattern out in the appropriate color
|
||||
* in a new layer
|
||||
*/
|
||||
cairo_push_group (cr);
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
|
||||
cairo_set_source_rgba (cr,
|
||||
shadow_spec->color.red / 255.0,
|
||||
shadow_spec->color.green / 255.0,
|
||||
shadow_spec->color.blue / 255.0,
|
||||
shadow_spec->color.alpha / 255.0);
|
||||
cairo_paint (cr);
|
||||
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_DEST_IN);
|
||||
|
||||
cairo_set_source (cr, shadow_pattern);
|
||||
cairo_paint (cr);
|
||||
cairo_pattern_destroy (shadow_pattern);
|
||||
|
||||
cairo_pop_group_to_source (cr);
|
||||
|
||||
/* mask and merge the shadow
|
||||
*/
|
||||
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
|
||||
cairo_save (cr);
|
||||
if (interior_path != NULL)
|
||||
{
|
||||
/* If there are borders, clip the shadow to the interior
|
||||
* of the borders
|
||||
*/
|
||||
cairo_append_path (cr, interior_path);
|
||||
cairo_clip (cr);
|
||||
}
|
||||
else if (outline_path != NULL)
|
||||
{
|
||||
/* If there is a visible outline, clip the shadow to
|
||||
* that outline
|
||||
*/
|
||||
cairo_append_path (cr, outline_path);
|
||||
cairo_clip (cr);
|
||||
}
|
||||
|
||||
cairo_paint (cr);
|
||||
cairo_restore (cr);
|
||||
}
|
||||
|
||||
/* In order for borders to be smoothly blended with non-solid backgrounds,
|
||||
* we need to use cairo. This function is a slow fallback path for those
|
||||
* cases (gradients, background images, etc).
|
||||
*/
|
||||
static CoglHandle
|
||||
st_theme_node_render_background_with_border (StThemeNode *node)
|
||||
{
|
||||
StBorderImage *border_image;
|
||||
CoglHandle texture;
|
||||
int radius[4], i;
|
||||
cairo_t *cr;
|
||||
cairo_surface_t *surface;
|
||||
StShadow *shadow_spec;
|
||||
cairo_pattern_t *pattern = NULL;
|
||||
cairo_path_t *outline_path = NULL;
|
||||
gboolean draw_solid_background = TRUE;
|
||||
gboolean draw_background_image_shadow = FALSE;
|
||||
gboolean has_visible_outline;
|
||||
ClutterColor border_color;
|
||||
int border_width[4];
|
||||
guint rowstride;
|
||||
guchar *data;
|
||||
ClutterActorBox actor_box;
|
||||
ClutterActorBox paint_box;
|
||||
cairo_path_t *interior_path = NULL;
|
||||
|
||||
border_image = st_theme_node_get_border_image (node);
|
||||
|
||||
shadow_spec = st_theme_node_get_background_image_shadow (node);
|
||||
|
||||
actor_box.x1 = 0;
|
||||
actor_box.x2 = node->alloc_width;
|
||||
actor_box.y1 = 0;
|
||||
actor_box.y2 = node->alloc_height;
|
||||
|
||||
/* If there's a background image shadow, we
|
||||
* may need to create an image bigger than the nodes
|
||||
* allocation
|
||||
*/
|
||||
st_theme_node_get_paint_box (node, &actor_box, &paint_box);
|
||||
|
||||
/* translate the boxes so the paint box is at 0,0
|
||||
*/
|
||||
actor_box.x1 += - paint_box.x1;
|
||||
actor_box.x2 += - paint_box.x1;
|
||||
actor_box.y1 += - paint_box.y1;
|
||||
actor_box.y2 += - paint_box.y1;
|
||||
|
||||
paint_box.x2 += - paint_box.x1;
|
||||
paint_box.x1 += - paint_box.x1;
|
||||
paint_box.y2 += - paint_box.y1;
|
||||
paint_box.y1 += - paint_box.y1;
|
||||
|
||||
rowstride = cairo_format_stride_for_width (CAIRO_FORMAT_ARGB32,
|
||||
paint_box.x2 - paint_box.x1);
|
||||
data = g_new0 (guchar, (paint_box.y2 - paint_box.y1) * rowstride);
|
||||
surface = cairo_image_surface_create_for_data (data,
|
||||
CAIRO_FORMAT_ARGB32,
|
||||
paint_box.x2 - paint_box.x1,
|
||||
paint_box.y2 - paint_box.y1,
|
||||
rowstride);
|
||||
cr = cairo_create (surface);
|
||||
|
||||
/* TODO - support non-uniform border colors */
|
||||
get_arbitrary_border_color (node, &border_color);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
border_width[i] = st_theme_node_get_border_width (node, i);
|
||||
|
||||
radius[i] = st_theme_node_get_border_radius (node, i);
|
||||
}
|
||||
|
||||
/* Note we don't support translucent background images on top
|
||||
* of gradients. It's strictly either/or.
|
||||
*/
|
||||
if (node->background_gradient_type != ST_GRADIENT_NONE)
|
||||
{
|
||||
pattern = create_cairo_pattern_of_background_gradient (node);
|
||||
draw_solid_background = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *background_image;
|
||||
|
||||
background_image = st_theme_node_get_background_image (node);
|
||||
|
||||
if (background_image != NULL)
|
||||
{
|
||||
pattern = create_cairo_pattern_of_background_image (node,
|
||||
&draw_solid_background);
|
||||
if (shadow_spec && pattern != NULL)
|
||||
draw_background_image_shadow = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (pattern == NULL)
|
||||
draw_solid_background = TRUE;
|
||||
|
||||
has_visible_outline = st_theme_node_has_visible_outline (node);
|
||||
|
||||
/* Create a path for the background's outline first */
|
||||
if (radius[ST_CORNER_TOPLEFT] > 0)
|
||||
cairo_arc (cr,
|
||||
radius[ST_CORNER_TOPLEFT],
|
||||
radius[ST_CORNER_TOPLEFT],
|
||||
actor_box.x1 + radius[ST_CORNER_TOPLEFT],
|
||||
actor_box.y1 + radius[ST_CORNER_TOPLEFT],
|
||||
radius[ST_CORNER_TOPLEFT], M_PI, 3 * M_PI / 2);
|
||||
else
|
||||
cairo_move_to (cr, 0, 0);
|
||||
cairo_line_to (cr, node->alloc_width - radius[ST_CORNER_TOPRIGHT], 0);
|
||||
cairo_move_to (cr, actor_box.x1, actor_box.y1);
|
||||
cairo_line_to (cr, actor_box.x2 - radius[ST_CORNER_TOPRIGHT], actor_box.x1);
|
||||
if (radius[ST_CORNER_TOPRIGHT] > 0)
|
||||
cairo_arc (cr,
|
||||
node->alloc_width - radius[ST_CORNER_TOPRIGHT],
|
||||
radius[ST_CORNER_TOPRIGHT],
|
||||
actor_box.x2 - radius[ST_CORNER_TOPRIGHT],
|
||||
actor_box.x1 + radius[ST_CORNER_TOPRIGHT],
|
||||
radius[ST_CORNER_TOPRIGHT], 3 * M_PI / 2, 2 * M_PI);
|
||||
cairo_line_to (cr, node->alloc_width, node->alloc_height - radius[ST_CORNER_BOTTOMRIGHT]);
|
||||
cairo_line_to (cr, actor_box.x2, actor_box.y2 - radius[ST_CORNER_BOTTOMRIGHT]);
|
||||
if (radius[ST_CORNER_BOTTOMRIGHT] > 0)
|
||||
cairo_arc (cr,
|
||||
node->alloc_width - radius[ST_CORNER_BOTTOMRIGHT],
|
||||
node->alloc_height - radius[ST_CORNER_BOTTOMRIGHT],
|
||||
actor_box.x2 - radius[ST_CORNER_BOTTOMRIGHT],
|
||||
actor_box.y2 - radius[ST_CORNER_BOTTOMRIGHT],
|
||||
radius[ST_CORNER_BOTTOMRIGHT], 0, M_PI / 2);
|
||||
cairo_line_to (cr, radius[ST_CORNER_BOTTOMLEFT], node->alloc_height);
|
||||
cairo_line_to (cr, actor_box.x1 + radius[ST_CORNER_BOTTOMLEFT], actor_box.y2);
|
||||
if (radius[ST_CORNER_BOTTOMLEFT] > 0)
|
||||
cairo_arc (cr,
|
||||
radius[ST_CORNER_BOTTOMLEFT],
|
||||
node->alloc_height - radius[ST_CORNER_BOTTOMLEFT],
|
||||
actor_box.x1 + radius[ST_CORNER_BOTTOMLEFT],
|
||||
actor_box.y2 - radius[ST_CORNER_BOTTOMLEFT],
|
||||
radius[ST_CORNER_BOTTOMLEFT], M_PI / 2, M_PI);
|
||||
cairo_close_path (cr);
|
||||
|
||||
outline_path = cairo_copy_path (cr);
|
||||
|
||||
/* If we have a border, we fill the outline with the border
|
||||
* color and create the inline shape for the background gradient;
|
||||
/* If we have a solid border, we fill the outline shape with the border
|
||||
* color and create the inline shape for the background;
|
||||
* otherwise the outline shape is filled with the background
|
||||
* gradient directly
|
||||
* directly
|
||||
*/
|
||||
if (border_width[ST_SIDE_TOP] > 0 ||
|
||||
border_width[ST_SIDE_RIGHT] > 0 ||
|
||||
border_width[ST_SIDE_BOTTOM] > 0 ||
|
||||
border_width[ST_SIDE_LEFT] > 0)
|
||||
if (border_image == NULL &&
|
||||
(border_width[ST_SIDE_TOP] > 0 ||
|
||||
border_width[ST_SIDE_RIGHT] > 0 ||
|
||||
border_width[ST_SIDE_BOTTOM] > 0 ||
|
||||
border_width[ST_SIDE_LEFT] > 0))
|
||||
{
|
||||
cairo_set_source_rgba (cr,
|
||||
border_color.red / 255.,
|
||||
@ -532,76 +861,124 @@ st_theme_node_render_gradient (StThemeNode *node)
|
||||
if (radius[ST_CORNER_TOPLEFT] > MAX(border_width[ST_SIDE_TOP],
|
||||
border_width[ST_SIDE_LEFT]))
|
||||
elliptical_arc (cr,
|
||||
radius[ST_CORNER_TOPLEFT],
|
||||
radius[ST_CORNER_TOPLEFT],
|
||||
actor_box.x1 + radius[ST_CORNER_TOPLEFT],
|
||||
actor_box.y1 + radius[ST_CORNER_TOPLEFT],
|
||||
radius[ST_CORNER_TOPLEFT] - border_width[ST_SIDE_LEFT],
|
||||
radius[ST_CORNER_TOPLEFT] - border_width[ST_SIDE_TOP],
|
||||
M_PI, 3 * M_PI / 2);
|
||||
else
|
||||
cairo_move_to (cr,
|
||||
border_width[ST_SIDE_LEFT],
|
||||
border_width[ST_SIDE_TOP]);
|
||||
actor_box.x1 + border_width[ST_SIDE_LEFT],
|
||||
actor_box.y1 + border_width[ST_SIDE_TOP]);
|
||||
|
||||
cairo_line_to (cr,
|
||||
node->alloc_width - MAX(radius[ST_CORNER_TOPRIGHT], border_width[ST_SIDE_RIGHT]),
|
||||
border_width[ST_SIDE_TOP]);
|
||||
actor_box.x2 - MAX(radius[ST_CORNER_TOPRIGHT], border_width[ST_SIDE_RIGHT]),
|
||||
actor_box.y1 + border_width[ST_SIDE_TOP]);
|
||||
|
||||
if (radius[ST_CORNER_TOPRIGHT] > MAX(border_width[ST_SIDE_TOP],
|
||||
border_width[ST_SIDE_RIGHT]))
|
||||
elliptical_arc (cr,
|
||||
node->alloc_width - radius[ST_CORNER_TOPRIGHT],
|
||||
radius[ST_CORNER_TOPRIGHT],
|
||||
actor_box.x2 - radius[ST_CORNER_TOPRIGHT],
|
||||
actor_box.y1 + radius[ST_CORNER_TOPRIGHT],
|
||||
radius[ST_CORNER_TOPRIGHT] - border_width[ST_SIDE_RIGHT],
|
||||
radius[ST_CORNER_TOPRIGHT] - border_width[ST_SIDE_TOP],
|
||||
3 * M_PI / 2, 2 * M_PI);
|
||||
else
|
||||
cairo_line_to (cr,
|
||||
node->alloc_width - border_width[ST_SIDE_RIGHT],
|
||||
border_width[ST_SIDE_TOP]);
|
||||
actor_box.x2 - border_width[ST_SIDE_RIGHT],
|
||||
actor_box.y1 + border_width[ST_SIDE_TOP]);
|
||||
|
||||
cairo_line_to (cr,
|
||||
node->alloc_width - border_width[ST_SIDE_RIGHT],
|
||||
node->alloc_height - MAX(radius[ST_CORNER_BOTTOMRIGHT], border_width[ST_SIDE_BOTTOM]));
|
||||
actor_box.x2 - border_width[ST_SIDE_RIGHT],
|
||||
actor_box.y2 - MAX(radius[ST_CORNER_BOTTOMRIGHT], border_width[ST_SIDE_BOTTOM]));
|
||||
|
||||
if (radius[ST_CORNER_BOTTOMRIGHT] > MAX(border_width[ST_SIDE_BOTTOM],
|
||||
border_width[ST_SIDE_RIGHT]))
|
||||
elliptical_arc (cr,
|
||||
node->alloc_width - radius[ST_CORNER_BOTTOMRIGHT],
|
||||
node->alloc_height - radius[ST_CORNER_BOTTOMRIGHT],
|
||||
actor_box.x2 - radius[ST_CORNER_BOTTOMRIGHT],
|
||||
actor_box.y2 - radius[ST_CORNER_BOTTOMRIGHT],
|
||||
radius[ST_CORNER_BOTTOMRIGHT] - border_width[ST_SIDE_RIGHT],
|
||||
radius[ST_CORNER_BOTTOMRIGHT] - border_width[ST_SIDE_BOTTOM],
|
||||
0, M_PI / 2);
|
||||
else
|
||||
cairo_line_to (cr,
|
||||
node->alloc_width - border_width[ST_SIDE_RIGHT],
|
||||
node->alloc_height - border_width[ST_SIDE_BOTTOM]);
|
||||
actor_box.x2 - border_width[ST_SIDE_RIGHT],
|
||||
actor_box.y2 - border_width[ST_SIDE_BOTTOM]);
|
||||
|
||||
cairo_line_to (cr,
|
||||
MAX(radius[ST_CORNER_BOTTOMLEFT], border_width[ST_SIDE_LEFT]),
|
||||
node->alloc_height - border_width[ST_SIDE_BOTTOM]);
|
||||
actor_box.y2 - border_width[ST_SIDE_BOTTOM]);
|
||||
|
||||
if (radius[ST_CORNER_BOTTOMLEFT] > MAX(border_width[ST_SIDE_BOTTOM],
|
||||
border_width[ST_SIDE_LEFT]))
|
||||
elliptical_arc (cr,
|
||||
radius[ST_CORNER_BOTTOMLEFT],
|
||||
node->alloc_height - radius[ST_CORNER_BOTTOMLEFT],
|
||||
actor_box.x1 + radius[ST_CORNER_BOTTOMLEFT],
|
||||
actor_box.y2 - radius[ST_CORNER_BOTTOMLEFT],
|
||||
radius[ST_CORNER_BOTTOMLEFT] - border_width[ST_SIDE_LEFT],
|
||||
radius[ST_CORNER_BOTTOMLEFT] - border_width[ST_SIDE_BOTTOM],
|
||||
M_PI / 2, M_PI);
|
||||
else
|
||||
cairo_line_to (cr,
|
||||
border_width[ST_SIDE_LEFT],
|
||||
node->alloc_height - border_width[ST_SIDE_BOTTOM]);
|
||||
actor_box.x1 + border_width[ST_SIDE_LEFT],
|
||||
actor_box.y2 - border_width[ST_SIDE_BOTTOM]);
|
||||
|
||||
cairo_close_path (cr);
|
||||
|
||||
interior_path = cairo_copy_path (cr);
|
||||
|
||||
/* clip drawing to the region inside of the borders
|
||||
*/
|
||||
cairo_clip (cr);
|
||||
|
||||
/* But fill the pattern as if it started at the edge of outline,
|
||||
* behind the borders. This is similar to
|
||||
* background-clip: border-box; semantics.
|
||||
*/
|
||||
cairo_append_path (cr, outline_path);
|
||||
}
|
||||
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_fill (cr);
|
||||
if (draw_solid_background)
|
||||
{
|
||||
cairo_set_source_rgba (cr,
|
||||
node->background_color.red / 255.,
|
||||
node->background_color.green / 255.,
|
||||
node->background_color.blue / 255.,
|
||||
node->background_color.alpha / 255.);
|
||||
cairo_fill_preserve (cr);
|
||||
}
|
||||
|
||||
cairo_pattern_destroy (pattern);
|
||||
if (draw_background_image_shadow)
|
||||
{
|
||||
paint_background_image_shadow_to_cairo_context (node,
|
||||
shadow_spec,
|
||||
pattern,
|
||||
cr,
|
||||
interior_path,
|
||||
has_visible_outline? outline_path : NULL,
|
||||
actor_box.x1,
|
||||
actor_box.y1,
|
||||
paint_box.x2 - paint_box.x1,
|
||||
paint_box.y2 - paint_box.y1);
|
||||
cairo_append_path (cr, outline_path);
|
||||
}
|
||||
|
||||
texture = cogl_texture_new_from_data (node->alloc_width, node->alloc_height,
|
||||
cairo_translate (cr, actor_box.x1, actor_box.y1);
|
||||
|
||||
if (pattern != NULL)
|
||||
{
|
||||
cairo_set_source (cr, pattern);
|
||||
cairo_fill (cr);
|
||||
cairo_pattern_destroy (pattern);
|
||||
}
|
||||
|
||||
if (outline_path != NULL)
|
||||
cairo_path_destroy (outline_path);
|
||||
|
||||
if (interior_path != NULL)
|
||||
cairo_path_destroy (interior_path);
|
||||
|
||||
texture = cogl_texture_new_from_data (paint_box.x2 - paint_box.x1,
|
||||
paint_box.y2 - paint_box.y1,
|
||||
COGL_TEXTURE_NONE,
|
||||
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
|
||||
COGL_PIXEL_FORMAT_BGRA_8888_PRE,
|
||||
@ -633,12 +1010,16 @@ _st_theme_node_free_drawing_state (StThemeNode *node)
|
||||
cogl_handle_unref (node->background_material);
|
||||
if (node->background_shadow_material != COGL_INVALID_HANDLE)
|
||||
cogl_handle_unref (node->background_shadow_material);
|
||||
if (node->border_texture != COGL_INVALID_HANDLE)
|
||||
cogl_handle_unref (node->border_texture);
|
||||
if (node->border_material != COGL_INVALID_HANDLE)
|
||||
cogl_handle_unref (node->border_material);
|
||||
if (node->border_shadow_material != COGL_INVALID_HANDLE)
|
||||
cogl_handle_unref (node->border_shadow_material);
|
||||
if (node->border_slices_texture != COGL_INVALID_HANDLE)
|
||||
cogl_handle_unref (node->border_slices_texture);
|
||||
if (node->border_slices_material != COGL_INVALID_HANDLE)
|
||||
cogl_handle_unref (node->border_slices_material);
|
||||
if (node->prerendered_texture != COGL_INVALID_HANDLE)
|
||||
cogl_handle_unref (node->prerendered_texture);
|
||||
if (node->prerendered_material != COGL_INVALID_HANDLE)
|
||||
cogl_handle_unref (node->prerendered_material);
|
||||
if (node->box_shadow_material != COGL_INVALID_HANDLE)
|
||||
cogl_handle_unref (node->box_shadow_material);
|
||||
|
||||
for (corner_id = 0; corner_id < 4; corner_id++)
|
||||
if (node->corner_material[corner_id] != COGL_INVALID_HANDLE)
|
||||
@ -655,9 +1036,11 @@ _st_theme_node_init_drawing_state (StThemeNode *node)
|
||||
node->background_texture = COGL_INVALID_HANDLE;
|
||||
node->background_material = COGL_INVALID_HANDLE;
|
||||
node->background_shadow_material = COGL_INVALID_HANDLE;
|
||||
node->border_shadow_material = COGL_INVALID_HANDLE;
|
||||
node->border_texture = COGL_INVALID_HANDLE;
|
||||
node->border_material = COGL_INVALID_HANDLE;
|
||||
node->box_shadow_material = COGL_INVALID_HANDLE;
|
||||
node->border_slices_texture = COGL_INVALID_HANDLE;
|
||||
node->border_slices_material = COGL_INVALID_HANDLE;
|
||||
node->prerendered_texture = COGL_INVALID_HANDLE;
|
||||
node->prerendered_material = COGL_INVALID_HANDLE;
|
||||
|
||||
for (corner_id = 0; corner_id < 4; corner_id++)
|
||||
node->corner_material[corner_id] = COGL_INVALID_HANDLE;
|
||||
@ -674,7 +1057,10 @@ st_theme_node_render_resources (StThemeNode *node,
|
||||
{
|
||||
StTextureCache *texture_cache;
|
||||
StBorderImage *border_image;
|
||||
StShadow *shadow_spec;
|
||||
gboolean has_border;
|
||||
gboolean has_border_radius;
|
||||
StShadow *box_shadow_spec;
|
||||
StShadow *background_image_shadow_spec;
|
||||
const char *background_image;
|
||||
|
||||
texture_cache = st_texture_cache_get_default ();
|
||||
@ -691,39 +1077,68 @@ st_theme_node_render_resources (StThemeNode *node,
|
||||
_st_theme_node_ensure_background (node);
|
||||
_st_theme_node_ensure_geometry (node);
|
||||
|
||||
shadow_spec = st_theme_node_get_shadow (node);
|
||||
box_shadow_spec = st_theme_node_get_box_shadow (node);
|
||||
|
||||
if (node->border_width[ST_SIDE_TOP] > 0 ||
|
||||
node->border_width[ST_SIDE_LEFT] > 0 ||
|
||||
node->border_width[ST_SIDE_RIGHT] > 0 ||
|
||||
node->border_width[ST_SIDE_BOTTOM] > 0)
|
||||
has_border = TRUE;
|
||||
else
|
||||
has_border = FALSE;
|
||||
|
||||
if (node->border_radius[ST_CORNER_TOPLEFT] > 0 ||
|
||||
node->border_radius[ST_CORNER_TOPRIGHT] > 0 ||
|
||||
node->border_radius[ST_CORNER_BOTTOMLEFT] > 0 ||
|
||||
node->border_radius[ST_CORNER_BOTTOMRIGHT] > 0)
|
||||
has_border_radius = TRUE;
|
||||
else
|
||||
has_border_radius = FALSE;
|
||||
|
||||
/* Load referenced images from disk and draw anything we need with cairo now */
|
||||
|
||||
background_image = st_theme_node_get_background_image (node);
|
||||
border_image = st_theme_node_get_border_image (node);
|
||||
|
||||
if (border_image)
|
||||
{
|
||||
const char *filename;
|
||||
|
||||
filename = st_border_image_get_filename (border_image);
|
||||
|
||||
node->border_texture = st_texture_cache_load_file_to_cogl_texture (texture_cache, filename);
|
||||
}
|
||||
else if (node->background_gradient_type != ST_GRADIENT_NONE)
|
||||
{
|
||||
node->border_texture = st_theme_node_render_gradient (node);
|
||||
node->border_slices_texture = st_texture_cache_load_file_to_cogl_texture (texture_cache, filename);
|
||||
}
|
||||
|
||||
if (node->border_texture)
|
||||
node->border_material = _st_create_texture_material (node->border_texture);
|
||||
if (node->border_slices_texture)
|
||||
node->border_slices_material = _st_create_texture_material (node->border_slices_texture);
|
||||
else
|
||||
node->border_material = COGL_INVALID_HANDLE;
|
||||
node->border_slices_material = COGL_INVALID_HANDLE;
|
||||
|
||||
if (shadow_spec)
|
||||
/* Use cairo to prerender the node if there is a gradient, or
|
||||
* background image with borders and/or rounded corners,
|
||||
* since we can't do those things easily with cogl.
|
||||
*
|
||||
* FIXME: if we could figure out ahead of time that a
|
||||
* background image won't overlap with the node borders,
|
||||
* then we could use cogl for that case.
|
||||
*/
|
||||
if ((node->background_gradient_type != ST_GRADIENT_NONE)
|
||||
|| (background_image && (has_border || has_border_radius)))
|
||||
node->prerendered_texture = st_theme_node_render_background_with_border (node);
|
||||
|
||||
if (node->prerendered_texture)
|
||||
node->prerendered_material = _st_create_texture_material (node->prerendered_texture);
|
||||
else
|
||||
node->prerendered_material = COGL_INVALID_HANDLE;
|
||||
|
||||
if (box_shadow_spec)
|
||||
{
|
||||
if (node->border_texture != COGL_INVALID_HANDLE)
|
||||
node->border_shadow_material = _st_create_shadow_material (shadow_spec,
|
||||
node->border_texture);
|
||||
else if (node->background_color.alpha > 0 ||
|
||||
node->border_width[ST_SIDE_TOP] > 0 ||
|
||||
node->border_width[ST_SIDE_LEFT] > 0 ||
|
||||
node->border_width[ST_SIDE_RIGHT] > 0 ||
|
||||
node->border_width[ST_SIDE_BOTTOM] > 0)
|
||||
if (node->border_slices_texture != COGL_INVALID_HANDLE)
|
||||
node->box_shadow_material = _st_create_shadow_material (box_shadow_spec,
|
||||
node->border_slices_texture);
|
||||
else if (node->prerendered_texture != COGL_INVALID_HANDLE)
|
||||
node->box_shadow_material = _st_create_shadow_material (box_shadow_spec,
|
||||
node->prerendered_texture);
|
||||
else if (node->background_color.alpha > 0 || has_border)
|
||||
{
|
||||
CoglHandle buffer, offscreen;
|
||||
|
||||
@ -743,23 +1158,50 @@ st_theme_node_render_resources (StThemeNode *node,
|
||||
cogl_pop_framebuffer ();
|
||||
cogl_handle_unref (offscreen);
|
||||
|
||||
node->border_shadow_material = _st_create_shadow_material (shadow_spec,
|
||||
buffer);
|
||||
node->box_shadow_material = _st_create_shadow_material (box_shadow_spec,
|
||||
buffer);
|
||||
}
|
||||
cogl_handle_unref (buffer);
|
||||
}
|
||||
}
|
||||
|
||||
background_image = st_theme_node_get_background_image (node);
|
||||
if (background_image != NULL)
|
||||
background_image_shadow_spec = st_theme_node_get_background_image_shadow (node);
|
||||
if (background_image != NULL && !has_border && !has_border_radius)
|
||||
{
|
||||
CoglHandle texture;
|
||||
|
||||
texture = st_texture_cache_load_file_to_cogl_texture (texture_cache, background_image);
|
||||
|
||||
/* If no background position is specified, then we will automatically scale
|
||||
* the background to fit within the node allocation. But, if a background
|
||||
* position is specified, we won't scale the background, and it could
|
||||
* potentially leak out of bounds. To prevent that, we subtexture from the
|
||||
* in bounds area when necessary.
|
||||
*/
|
||||
if (node->background_position_set &&
|
||||
(cogl_texture_get_width (texture) > width ||
|
||||
cogl_texture_get_height (texture) > height))
|
||||
{
|
||||
CoglHandle subtexture;
|
||||
|
||||
subtexture = cogl_texture_new_from_sub_texture (texture,
|
||||
0, 0,
|
||||
width - node->background_position_x,
|
||||
height - node->background_position_y);
|
||||
cogl_handle_unref (texture);
|
||||
|
||||
node->background_texture = subtexture;
|
||||
}
|
||||
else
|
||||
{
|
||||
node->background_texture = texture;
|
||||
}
|
||||
|
||||
node->background_texture = st_texture_cache_load_file_to_cogl_texture (texture_cache, background_image);
|
||||
node->background_material = _st_create_texture_material (node->background_texture);
|
||||
|
||||
if (shadow_spec)
|
||||
if (background_image_shadow_spec)
|
||||
{
|
||||
node->background_shadow_material = _st_create_shadow_material (shadow_spec,
|
||||
node->background_shadow_material = _st_create_shadow_material (background_image_shadow_spec,
|
||||
node->background_texture);
|
||||
}
|
||||
}
|
||||
@ -1069,8 +1511,8 @@ st_theme_node_paint_sliced_border_image (StThemeNode *node,
|
||||
st_border_image_get_borders (border_image,
|
||||
&border_left, &border_right, &border_top, &border_bottom);
|
||||
|
||||
img_width = cogl_texture_get_width (node->border_texture);
|
||||
img_height = cogl_texture_get_height (node->border_texture);
|
||||
img_width = cogl_texture_get_width (node->border_slices_texture);
|
||||
img_height = cogl_texture_get_height (node->border_slices_texture);
|
||||
|
||||
tx1 = border_left / img_width;
|
||||
tx2 = (img_width - border_right) / img_width;
|
||||
@ -1085,7 +1527,7 @@ st_theme_node_paint_sliced_border_image (StThemeNode *node,
|
||||
if (ey < 0)
|
||||
ey = border_bottom; /* FIXME ? */
|
||||
|
||||
material = node->border_material;
|
||||
material = node->border_slices_material;
|
||||
cogl_material_set_color4ub (material,
|
||||
paint_opacity, paint_opacity, paint_opacity, paint_opacity);
|
||||
|
||||
@ -1230,41 +1672,58 @@ st_theme_node_paint (StThemeNode *node,
|
||||
* - The combination of border image and a non-zero border radius is
|
||||
* not supported; the background color will be drawn with square
|
||||
* corners.
|
||||
* - The combination of border image and a background gradient is not
|
||||
* supported; the background will be drawn as a solid color
|
||||
* - The background image is drawn above the border color or image,
|
||||
* not below it.
|
||||
* - We don't clip the background image to the (rounded) border area.
|
||||
*
|
||||
* The first three allow us to always draw with no more than a single
|
||||
* border_image and a single background image above it.
|
||||
* - The background image is drawn above the border color, not below it.
|
||||
* - We clip the background image to the inside edges of the border
|
||||
* instead of the outside edges of the border (but position the image
|
||||
* such that it's aligned to the outside edges)
|
||||
*/
|
||||
|
||||
if (node->border_shadow_material)
|
||||
_st_paint_shadow_with_opacity (node->shadow,
|
||||
node->border_shadow_material,
|
||||
if (node->box_shadow_material)
|
||||
_st_paint_shadow_with_opacity (node->box_shadow,
|
||||
node->box_shadow_material,
|
||||
&allocation,
|
||||
paint_opacity);
|
||||
|
||||
if (node->border_material != COGL_INVALID_HANDLE)
|
||||
if (node->prerendered_material != COGL_INVALID_HANDLE ||
|
||||
node->border_slices_material != COGL_INVALID_HANDLE)
|
||||
{
|
||||
/* Gradients and border images are mutually exclusive at this time */
|
||||
if (node->background_gradient_type != ST_GRADIENT_NONE)
|
||||
paint_material_with_opacity (node->border_material, &allocation, paint_opacity);
|
||||
else
|
||||
if (node->prerendered_material != COGL_INVALID_HANDLE)
|
||||
{
|
||||
ClutterActorBox paint_box;
|
||||
|
||||
st_theme_node_get_paint_box (node, &allocation, &paint_box);
|
||||
|
||||
paint_material_with_opacity (node->prerendered_material,
|
||||
&paint_box,
|
||||
paint_opacity);
|
||||
}
|
||||
|
||||
if (node->border_slices_material != COGL_INVALID_HANDLE)
|
||||
st_theme_node_paint_sliced_border_image (node, &allocation, paint_opacity);
|
||||
}
|
||||
else
|
||||
st_theme_node_paint_borders (node, box, paint_opacity);
|
||||
{
|
||||
st_theme_node_paint_borders (node, box, paint_opacity);
|
||||
}
|
||||
|
||||
st_theme_node_paint_outline (node, box, paint_opacity);
|
||||
|
||||
if (node->background_texture != COGL_INVALID_HANDLE)
|
||||
{
|
||||
ClutterActorBox background_box;
|
||||
gboolean has_visible_outline;
|
||||
|
||||
/* If the background doesn't have a border or opaque background,
|
||||
* then we let its background image shadows leak out, but other
|
||||
* wise we clip it.
|
||||
*/
|
||||
has_visible_outline = st_theme_node_has_visible_outline (node);
|
||||
|
||||
get_background_position (node, &allocation, &background_box);
|
||||
|
||||
if (has_visible_outline)
|
||||
cogl_clip_push_rectangle (allocation.x1, allocation.y1, allocation.x2, allocation.y2);
|
||||
|
||||
/* CSS based drop shadows
|
||||
*
|
||||
* Drop shadows in ST are modelled after the CSS3 box-shadow property;
|
||||
@ -1274,16 +1733,20 @@ st_theme_node_paint (StThemeNode *node,
|
||||
* multiple shadows and allow for a more liberal placement of the color
|
||||
* parameter - its interpretation defers significantly in that the shadow's
|
||||
* shape is not determined by the bounding box, but by the CSS background
|
||||
* image (we could exend this in the future to take other CSS properties
|
||||
* like boder and background color into account).
|
||||
* image. The drop shadows are allowed to escape the nodes allocation if
|
||||
* there is nothing (like a border, or the edge of the background color)
|
||||
* to logically confine it.
|
||||
*/
|
||||
if (node->background_shadow_material != COGL_INVALID_HANDLE)
|
||||
_st_paint_shadow_with_opacity (node->shadow,
|
||||
_st_paint_shadow_with_opacity (node->background_image_shadow,
|
||||
node->background_shadow_material,
|
||||
&background_box,
|
||||
paint_opacity);
|
||||
|
||||
paint_material_with_opacity (node->background_material, &background_box, paint_opacity);
|
||||
|
||||
if (has_visible_outline)
|
||||
cogl_clip_pop ();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1316,16 +1779,20 @@ st_theme_node_copy_cached_paint_state (StThemeNode *node,
|
||||
|
||||
if (other->background_shadow_material)
|
||||
node->background_shadow_material = cogl_handle_ref (other->background_shadow_material);
|
||||
if (other->border_shadow_material)
|
||||
node->border_shadow_material = cogl_handle_ref (other->border_shadow_material);
|
||||
if (other->box_shadow_material)
|
||||
node->box_shadow_material = cogl_handle_ref (other->box_shadow_material);
|
||||
if (other->background_texture)
|
||||
node->background_texture = cogl_handle_ref (other->background_texture);
|
||||
if (other->background_material)
|
||||
node->background_material = cogl_handle_ref (other->background_material);
|
||||
if (other->border_texture)
|
||||
node->border_texture = cogl_handle_ref (other->border_texture);
|
||||
if (other->border_material)
|
||||
node->border_material = cogl_handle_ref (other->border_material);
|
||||
if (other->border_slices_texture)
|
||||
node->border_slices_texture = cogl_handle_ref (other->border_slices_texture);
|
||||
if (other->border_slices_material)
|
||||
node->border_slices_material = cogl_handle_ref (other->border_slices_material);
|
||||
if (other->prerendered_texture)
|
||||
node->prerendered_texture = cogl_handle_ref (other->prerendered_texture);
|
||||
if (other->prerendered_material)
|
||||
node->prerendered_material = cogl_handle_ref (other->prerendered_material);
|
||||
for (corner_id = 0; corner_id < 4; corner_id++)
|
||||
if (other->corner_material[corner_id])
|
||||
node->corner_material[corner_id] = cogl_handle_ref (other->corner_material[corner_id]);
|
||||
|
@ -65,7 +65,8 @@ struct _StThemeNode {
|
||||
|
||||
char *background_image;
|
||||
StBorderImage *border_image;
|
||||
StShadow *shadow;
|
||||
StShadow *box_shadow;
|
||||
StShadow *background_image_shadow;
|
||||
StShadow *text_shadow;
|
||||
StIconColors *icon_colors;
|
||||
|
||||
@ -86,7 +87,8 @@ struct _StThemeNode {
|
||||
guint background_computed : 1;
|
||||
guint foreground_computed : 1;
|
||||
guint border_image_computed : 1;
|
||||
guint shadow_computed : 1;
|
||||
guint box_shadow_computed : 1;
|
||||
guint background_image_shadow_computed : 1;
|
||||
guint text_shadow_computed : 1;
|
||||
guint link_type : 2;
|
||||
|
||||
@ -95,11 +97,13 @@ struct _StThemeNode {
|
||||
float alloc_height;
|
||||
|
||||
CoglHandle background_shadow_material;
|
||||
CoglHandle border_shadow_material;
|
||||
CoglHandle box_shadow_material;
|
||||
CoglHandle background_texture;
|
||||
CoglHandle background_material;
|
||||
CoglHandle border_texture;
|
||||
CoglHandle border_material;
|
||||
CoglHandle border_slices_texture;
|
||||
CoglHandle border_slices_material;
|
||||
CoglHandle prerendered_texture;
|
||||
CoglHandle prerendered_material;
|
||||
CoglHandle corner_material[4];
|
||||
};
|
||||
|
||||
|
@ -182,6 +182,22 @@ st_theme_node_transition_update (StThemeNodeTransition *transition,
|
||||
static void
|
||||
calculate_offscreen_box (StThemeNodeTransition *transition,
|
||||
const ClutterActorBox *allocation)
|
||||
{
|
||||
ClutterActorBox paint_box;
|
||||
|
||||
st_theme_node_transition_get_paint_box (transition,
|
||||
allocation,
|
||||
&paint_box);
|
||||
transition->priv->offscreen_box.x1 = paint_box.x1 - allocation->x1;
|
||||
transition->priv->offscreen_box.y1 = paint_box.y1 - allocation->y1;
|
||||
transition->priv->offscreen_box.x2 = paint_box.x2 - allocation->x1;
|
||||
transition->priv->offscreen_box.y2 = paint_box.y2 - allocation->y1;
|
||||
}
|
||||
|
||||
void
|
||||
st_theme_node_transition_get_paint_box (StThemeNodeTransition *transition,
|
||||
const ClutterActorBox *allocation,
|
||||
ClutterActorBox *paint_box)
|
||||
{
|
||||
StThemeNodeTransitionPrivate *priv = transition->priv;
|
||||
ClutterActorBox old_node_box, new_node_box;
|
||||
@ -194,14 +210,10 @@ calculate_offscreen_box (StThemeNodeTransition *transition,
|
||||
allocation,
|
||||
&new_node_box);
|
||||
|
||||
priv->offscreen_box.x1 = MIN (old_node_box.x1, new_node_box.x1)
|
||||
- allocation->x1;
|
||||
priv->offscreen_box.y1 = MIN (old_node_box.y1, new_node_box.y1)
|
||||
- allocation->y1;
|
||||
priv->offscreen_box.x2 = MAX (old_node_box.x2, new_node_box.x2)
|
||||
- allocation->x1;
|
||||
priv->offscreen_box.y2 = MAX (old_node_box.y2, new_node_box.y2)
|
||||
- allocation->y1;
|
||||
paint_box->x1 = MIN (old_node_box.x1, new_node_box.x1);
|
||||
paint_box->y1 = MIN (old_node_box.y1, new_node_box.y1);
|
||||
paint_box->x2 = MAX (old_node_box.x2, new_node_box.x2);
|
||||
paint_box->y2 = MAX (old_node_box.y2, new_node_box.y2);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
@ -65,6 +65,10 @@ void st_theme_node_transition_paint (StThemeNodeTransition *transition,
|
||||
ClutterActorBox *allocation,
|
||||
guint8 paint_opacity);
|
||||
|
||||
void st_theme_node_transition_get_paint_box (StThemeNodeTransition *transition,
|
||||
const ClutterActorBox *allocation,
|
||||
ClutterActorBox *paint_box);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
|
@ -122,10 +122,16 @@ st_theme_node_finalize (GObject *object)
|
||||
node->font_desc = NULL;
|
||||
}
|
||||
|
||||
if (node->shadow)
|
||||
if (node->box_shadow)
|
||||
{
|
||||
st_shadow_unref (node->shadow);
|
||||
node->shadow = NULL;
|
||||
st_shadow_unref (node->box_shadow);
|
||||
node->box_shadow = NULL;
|
||||
}
|
||||
|
||||
if (node->background_image_shadow)
|
||||
{
|
||||
st_shadow_unref (node->background_image_shadow);
|
||||
node->background_image_shadow = NULL;
|
||||
}
|
||||
|
||||
if (node->text_shadow)
|
||||
@ -2606,16 +2612,17 @@ st_theme_node_get_vertical_padding (StThemeNode *node)
|
||||
return padding;
|
||||
}
|
||||
|
||||
static void
|
||||
parse_shadow_property (StThemeNode *node,
|
||||
CRDeclaration *decl,
|
||||
ClutterColor *color,
|
||||
gdouble *xoffset,
|
||||
gdouble *yoffset,
|
||||
gdouble *blur,
|
||||
gdouble *spread)
|
||||
static GetFromTermResult
|
||||
parse_shadow_property (StThemeNode *node,
|
||||
CRDeclaration *decl,
|
||||
ClutterColor *color,
|
||||
gdouble *xoffset,
|
||||
gdouble *yoffset,
|
||||
gdouble *blur,
|
||||
gdouble *spread)
|
||||
{
|
||||
/* Set value for width/color/blur in any order */
|
||||
GetFromTermResult result;
|
||||
CRTerm *term;
|
||||
int n_offsets = 0;
|
||||
|
||||
@ -2628,8 +2635,6 @@ parse_shadow_property (StThemeNode *node,
|
||||
|
||||
for (term = decl->value; term; term = term->next)
|
||||
{
|
||||
GetFromTermResult result;
|
||||
|
||||
if (term->type == TERM_NUMBER)
|
||||
{
|
||||
gdouble value;
|
||||
@ -2637,7 +2642,16 @@ parse_shadow_property (StThemeNode *node,
|
||||
|
||||
multiplier = (term->unary_op == MINUS_UOP) ? -1. : 1.;
|
||||
result = get_length_from_term (node, term, FALSE, &value);
|
||||
if (result != VALUE_NOT_FOUND)
|
||||
|
||||
if (result == VALUE_INHERIT)
|
||||
{
|
||||
/* we only allow inherit on the line by itself */
|
||||
if (n_offsets > 0)
|
||||
return VALUE_NOT_FOUND;
|
||||
else
|
||||
return VALUE_INHERIT;
|
||||
}
|
||||
else if (result == VALUE_FOUND)
|
||||
{
|
||||
switch (n_offsets++)
|
||||
{
|
||||
@ -2665,57 +2679,200 @@ parse_shadow_property (StThemeNode *node,
|
||||
}
|
||||
|
||||
result = get_color_from_term (node, term, color);
|
||||
if (result != VALUE_NOT_FOUND)
|
||||
|
||||
if (result == VALUE_INHERIT)
|
||||
{
|
||||
if (n_offsets > 0)
|
||||
return VALUE_NOT_FOUND;
|
||||
else
|
||||
return VALUE_INHERIT;
|
||||
}
|
||||
else if (result == VALUE_FOUND)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* The only required terms are the x and y offsets
|
||||
*/
|
||||
if (n_offsets >= 2)
|
||||
return VALUE_FOUND;
|
||||
else
|
||||
return VALUE_NOT_FOUND;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_theme_node_get_shadow:
|
||||
* st_theme_node_lookup_shadow:
|
||||
* @node: a #StThemeNode
|
||||
* @property_name: The name of the shadow property
|
||||
* @inherit: if %TRUE, if a value is not found for the property on the
|
||||
* node, then it will be looked up on the parent node, and then on the
|
||||
* 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.
|
||||
* @shadow: (out): location to store the shadow
|
||||
*
|
||||
* Gets the value for the -st-shadow style property
|
||||
* If the property is not found, the value in the shadow variable will not
|
||||
* be changed.
|
||||
*
|
||||
* Return value: (transfer none): the node's shadow, or %NULL
|
||||
* if node has no shadow
|
||||
* Generically looks up a property containing a set of shadow values. When
|
||||
* specific getters (like st_theme_node_get_box_shadow ()) exist, they
|
||||
* should be used instead. They are cached, so more efficient, and have
|
||||
* handling for shortcut properties and other details of CSS.
|
||||
*
|
||||
* See also st_theme_node_get_shadow(), which provides a simpler API.
|
||||
*
|
||||
* Return value: %TRUE if the property was found in the properties for this
|
||||
* theme node (or in the properties of parent nodes when inheriting.)
|
||||
*/
|
||||
StShadow *
|
||||
st_theme_node_get_shadow (StThemeNode *node)
|
||||
gboolean
|
||||
st_theme_node_lookup_shadow (StThemeNode *node,
|
||||
const char *property_name,
|
||||
gboolean inherit,
|
||||
StShadow **shadow)
|
||||
{
|
||||
ClutterColor color = { 0., };
|
||||
gdouble xoffset = 0.;
|
||||
gdouble yoffset = 0.;
|
||||
gdouble blur = 0.;
|
||||
gdouble spread = 0.;
|
||||
|
||||
int i;
|
||||
|
||||
if (node->shadow_computed)
|
||||
return node->shadow;
|
||||
|
||||
node->shadow = NULL;
|
||||
node->shadow_computed = TRUE;
|
||||
|
||||
ensure_properties (node);
|
||||
|
||||
for (i = node->n_properties - 1; i >= 0; i--)
|
||||
{
|
||||
CRDeclaration *decl = node->properties[i];
|
||||
|
||||
if (strcmp (decl->property->stryng->str, "-st-shadow") == 0)
|
||||
if (strcmp (decl->property->stryng->str, property_name) == 0)
|
||||
{
|
||||
ClutterColor color;
|
||||
gdouble xoffset;
|
||||
gdouble yoffset;
|
||||
gdouble blur;
|
||||
gdouble spread;
|
||||
|
||||
parse_shadow_property (node, decl,
|
||||
&color, &xoffset, &yoffset, &blur, &spread);
|
||||
|
||||
node->shadow = st_shadow_new (&color,
|
||||
xoffset, yoffset,
|
||||
blur, spread);
|
||||
|
||||
return node->shadow;
|
||||
GetFromTermResult result = parse_shadow_property (node,
|
||||
decl,
|
||||
&color,
|
||||
&xoffset,
|
||||
&yoffset,
|
||||
&blur,
|
||||
&spread);
|
||||
if (result == VALUE_FOUND)
|
||||
{
|
||||
*shadow = st_shadow_new (&color, xoffset, yoffset, blur, spread);
|
||||
return TRUE;
|
||||
}
|
||||
else if (result == VALUE_INHERIT)
|
||||
{
|
||||
if (node->parent_node)
|
||||
return st_theme_node_lookup_shadow (node->parent_node,
|
||||
property_name,
|
||||
inherit,
|
||||
shadow);
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inherit && node->parent_node)
|
||||
return st_theme_node_lookup_shadow (node->parent_node,
|
||||
property_name,
|
||||
inherit,
|
||||
shadow);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_theme_node_get_shadow:
|
||||
* @node: a #StThemeNode
|
||||
* @property_name: The name of the shadow property
|
||||
*
|
||||
* Generically looks up a property containing a set of shadow values. When
|
||||
* specific getters (like st_theme_node_get_box_shadow()) exist, they
|
||||
* should be used instead. They are cached, so more efficient, and have
|
||||
* handling for shortcut properties and other details of CSS.
|
||||
*
|
||||
* Like st_theme_get_length(), this does not print a warning if the property is
|
||||
* not found; it just returns %NULL
|
||||
*
|
||||
* See also st_theme_node_lookup_shadow (), which provides more options.
|
||||
*
|
||||
* Return value: (transfer full): the shadow, or %NULL if the property was not found.
|
||||
*/
|
||||
StShadow *
|
||||
st_theme_node_get_shadow (StThemeNode *node,
|
||||
const char *property_name)
|
||||
{
|
||||
StShadow *shadow;
|
||||
|
||||
if (st_theme_node_lookup_shadow (node, property_name, FALSE, &shadow))
|
||||
return shadow;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_theme_node_get_box_shadow:
|
||||
* @node: a #StThemeNode
|
||||
*
|
||||
* Gets the value for the box-shadow style property
|
||||
*
|
||||
* Return value: (transfer none): the node's shadow, or %NULL
|
||||
* if node has no shadow
|
||||
*/
|
||||
StShadow *
|
||||
st_theme_node_get_box_shadow (StThemeNode *node)
|
||||
{
|
||||
StShadow *shadow;
|
||||
|
||||
if (node->box_shadow_computed)
|
||||
return node->box_shadow;
|
||||
|
||||
node->box_shadow = NULL;
|
||||
node->box_shadow_computed = TRUE;
|
||||
|
||||
if (st_theme_node_lookup_shadow (node,
|
||||
"box-shadow",
|
||||
FALSE,
|
||||
&shadow))
|
||||
{
|
||||
node->box_shadow = shadow;
|
||||
|
||||
return node->box_shadow;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_theme_node_get_background_image_shadow:
|
||||
* @node: a #StThemeNode
|
||||
*
|
||||
* Gets the value for the -st-background-image-shadow style property
|
||||
*
|
||||
* Return value: (transfer none): the node's background image shadow, or %NULL
|
||||
* if node has no such shadow
|
||||
*/
|
||||
StShadow *
|
||||
st_theme_node_get_background_image_shadow (StThemeNode *node)
|
||||
{
|
||||
StShadow *shadow;
|
||||
|
||||
if (node->background_image_shadow_computed)
|
||||
return node->background_image_shadow;
|
||||
|
||||
node->background_image_shadow = NULL;
|
||||
node->background_image_shadow_computed = TRUE;
|
||||
|
||||
if (st_theme_node_lookup_shadow (node,
|
||||
"-st-background-image-shadow",
|
||||
FALSE,
|
||||
&shadow))
|
||||
{
|
||||
node->background_image_shadow = shadow;
|
||||
|
||||
return node->background_image_shadow;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -2732,43 +2889,25 @@ StShadow *
|
||||
st_theme_node_get_text_shadow (StThemeNode *node)
|
||||
{
|
||||
StShadow *result = NULL;
|
||||
int i;
|
||||
|
||||
if (node->text_shadow_computed)
|
||||
return node->text_shadow;
|
||||
|
||||
ensure_properties (node);
|
||||
|
||||
for (i = node->n_properties - 1; i >= 0; i--)
|
||||
if (!st_theme_node_lookup_shadow (node,
|
||||
"text-shadow",
|
||||
FALSE,
|
||||
&result))
|
||||
{
|
||||
CRDeclaration *decl = node->properties[i];
|
||||
|
||||
if (strcmp (decl->property->stryng->str, "text-shadow") == 0)
|
||||
if (node->parent_node)
|
||||
{
|
||||
ClutterColor color;
|
||||
gdouble xoffset;
|
||||
gdouble yoffset;
|
||||
gdouble blur;
|
||||
gdouble spread;
|
||||
|
||||
parse_shadow_property (node, decl,
|
||||
&color, &xoffset, &yoffset, &blur, &spread);
|
||||
|
||||
result = st_shadow_new (&color,
|
||||
xoffset, yoffset,
|
||||
blur, spread);
|
||||
|
||||
break;
|
||||
result = st_theme_node_get_text_shadow (node->parent_node);
|
||||
if (result)
|
||||
st_shadow_ref (result);
|
||||
}
|
||||
}
|
||||
|
||||
if (!result && node->parent_node)
|
||||
{
|
||||
result = st_theme_node_get_text_shadow (node->parent_node);
|
||||
if (result)
|
||||
st_shadow_ref (result);
|
||||
}
|
||||
|
||||
node->text_shadow = result;
|
||||
node->text_shadow_computed = TRUE;
|
||||
|
||||
@ -3102,7 +3241,8 @@ st_theme_node_get_paint_box (StThemeNode *node,
|
||||
const ClutterActorBox *actor_box,
|
||||
ClutterActorBox *paint_box)
|
||||
{
|
||||
StShadow *shadow;
|
||||
StShadow *box_shadow;
|
||||
StShadow *background_image_shadow;
|
||||
ClutterActorBox shadow_box;
|
||||
int outline_width;
|
||||
|
||||
@ -3110,26 +3250,41 @@ st_theme_node_get_paint_box (StThemeNode *node,
|
||||
g_return_if_fail (actor_box != NULL);
|
||||
g_return_if_fail (paint_box != NULL);
|
||||
|
||||
shadow = st_theme_node_get_shadow (node);
|
||||
box_shadow = st_theme_node_get_box_shadow (node);
|
||||
background_image_shadow = st_theme_node_get_background_image_shadow (node);
|
||||
outline_width = st_theme_node_get_outline_width (node);
|
||||
if (!shadow && !outline_width)
|
||||
|
||||
*paint_box = *actor_box;
|
||||
|
||||
if (!box_shadow && !background_image_shadow && !outline_width)
|
||||
return;
|
||||
|
||||
paint_box->x1 -= outline_width;
|
||||
paint_box->x2 += outline_width;
|
||||
paint_box->y1 -= outline_width;
|
||||
paint_box->y2 += outline_width;
|
||||
|
||||
if (box_shadow)
|
||||
{
|
||||
*paint_box = *actor_box;
|
||||
return;
|
||||
st_shadow_get_box (box_shadow, actor_box, &shadow_box);
|
||||
|
||||
paint_box->x1 = MIN (paint_box->x1, shadow_box.x1);
|
||||
paint_box->x2 = MAX (paint_box->x2, shadow_box.x2);
|
||||
paint_box->y1 = MIN (paint_box->y1, shadow_box.y1);
|
||||
paint_box->y2 = MAX (paint_box->y2, shadow_box.y2);
|
||||
}
|
||||
|
||||
if (shadow)
|
||||
st_shadow_get_box (shadow, actor_box, &shadow_box);
|
||||
else
|
||||
shadow_box = *actor_box;
|
||||
if (background_image_shadow)
|
||||
{
|
||||
st_shadow_get_box (background_image_shadow, actor_box, &shadow_box);
|
||||
|
||||
paint_box->x1 = MIN (actor_box->x1 - outline_width, shadow_box.x1);
|
||||
paint_box->x2 = MAX (actor_box->x2 + outline_width, shadow_box.x2);
|
||||
paint_box->y1 = MIN (actor_box->y1 - outline_width, shadow_box.y1);
|
||||
paint_box->y2 = MAX (actor_box->y2 + outline_width, shadow_box.y2);
|
||||
paint_box->x1 = MIN (paint_box->x1, shadow_box.x1);
|
||||
paint_box->x2 = MAX (paint_box->x2, shadow_box.x2);
|
||||
paint_box->y1 = MIN (paint_box->y1, shadow_box.y1);
|
||||
paint_box->y2 = MAX (paint_box->y2, shadow_box.y2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* st_theme_node_geometry_equal:
|
||||
* @node: a #StThemeNode
|
||||
@ -3240,8 +3395,17 @@ st_theme_node_paint_equal (StThemeNode *node,
|
||||
if (border_image != NULL && !st_border_image_equal (border_image, other_border_image))
|
||||
return FALSE;
|
||||
|
||||
shadow = st_theme_node_get_shadow (node);
|
||||
other_shadow = st_theme_node_get_shadow (other);
|
||||
shadow = st_theme_node_get_box_shadow (node);
|
||||
other_shadow = st_theme_node_get_box_shadow (other);
|
||||
|
||||
if ((shadow == NULL) != (other_shadow == NULL))
|
||||
return FALSE;
|
||||
|
||||
if (shadow != NULL && !st_shadow_equal (shadow, other_shadow))
|
||||
return FALSE;
|
||||
|
||||
shadow = st_theme_node_get_background_image_shadow (node);
|
||||
other_shadow = st_theme_node_get_background_image_shadow (other);
|
||||
|
||||
if ((shadow == NULL) != (other_shadow == NULL))
|
||||
return FALSE;
|
||||
|
@ -133,6 +133,10 @@ gboolean st_theme_node_lookup_length (StThemeNode *node,
|
||||
const char *property_name,
|
||||
gboolean inherit,
|
||||
gdouble *length);
|
||||
gboolean st_theme_node_lookup_shadow (StThemeNode *node,
|
||||
const char *property_name,
|
||||
gboolean inherit,
|
||||
StShadow **shadow);
|
||||
|
||||
/* Easier-to-use variants of the above, for application-level use */
|
||||
void st_theme_node_get_color (StThemeNode *node,
|
||||
@ -142,6 +146,8 @@ gdouble st_theme_node_get_double (StThemeNode *node,
|
||||
const char *property_name);
|
||||
gdouble st_theme_node_get_length (StThemeNode *node,
|
||||
const char *property_name);
|
||||
StShadow *st_theme_node_get_shadow (StThemeNode *node,
|
||||
const char *property_name);
|
||||
|
||||
/* Specific getters for particular properties: cached
|
||||
*/
|
||||
@ -195,9 +201,11 @@ StTextAlign st_theme_node_get_text_align (StThemeNode *node);
|
||||
const PangoFontDescription *st_theme_node_get_font (StThemeNode *node);
|
||||
|
||||
StBorderImage *st_theme_node_get_border_image (StThemeNode *node);
|
||||
StShadow *st_theme_node_get_shadow (StThemeNode *node);
|
||||
StShadow *st_theme_node_get_box_shadow (StThemeNode *node);
|
||||
StShadow *st_theme_node_get_text_shadow (StThemeNode *node);
|
||||
|
||||
StShadow *st_theme_node_get_background_image_shadow (StThemeNode *node);
|
||||
|
||||
StIconColors *st_theme_node_get_icon_colors (StThemeNode *node);
|
||||
|
||||
/* Helpers for get_preferred_width()/get_preferred_height() ClutterActor vfuncs */
|
||||
|
@ -357,13 +357,10 @@ st_widget_allocate (ClutterActor *actor,
|
||||
{
|
||||
StWidget *self = ST_WIDGET (actor);
|
||||
StWidgetPrivate *priv = self->priv;
|
||||
StThemeNode *theme_node;
|
||||
ClutterActorClass *klass;
|
||||
ClutterGeometry area;
|
||||
ClutterVertex in_v, out_v;
|
||||
|
||||
theme_node = st_widget_get_theme_node (self);
|
||||
|
||||
klass = CLUTTER_ACTOR_CLASS (st_widget_parent_class);
|
||||
klass->allocate (actor, box, flags);
|
||||
|
||||
@ -686,15 +683,23 @@ st_widget_get_paint_volume (ClutterActor *self, ClutterPaintVolume *volume)
|
||||
{
|
||||
ClutterActorBox paint_box, alloc_box;
|
||||
StThemeNode *theme_node;
|
||||
StWidgetPrivate *priv;
|
||||
ClutterVertex origin;
|
||||
|
||||
/* Setting the paint volume does not make sense when we don't have any allocation */
|
||||
if (!clutter_actor_has_allocation (self))
|
||||
return FALSE;
|
||||
|
||||
priv = ST_WIDGET(self)->priv;
|
||||
|
||||
theme_node = st_widget_get_theme_node (ST_WIDGET(self));
|
||||
clutter_actor_get_allocation_box (self, &alloc_box);
|
||||
st_theme_node_get_paint_box (theme_node, &alloc_box, &paint_box);
|
||||
|
||||
if (priv->transition_animation)
|
||||
st_theme_node_transition_get_paint_box (priv->transition_animation,
|
||||
&alloc_box, &paint_box);
|
||||
else
|
||||
st_theme_node_get_paint_box (theme_node, &alloc_box, &paint_box);
|
||||
|
||||
origin.x = paint_box.x1 - alloc_box.x1;
|
||||
origin.y = paint_box.y1 - alloc_box.y1;
|
||||
|
@ -15,6 +15,7 @@ TEST_JS = \
|
||||
interactive/scroll-view-sizing.js \
|
||||
interactive/table.js \
|
||||
testcommon/border-image.png \
|
||||
testcommon/face-plain.png \
|
||||
testcommon/ui.js \
|
||||
unit/format.js
|
||||
EXTRA_DIST += $(TEST_JS)
|
||||
|
@ -71,6 +71,65 @@ box.add(new St.Label({ text: "Border Image",
|
||||
style_class: "border-image",
|
||||
style: "padding: 10px;" }));
|
||||
|
||||
box.add(new St.Label({ text: "Border Image with Gradient",
|
||||
style_class: 'border-image-with-background-gradient',
|
||||
style: "padding: 10px;"
|
||||
+ 'background-gradient-direction: vertical;' }));
|
||||
|
||||
box.add(new St.Label({ text: "Rounded, framed, shadowed gradients" }));
|
||||
|
||||
let framedGradients = new St.BoxLayout({ vertical: false,
|
||||
style: 'padding: 10px; spacing: 12px;' });
|
||||
box.add(framedGradients);
|
||||
|
||||
function addGradientCase(direction, borderWidth, borderRadius, extra) {
|
||||
let gradientBox = new St.BoxLayout({ style_class: 'background-gradient',
|
||||
style: 'border: ' + borderWidth + 'px solid #8b8b8b;'
|
||||
+ 'border-radius: ' + borderRadius + 'px;'
|
||||
+ 'background-gradient-direction: ' + direction + ';'
|
||||
+ 'width: 32px;'
|
||||
+ 'height: 32px;'
|
||||
+ extra });
|
||||
framedGradients.add(gradientBox, { x_fill: false, y_fill: false } );
|
||||
}
|
||||
|
||||
addGradientCase ('horizontal', 0, 5, 'box-shadow: 0px 0px 0px 0px rgba(0,0,0,0.5);');
|
||||
addGradientCase ('horizontal', 2, 5, 'box-shadow: 0px 2px 0px 0px rgba(0,255,0,0.5);');
|
||||
addGradientCase ('horizontal', 5, 2, 'box-shadow: 2px 0px 0px 0px rgba(0,0,255,0.5);');
|
||||
addGradientCase ('horizontal', 5, 20, 'box-shadow: 0px 0px 4px 0px rgba(255,0,0,0.5);');
|
||||
addGradientCase ('vertical', 0, 5, 'box-shadow: 0px 0px 0px 4px rgba(0,0,0,0.5);');
|
||||
addGradientCase ('vertical', 2, 5, 'box-shadow: 0px 0px 4px 4px rgba(0,0,0,0.5);');
|
||||
addGradientCase ('vertical', 5, 2, 'box-shadow: -2px -2px 6px 0px rgba(0,0,0,0.5);');
|
||||
addGradientCase ('vertical', 5, 20, 'box-shadow: -2px -2px 0px 6px rgba(0,0,0,0.5);');
|
||||
|
||||
box.add(new St.Label({ text: "Rounded, framed, shadowed images" }));
|
||||
|
||||
let framedImages = new St.BoxLayout({ vertical: false,
|
||||
style: 'padding: 10px; spacing: 6px;' });
|
||||
box.add(framedImages);
|
||||
|
||||
function addBackgroundImageCase(borderWidth, borderRadius, width, height, extra) {
|
||||
let imageBox = new St.BoxLayout({ style_class: 'background-image',
|
||||
style: 'border: ' + borderWidth + 'px solid #8b8b8b;'
|
||||
+ 'border-radius: ' + borderRadius + 'px;'
|
||||
+ 'width: ' + width + 'px;'
|
||||
+ 'height: ' + height + 'px;'
|
||||
+ extra });
|
||||
framedImages.add(imageBox, { x_fill: false, y_fill: false } );
|
||||
}
|
||||
|
||||
addBackgroundImageCase (0, 0, 32, 32, 'background-position: 2px 5px');
|
||||
addBackgroundImageCase (0, 0, 16, 16, '-st-background-image-shadow: 1px 1px 4px 0px rgba(0,0,0,0.5); background-color: rgba(0,0,0,0)');
|
||||
addBackgroundImageCase (0, 5, 32, 32, '-st-background-image-shadow: 0px 0px 0px 0px rgba(0,0,0,0.5);');
|
||||
addBackgroundImageCase (2, 5, 32, 32, '-st-background-image-shadow: 0px 2px 0px 0px rgba(0,255,0,0.5);');
|
||||
addBackgroundImageCase (5, 2, 32, 32, '-st-background-image-shadow: 2px 0px 0px 0px rgba(0,0,255,0.5);');
|
||||
addBackgroundImageCase (5, 20, 32, 32, '-st-background-image-shadow: 0px 0px 4px 0px rgba(255,0,0,0.5);');
|
||||
addBackgroundImageCase (0, 5, 48, 48, '-st-background-image-shadow: 0px 0px 0px 4px rgba(0,0,0,0.5);');
|
||||
addBackgroundImageCase (5, 5, 48, 48, '-st-background-image-shadow: 0px 0px 4px 4px rgba(0,0,0,0.5);');
|
||||
addBackgroundImageCase (0, 5, 64, 64, '-st-background-image-shadow: -2px -2px 6px 0px rgba(0,0,0,0.5);');
|
||||
addBackgroundImageCase (5, 5, 64, 64, '-st-background-image-shadow: -2px -2px 0px 6px rgba(0,0,0,0.5);');
|
||||
addBackgroundImageCase (0, 5, 32, 32, 'background-position: 2px 5px');
|
||||
|
||||
stage.show();
|
||||
Clutter.main();
|
||||
stage.destroy();
|
||||
|
@ -319,17 +319,17 @@ function togglePolicy(button) {
|
||||
hpolicy.connect('clicked', function() { togglePolicy(hpolicy); });
|
||||
vpolicy.connect('clicked', function() { togglePolicy(vpolicy); });
|
||||
|
||||
let shadowsBox = new St.BoxLayout({ vertical: false });
|
||||
mainBox.add(shadowsBox);
|
||||
let fadeBox = new St.BoxLayout({ vertical: false });
|
||||
mainBox.add(fadeBox);
|
||||
|
||||
spacer = new St.Bin();
|
||||
shadowsBox.add(spacer, { expand: true });
|
||||
fadeBox.add(spacer, { expand: true });
|
||||
|
||||
shadowsBox.add(new St.Label({ text: 'Vertical Shadows: '}));
|
||||
let vshadows = new St.Button({ label: 'No', style: 'text-decoration: underline; color: #4444ff;' });
|
||||
shadowsBox.add(vshadows);
|
||||
fadeBox.add(new St.Label({ text: 'Vertical Fade: '}));
|
||||
let vfade = new St.Button({ label: 'No', style: 'text-decoration: underline; color: #4444ff;' });
|
||||
fadeBox.add(vfade);
|
||||
|
||||
function toggleShadows(button) {
|
||||
function toggleFade(button) {
|
||||
switch(button.label) {
|
||||
case 'No':
|
||||
button.label = 'Yes';
|
||||
@ -338,10 +338,10 @@ function toggleShadows(button) {
|
||||
button.label = 'No';
|
||||
break;
|
||||
}
|
||||
scrollView.set_vshadows(vshadows.label == 'Yes');
|
||||
scrollView.set_vfade(vfade.label == 'Yes');
|
||||
}
|
||||
|
||||
vshadows.connect('clicked', function() { toggleShadows(vshadows); });
|
||||
vfade.connect('clicked', function() { toggleFade(vfade); });
|
||||
|
||||
stage.show();
|
||||
Clutter.main();
|
||||
|
BIN
tests/testcommon/face-plain.png
Normal file
BIN
tests/testcommon/face-plain.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
@ -37,6 +37,23 @@ stage {
|
||||
border-image: url('border-image.png') 16;
|
||||
}
|
||||
|
||||
.background-gradient {
|
||||
background-gradient-start: #88ff88;
|
||||
background-gradient-end: #8888ff;
|
||||
}
|
||||
|
||||
.border-image-with-background-gradient {
|
||||
border: 15px black solid;
|
||||
border-image: url('border-image.png') 16;
|
||||
background-gradient-start: #88ff88;
|
||||
background-gradient-end: #8888ff;
|
||||
}
|
||||
|
||||
.background-image {
|
||||
background-image: url('face-plain.png');
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.push-button {
|
||||
background: #eeddbb;
|
||||
border: 1px solid black;
|
||||
|
Loading…
Reference in New Issue
Block a user