Compare commits
24 Commits
citadel
...
message-tr
Author | SHA1 | Date | |
---|---|---|---|
|
8fc9d0c8ba | ||
|
803a204604 | ||
|
a02e6d30f7 | ||
|
a424bbbabf | ||
|
4ab513ca77 | ||
|
09653fbaf6 | ||
|
b1791951cb | ||
|
af1a3b11f5 | ||
|
ef49ada575 | ||
|
6c3b8e2add | ||
|
3658f8a8b4 | ||
|
74418f2129 | ||
|
3b4e2202f7 | ||
|
3b5c468cbf | ||
|
b0a0ee297c | ||
|
b48b21e578 | ||
|
e823a3b554 | ||
|
e5b12619ef | ||
|
242c2bce04 | ||
|
64373fe77e | ||
|
f106ee7182 | ||
|
56d2691c31 | ||
|
f883e32f26 | ||
|
c985c3cf78 |
@ -472,6 +472,27 @@ StTooltip {
|
|||||||
color: #cccccc;
|
color: #cccccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Message Tray */
|
||||||
|
#message-tray {
|
||||||
|
background-gradient-direction: vertical;
|
||||||
|
background-gradient-start: rgba(0,0,0,0.01);
|
||||||
|
background-gradient-end: rgba(0,0,0,0.95);
|
||||||
|
height: 28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#notification {
|
||||||
|
border-radius: 5px;
|
||||||
|
background: rgba(0,0,0,0.9);
|
||||||
|
color: white;
|
||||||
|
padding: 2px 10px;
|
||||||
|
spacing: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#summary-mode {
|
||||||
|
spacing: 10px;
|
||||||
|
padding: 2px 4px;
|
||||||
|
}
|
||||||
|
|
||||||
/* App Switcher */
|
/* App Switcher */
|
||||||
.switcher-list {
|
.switcher-list {
|
||||||
background: rgba(0,0,0,0.8);
|
background: rgba(0,0,0,0.8);
|
||||||
|
@ -16,6 +16,8 @@ dist_jsui_DATA = \
|
|||||||
link.js \
|
link.js \
|
||||||
lookingGlass.js \
|
lookingGlass.js \
|
||||||
main.js \
|
main.js \
|
||||||
|
messageTray.js \
|
||||||
|
notificationDaemon.js \
|
||||||
overview.js \
|
overview.js \
|
||||||
panel.js \
|
panel.js \
|
||||||
placeDisplay.js \
|
placeDisplay.js \
|
||||||
|
@ -15,11 +15,13 @@ const St = imports.gi.St;
|
|||||||
const Chrome = imports.ui.chrome;
|
const Chrome = imports.ui.chrome;
|
||||||
const Environment = imports.ui.environment;
|
const Environment = imports.ui.environment;
|
||||||
const ExtensionSystem = imports.ui.extensionSystem;
|
const ExtensionSystem = imports.ui.extensionSystem;
|
||||||
|
const MessageTray = imports.ui.messageTray;
|
||||||
const Overview = imports.ui.overview;
|
const Overview = imports.ui.overview;
|
||||||
const Panel = imports.ui.panel;
|
const Panel = imports.ui.panel;
|
||||||
const PlaceDisplay = imports.ui.placeDisplay;
|
const PlaceDisplay = imports.ui.placeDisplay;
|
||||||
const RunDialog = imports.ui.runDialog;
|
const RunDialog = imports.ui.runDialog;
|
||||||
const LookingGlass = imports.ui.lookingGlass;
|
const LookingGlass = imports.ui.lookingGlass;
|
||||||
|
const NotificationDaemon = imports.ui.notificationDaemon;
|
||||||
const ShellDBus = imports.ui.shellDBus;
|
const ShellDBus = imports.ui.shellDBus;
|
||||||
const Sidebar = imports.ui.sidebar;
|
const Sidebar = imports.ui.sidebar;
|
||||||
const WindowManager = imports.ui.windowManager;
|
const WindowManager = imports.ui.windowManager;
|
||||||
@ -35,6 +37,9 @@ let overview = null;
|
|||||||
let runDialog = null;
|
let runDialog = null;
|
||||||
let lookingGlass = null;
|
let lookingGlass = null;
|
||||||
let wm = null;
|
let wm = null;
|
||||||
|
let notificationDaemon = null;
|
||||||
|
let notificationPopup = null;
|
||||||
|
let messageTray = null;
|
||||||
let recorder = null;
|
let recorder = null;
|
||||||
let shellDBusService = null;
|
let shellDBusService = null;
|
||||||
let modalCount = 0;
|
let modalCount = 0;
|
||||||
@ -113,6 +118,9 @@ function start() {
|
|||||||
panel = new Panel.Panel();
|
panel = new Panel.Panel();
|
||||||
sidebar = new Sidebar.Sidebar();
|
sidebar = new Sidebar.Sidebar();
|
||||||
wm = new WindowManager.WindowManager();
|
wm = new WindowManager.WindowManager();
|
||||||
|
notificationDaemon = new NotificationDaemon.NotificationDaemon();
|
||||||
|
notificationPopup = new MessageTray.Notification();
|
||||||
|
messageTray = new MessageTray.MessageTray();
|
||||||
|
|
||||||
_startDate = new Date();
|
_startDate = new Date();
|
||||||
|
|
||||||
|
271
js/ui/messageTray.js
Normal file
271
js/ui/messageTray.js
Normal file
@ -0,0 +1,271 @@
|
|||||||
|
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
|
|
||||||
|
const Clutter = imports.gi.Clutter;
|
||||||
|
const Lang = imports.lang;
|
||||||
|
const Mainloop = imports.mainloop;
|
||||||
|
const Pango = imports.gi.Pango;
|
||||||
|
const Shell = imports.gi.Shell;
|
||||||
|
const St = imports.gi.St;
|
||||||
|
const Signals = imports.signals;
|
||||||
|
const Tweener = imports.ui.tweener;
|
||||||
|
|
||||||
|
const Main = imports.ui.main;
|
||||||
|
|
||||||
|
const ANIMATION_TIME = 0.2;
|
||||||
|
const NOTIFICATION_TIMEOUT = 4;
|
||||||
|
|
||||||
|
const MESSAGE_TRAY_TIMEOUT = 0.2;
|
||||||
|
|
||||||
|
const ICON_SIZE = 24;
|
||||||
|
|
||||||
|
function Notification(icon, text) {
|
||||||
|
this._init(icon, text);
|
||||||
|
}
|
||||||
|
|
||||||
|
Notification.prototype = {
|
||||||
|
_init: function(icon, text) {
|
||||||
|
this.icon = icon;
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function NotificationBox() {
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
NotificationBox.prototype = {
|
||||||
|
_init: function() {
|
||||||
|
this.actor = new St.BoxLayout({ name: 'notification' });
|
||||||
|
|
||||||
|
this._iconBox = new St.Bin();
|
||||||
|
this.actor.add(this._iconBox);
|
||||||
|
|
||||||
|
this._textBox = new Shell.GenericContainer();
|
||||||
|
this._textBox.connect('get-preferred-width', Lang.bind(this, this._textBoxGetPreferredWidth));
|
||||||
|
this._textBox.connect('get-preferred-height', Lang.bind(this, this._textBoxGetPreferredHeight));
|
||||||
|
this._textBox.connect('allocate', Lang.bind(this, this._textBoxAllocate));
|
||||||
|
this.actor.add(this._textBox, { expand: true, x_fill: false, y_fill: false, y_align: St.Align.MIDDLE });
|
||||||
|
|
||||||
|
this._text = new St.Label();
|
||||||
|
this._text.clutter_text.line_wrap = true;
|
||||||
|
this._text.clutter_text.ellipsize = Pango.EllipsizeMode.NONE;
|
||||||
|
this._textBox.add_actor(this._text);
|
||||||
|
},
|
||||||
|
|
||||||
|
_textBoxGetPreferredWidth: function (actor, forHeight, alloc) {
|
||||||
|
let [min, nat] = this._text.get_preferred_width(forHeight);
|
||||||
|
|
||||||
|
alloc.min_size = alloc.nat_size = Math.min(nat, global.screen_width / 2);
|
||||||
|
},
|
||||||
|
|
||||||
|
_textBoxGetPreferredHeight: function (actor, forWidth, alloc) {
|
||||||
|
// St.BoxLayout passes -1 for @forWidth, which isn't what we want.
|
||||||
|
let prefWidth = {};
|
||||||
|
this._textBoxGetPreferredWidth(this._textBox, -1, prefWidth);
|
||||||
|
[alloc.min_size, alloc.nat_size] = this._text.get_preferred_height(prefWidth.nat_size);
|
||||||
|
log('for width ' + prefWidth.nat_size + ', height ' + alloc.nat_size);
|
||||||
|
},
|
||||||
|
|
||||||
|
_textBoxAllocate: function (actor, box, flags) {
|
||||||
|
let childBox = new Clutter.ActorBox();
|
||||||
|
childBox.x1 = childBox.y1 = 0;
|
||||||
|
childBox.x2 = box.x2 - box.x1;
|
||||||
|
childBox.y2 = box.y2 - box.y1;
|
||||||
|
this._text.allocate(childBox, flags);
|
||||||
|
},
|
||||||
|
|
||||||
|
setContent: function(notification) {
|
||||||
|
this._iconBox.child = notification.icon;
|
||||||
|
|
||||||
|
// Support <b>, <i>, and <u>, escape anything else
|
||||||
|
// so it displays as raw markup.
|
||||||
|
let markup = notification.text.replace(/<(\/?[^biu]>|[^>\/][^>])/g, "<$1");
|
||||||
|
this._text.clutter_text.set_markup(markup);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function Source(id, createIcon) {
|
||||||
|
this._init(id, createIcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
Source.prototype = {
|
||||||
|
_init: function(id, createIcon) {
|
||||||
|
this.id = id;
|
||||||
|
if (createIcon)
|
||||||
|
this.createIcon = createIcon;
|
||||||
|
},
|
||||||
|
|
||||||
|
// This can be overridden by a subclass, or by the createIcon
|
||||||
|
// parameter to _init()
|
||||||
|
createIcon: function(size) {
|
||||||
|
throw new Error('no implementation of createIcon in ' + this);
|
||||||
|
},
|
||||||
|
|
||||||
|
notify: function(text) {
|
||||||
|
Main.messageTray.showNotification(new Notification(this.createIcon(ICON_SIZE), text));
|
||||||
|
},
|
||||||
|
|
||||||
|
clicked: function() {
|
||||||
|
this.emit('clicked');
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function() {
|
||||||
|
this.emit('destroy');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Signals.addSignalMethods(Source.prototype);
|
||||||
|
|
||||||
|
function MessageTray() {
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageTray.prototype = {
|
||||||
|
_init: function() {
|
||||||
|
this.actor = new St.BoxLayout({ name: 'message-tray',
|
||||||
|
reactive: true });
|
||||||
|
|
||||||
|
let primary = global.get_primary_monitor();
|
||||||
|
this.actor.x = 0;
|
||||||
|
this.actor.y = primary.height - 1;
|
||||||
|
|
||||||
|
this.actor.width = primary.width;
|
||||||
|
|
||||||
|
this._summaryBin = new St.Bin({ x_align: St.Align.END });
|
||||||
|
this.actor.add(this._summaryBin, { expand: true });
|
||||||
|
this._summaryBin.hide();
|
||||||
|
|
||||||
|
this._notificationBox = new NotificationBox();
|
||||||
|
this._notificationQueue = [];
|
||||||
|
this.actor.add(this._notificationBox.actor);
|
||||||
|
this._notificationBox.actor.hide();
|
||||||
|
|
||||||
|
Main.chrome.addActor(this.actor, { affectsStruts: false });
|
||||||
|
|
||||||
|
this.actor.connect('enter-event',
|
||||||
|
Lang.bind(this, this._onMessageTrayEntered));
|
||||||
|
this.actor.connect('leave-event',
|
||||||
|
Lang.bind(this, this._onMessageTrayLeft));
|
||||||
|
this._isShowing = false;
|
||||||
|
this.actor.show();
|
||||||
|
|
||||||
|
this._summary = new St.BoxLayout({ name: 'summary-mode' });
|
||||||
|
this._summaryBin.child = this._summary;
|
||||||
|
|
||||||
|
this._sources = {};
|
||||||
|
this._icons = {};
|
||||||
|
},
|
||||||
|
|
||||||
|
contains: function(source) {
|
||||||
|
return this._sources.hasOwnProperty(source.id);
|
||||||
|
},
|
||||||
|
|
||||||
|
add: function(source) {
|
||||||
|
if (this.contains(source)) {
|
||||||
|
log('Trying to re-add source ' + source.id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let iconBox = new St.Bin({ reactive: true });
|
||||||
|
iconBox.child = source.createIcon(ICON_SIZE);
|
||||||
|
this._summary.insert_actor(iconBox, 0);
|
||||||
|
this._icons[source.id] = iconBox;
|
||||||
|
this._sources[source.id] = source;
|
||||||
|
|
||||||
|
iconBox.connect('button-release-event', Lang.bind(this,
|
||||||
|
function () {
|
||||||
|
source.clicked();
|
||||||
|
}));
|
||||||
|
|
||||||
|
source.connect('destroy', Lang.bind(this,
|
||||||
|
function () {
|
||||||
|
this.remove(source);
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
remove: function(source) {
|
||||||
|
if (!this.contains(source))
|
||||||
|
return;
|
||||||
|
|
||||||
|
this._summary.remove_actor(this._icons[source.id]);
|
||||||
|
delete this._icons[source.id];
|
||||||
|
delete this._sources[source.id];
|
||||||
|
},
|
||||||
|
|
||||||
|
getSource: function(id) {
|
||||||
|
return this._sources[id];
|
||||||
|
},
|
||||||
|
|
||||||
|
_onMessageTrayEntered: function() {
|
||||||
|
// Don't hide the message tray after a timeout if the user has moved the mouse over it.
|
||||||
|
// We might have a timeout in place if the user moved the mouse away from the message tray for a very short period of time
|
||||||
|
// or if we are showing a notification.
|
||||||
|
if (this._hideTimeoutId > 0)
|
||||||
|
Mainloop.source_remove(this._hideTimeoutId);
|
||||||
|
|
||||||
|
if (this._isShowing)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If the message tray was not already showing, we'll show it in the summary mode.
|
||||||
|
this._summaryBin.show();
|
||||||
|
this._show();
|
||||||
|
},
|
||||||
|
|
||||||
|
_onMessageTrayLeft: function() {
|
||||||
|
if (!this._isShowing)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// We wait just a little before hiding the message tray in case the user will quickly move the mouse back over it.
|
||||||
|
this._hideTimeoutId = Mainloop.timeout_add(MESSAGE_TRAY_TIMEOUT * 1000, Lang.bind(this, this._hide));
|
||||||
|
},
|
||||||
|
|
||||||
|
_show: function() {
|
||||||
|
this._isShowing = true;
|
||||||
|
let primary = global.get_primary_monitor();
|
||||||
|
Tweener.addTween(this.actor,
|
||||||
|
{ y: primary.height - this.actor.height,
|
||||||
|
time: ANIMATION_TIME,
|
||||||
|
transition: "easeOutQuad"
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
_hide: function() {
|
||||||
|
this._hideTimeoutId = 0;
|
||||||
|
|
||||||
|
let primary = global.get_primary_monitor();
|
||||||
|
|
||||||
|
Tweener.addTween(this.actor,
|
||||||
|
{ y: primary.height - 1,
|
||||||
|
time: ANIMATION_TIME,
|
||||||
|
transition: "easeOutQuad",
|
||||||
|
onComplete: this._hideComplete,
|
||||||
|
onCompleteScope: this
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
_hideComplete: function() {
|
||||||
|
this._isShowing = false;
|
||||||
|
this._summaryBin.hide();
|
||||||
|
this._notificationBox.actor.hide();
|
||||||
|
if (this._notificationQueue.length > 0)
|
||||||
|
this.showNotification(this._notificationQueue.shift());
|
||||||
|
},
|
||||||
|
|
||||||
|
showNotification: function(notification) {
|
||||||
|
if (this._isShowing) {
|
||||||
|
this._notificationQueue.push(notification);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._notificationBox.setContent(notification);
|
||||||
|
|
||||||
|
this._notificationBox.actor.x = Math.round((this.actor.width - this._notificationBox.actor.width) / 2);
|
||||||
|
this._notificationBox.actor.show();
|
||||||
|
|
||||||
|
// Because we set up the timeout before we do the animation, we add ANIMATION_TIME to NOTIFICATION_TIMEOUT, so that
|
||||||
|
// NOTIFICATION_TIMEOUT represents the time the notifiation is fully shown.
|
||||||
|
this._hideTimeoutId = Mainloop.timeout_add((NOTIFICATION_TIMEOUT + ANIMATION_TIME) * 1000, Lang.bind(this, this._hide));
|
||||||
|
|
||||||
|
this._show();
|
||||||
|
}
|
||||||
|
};
|
218
js/ui/notificationDaemon.js
Normal file
218
js/ui/notificationDaemon.js
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
|
|
||||||
|
const DBus = imports.dbus;
|
||||||
|
const GLib = imports.gi.GLib;
|
||||||
|
const Lang = imports.lang;
|
||||||
|
const Shell = imports.gi.Shell;
|
||||||
|
const Mainloop = imports.mainloop;
|
||||||
|
|
||||||
|
const Main = imports.ui.main;
|
||||||
|
const MessageTray = imports.ui.messageTray;
|
||||||
|
const Params = imports.misc.params;
|
||||||
|
|
||||||
|
let nextNotificationId = 1;
|
||||||
|
|
||||||
|
const NotificationDaemonIface = {
|
||||||
|
name: 'org.freedesktop.Notifications',
|
||||||
|
methods: [{ name: 'Notify',
|
||||||
|
inSignature: 'susssasa{sv}i',
|
||||||
|
outSignature: 'u'
|
||||||
|
},
|
||||||
|
{ name: 'CloseNotification',
|
||||||
|
inSignature: 'u',
|
||||||
|
outSignature: ''
|
||||||
|
},
|
||||||
|
{ name: 'GetCapabilities',
|
||||||
|
inSignature: '',
|
||||||
|
outSignature: 'as'
|
||||||
|
},
|
||||||
|
{ name: 'GetServerInformation',
|
||||||
|
inSignature: '',
|
||||||
|
outSignature: 'ssss'
|
||||||
|
}],
|
||||||
|
signals: [{ name: 'NotificationClosed',
|
||||||
|
inSignature: 'uu' },
|
||||||
|
{ name: 'ActionInvoked',
|
||||||
|
inSignature: 'us' }]
|
||||||
|
};
|
||||||
|
|
||||||
|
const NotificationClosedReason = {
|
||||||
|
EXPIRED: 1,
|
||||||
|
DISMISSED: 2,
|
||||||
|
APP_CLOSED: 3,
|
||||||
|
UNDEFINED: 4
|
||||||
|
};
|
||||||
|
|
||||||
|
const Urgency = {
|
||||||
|
LOW: 0,
|
||||||
|
NORMAL: 1,
|
||||||
|
CRITICAL: 2
|
||||||
|
};
|
||||||
|
|
||||||
|
function NotificationDaemon() {
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
NotificationDaemon.prototype = {
|
||||||
|
_init: function() {
|
||||||
|
DBus.session.exportObject('/org/freedesktop/Notifications', this);
|
||||||
|
|
||||||
|
this._everAcquiredName = false;
|
||||||
|
DBus.session.acquire_name('org.freedesktop.Notifications',
|
||||||
|
// We pass MANY_INSTANCES so that if
|
||||||
|
// notification-daemon is running, we'll
|
||||||
|
// get queued behind it and then get the
|
||||||
|
// name after killing it below
|
||||||
|
DBus.MANY_INSTANCES,
|
||||||
|
Lang.bind(this, this._acquiredName),
|
||||||
|
Lang.bind(this, this._lostName));
|
||||||
|
},
|
||||||
|
|
||||||
|
_acquiredName: function() {
|
||||||
|
this._everAcquiredName = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
_lostName: function() {
|
||||||
|
if (this._everAcquiredName)
|
||||||
|
log('Lost name org.freedesktop.Notifications!');
|
||||||
|
else if (GLib.getenv('GNOME_SHELL_NO_REPLACE'))
|
||||||
|
log('Failed to acquire org.freedesktop.Notifications');
|
||||||
|
else {
|
||||||
|
log('Failed to acquire org.freedesktop.Notifications; trying again');
|
||||||
|
|
||||||
|
// kill the notification-daemon. pkill is more portable
|
||||||
|
// than killall, but on Linux at least it won't match if
|
||||||
|
// you pass more than 15 characters of the process name...
|
||||||
|
// However, if you use the "-f" flag to match the entire
|
||||||
|
// command line, it will work, but we have to be careful
|
||||||
|
// in that case that we don't match "gedit
|
||||||
|
// notification-daemon.c" or whatever...
|
||||||
|
let p = new Shell.Process({ args: ['pkill', '-f',
|
||||||
|
'^([^ ]*/)?(notification-daemon|notify-osd)$']});
|
||||||
|
p.run();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_sourceId: function(id) {
|
||||||
|
return 'notification-' + id;
|
||||||
|
},
|
||||||
|
|
||||||
|
Notify: function(appName, replacesId, icon, summary, body,
|
||||||
|
actions, hints, timeout) {
|
||||||
|
let id, source = null;
|
||||||
|
|
||||||
|
if (replacesId != 0) {
|
||||||
|
id = replacesId;
|
||||||
|
source = Main.messageTray.getSource(this._sourceId(id));
|
||||||
|
// source may be null if the current source was destroyed
|
||||||
|
// right as the client sent the new notification
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source == null) {
|
||||||
|
id = nextNotificationId++;
|
||||||
|
|
||||||
|
source = new Source(this._sourceId(id), icon, hints);
|
||||||
|
Main.messageTray.add(source);
|
||||||
|
|
||||||
|
source.connect('clicked', Lang.bind(this,
|
||||||
|
function() {
|
||||||
|
source.destroy();
|
||||||
|
this._emitNotificationClosed(id, NotificationClosedReason.DISMISSED);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
summary = GLib.markup_escape_text(summary, -1);
|
||||||
|
if (body)
|
||||||
|
source.notify('<b>' + summary + '</b>: ' + body);
|
||||||
|
else
|
||||||
|
source.notify('<b>' + summary + '</b>');
|
||||||
|
return id;
|
||||||
|
},
|
||||||
|
|
||||||
|
CloseNotification: function(id) {
|
||||||
|
let source = Main.messageTray.getSource(this._sourceId(id));
|
||||||
|
if (source)
|
||||||
|
source.destroy();
|
||||||
|
this._emitNotificationClosed(id, NotificationClosedReason.APP_CLOSED);
|
||||||
|
},
|
||||||
|
|
||||||
|
GetCapabilities: function() {
|
||||||
|
return [
|
||||||
|
// 'actions',
|
||||||
|
'body',
|
||||||
|
// 'body-hyperlinks',
|
||||||
|
// 'body-images',
|
||||||
|
'body-markup',
|
||||||
|
// 'icon-multi',
|
||||||
|
'icon-static'
|
||||||
|
// 'sound',
|
||||||
|
];
|
||||||
|
},
|
||||||
|
|
||||||
|
GetServerInformation: function() {
|
||||||
|
return [
|
||||||
|
'GNOME Shell',
|
||||||
|
'GNOME',
|
||||||
|
'0.1', // FIXME, get this from somewhere
|
||||||
|
'1.0'
|
||||||
|
];
|
||||||
|
},
|
||||||
|
|
||||||
|
_emitNotificationClosed: function(id, reason) {
|
||||||
|
DBus.session.emit_signal('/org/freedesktop/Notifications',
|
||||||
|
'org.freedesktop.Notifications',
|
||||||
|
'NotificationClosed', 'uu',
|
||||||
|
[id, reason]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
DBus.conformExport(NotificationDaemon.prototype, NotificationDaemonIface);
|
||||||
|
|
||||||
|
function Source(sourceId, icon, hints) {
|
||||||
|
this._init(sourceId, icon, hints);
|
||||||
|
}
|
||||||
|
|
||||||
|
Source.prototype = {
|
||||||
|
__proto__: MessageTray.Source.prototype,
|
||||||
|
|
||||||
|
_init: function(sourceId, icon, hints) {
|
||||||
|
MessageTray.Source.prototype._init.call(this, sourceId);
|
||||||
|
|
||||||
|
hints = Params.parse(hints, { urgency: Urgency.NORMAL }, true);
|
||||||
|
|
||||||
|
this._icon = icon;
|
||||||
|
this._iconData = hints.icon_data;
|
||||||
|
this._urgency = hints.urgency;
|
||||||
|
},
|
||||||
|
|
||||||
|
createIcon: function(size) {
|
||||||
|
let textureCache = Shell.TextureCache.get_default();
|
||||||
|
|
||||||
|
if (this._icon) {
|
||||||
|
if (this._icon.substr(0, 7) == 'file://')
|
||||||
|
return textureCache.load_uri_async(this._icon, size, size);
|
||||||
|
else if (this._icon[0] == '/') {
|
||||||
|
let uri = GLib.filename_to_uri(this._icon, null);
|
||||||
|
return textureCache.load_uri_async(uri, size, size);
|
||||||
|
} else
|
||||||
|
return textureCache.load_icon_name(this._icon, size);
|
||||||
|
} else if (this._iconData) {
|
||||||
|
let [width, height, rowStride, hasAlpha,
|
||||||
|
bitsPerSample, nChannels, data] = this._iconData;
|
||||||
|
return textureCache.load_from_raw(data, data.length, hasAlpha,
|
||||||
|
width, height, rowStride, size);
|
||||||
|
} else {
|
||||||
|
let stockIcon;
|
||||||
|
switch (this._urgency) {
|
||||||
|
case Urgency.LOW:
|
||||||
|
case Urgency.NORMAL:
|
||||||
|
stockIcon = 'gtk-dialog-info';
|
||||||
|
break;
|
||||||
|
case Urgency.CRITICAL:
|
||||||
|
stockIcon = 'gtk-dialog-error';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return textureCache.load_icon_name(stockIcon, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
5
src/gnome-shell.in
Normal file → Executable file
5
src/gnome-shell.in
Normal file → Executable file
@ -357,8 +357,9 @@ try:
|
|||||||
shell = None
|
shell = None
|
||||||
if options.xephyr:
|
if options.xephyr:
|
||||||
xephyr = start_xephyr()
|
xephyr = start_xephyr()
|
||||||
# This makes us not grab the org.gnome.Panel name
|
# This makes us not grab the org.gnome.Panel or
|
||||||
os.environ['GNOME_SHELL_NO_REPLACE_PANEL'] = '1'
|
# org.freedesktop.Notifications D-Bus names
|
||||||
|
os.environ['GNOME_SHELL_NO_REPLACE'] = '1'
|
||||||
shell = start_shell()
|
shell = start_shell()
|
||||||
else:
|
else:
|
||||||
xephyr = None
|
xephyr = None
|
||||||
|
@ -751,7 +751,7 @@ shell_global_grab_dbus_service (ShellGlobal *global)
|
|||||||
* unless a special environment variable is passed. The environment
|
* unless a special environment variable is passed. The environment
|
||||||
* variable is used by the gnome-shell (no --replace) launcher in
|
* variable is used by the gnome-shell (no --replace) launcher in
|
||||||
* Xephyr */
|
* Xephyr */
|
||||||
if (!g_getenv ("GNOME_SHELL_NO_REPLACE_PANEL"))
|
if (!g_getenv ("GNOME_SHELL_NO_REPLACE"))
|
||||||
{
|
{
|
||||||
if (!dbus_g_proxy_call (bus, "RequestName", &error, G_TYPE_STRING,
|
if (!dbus_g_proxy_call (bus, "RequestName", &error, G_TYPE_STRING,
|
||||||
"org.gnome.Panel", G_TYPE_UINT,
|
"org.gnome.Panel", G_TYPE_UINT,
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#define GNOME_DESKTOP_USE_UNSTABLE_API
|
#define GNOME_DESKTOP_USE_UNSTABLE_API
|
||||||
#include <libgnomeui/gnome-desktop-thumbnail.h>
|
#include <libgnomeui/gnome-desktop-thumbnail.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <glib.h>
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
@ -17,6 +18,7 @@ typedef struct
|
|||||||
GIcon *icon;
|
GIcon *icon;
|
||||||
gchar *uri;
|
gchar *uri;
|
||||||
gchar *thumbnail_uri;
|
gchar *thumbnail_uri;
|
||||||
|
gchar *checksum;
|
||||||
|
|
||||||
/* This one is common to all */
|
/* This one is common to all */
|
||||||
guint size;
|
guint size;
|
||||||
@ -51,6 +53,8 @@ cache_key_hash (gconstpointer a)
|
|||||||
base_hash = g_str_hash (akey->uri);
|
base_hash = g_str_hash (akey->uri);
|
||||||
else if (akey->thumbnail_uri)
|
else if (akey->thumbnail_uri)
|
||||||
base_hash = g_str_hash (akey->thumbnail_uri);
|
base_hash = g_str_hash (akey->thumbnail_uri);
|
||||||
|
else if (akey->checksum)
|
||||||
|
base_hash = g_str_hash (akey->checksum);
|
||||||
else
|
else
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
return base_hash + 31*akey->size;
|
return base_hash + 31*akey->size;
|
||||||
@ -76,6 +80,8 @@ cache_key_equal (gconstpointer a,
|
|||||||
return strcmp (akey->uri, bkey->uri) == 0;
|
return strcmp (akey->uri, bkey->uri) == 0;
|
||||||
else if (akey->thumbnail_uri && bkey->thumbnail_uri)
|
else if (akey->thumbnail_uri && bkey->thumbnail_uri)
|
||||||
return strcmp (akey->thumbnail_uri, bkey->thumbnail_uri) == 0;
|
return strcmp (akey->thumbnail_uri, bkey->thumbnail_uri) == 0;
|
||||||
|
else if (akey->checksum && bkey->checksum)
|
||||||
|
return strcmp (akey->checksum, bkey->checksum) == 0;
|
||||||
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -89,6 +95,7 @@ cache_key_dup (CacheKey *key)
|
|||||||
ret->icon = g_object_ref (key->icon);
|
ret->icon = g_object_ref (key->icon);
|
||||||
ret->uri = g_strdup (key->uri);
|
ret->uri = g_strdup (key->uri);
|
||||||
ret->thumbnail_uri = g_strdup (key->thumbnail_uri);
|
ret->thumbnail_uri = g_strdup (key->thumbnail_uri);
|
||||||
|
ret->checksum = g_strdup (key->checksum);
|
||||||
ret->size = key->size;
|
ret->size = key->size;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -101,6 +108,7 @@ cache_key_destroy (gpointer a)
|
|||||||
g_object_unref (akey->icon);
|
g_object_unref (akey->icon);
|
||||||
g_free (akey->uri);
|
g_free (akey->uri);
|
||||||
g_free (akey->thumbnail_uri);
|
g_free (akey->thumbnail_uri);
|
||||||
|
g_free (akey->checksum);
|
||||||
g_free (akey);
|
g_free (akey);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,7 +326,8 @@ on_image_size_prepared (GdkPixbufLoader *pixbuf_loader,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static GdkPixbuf *
|
static GdkPixbuf *
|
||||||
impl_load_pixbuf_file (const char *uri,
|
impl_load_pixbuf_data (const guchar *data,
|
||||||
|
gsize size,
|
||||||
int available_width,
|
int available_width,
|
||||||
int available_height,
|
int available_height,
|
||||||
GError **error)
|
GError **error)
|
||||||
@ -326,22 +335,10 @@ impl_load_pixbuf_file (const char *uri,
|
|||||||
GdkPixbufLoader *pixbuf_loader = NULL;
|
GdkPixbufLoader *pixbuf_loader = NULL;
|
||||||
GdkPixbuf *rotated_pixbuf = NULL;
|
GdkPixbuf *rotated_pixbuf = NULL;
|
||||||
GdkPixbuf *pixbuf;
|
GdkPixbuf *pixbuf;
|
||||||
GFile *file = NULL;
|
|
||||||
char *contents = NULL;
|
|
||||||
gsize size;
|
|
||||||
gboolean success;
|
gboolean success;
|
||||||
Dimensions available_dimensions;
|
Dimensions available_dimensions;
|
||||||
int width_before_rotation, width_after_rotation;
|
int width_before_rotation, width_after_rotation;
|
||||||
|
|
||||||
file = g_file_new_for_uri (uri);
|
|
||||||
|
|
||||||
success = g_file_load_contents (file, NULL, &contents, &size, NULL, error);
|
|
||||||
|
|
||||||
if (!success)
|
|
||||||
{
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
pixbuf_loader = gdk_pixbuf_loader_new ();
|
pixbuf_loader = gdk_pixbuf_loader_new ();
|
||||||
|
|
||||||
available_dimensions.width = available_width;
|
available_dimensions.width = available_width;
|
||||||
@ -349,10 +346,7 @@ impl_load_pixbuf_file (const char *uri,
|
|||||||
g_signal_connect (pixbuf_loader, "size-prepared",
|
g_signal_connect (pixbuf_loader, "size-prepared",
|
||||||
G_CALLBACK (on_image_size_prepared), &available_dimensions);
|
G_CALLBACK (on_image_size_prepared), &available_dimensions);
|
||||||
|
|
||||||
success = gdk_pixbuf_loader_write (pixbuf_loader,
|
success = gdk_pixbuf_loader_write (pixbuf_loader, data, size, error);
|
||||||
(const guchar *) contents,
|
|
||||||
size,
|
|
||||||
error);
|
|
||||||
if (!success)
|
if (!success)
|
||||||
goto out;
|
goto out;
|
||||||
success = gdk_pixbuf_loader_close (pixbuf_loader, error);
|
success = gdk_pixbuf_loader_close (pixbuf_loader, error);
|
||||||
@ -384,10 +378,7 @@ impl_load_pixbuf_file (const char *uri,
|
|||||||
g_signal_connect (pixbuf_loader, "size-prepared",
|
g_signal_connect (pixbuf_loader, "size-prepared",
|
||||||
G_CALLBACK (on_image_size_prepared), &available_dimensions);
|
G_CALLBACK (on_image_size_prepared), &available_dimensions);
|
||||||
|
|
||||||
success = gdk_pixbuf_loader_write (pixbuf_loader,
|
success = gdk_pixbuf_loader_write (pixbuf_loader, data, size, error);
|
||||||
(const guchar *) contents,
|
|
||||||
size,
|
|
||||||
error);
|
|
||||||
if (!success)
|
if (!success)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@ -401,14 +392,36 @@ impl_load_pixbuf_file (const char *uri,
|
|||||||
}
|
}
|
||||||
|
|
||||||
out:
|
out:
|
||||||
g_free (contents);
|
|
||||||
if (file)
|
|
||||||
g_object_unref (file);
|
|
||||||
if (pixbuf_loader)
|
if (pixbuf_loader)
|
||||||
g_object_unref (pixbuf_loader);
|
g_object_unref (pixbuf_loader);
|
||||||
return rotated_pixbuf;
|
return rotated_pixbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GdkPixbuf *
|
||||||
|
impl_load_pixbuf_file (const char *uri,
|
||||||
|
int available_width,
|
||||||
|
int available_height,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
GdkPixbuf *pixbuf = NULL;
|
||||||
|
GFile *file;
|
||||||
|
char *contents = NULL;
|
||||||
|
gsize size;
|
||||||
|
|
||||||
|
file = g_file_new_for_uri (uri);
|
||||||
|
if (g_file_load_contents (file, NULL, &contents, &size, NULL, error))
|
||||||
|
{
|
||||||
|
pixbuf = impl_load_pixbuf_data ((const guchar *) contents, size,
|
||||||
|
available_width, available_height,
|
||||||
|
error);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_object_unref (file);
|
||||||
|
g_free (contents);
|
||||||
|
|
||||||
|
return pixbuf;
|
||||||
|
}
|
||||||
|
|
||||||
static GdkPixbuf *
|
static GdkPixbuf *
|
||||||
impl_load_thumbnail (ShellTextureCache *cache,
|
impl_load_thumbnail (ShellTextureCache *cache,
|
||||||
const char *uri,
|
const char *uri,
|
||||||
@ -655,6 +668,7 @@ typedef struct {
|
|||||||
gboolean thumbnail;
|
gboolean thumbnail;
|
||||||
char *mimetype;
|
char *mimetype;
|
||||||
GtkRecentInfo *recent_info;
|
GtkRecentInfo *recent_info;
|
||||||
|
char *checksum;
|
||||||
GIcon *icon;
|
GIcon *icon;
|
||||||
GtkIconInfo *icon_info;
|
GtkIconInfo *icon_info;
|
||||||
guint width;
|
guint width;
|
||||||
@ -1137,6 +1151,128 @@ shell_texture_cache_load_uri_sync (ShellTextureCache *cache,
|
|||||||
return CLUTTER_ACTOR (texture);
|
return CLUTTER_ACTOR (texture);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* shell_texture_cache_load_from_data:
|
||||||
|
* @cache: The texture cache instance
|
||||||
|
* @data: Image data in PNG, GIF, etc format
|
||||||
|
* @len: length of @data
|
||||||
|
* @size: Size in pixels to use for the resulting texture
|
||||||
|
* @error: Return location for error
|
||||||
|
*
|
||||||
|
* Synchronously creates an image from @data. The image is scaled down
|
||||||
|
* to fit the available width and height dimensions, but the image is
|
||||||
|
* never scaled up beyond its actual size. The pixbuf is rotated
|
||||||
|
* according to the associated orientation setting.
|
||||||
|
*
|
||||||
|
* Return value: (transfer none): A new #ClutterActor with the image data loaded if it was
|
||||||
|
* generated succesfully, %NULL otherwise
|
||||||
|
*/
|
||||||
|
ClutterActor *
|
||||||
|
shell_texture_cache_load_from_data (ShellTextureCache *cache,
|
||||||
|
const guchar *data,
|
||||||
|
gsize len,
|
||||||
|
int size,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
ClutterTexture *texture;
|
||||||
|
CoglHandle texdata;
|
||||||
|
GdkPixbuf *pixbuf;
|
||||||
|
CacheKey key;
|
||||||
|
gchar *checksum;
|
||||||
|
|
||||||
|
texture = create_default_texture (cache);
|
||||||
|
clutter_actor_set_size (CLUTTER_ACTOR (texture), size, size);
|
||||||
|
|
||||||
|
checksum = g_compute_checksum_for_data (G_CHECKSUM_SHA1, data, len);
|
||||||
|
|
||||||
|
memset (&key, 0, sizeof(key));
|
||||||
|
key.size = size;
|
||||||
|
key.checksum = checksum;
|
||||||
|
|
||||||
|
texdata = g_hash_table_lookup (cache->priv->keyed_cache, &key);
|
||||||
|
if (texdata == NULL)
|
||||||
|
{
|
||||||
|
pixbuf = impl_load_pixbuf_data (data, len, size, size, error);
|
||||||
|
if (!pixbuf)
|
||||||
|
{
|
||||||
|
g_object_unref (texture);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
texdata = pixbuf_to_cogl_handle (pixbuf);
|
||||||
|
g_object_unref (pixbuf);
|
||||||
|
|
||||||
|
set_texture_cogl_texture (texture, texdata);
|
||||||
|
|
||||||
|
g_hash_table_insert (cache->priv->keyed_cache, cache_key_dup (&key), texdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (key.checksum);
|
||||||
|
|
||||||
|
set_texture_cogl_texture (texture, texdata);
|
||||||
|
return CLUTTER_ACTOR (texture);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* shell_texture_cache_load_from_raw:
|
||||||
|
* @cache: a #ShellTextureCache
|
||||||
|
* @data: raw pixel data
|
||||||
|
* @len: the length of @data
|
||||||
|
* @has_alpha: whether @data includes an alpha channel
|
||||||
|
* @width: width in pixels of @data
|
||||||
|
* @height: width in pixels of @data
|
||||||
|
* @rowstride: rowstride of @data
|
||||||
|
* @size: size of icon to return
|
||||||
|
*
|
||||||
|
* Creates (or retrieves from cache) an icon based on raw pixel data.
|
||||||
|
*
|
||||||
|
* Return value: (transfer none): a new #ClutterActor displaying a
|
||||||
|
* pixbuf created from @data and the other parameters.
|
||||||
|
**/
|
||||||
|
ClutterActor *
|
||||||
|
shell_texture_cache_load_from_raw (ShellTextureCache *cache,
|
||||||
|
const guchar *data,
|
||||||
|
gsize len,
|
||||||
|
gboolean has_alpha,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
int rowstride,
|
||||||
|
int size,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
ClutterTexture *texture;
|
||||||
|
CoglHandle texdata;
|
||||||
|
CacheKey key;
|
||||||
|
gchar *checksum;
|
||||||
|
|
||||||
|
texture = create_default_texture (cache);
|
||||||
|
clutter_actor_set_size (CLUTTER_ACTOR (texture), size, size);
|
||||||
|
|
||||||
|
/* In theory, two images of different size could have the same
|
||||||
|
* pixel data. We ignore that theory.
|
||||||
|
*/
|
||||||
|
checksum = g_compute_checksum_for_data (G_CHECKSUM_SHA1, data, len);
|
||||||
|
|
||||||
|
memset (&key, 0, sizeof(key));
|
||||||
|
key.size = size;
|
||||||
|
key.checksum = checksum;
|
||||||
|
|
||||||
|
texdata = g_hash_table_lookup (cache->priv->keyed_cache, &key);
|
||||||
|
if (texdata == NULL)
|
||||||
|
{
|
||||||
|
texdata = cogl_texture_new_from_data (width, height, COGL_TEXTURE_NONE,
|
||||||
|
has_alpha ? COGL_PIXEL_FORMAT_RGBA_8888 : COGL_PIXEL_FORMAT_RGB_888,
|
||||||
|
COGL_PIXEL_FORMAT_ANY,
|
||||||
|
rowstride, data);
|
||||||
|
g_hash_table_insert (cache->priv->keyed_cache, cache_key_dup (&key), texdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (key.checksum);
|
||||||
|
|
||||||
|
set_texture_cogl_texture (texture, texdata);
|
||||||
|
return CLUTTER_ACTOR (texture);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* shell_texture_cache_load_thumbnail:
|
* shell_texture_cache_load_thumbnail:
|
||||||
* @cache:
|
* @cache:
|
||||||
|
@ -80,6 +80,21 @@ ClutterActor *shell_texture_cache_load_uri_sync (ShellTextureCache *cache,
|
|||||||
int available_height,
|
int available_height,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
|
ClutterActor *shell_texture_cache_load_from_data (ShellTextureCache *cache,
|
||||||
|
const guchar *data,
|
||||||
|
gsize len,
|
||||||
|
int size,
|
||||||
|
GError **error);
|
||||||
|
ClutterActor *shell_texture_cache_load_from_raw (ShellTextureCache *cache,
|
||||||
|
const guchar *data,
|
||||||
|
gsize len,
|
||||||
|
gboolean has_alpha,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
int rowstride,
|
||||||
|
int size,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
gboolean shell_texture_cache_pixbuf_equal (ShellTextureCache *cache, GdkPixbuf *a, GdkPixbuf *b);
|
gboolean shell_texture_cache_pixbuf_equal (ShellTextureCache *cache, GdkPixbuf *a, GdkPixbuf *b);
|
||||||
|
|
||||||
#endif /* __SHELL_TEXTURE_CACHE_H__ */
|
#endif /* __SHELL_TEXTURE_CACHE_H__ */
|
||||||
|
@ -1418,3 +1418,36 @@ st_box_layout_get_n_children (StBoxLayout *self)
|
|||||||
{
|
{
|
||||||
return g_list_length (self->priv->children);
|
return g_list_length (self->priv->children);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
st_box_layout_move_child (StBoxLayout *self,
|
||||||
|
ClutterActor *actor,
|
||||||
|
int pos)
|
||||||
|
{
|
||||||
|
StBoxLayoutPrivate *priv = ST_BOX_LAYOUT (self)->priv;
|
||||||
|
|
||||||
|
GList *item = NULL;
|
||||||
|
|
||||||
|
item = g_list_find (priv->children, actor);
|
||||||
|
|
||||||
|
if (item == NULL)
|
||||||
|
{
|
||||||
|
g_warning ("Actor of type '%s' is not a child of the StBoxLayout container",
|
||||||
|
g_type_name (G_OBJECT_TYPE (actor)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
priv->children = g_list_delete_link (priv->children, item);
|
||||||
|
priv->children = g_list_insert (priv->children, actor, pos);
|
||||||
|
clutter_actor_queue_relayout ((ClutterActor*) self);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
st_box_layout_insert_actor (StBoxLayout *self,
|
||||||
|
ClutterActor *actor,
|
||||||
|
int pos)
|
||||||
|
{
|
||||||
|
clutter_container_add_actor((ClutterContainer*) self, actor);
|
||||||
|
st_box_layout_move_child(self, actor, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -95,6 +95,14 @@ void st_box_layout_destroy_children (StBoxLayout *box);
|
|||||||
|
|
||||||
guint st_box_layout_get_n_children (StBoxLayout *box);
|
guint st_box_layout_get_n_children (StBoxLayout *box);
|
||||||
|
|
||||||
|
void st_box_layout_move_child (StBoxLayout *self,
|
||||||
|
ClutterActor *actor,
|
||||||
|
int pos);
|
||||||
|
|
||||||
|
void st_box_layout_insert_actor (StBoxLayout *self,
|
||||||
|
ClutterActor *actor,
|
||||||
|
int pos);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* _ST_BOX_LAYOUT_H */
|
#endif /* _ST_BOX_LAYOUT_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user