其中一个与地精3.2壳顶部面板按钮的当前局限是没有支持显示不同的鼠标键点击的分开的菜单。 是,是,我能听见地精壳设计师说与完全当局和信念这个用途案件是故意的。 他们对所有批评的答复,建设性或者,关于他们的设计通常是他们比任何人更好知道,并且他们的(从未出版)实用性研究支持他们的设计。 请看喷发的暂停versa停电菜单选择辩论,当最初发布了地精壳!
无论如何,这个特殊局限使我困恼有一阵子和我最近决定看问题和尝试和搞到一种简单的可使用的解答到局限。
假设我要以下菜单被显示,当我使用我的鼠标左键激活在顶部面板的地精脚按钮:

当我使用我的鼠标右键激活同一个顶部面板按钮时,并且我要以下菜单选择被显示:

没什么在强调 嘟囔 极限为这样功能支持的代码。 实际上 嘟囔 有明确支持退回代表按的或被发布的鼠标键的整数。 根据 凌乱 (在哪些嘟囔根据)文献,在一只标准纸卷老鼠情况下,以下数字是可靠的:
- 1 =鼠标左键
- 2 =纸卷轮子
- 3 =鼠标右键
对于与更多按钮的老鼠,您可以必须试验看特殊的值的哪个特殊按钮返回。
用您的代码,您怎么确定哪特殊鼠标键按? 连接一个事件处理程序(AKA收回或信号经理)到按钮按事件并且/或者一名适当的演员的按钮发布事件信号。 在事件处理程序, ()退回整数的用途get_button代表按并且/或者被发布的具体鼠标键。 您能为新闻和发行信号使用一个唯一作用。
...
_init: function(menuAlignment) {
PanelMenu.ButtonBox.prototype._init.call(this,
{ reactive: true,
can_focus: true,
track_hover: true
});
...
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
...
},
_onButtonPress: function(actor, event) {
let button = event.get_button();
if (button == 1) {
// do something
} else if (button == 3) {
// do something
}
},
...
按钮按事件在一名易反应的演员散发,当鼠标键按时,但是不一定被发布。 按钮发布事件散发,当鼠标键在一名易反应的演员时被发布(即使老鼠予先被按了其他地方)。 通常您必须明白地使能演员的易反应的物产。 顺便说一句,一名易反应的演员(凌乱概念)是能散发尖事件的演员。
一个可选择方法将使用Clutter.ClickAction。
...
let clickAction = new Clutter.ClickAction();
clickAction.connect('clicked', Lang.bind(this, function(button) {
this._onButtonPress(button);
}));
this.actor.add_action(clickAction);
...
_onButtonPress: function(button) {
if (button == 1) {
// do something
} else if (button == 3) {
// do something
}
},
...
以Clutter.ClickAction怎样和哪里为例用于地精壳3.2在/usr/share/gnome-shell/js/ui/shellEntry.js的代码、它
回到手头的问题。 它结果对实施双重行动菜单的主要障碍在地精壳3.2在实施按钮对象的代码在。 看见/usr/share/gnome-shell/js/ui/panelMenu.js。 这相关的代码:
function Button(menuAlignment) {
this._init(menuAlignment);
}
Button.prototype = {
__proto__: ButtonBox.prototype,
_init: function(menuAlignment) {
ButtonBox.prototype._init.call(this, { reactive: true,
can_focus: true,
track_hover: true });
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
this.actor.connect('key-press-event', Lang.bind(this, this._onSourceKeyPress));
this.menu = new PopupMenu.PopupMenu(this.actor, menuAlignment, St.Side.TOP);
this.menu.actor.add_style_class_name('panel-menu');
this.menu.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged));
this.menu.actor.connect('key-press-event', Lang.bind(this, this._onMenuKeyPress));
Main.uiGroup.add_actor(this.menu.actor);
this.menu.actor.hide();
},
function Button(menuAlignment) {
this._init(menuAlignment);
}
Button.prototype = {
__proto__: ButtonBox.prototype,
_init: function(menuAlignment) {
ButtonBox.prototype._init.call(this, { reactive: true,
can_focus: true,
track_hover: true });
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
this.actor.connect('key-press-event', Lang.bind(this, this._onSourceKeyPress));
this.menu = new PopupMenu.PopupMenu(this.actor, menuAlignment, St.Side.TOP);
this.menu.actor.add_style_class_name('panel-menu');
this.menu.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged));
this.menu.actor.connect('key-press-event', Lang.bind(this, this._onMenuKeyPress));
Main.uiGroup.add_actor(this.menu.actor);
this.menu.actor.hide();
},
_onButtonPress: function(actor, event) {
if (!this.menu.isOpen) {
// Setting the max-height won't do any good if the minimum height of the
// menu is higher then the screen; it's useful if part of the menu is
// scrollable so the minimum height is smaller than the natural height
let monitor = Main.layoutManager.primaryMonitor;
this.menu.actor.style = ('max-height: ' +
Math.round(monitor.height - Main.panel.actor.height) +
'px;');
}
this.menu.toggle();
},
_onSourceKeyPress: function(actor, event) {
let symbol = event.get_key_symbol();
if (symbol == Clutter.KEY_space || symbol == Clutter.KEY_Return) {
this.menu.toggle();
return true;
} else if (symbol == Clutter.KEY_Escape && this.menu.isOpen) {
this.menu.close();
return true;
} else if (symbol == Clutter.KEY_Down) {
if (!this.menu.isOpen)
this.menu.toggle();
this.menu.actor.navigate_focus(this.actor, Gtk.DirectionType.DOWN, false);
return true;
} else
return false;
},
_onMenuKeyPress: function(actor, event) {
let symbol = event.get_key_symbol();
if (symbol == Clutter.KEY_Left || symbol == Clutter.KEY_Right) {
let focusManager = St.FocusManager.get_for_stage(global.stage);
let group = focusManager.get_group(this.actor);
if (group) {
let direction = (symbol == Clutter.KEY_Left) ? Gtk.DirectionType.LEFT : Gtk.DirectionType.RIGHT;
group.navigate_focus(this.actor, direction, false);
return true;
}
}
return false;
},
_onOpenStateChanged: function(menu, open) {
if (open)
this.actor.add_style_pseudo_class('active');
else
this.actor.remove_style_pseudo_class('active');
},
destroy: function() {
this.actor._delegate = null;
this.menu.destroy();
this.actor.destroy();
this.emit('destroy');
}
};
Signals.addSignalMethods(Button.prototype);
如果您审查上述代码,您看见尝试没有被做区分区别鼠标键之间。 就上述代码而言,一鼠标键是相同的象另一鼠标键。 或许地精壳的设计师长大使用一只唯一按钮苹果计算机公司老鼠或,许多位评论员建议了,地精壳为老鼠不是通常使用或可利用的片剂和palmhelds真正地设计。
对实施双重菜单功能的解答使用鼠标键将修改上面按钮代码的buttom按事件信号经理确定哪鼠标键相应地按和行动。
这我使用对原型双重菜单功能的运作的实施的一个简单的地精壳引伸的原始代码:
const St = imports.gi.St;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Lang = imports.lang;
const Clutter = imports.gi.Clutter;
const Shell = imports.gi.Shell;
const Signals = imports.signals;
function DualActionButton(menuAlignment) {
this._init(menuAlignment);
}
DualActionButton.prototype = {
__proto__: PanelMenu.ButtonBox.prototype,
_init: function(menuAlignment) {
PanelMenu.ButtonBox.prototype._init.call(this, { reactive: true,
can_focus: true,
track_hover: true });
this.actor.connect('button-press-event', Lang.bind(this, this._onButtonPress));
this.actor.connect('key-press-event', Lang.bind(this, this._onSourceKeyPress));
this.menuL = new PopupMenu.PopupMenu(this.actor, menuAlignment, St.Side.TOP);
this.menuL.actor.add_style_class_name('panel-menu');
this.menuL.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged));
this.menuL.actor.connect('key-press-event', Lang.bind(this, this._onMenuKeyPress));
Main.uiGroup.add_actor(this.menuL.actor);
this.menuL.actor.hide();
this.menuR = new PopupMenu.PopupMenu(this.actor, menuAlignment, St.Side.TOP);
this.menuR.actor.add_style_class_name('panel-menu');
this.menuR.connect('open-state-changed', Lang.bind(this, this._onOpenStateChanged));
this.menuR.actor.connect('key-press-event', Lang.bind(this, this._onMenuKeyPress));
Main.uiGroup.add_actor(this.menuR.actor);
this.menuR.actor.hide();
},
_onButtonPress: function(actor, event) {
let button = event.get_button();
if (button == 1) {
if (this.menuL.isOpen) {
this.menuL.close();
} else {
if (this.menuR.isOpen)
this.menuR.close();
this.menuL.open();
}
} else if (button == 3) {
if (this.menuR.isOpen) {
this.menuR.close();
} else {
if (this.menuL.isOpen)
this.menuL.close();
this.menuR.open();
}
}
},
_onButtonPress: function(actor, event) {
let button = event.get_button();
if (button == 1) {
if (this.menuL.isOpen) {
this.menuL.close();
} else {
if (this.menuR.isOpen)
this.menuR.close();
this.menuL.open();
}
} else if (button == 3) {
if (this.menuR.isOpen) {
this.menuR.close();
} else {
if (this.menuL.isOpen)
this.menuL.close();
this.menuR.open();
}
}
},
_onSourceKeyPress: function(actor, event) {
let symbol = event.get_key_symbol();
if (symbol == Clutter.KEY_space || symbol == Clutter.KEY_Return) {
if (this.menuL.isOpen) {
this.menuL.close();
} else if (this.menuR.isOpen) {
this.menuR.close();
}
return true;
} else if (symbol == Clutter.KEY_Escape) {
if (this.menuL.isOpen)
this.menuL.close();
if (this.menuR.isOpen)
this.menuR.close();
return true;
} else
return false;
},
_onMenuKeyPress: function(actor, event) {
let symbol = event.get_key_symbol();
if (symbol == Clutter.KEY_Left || symbol == Clutter.KEY_Right) {
let focusManager = St.FocusManager.get_for_stage(global.stage);
let group = focusManager.get_group(this.actor);
if (group) {
let direction = (symbol == Clutter.KEY_Left) ? Gtk.DirectionType.LEFT : Gtk.DirectionType.RIGHT;
group.navigate_focus(this.actor, direction, false);
return true;
}
}
return false;
},
_onOpenStateChanged: function(menu, open) {
if (open)
this.actor.add_style_pseudo_class('active');
else
this.actor.remove_style_pseudo_class('active');
},
destroy: function() {
this.actor._delegate = null;
this.menuL.destroy();
this.menuR.destroy();
this.actor.destroy();
this.emit('destroy');
},
};
Signals.addSignalMethods(DualActionButton.prototype);
function DemoDualActionButton() {
this._init();
}
DemoDualActionButton.prototype = {
__proto__: DualActionButton.prototype,
_init: function() {
DualActionButton.prototype._init.call(this, 0.0);
this._iconActor = new St.Icon({ icon_name: 'start-here',
icon_type: St.IconType.SYMBOLIC,
style_class: 'system-status-icon' });
this.actor.add_actor(this._iconActor);
this.actor.add_style_class_name('panel-status-button');
let item = new PopupMenu.PopupMenuItem(_("Left Menu Item 1"));
this.menuL.addMenuItem(item);
item = new PopupMenu.PopupMenuItem(_("Left Menu Item 2"));
this.menuL.addMenuItem(item);
item = new PopupMenu.PopupMenuItem(_("Right Menu Item 1"));
this.menuR.addMenuItem(item);
item = new PopupMenu.PopupMenuItem(_("Right Menu Item 2"));
this.menuR.addMenuItem(item);
item = new PopupMenu.PopupMenuItem(_("Right Menu Item 3"));
this.menuR.addMenuItem(item);
item = new PopupMenu.PopupMenuItem(_("Right Menu Item 4"));
this.menuR.addMenuItem(item);
},
enable: function() {
Main.panel._centerBox.add(this.actor, { y_fill: true });
Main.panel._menus.addMenu(this.menuL);
Main.panel._menus.addMenu(this.menuR);
},
disable: function() {
Main.panel._centerBox.remove_actor(this.actor);
Main.panel._menus.removeMenu(this.menuL);
Main.panel._menus.removeMenu(this.menuR);
}
};
function init() {
return new DemoDualActionButton();
}
DualActionButton目标代码是按钮代码的修改版本。 增加支持中心鼠标键菜单是琐细的; 如果您需要它,我将留下那您的能做。
注意我不在姓或价值对以后包括一个逗号。 根据Mozilla Java语言文献, 道格拉斯Crockford 和其他,这是正确句法。 不幸地,许多壳引伸开发商看上去不知道对象印刷错误的正确句法,并且包括逗号从 gjs,根据Mozilla SpiderMonkey Java语言 引擎和GObject 内省 框架,不抱怨这个特殊句法错误。
对于不喜欢浓缩地精壳引伸的那些读者使能并且使方法失去能力,并且有一些您根据评论,并且我收到的电子邮件,这作用基于初始化,使能和失去能力的原始代码上述引伸。
let button;
function init() {
button = new DemoDualActionButton();
}
function enable() {
Main.panel._centerBox.add(button.actor, { y_fill: true });
Main.panel._menus.addMenu(button.menuL);
Main.panel._menus.addMenu(button.menuR);
}
function disable() {
Main.panel._centerBox.remove_actor(button.actor);
Main.panel._menus.removeMenu(button.menuL);
Main.panel._menus.removeMenu(button.menuR);
}
某些人民声称处理的壳引伸上述代码比我通常使用的对象逐字编制程序样式是简单和容易了解。 我的答复是作用方法要求您使用有引伸范围,并且至少的一可变物,经常时期,在更加复杂的壳引伸的许多这样可变物。 当前非标准Mozilla Java语言让主题词极限可变物的词汇范围对可变物被定义的块以及所有内在块包含了的里面让块。 然而,如果var主题词使用而不是让主题词或没有使用主题词,可变物的范围默认为全球性。 他们可以介绍应该尽可能避免在Java语言的全局变量由于潜在的副作用和错误。 此种观察错误可以是难发现和,因此我选择完全地避免问题。 读附录A (可怕的零件)道格拉斯Crockford的精液书 Java语言: 好部分 ,如果您不了解与全球性范围的Java语言可变物为什么是邪恶的。
顺便说一句,我不是肯定的,如果一个双重行动菜单按钮的概念将破坏计算机地精壳的可及性(a11y)指南,但是假设范例在微软视窗中是共同的,我怀疑没有。
我根据您能从我的地精壳引伸网站下载的上述代码创造了一个简单的地精壳 引伸, demodualmenubutton 。
享用!


























我不喜欢是很简略的。 但是您为什么浪费您的在所有这些引伸的时间(那我顺便说一句使用日报) ? 我一直看您的名字和横跨网的这个网站-我从您张贴的页学会,但是一个问题依然存在: 您为什么不带领地精的编制程序?
实际上,我在地精引伸上花费很少时间或能量。 不要有时间或倾向。 当我不同意地精壳核心队的设计和施行哲学,关于“带领地精的编制程序”,它不发生。
我对您的版权是好奇的。 版权是否意味您的工作不能被重新分配? 为什么版权FOSS ?
执照和版权是在FOSS世界经常被混淆的二个不同概念。 我的工作可以每GPL被重新分配提供了您事假我的版权告示对此。 您能增加您自己的版权告示,如果您修改我的工作,但是您必须留给我的版权告示到位。
在美国和在多数国家,您自动地有版权对所有出版工作。 默认情况下,当工作被出版,那发生。 的确,如果您不要工作被复制权,您在公共领域必须明白地安置您的工作。
欲知详情 看见 http://www.gnu.org/licenses/gpl-faq.html#RequiredToClaimCopyright。