Vertaal

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
Beeld van Geavanceerde Programmering in het Milieu van UNIX, Tweede Uitgave (de Professionele Reeks van de Gegevensverwerking addison-Wesley)
Beeld van de Concepten van het Werkende Systeem
Beeld van XSLT 2.0 en XPath 2.0 de Verwijzing van de Programmeur (Programmeur aan Programmeur)
Beeld van Ontwikkeling van de Pit Linux (3de Uitgave)

Dubbele Menu's voor een GNOOM Shell 3.2 Knoop

n van de huidige beperkingen met GNOOM 3.2 hoogste het paneelknopen van Shell is dat er geen steun voor het tonen van afzonderlijke menu's voor verschillende muisknoop klikt is. Ja, ja, kan ik horen de ontwerpers van Shell van de GNOOM met volledige gezag en overtuiging zeggen dat dit gebruiksgeval door ontwerp is. Hun antwoord op om het even welke kritiek, constructief of anders, over hun ontwerp is over het algemeen dat zij beter dan om het even wie anders het weten en hun (nooit-gepubliceerde) bruikbaarheidsstudies steunen hun ontwerp. Bekijk enkel de Suspend versaMacht van het debat van de menuoptie dat losbarstte toen de GNOOM Shell oorspronkelijk werd vrijgegeven!

In elk geval, heeft deze bepaalde beperking me voor een tijdje gergerds en ik besliste onlangs ter discussie te bekijken en met een eenvoudige uitvoerbare oplossing aan de beperking te proberen en op de proppen te komen.

Veronderstel dat ik wilde dat het volgende menu worden getoond wanneer ik mijn linkermuisknoop gebruik om de knoop van de Voet van de GNOOM op het hoogste paneel te activeren:

en ik wil dat de volgende menuopties worden getoond wanneer ik mijn juiste muisknoop gebruik om de zelfde hoogste paneelknoop te activeren:

Er zijn niets in het ten grondslag liggen aan mompelt code die steun voor dergelijke functionaliteit beperkt. Mompel in feite heeft expliciete steun voor het terugkeren van een geheel dat een gedrukte of vrijgegeven muisknoop vertegenwoordigt. Volgens de Rommel (waarop gebaseerd is) mompel documentatie, in het geval van een standaardrolmuis, de volgende aantallen zijn betrouwbaar:

  • 1 = Verlaten muisknoop
  • 2 = het wiel van de Rol
  • 3 = Juiste muisknoop

Voor muizen met meer knopen, kunt u moeten experimenteren om te zien welke bijzondere knoopwinst die bijzondere waarde.

In uw code, hoe bepaalt u welke bijzondere muisknoop werd gedrukt? Verbind eenvoudig een gebeurtenismanager (callback AKA of signaalmanagers) met de knoop-pers-gebeurtenis en/of de knoop-versie-gebeurtenis signalen van een geschikte acteur. In de gebeurtenismanager, gebruik get_button () om het geheel terug te keren dat de specifieke muisknoop vertegenwoordigt die werd gedrukt en/of werd vrijgegeven. U kunt n enkele functie voor zowel pers gebruiken als signalen vrijgeven.

   ...

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

    ...


Een knoop-pers-gebeurtenis wordt uitgezonden wanneer een muisknoop wordt gedrukt, maar niet noodzakelijk, op een reactieve acteur vrijgegeven. Een knoop-versie-gebeurtenis wordt uitgezonden wanneer een muisknoop op een reactieve acteur wordt vrijgegeven (zelfs als de muis ergens anders vooraf werd neergedrukt). Gewoonlijk moet u het reactieve bezit van een acteur uitdrukkelijk toelaten. Door de manier, is een reactieve acteur (een concept van de Rommel) een acteur die wijzergebeurtenissen kan uitzenden.

Een alternatieve benadering is Clutter.ClickAction te gebruiken.


   ...

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

    ...


Als voorbeelden van hoe en waar Clutter.ClickAction in de GNOOM Shell 3.2 code wordt gebruikt, kijk in /usr/share/gnome-shell/js/ui/shellEntry.js en /usr/share/gnome-shell/js/ui/workspace.js waar het wordt gebruikt om geklikte en lang-persgebeurtenis behandeling uit te voeren.

Terug naar het dichtbije probleem. Het blijkt dat het belangrijkste beletsel aan het uitvoeren van dubbele actiemenu's in GNOOM Shell 3.2 in de code ligt die het voorwerp van de Knoop uitvoert. Zie /usr/share/gnome-shell/js/ui/panelMenu.js. Hier is de relevante code:

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


Als u de bovengenoemde code onderzoekt, zult u zien dat geen poging om tussen de verschillende muisknopen wordt gemaakt te onderscheiden. Wat betreft de bovengenoemde code, is n muisknoop het zelfde als een andere muisknoop. Misschien groeiden de ontwerpers van de GNOOM Shell het gebruiken van n enkele muis van knoopApple of, zoals vele commentators hebben voorgesteld, werd de GNOOM Shell werkelijk ontworpen voor tabletten en palmhelds waar geen muis over het algemeen of beschikbaar wordt gebruikt.

De oplossing voor het uitvoeren van dubbele menufunctionaliteit die muisknopen gebruikt was de manager van het buttom-pers-gebeurtenissignaal in de bovengenoemde code van de Knoop te wijzigen om te bepalen welke muisknoop en handeling dienovereenkomstig werd gedrukt.

