Traduisez

Translate to EnglishÜbersetzen Sie zum Deutsch/GermanΜεταφράστε στα ελληνικά/GreekПереведите к русскому/RussianOversetter til Norsk/NorwegianÖversätta till Svensk/Swedishहिनà¥à¤¦à¥€ अनà¥à¤µà¤¾à¤¦ करने के लिà¤/Hindi
Tradueix al català/CatalanTulkot uz latviešu/LatvianPreložiť do slovenčiny/SlovakVertaal aan het Nederlands/Dutchترجمة الى العربية/ArabicTraduzca al Español/SpanishTraduisez au Français/French
Traduca ad Italiano/ItalianTraduza ao Português/Portuguese日本語に翻訳しなさい /Japanese한국어에게 번역하십시오/Korean中文翻译/Chinese Simplified中文翻译/Chinese TraditionalПереклад на українську/Ukrainian
Image de XSLT 2.0 et de référence de programmeur de XPath 2.0 (programmeur au programmeur)
L'image de RHCE Red Hat a certifié le guide d'étude de Linux d'ingénieur (examen RH302) (la presse de certification)
Image de commencer Google Maps api 3
Image des logiciels d'exploitation modernes (3ème édition)

Menus duels pour un bouton de Shell 3.2 de GNOME

Une des limitations courantes avec les boutons de panneau supérieur de Shell du GNOME 3.2 est qu'il n'y a aucun soutien de montrer les menus séparés pour différents clics de bouton de souris. Oui, oui, je peux entendre que les concepteurs de Shell de GNOME disent avec l'autorité et la conviction complètes que ce cas d'utilisation est par conception. Leur réponse à n'importe quelle critique, constructive ou autrement, au sujet de leur conception est généralement qu'elles savent mieux que quiconque autrement et leurs études (jamais-éditées) de rentabilité soutiennent leur conception. Regardez juste la discussion d'option de menu de mise hors tension de versa de suspension qui a éclaté quand le GNOME Shell a été à l'origine libéré !

Quoi qu'il en soit, cette limitation particulière a ennuyé moi que pendant un moment et moi a récemment décidé de regarder l'issue et d'essayer et fournir une solution réalisable simple à la limitation.

Supposez que j'ai voulu que le menu suivant fût montré quand j'utilise mon bouton de souris gauche pour actionner le bouton de pied de GNOME sur le panneau supérieur :

et je veux que les options suivantes de menu soient présentées quand j'utilise mon bouton de souris droite pour actionner le même bouton de panneau supérieur :

Il n'y a rien dans être à la base murmurent le code que les limites soutiennent pour une telle fonctionnalité. Murmurez en fait a le soutien explicite de renvoyer un nombre entier qui représente un bouton appuyé sur ou libéré de souris. Selon la documentation d'image de fond (sur ce qui murmurent est basé), dans le cas d'une souris standard de rouleau, les nombres suivants sont fiables :

  • 1 = bouton de souris gauche
  • 2 = roue de rouleau
  • 3 = bouton de souris droite

Pour des souris avec plus de boutons, vous pouvez devoir expérimenter pour voir quel bouton particulier retourne qui valeur particulière.

En votre code, comment déterminez-vous quel bouton particulier de souris a été appuyé sur ? Reliez simplement un traiteur d'événement (des traiteurs de rappel de service ou de signal d'AKA) au bouton-presser-événement et/ou les signaux de bouton-libérer-événement d'un acteur approprié. En cas traiteur, get_button d'utilisation () pour renvoyer le nombre entier représentant le bouton spécifique de souris qui a été appuyé sur et/ou libéré. Vous pouvez employer une fonction simple pour des signaux de presse et de dégagement.

   ...

   _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
        }
    },

    ...


Un bouton-presser-événement est émis quand un bouton de souris est appuyé sur, mais pas nécessairement est libéré, sur un acteur réactif. Un bouton-libérer-événement est émis quand un bouton de souris est libéré sur un acteur réactif (même si la souris a été enfoncée quelque part autrement à l'avance). Habituellement vous devez explicitement permettre la propriété réactive d'un acteur. D'ailleurs, un acteur réactif (un concept d'image de fond) est un acteur qui peut émettre des événements d'indicateur.

Une approche alternative est d'employer 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
        }
    },

    ...


Pour des exemples de la façon dont et où Clutter.ClickAction est employé dans le code de Shell 3.2 de GNOME, le regard dans /usr/share/gnome-shell/js/ui/shellEntry.js et le /usr/share/gnome-shell/js/ui/workspace.js où il est employé à l'instrument cliqué sur et long-pressez la manipulation d'événement.

De nouveau au problème actuel. Il s'avère que l'empêchement principal à mettre en application les menus duels d'action dans le GNOME Shell 3.2 se situe dans le code qui met en application l'objet de bouton. Voir le /usr/share/gnome-shell/js/ui/panelMenu.js. Voici le code approprié :

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);


Si vous examinez le code ci-dessus, vous verrez qu'aucune tentative n'est faite de différencier entre les différents boutons de souris. En ce qui concerne le code ci-dessus, un bouton de souris est identique qu'un autre bouton de souris. Peut-être les concepteurs du GNOME Shell ont grandi utilisant une souris simple d'Apple de bouton ou, autant de commentateurs ont proposé, le GNOME Shell a été vraiment conçu pour des comprimés et des palmhelds où aucune souris n'est généralement utilisée ou disponible.

