Одно из настоящих ограничений с кнопками верхней панели раковины GNOME 3.2 что никакая поддержка для показа отдельно меню для различных щелчков кнопки мыши. Да, да, я могу услышать что конструкторы раковины GNOME говорят с полными авторитетом и осуждением что этот случай пользы конструкцией. Их ответ к любому критицизму, конструктивные или в противном случае, о их конструкции вообще что они знают более лучше чем кто-нибудь еще и их (никогда-опубликованные) изучения практичности поддерживают их конструкцию. Как раз взгляд на дискуссии варианта меню силы versa суспендировать которая извергла когда раковина GNOME первоначально была выпущена!
В лубом случае, это определенное ограничение надоедало меня на некоторое время и я недавно решил посмотреть вопрос и попробовать и прийти вверх с просто выполнимый разрешением к ограничению.
Предположите что я хотел следующее меню быть показанным когда я использую мою кнопку левой мыши для того чтобы активировать кнопку ноги GNOME на верхней панели:

и я хочу следующие варианты меню быть показанным когда я использую мою кнопку правой мыши для того чтобы активировать такую же кнопку верхней панели:

Ничего в класть в основу бормочут Код который пределы поддерживают для такой функциональности. В действительности пробормочите имеет точную поддержку для возвращающ интежер который представляет отжатую или выпущенную кнопку мыши. Согласно документации местных помех (на что бормочет основывает), в случае стандартной мыши переченя, следующие номера надежны:
- 1 = кнопка левой мыши
- 2 = колесо переченя
- 3 = кнопка правой мыши
Для мышей с больше кнопок, вы можете экспериментировать для того чтобы увидеть которая определенная кнопка возвращает которая определенное значение.
В вашем Коде, как вы определяете которая определенная кнопка мыши была отжата? Просто соедините укротитель случая (укротители callback или сигнала AKA) к кнопк-отжимать-случаю and/or сигналы кнопк-выпускать-случая соответствующего актера. В случае укротитель, get_button пользы () для того чтобы возвратить интежер представляя специфическую кнопку мыши которая была отжата and/or была выпущена. Вы можете использовать одиночную функцию и для сигналов давления и отпуска.
...
_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 GNOME, взгляде в /usr/share/gnome-shell/js/ui/shellEntry.js и
Подоприте к проблеме под рукой adverb. Она поворачивает вне что главное препятствие к снабжать двойные меню действия в раковине 3.2 GNOME лежит в Коде который снабжает предмет кнопки. См. /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);
Если вы рассматриваете вышеуказанный Код, то вы увидите что не сделана никакая попытка продифференцировать между разными кнопками мыши. Насколько вышеуказанный Код обеспокоенный, одна кнопка мыши это же как другая кнопка мыши. Возможно конструкторы раковины GNOME росли вверх используя одиночную мышь Apple кнопки или, так много комментаторы предлагали, раковину GNOME действительно конструировал для таблеток и palmhelds где никакая мышь вообще используема или не имеющася.
Разрешение к снабжать двойную функциональность меню используя кнопки мыши было доработать укротитель сигнала buttom-отжимать-случая в вышеуказанном Коде кнопки для того чтобы определить была отжата и поступать соответствующим образом которая кнопка мыши.
Здесь исходный код для просто выдвижения раковины GNOME которому я использовал к прототипу работая вставку двойной функциональности меню:
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, Дуглас Crockford и другие, это правильно синтаксис. Несчастливо, кажется, что знают много проявителей выдвижений раковины правильно синтаксис для литералов предмета и включить запятой с gjs, которая основана на двигателе яваскрипта Mozilla SpiderMonkey и рамках самоанализа GObject, не жалует о этой определенной ошибке синтаксиса.
Для тех читателей которые не любят поместить выдвижение раковины GNOME включите и выведите методы из строя, и довольно несколько из вас согласно комментариям и электронная почта которую я получаю, здесь исходный код для начинания основанного функцией, позволять и выводить из строя вышеуказанного выдвижения.
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 препятствовал пределам ключевого слова объем перемеююого словарный к блоку в котором перемеююый определена так же, как любые внутренние блоки содержал внутренность препятствовал блоку самому. Однако, если ключевое слово var использовано вместо препятствовало ключевому слову или никакое ключевое слово не использовано, то объем перемеююого не выполняет обязательство к глобальный. Глобальные перемеююые в яваскрипте должны быть во избежаниеы где возможно из-за потенциальных побочных эффектов и ошибок они могут ввести. Этот тип ошибки scoping может быть трудн для того чтобы найти и поэтому я выбираю во избежание вопрос полностью. Прочитайте приложение a (ужасные части) яваскрипта основополагающей книги Дуглас Crockford: Интересные отрывки из книг если вы не понимаете, то почему перемеююые яваскрипта с глобальный объемом злейши.
Кстати, я не уверен если принципиальная схема двойной кнопки меню действия пробила бы брешь директивы доступности компьютера (a11y) для раковины, то GNOME но дано что парадигма общяя в Microsoft Windows, я подозрюю не.
Я создавал просто выдвижение раковины GNOME, demodualmenubutton, основанное на вышеуказанном Коде который вы можете загружать от моего вебсайта выдвижений раковины GNOME.
Насладитесь!


























Я ненавижу быть настолько краток. Но почему вы расточительствуете ваше время на всех этих выдвижениях (тех я использую повседневность кстати)? Я вижу ваше имя и этот вебсайт через сетчатое все время - я учу от страниц вы вывешиваете, но один вопрос остает: Почему вы не водите кодирвоание для GNOME?
Фактически, я трачу очень маленькие время или энергию на выдвижениях GNOME. Просто не имейте время или наклонение. Как для «ведения кодирвоания для GNOME», оно не идет случиться по мере того как я противоречу с конструкцией и общим соображением исполнения команды сердечника раковины GNOME.
Я был любознательон о вашем авторском праве. Авторское право значит вашу работу нельзя перераспределить? Почему авторское право FOSS?
Лицензия и авторское право 2 различных принципиальной схемы которая часто смущены в мире FOSS. Мою работу можно перераспределить в GPL обеспечила вам разрешение мои сведения об авторских правах на ей. Вы можете добавить ваши собственные сведения об авторских правах если вы дорабатываете мою работу, то но вы должны выйти мои сведения об авторских правах в место.
В США, и в большинств странах, вы автоматически имеете авторское право к любой опубликованной работе. То случается значением по умолчанию как только работа опубликована. Деиствительно, вы должны установить вашу работу недвусмысленно в сфере деятельности государства если вы не хотите работу быть авторским прав.
См. http://www.gnu.org/licenses/gpl-faq.html#RequiredToClaimCopyright для более подробная информация.