Hier is de broncode voor een eenvoudige uitbreiding van Shell van de GNOOM dat ik aan prototype een het werk implementatie van dubbele menufunctionaliteit gebruikte:

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


De objecten DualActionButton code is eenvoudig een gewijzigde versie van de code van de Knoop. Toevoegen van steun voor een de knoopmenu van de centrummuis is onbelangrijk; Ik zal dat voor u om verlaten te doen als u het nodig hebt.

Merk op dat ik geen komma na het familienaam/waardepaar omvat. Volgens de documentatie van Mozilla JavaScript, Douglas Crockford en anderen, is dit de correcte syntaxis. Jammer genoeg, schijnen vele de uitbreidingenontwikkelaars van Shell om de correcte syntaxis voor objecten literals niet te kennen en de komma sinds te omvatten gjs, die op de motor van Mozilla SpiderMonkey JavaScript en het GObject introspectie kader , niet klaagt over deze bepaalde syntaxisfout gebaseerd is.

Voor die lezers die niet houden van de uitbreiding van Shell van de GNOOM in te kapselen laat en maak methodes toe onbruikbaar, en er zijn heel wat van u volgens commentaren en e-mail die ik ontvang, hier is de broncode voor functie het gebaseerde initialisering, toelaten en onbruikbaar maken van de bovengenoemde uitbreiding.

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


Sommige mensen beweren dat de bovengenoemde code voor de behandeling van een uitbreiding van Shell eenvoudiger en gemakkelijker is te begrijpen dan de objecten letterlijke codagestijl die ik over het algemeen gebruik. Mijn antwoord is dat de functiebenadering u vereist om minstens n variabele die uitbreidingswerkingsgebied hebben en, vaak tijden, veel dergelijke variabelen te gebruiken in de complexere uitbreidingen van Shell. Momenteel niet genormaliseerde Mozilla JavaScript liet sleutelwoord beperkt het lexicale werkingsgebied van een variabele tot het blok waarin de variabele wordt bepaald evenals laten om het even welke binnenblokken bevat binnen blok zelf. Nochtans, als het var sleutelwoord in plaats van wordt gebruikt laat sleutelwoord of geen sleutelwoord wordt gebruikt, het werkingsgebied van de veranderlijke gebreken aan globaal. De globale variabelen in JavaScript zouden moeten worden vermeden waar mogelijk wegens de potentile bijwerkingen en de fouten kunnen zij introduceren. Dit type van het scoping van fout kan moeilijk zijn te vinden en zodat verkies ik om de kwestie volledig te vermijden. Lees Bijlage A (Vreselijke Delen) van het rudimentaire boek JavaScript van Douglas Crockford: De goede Delen als u begrijpt niet waarom de variabelen JavaScript met globaal werkingsgebied kwaad zijn.

Door de manier, ben ik niet zeker als het concept een dubbele knoop van het actiemenu de richtlijnen van de computertoegankelijkheid (a11y) voor de GNOOM Shell zou overtreden maar gezien het paradigma in Microsoft Windows gemeenschappelijk is, verdenk ik niet.

Ik heb een eenvoudige uitbreiding van Shell van de GNOOM, demodualmenubutton gecrerd, die op de bovengenoemde code wordt gebaseerd die u van mijn de uitbreidingenwebsite van Shell van de GNOOM kunt downloaden.

Geniet van!

4 commentaren aan Dubbele Menu's voor een GNOOM Shell 3.2 Knoop

  • Ik haat zo bondig te zijn. Verspillend maar waarom zijn u uw tijd op al deze uitbreidingen (dat ik dagelijks door de manier gebruik)? Ik zie uw naam en deze website de hele tijd over netto - ik leer van de pagina's u post, maar n vraag blijft: Waarom niet leidt u de codage voor GNOOM?

    • Eigenlijk, breng ik zeer weinig tijd of energie aan de uitbreidingen van de GNOOM door. Eenvoudig hebben niet de tijd of de neiging. Zoals voor het leiden van de codage voor GNOOM, gaat het niet gebeuren aangezien ik met de ontwerp en uitvoeringsfilosofie van het de kernteam van Shell van de GNOOM niet akkoord ga.

  • LONNIEFUTURE

    Ik was nieuwsgierig over uw auteursrecht. Betekent het auteursrecht uw werk kan niet worden opnieuw verdeeld? Waarom auteursrecht FOSS?

    • De vergunning en het auteursrecht zijn twee verschillende concepten die in de wereld FOSS vaak verward zijn. Mijn werk kan per GPL worden opnieuw verdeeld op voorwaarde dat u mijn verklaring inzake auteursrecht op het verlaat. U kunt uw eigen verklaring inzake auteursrecht toevoegen als u mijn werk wijzigt maar u moet mijn verklaring inzake auteursrecht op zijn plaats verlaten.

      In de V.S., en in de meeste landen, hebt u automatisch auteursrecht aan om het even welk gepubliceerd werk. Dat gebeurt door gebrek zodra het werk wordt gepubliceerd. U moet namelijk uw werk in het openbare domein uitdrukkelijk plaatsen als u niet het werk wilt zijn copyrighted.

      Zie http://www.gnu.org/licenses/gpl-faq.html#RequiredToClaimCopyright voor verdere informatie.

Verlaat een Antwoord