La solution à mettre en application la fonctionnalité duelle de menu utilisant des boutons de souris était de modifier le traiteur de signal de buttom-presser-événement dans le code ci-dessus de bouton pour déterminer quel bouton de souris a été appuyé sur et acte en conséquence.

Voici le code source pour une prolongation simple de Shell de GNOME que j'ai employé au prototype une exécution fonctionnante de la fonctionnalité duelle de menu :

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();
}


Le code d'objet de DualActionButton est simplement une version modifiée du code de bouton. Ajouter le soutien d'un menu central de bouton de souris est insignifiant ; Je laisserai cela pour que vous fassiez si vous avez besoin de lui.

Notez que je n'inclus pas une virgule après les paires de nom de famille/valeur. Selon la documentation de Javascript de Mozilla, Douglas Crockford et d'autres, ceci est la syntaxe correcte. Malheureusement, beaucoup de lotisseurs de prolongements de Shell semblent ne pas savoir la syntaxe correcte pour des coquilles d'objet et inclure la virgule depuis des gjs, qui est basée sur le moteur de Javascript de Mozilla SpiderMonkey et le cadre d'introspection de GObject, ne se plaint pas au sujet de cette erreur de syntaxe particulière.

Pour ces lecteurs qui n'aiment pas encapsuler la prolongation de Shell de GNOME permettez et désactivez les méthodes, et il y a tout à fait quelques uns de vous selon des commentaires et l'email que je reçois, voici le code source pour l'initialisation basée par fonction, permettre et désactiver de la prolongation ci-dessus.

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);
}


Certains réclament que le code ci-dessus pour manipuler une prolongation de Shell est plus simple et plus facile pour comprendre que le modèle littéral de codage d'objet que j'emploie généralement. Ma réponse est que l'approche de fonction exige de vous d'employer au moins une variable qui a la portée de prolongation et, souvent les périodes, beaucoup de telles variables dans des prolongements plus complexes de Shell. Le Javascript actuellement non standard de Mozilla a laissé des limites de mot-clé la portée lexicologique d'une variable au bloc dans lequel la variable est définie comme tous les blocs intérieurs a contenu l'intérieur a laissé le bloc lui-même. Cependant, si le mot-clé de variété est employé au lieu du laissait le mot-clé ou aucun mot-clé n'est employé, la portée de la variable se transfère sur global. Des variables globales dans le Javascript devraient être évitées si possible en raison des effets secondaires et des erreurs potentiels qu'elles peuvent présenter. Il peut être difficile trouver ce type d'erreur de portée et ainsi je choisis d'éviter l'issue entièrement. Lisez l'annexe A (pièces terribles) du Javascript séminal de livre de Douglas Crockford : Les bonnes parts si vous ne comprenez pas pourquoi les variables de Javascript avec la portée globale sont mauvaises.

D'ailleurs, je ne suis pas sûr si le concept d'un bouton duel de menu d'action ouvrirait une brèche des directives de l'accessibilité d'ordinateur (a11y) pour le GNOME Shell mais étant donné que le paradigme est commun dans Microsoft Windows, je suspecte pas.

J'ai créé une prolongation simple de Shell de GNOME, demodualmenubutton, basé sur le code ci-dessus que vous pouvez télécharger de mon site Web de prolongements de Shell de GNOME.

Appréciez !

4 commentaires à conjuguer menus pour un bouton de Shell 3.2 de GNOME

  • Je déteste pour être si brusque. Mais pourquoi perdez-vous votre temps sur tous ces prolongements est-ce que (ces j'utilise le journal d'ailleurs) ? Je vois votre nom et ce site Web à travers le filet toute l'heure - j'apprends des pages que vous signalez, mais une question demeure : Pourquoi ne menez-vous pas le codage pour le GNOME ?

    • En fait, je dépense le temps ou l'énergie très petit sur des prolongements de GNOME. Simplement n'ayez pas le temps ou l'inclination. Quant à « mener le codage pour le GNOME », elle ne va pas se produire pendant que je suis en désaccord avec la conception et la philosophie d'exécution de l'équipe de noyau de Shell de GNOME.

  • LONNIEFUTURE

    J'étais curieux au sujet de votre copyright. Copyright signifie-t-il votre travail ne peut-il pas être redistribué ? Pourquoi copyright FOSS ?

    • Le permis et le copyright sont deux concepts différents qui sont souvent confondus dans le monde de FOSS. Mon travail peut être redistribué par GPL t'a fourni le congé ma notification de copyright là-dessus. Vous pouvez ajouter votre propre notification de copyright si vous modifiez mon travail mais vous devez laisser ma notification de copyright en place.

      Aux Etats-Unis, et dans la plupart des pays, vous avez automatiquement copyright à n'importe quel travail édité. Cela se produit par défaut dès que le travail sera édité. En effet, vous devez placer votre travail explicitement dans le public domain si vous ne voulez pas que le travail soit garanti les droits d'auteur.

      Voir le http://www.gnu.org/licenses/gpl-faq.html#RequiredToClaimCopyright pour de plus amples informations.

Laissez une réponse