Add an OSD monitor labeler exposed on DBus

This DBus API is intended to be used by gnome-control-center's
displays panel to show monitor labels.

Each output (i.e. hardware monitor) identified by its
org.gnome.Mutter.DisplayConfig API ID has at most one label. On
mirrored setups, all the labels for outputs corresponding to the same
logical monitor (i.e. showing the same contents in the same mode) are
shown together.

At most, only one DBus client at a time is allowed to show labels.

https://bugzilla.gnome.org/show_bug.cgi?id=743744
This commit is contained in:
Rui Matos 2015-01-26 15:52:10 +01:00
parent fb6598ac10
commit 1900468846
5 changed files with 167 additions and 0 deletions

View File

@ -1812,6 +1812,9 @@ StScrollBar StButton#vhandle:active {
text-align: center;
font-weight: bold;
spacing: 1em;
margin: 32px;
min-width: 64px;
min-height: 64px;
}
.osd-window .level {
@ -1820,6 +1823,10 @@ StScrollBar StButton#vhandle:active {
background-color: rgba(190,190,190,0.2);
}
.osd-monitor-label {
font-size: 3em;
}
/* App Switcher */
.switcher-popup {
padding: 8px;

View File

@ -64,6 +64,7 @@
<file>ui/modalDialog.js</file>
<file>ui/notificationDaemon.js</file>
<file>ui/osdWindow.js</file>
<file>ui/osdMonitorLabeler.js</file>
<file>ui/overview.js</file>
<file>ui/overviewControls.js</file>
<file>ui/panel.js</file>

View File

@ -21,6 +21,7 @@ const Keyboard = imports.ui.keyboard;
const MessageTray = imports.ui.messageTray;
const ModalDialog = imports.ui.modalDialog;
const OsdWindow = imports.ui.osdWindow;
const OsdMonitorLabeler = imports.ui.osdMonitorLabeler;
const Overview = imports.ui.overview;
const Panel = imports.ui.panel;
const Params = imports.misc.params;
@ -57,6 +58,7 @@ let notificationDaemon = null;
let windowAttentionHandler = null;
let ctrlAltTabManager = null;
let osdWindowManager = null;
let osdMonitorLabeler = null;
let sessionMode = null;
let shellDBusService = null;
let shellMountOpDBusService = null;
@ -150,6 +152,7 @@ function _initializeUI() {
xdndHandler = new XdndHandler.XdndHandler();
ctrlAltTabManager = new CtrlAltTab.CtrlAltTabManager();
osdWindowManager = new OsdWindow.OsdWindowManager();
osdMonitorLabeler = new OsdMonitorLabeler.OsdMonitorLabeler();
overview = new Overview.Overview();
wm = new WindowManager.WindowManager();
magnifier = new Magnifier.Magnifier();

141
js/ui/osdMonitorLabeler.js Normal file
View File

@ -0,0 +1,141 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const St = imports.gi.St;
const Lang = imports.lang;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
const Meta = imports.gi.Meta;
const FADE_TIME = 0.1;
const OsdMonitorLabel = new Lang.Class({
Name: 'OsdMonitorLabel',
_init: function(monitor, label) {
this._actor = new St.Widget({ opacity: 0,
x_expand: true,
y_expand: true });
this._monitor = monitor;
this._box = new St.BoxLayout({ style_class: 'osd-window',
vertical: true });
this._actor.add_actor(this._box);
this._label = new St.Label({ style_class: 'osd-monitor-label',
text: label });
this._box.add(this._label);
Main.uiGroup.add_child(this._actor);
Main.uiGroup.set_child_above_sibling(this._actor, null);
this._position();
Meta.disable_unredirect_for_screen(global.screen);
Tweener.addTween(this._actor,
{ opacity: 255,
time: FADE_TIME,
transition: 'easeOutQuad' });
},
_position: function() {
let workArea = Main.layoutManager.getWorkAreaForMonitor(this._monitor);
if (Clutter.get_default_text_direction() == Clutter.TextDirection.RTL)
this._box.x = workArea.x + (workArea.width - this._box.width);
else
this._box.x = workArea.x;
this._box.y = workArea.y;
},
destroy: function() {
Tweener.addTween(this._actor,
{ opacity: 0,
time: FADE_TIME,
transition: 'easeOutQuad',
onComplete: Lang.bind(this, function() {
this._actor.destroy();
Meta.enable_unredirect_for_screen(global.screen);
})
});
}
});
const OsdMonitorLabeler = new Lang.Class({
Name: 'OsdMonitorLabeler',
_init: function() {
this._monitorManager = Meta.MonitorManager.get();
this._client = null;
this._clientWatchId = 0;
this._osdLabels = [];
this._monitorLabels = null;
Main.layoutManager.connect('monitors-changed',
Lang.bind(this, this._reset));
this._reset();
},
_reset: function() {
for (let i in this._osdLabels)
this._osdLabels[i].destroy();
this._osdLabels = [];
this._monitorLabels = new Map();
let monitors = Main.layoutManager.monitors;
for (let i in monitors)
this._monitorLabels.set(monitors[i].index, []);
},
_trackClient: function(client) {
if (this._client)
return (this._client == client);
this._client = client;
this._clientWatchId = Gio.bus_watch_name(Gio.BusType.SESSION, client, 0, null,
Lang.bind(this, function(c, name) {
this.hide(name);
}));
return true;
},
_untrackClient: function(client) {
if (!this._client || this._client != client)
return false;
Gio.bus_unwatch_name(this._clientWatchId);
this._clientWatchId = 0;
this._client = null;
return true;
},
show: function(client, params) {
if (!this._trackClient(client))
return;
this._reset();
for (let id in params) {
let monitor = this._monitorManager.get_monitor_for_output(id);
if (monitor == -1)
continue;
this._monitorLabels.get(monitor).push(params[id].deep_unpack());
}
// In mirrored display setups, more than one physical outputs
// might be showing the same logical monitor. In that case, we
// join each output's labels on the same OSD widget.
for (let [monitor, labels] of this._monitorLabels.entries()) {
labels.sort();
this._osdLabels.push(new OsdMonitorLabel(monitor, labels.join(' ')));
}
},
hide: function(client) {
if (!this._untrackClient(client))
return;
this._reset();
}
});

View File

@ -25,6 +25,10 @@ const GnomeShellIface = '<node> \
<method name="ShowOSD"> \
<arg type="a{sv}" direction="in" name="params"/> \
</method> \
<method name="ShowMonitorLabels"> \
<arg type="a{uv}" direction="in" name="params" /> \
</method> \
<method name="HideMonitorLabels" /> \
<method name="FocusApp"> \
<arg type="s" direction="in" name="id"/> \
</method> \
@ -240,6 +244,17 @@ const GnomeShell = new Lang.Class({
this._grabbers.delete(name);
},
ShowMonitorLabelsAsync: function(params, invocation) {
let sender = invocation.get_sender();
let [dict] = params;
Main.osdMonitorLabeler.show(sender, dict);
},
HideMonitorLabelsAsync: function(params, invocation) {
let sender = invocation.get_sender();
Main.osdMonitorLabeler.hide(sender);
},
Mode: global.session_mode,