11064c0e35
The status icon should always be visible if more than two layouts are configured. The settings key which was used to enforce hiding the icon in this case as well has already been removed from the g-s-d schema, causing an error on startup.
199 lines
6.9 KiB
JavaScript
199 lines
6.9 KiB
JavaScript
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
|
|
const Clutter = imports.gi.Clutter;
|
|
const GdkPixbuf = imports.gi.GdkPixbuf;
|
|
const Gkbd = imports.gi.Gkbd;
|
|
const Gio = imports.gi.Gio;
|
|
const GLib = imports.gi.GLib;
|
|
const Lang = imports.lang;
|
|
const Shell = imports.gi.Shell;
|
|
const St = imports.gi.St;
|
|
|
|
const PopupMenu = imports.ui.popupMenu;
|
|
const PanelMenu = imports.ui.panelMenu;
|
|
|
|
const Gettext = imports.gettext.domain('gnome-shell');
|
|
const _ = Gettext.gettext;
|
|
|
|
function LayoutMenuItem() {
|
|
this._init.apply(this, arguments);
|
|
}
|
|
|
|
LayoutMenuItem.prototype = {
|
|
__proto__: PopupMenu.PopupBaseMenuItem.prototype,
|
|
|
|
_init: function(config, id, indicator, long_name) {
|
|
PopupMenu.PopupBaseMenuItem.prototype._init.call(this);
|
|
|
|
this._config = config;
|
|
this._id = id;
|
|
this.label = new St.Label({ text: long_name });
|
|
this.indicator = indicator;
|
|
this.addActor(this.label);
|
|
this.addActor(this.indicator);
|
|
},
|
|
|
|
activate: function(event) {
|
|
PopupMenu.PopupBaseMenuItem.prototype.activate.call(this);
|
|
this._config.lock_group(this._id);
|
|
}
|
|
};
|
|
|
|
function XKBIndicator() {
|
|
this._init.call(this);
|
|
}
|
|
|
|
XKBIndicator.prototype = {
|
|
__proto__: PanelMenu.Button.prototype,
|
|
|
|
_init: function() {
|
|
PanelMenu.Button.prototype._init.call(this, St.Align.START);
|
|
|
|
this._container = new Shell.GenericContainer();
|
|
this._container.connect('get-preferred-width', Lang.bind(this, this._get_preferred_width));
|
|
this._container.connect('get-preferred-height', Lang.bind(this, this._get_preferred_height));
|
|
this._container.connect('allocate', Lang.bind(this, this._allocate));
|
|
this.actor.set_child(this._container);
|
|
|
|
this._iconActor = new St.Icon({ icon_name: 'keyboard', icon_type: St.IconType.SYMBOLIC, style_class: 'system-status-icon' });
|
|
this._container.add_actor(this._iconActor);
|
|
this._labelActors = [ ];
|
|
this._layoutItems = [ ];
|
|
|
|
this._showFlags = false;
|
|
this._config = Gkbd.Configuration.get();
|
|
this._config.connect('changed', Lang.bind(this, this._sync_config));
|
|
this._config.connect('group-changed', Lang.bind(this, this._sync_group));
|
|
this._config.start_listen();
|
|
|
|
this._sync_config();
|
|
|
|
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
|
|
this.menu.addAction(_("Localization Settings"), function() {
|
|
GLib.spawn_command_line_async('gnome-control-center region');
|
|
});
|
|
},
|
|
|
|
_sync_config: function() {
|
|
this._showFlags = this._config.if_flags_shown();
|
|
if (this._showFlags) {
|
|
this._container.set_skip_paint(this._iconActor, false);
|
|
} else {
|
|
this._container.set_skip_paint(this._iconActor, true);
|
|
}
|
|
|
|
let groups = this._config.get_group_names();
|
|
if (groups.length > 1) {
|
|
this.actor.show();
|
|
} else {
|
|
this.menu.close();
|
|
this.actor.hide();
|
|
}
|
|
|
|
for (let i = 0; i < this._layoutItems.length; i++)
|
|
this._layoutItems[i].destroy();
|
|
|
|
for (let i = 0; i < this._labelActors.length; i++)
|
|
this._labelActors[i].destroy();
|
|
|
|
let short_names = this._config.get_short_group_names();
|
|
|
|
this._selectedLayout = null;
|
|
this._layoutItems = [ ];
|
|
this._selectedLabel = null;
|
|
this._labelActors = [ ];
|
|
for (let i = 0; i < groups.length; i++) {
|
|
let icon_name = this._config.get_group_name(i);
|
|
let actor;
|
|
if (this._showFlags)
|
|
actor = new St.Icon({ icon_name: icon_name, icon_type: St.IconType.SYMBOLIC, style_class: 'popup-menu-icon' });
|
|
else
|
|
actor = new St.Label({ text: short_names[i] });
|
|
let item = new LayoutMenuItem(this._config, i, actor, groups[i]);
|
|
item._short_group_name = short_names[i];
|
|
item._icon_name = icon_name;
|
|
this._layoutItems.push(item);
|
|
this.menu.addMenuItem(item, i);
|
|
|
|
let shortLabel = new St.Label({ text: short_names[i] });
|
|
this._labelActors.push(shortLabel);
|
|
this._container.add_actor(shortLabel);
|
|
this._container.set_skip_paint(shortLabel, true);
|
|
}
|
|
|
|
this._sync_group();
|
|
},
|
|
|
|
_sync_group: function() {
|
|
let selected = this._config.get_current_group();
|
|
|
|
if (this._selectedLayout) {
|
|
this._selectedLayout.setShowDot(false);
|
|
this._selectedLayout = null;
|
|
}
|
|
|
|
if (this._selectedLabel) {
|
|
this._container.set_skip_paint(this._selectedLabel, true);
|
|
this._selectedLabel = null;
|
|
}
|
|
|
|
let item = this._layoutItems[selected];
|
|
item.setShowDot(true);
|
|
|
|
this._iconActor.icon_name = item._icon_name;
|
|
this._selectedLabel = this._labelActors[selected];
|
|
this._container.set_skip_paint(this._selectedLabel, this._showFlags);
|
|
|
|
this._selectedLayout = item;
|
|
},
|
|
|
|
_get_preferred_width: function(container, for_height, alloc) {
|
|
/* Here, and in _get_preferred_height, we need to query for the
|
|
height of all children, but we ignore the results for those
|
|
we don't actually display. */
|
|
let max_min_width = 0, max_natural_width = 0;
|
|
if (this._showFlags)
|
|
[max_min_width, max_natural_width] = this._iconActor.get_preferred_width(for_height);
|
|
|
|
for (let i = 0; i < this._labelActors.length; i++) {
|
|
let [min_width, natural_width] = this._labelActors[i].get_preferred_width(for_height);
|
|
if (!this._showFlags) {
|
|
max_min_width = Math.max(max_min_width, min_width);
|
|
max_natural_width = Math.max(max_natural_width, natural_width);
|
|
}
|
|
}
|
|
|
|
alloc.min_size = max_min_width;
|
|
alloc.natural_size = max_natural_width;
|
|
},
|
|
|
|
_get_preferred_height: function(container, for_width, alloc) {
|
|
let max_min_height = 0, max_natural_height = 0;
|
|
if (this._showFlags)
|
|
[max_min_height, max_natural_height] = this._iconActor.get_preferred_height(for_width);
|
|
|
|
for (let i = 0; i < this._labelActors.length; i++) {
|
|
let [min_height, natural_height] = this._labelActors[i].get_preferred_height(for_width);
|
|
if (!this._showFlags) {
|
|
max_min_height = Math.max(max_min_height, min_height);
|
|
max_natural_height = Math.max(max_natural_height, natural_height);
|
|
}
|
|
}
|
|
|
|
alloc.min_size = max_min_height;
|
|
alloc.natural_size = max_natural_height;
|
|
},
|
|
|
|
_allocate: function(container, box, flags) {
|
|
// translate box to (0, 0)
|
|
box.x2 -= box.x1;
|
|
box.x1 = 0;
|
|
box.y2 -= box.y1;
|
|
box.y1 = 0;
|
|
|
|
this._iconActor.allocate_align_fill(box, 0.5, 0, false, false, flags);
|
|
for (let i = 0; i < this._labelActors.length; i++)
|
|
this._labelActors[i].allocate_align_fill(box, 0.5, 0, false, false, flags);
|
|
}
|
|
};
|