Traduca

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
Immagine dei concetti del sistema operativo
L'immagine di RHCE Red Hat ha certificato la guida di studio di Linux dell'assistente tecnico (esame RH302) (pressa di certificazione)
Immagine di programmazione avanzata nell'ambiente di UNIX, seconda edizione (serie di calcolo del professionista del Addison-Wesley)
Immagine di cominciare Google Maps api 3

Menu doppi per un tasto di Shell 3.2 di GNOME

Una delle limitazioni correnti con i tasti del pannello superiore di Shell di GNOME 3.2 che non ci contributo a visualizzare i menu separati per gli scatti differenti del tasto di mouse. S, s, posso sentire che i progettisti di Shell di GNOME dicono con l'autorit e la convinzione complete che questo caso di uso dal disegno. La loro risposta a tutta la critica, costruttiva o al contrario, circa il loro disegno generalmente che sanno pi meglio di qualcuno altrimenti ed i loro studi (mai-pubblicati) di impiego possibile sostengono il loro disegno. Esamini appena il dibattito di opzione del menu di potere di versa di sospensione fuori che ha scoppiato quando lo GNOME Shell originale stato liberato!

In ogni modo, questa limitazione particolare lo ha infastidetto me che per un istante e recentemente ha deciso di esaminare l'edizione e di provare e fornire una soluzione realizzabile semplice alla limitazione.

Supponga che abbia voluto il seguente menu essere visualizzato quando utilizzo il mio tasto di mouse di sinistra per attivare il tasto del piede di GNOME sul pannello superiore:

e voglio le seguenti opzioni del menu essere visualizzato quando utilizzo il mio tasto di mouse di destra per attivare lo stesso tasto del pannello superiore:

Ci niente nel essere alla base mormora il codice che i limiti contributo a tale funzionalit. In effetti mormori ha contributo esplicito a restituire un numero intero che rappresenta un tasto di mouse urgente o liberato. Secondo la documentazione di ammasso (su quale mormorano basato), nel caso di un mouse standard del rotolo, i seguenti numeri sono certi:

  • 1 = tasto di mouse di sinistra
  • 2 = rotella del rotolo
  • 3 = tasto di mouse di destra

Per i mouse con pi tasti, potete dovere sperimentare per vedere quale tasto particolare rinvia che valore particolare.

Nel vostro codice, come determinate quale tasto di mouse particolare stato premuto? Colleghi semplicemente un alimentatore di evento (alimentatori di chiamata ripetuta o del segnale di AKA) all'tasto-premere-evento e/o i segnali di tasto-liberare-evento di un attore adatto. Nel caso alimentatore, get_button di uso () per restituire il numero intero che rappresenta il tasto di mouse specifico che stato premuto e/o liberato stato. Potete usare una singola funzione per sia i segnali del rilascio che della pressa.

   ...

   _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 tasto-premere-evento emesso quando un tasto di mouse premuto, ma non necessariamente liberato, su un attore reattivo. Un tasto-liberare-evento emesso quando un tasto di mouse liberato su un attore reattivo (anche se il mouse stato compresso altrimenti in anticipo in qualche luogo). Dovete permettere solitamente esplicitamente alla propriet reattiva di un attore. A proposito, un attore reattivo (un concetto di ammasso) un attore che pu emettere gli eventi dell'indicatore.

Un metodo alternativo di usare 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
        }
    },

    ...


Per degli esempi di come e dove Clutter.ClickAction utilizzato nel codice di Shell 3.2 di GNOME, nello sguardo in /usr/share/gnome-shell/js/ui/shellEntry.js ed in /usr/share/gnome-shell/js/ui/workspace.js dove usato allo strumento scattato e lungo-premi il trattamento di evento.

Di nuovo al problema attuale. Risulta che l'impedimento principale a realizzare i menu doppi di azione nello GNOME Shell 3.2 si trova nel codice che realizza l'oggetto del tasto. Vedi /usr/share/gnome-shell/js/ui/panelMenu.js. Qui il codice relativo:

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


Se esaminate il codice di cui sopra, vederete che nessun tentativo fatto di differenziarsi fra i tasti di mouse differenti. Per quanto il codice di cui sopra, un tasto di mouse lo stesso di un altro tasto di mouse. Forse i progettisti dello GNOME Shell si sono sviluppati consumanti un singolo mouse di Apple del tasto o, altretanti commentatori hanno suggerito, lo GNOME Shell realmente stato progettato per i ridurre in pani e i palmhelds in cui non c' nessun mouse usato generalmente o disponibile.

La soluzione a realizzare la funzionalit doppia del menu che per mezzo dei tasti di mouse era di modificare l'alimentatore del segnale di buttom-premere-evento nel codice di cui sopra del tasto per determinare quale tasto di mouse stato premuto di conseguenza ed atto.

Qui il codice sorgente per un'estensione semplice di Shell di GNOME che ho usato al prototipo un'esecuzione di funzionamento di funzionalit doppia del 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();
}


Il codice di oggetto di DualActionButton semplicemente una versione modificata del codice del tasto. L'aggiunta del contributo ad un menu concentrare del tasto di mouse insignificante; Gli lascer quello affinch faccia se lo avete bisogno.

Si noti che non comprendo un virgola dopo gli accoppiamenti valore/di cognome. Secondo la documentazione di Javascript di Mozilla, Douglas Crockford ed altre, questa la sintassi corretta. Purtroppo, molti sviluppatori di estensioni di Shell sembrano non conoscere la sintassi corretta per le costanti letterali dell'oggetto e comprendere il virgola dai gjs, che basato sul motore di Javascript di Mozilla SpiderMonkey e sulla struttura di introspezione di GObject, non protesta circa questo errore di sintassi particolare.

Per quei lettori che non gradicono incapsulare l'estensione di Shell di GNOME permetta e renda invalidi ai metodi e ci sono parecchi di voi secondo le osservazioni ed il email che ricevo, qui il codice sorgente per inizio basato funzione, permettere e rendere invalido dell'estensione di cui sopra.

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


Qualche gente sostiene che il codice di cui sopra per il trattamento dell'estensione di Shell pi semplice e pi facile capire che lo stile letterale di codificazione dell'oggetto che uso generalmente. La mia risposta che il metodo di funzione gli richiede di usare almeno una variabile che ha la portata di estensione e, spesso i periodi, molte tali variabili nelle estensioni pi complesse di Shell. Il Javascript attualmente non standard di Mozilla ha lasciato i limiti di parola chiave portata del lessico della variabile al blocco in cui la variabile definita come pure tutti i blocchi interni ha contenuto la parte interna ha lasciato il blocco in se. Tuttavia, se la parola chiave di variet usata anzich lasciasse la parola chiave o nessuna parola chiave usata, la portata della variabile stabilizza a globale. Le variabili globali nel Javascript dovrebbero essere evitate nel possibile a causa degli effetti secondari e degli errori che potenziali possono introdurre. Questo tipo di errore di scoping pu essere difficile da trovare ed in modo da scelgo di evitare l'edizione interamente. Legga l'appendice A (parti terribili) del Javascript seminale del libro della Douglas Crockford: La buona parte se non capite perch le variabili di Javascript con portata globale sono diaboliche.

A proposito, non sono sicuro se il concetto di un tasto doppio del menu di azione abbia aperto un varco la guida di riferimento di accessibilit del calcolatore (a11y) per lo GNOME Shell ma poich il paradigma comune in Microsoft Windows, ritengo sospetto non.

Ho generato un'estensione semplice di Shell di GNOME, demodualmenubutton, basato sul codice di cui sopra che potete caricare programmi oggetto dal mio Web site di estensioni di Shell di GNOME.

Goda di!

4 osservazioni da raddoppiarsi menu per un tasto di Shell 3.2 di GNOME

  • Odio essere cos brusco. Ma perch state sprecando il vostro tempo su tutte queste estensioni (quelle utilizzo il quotidiano a proposito)? Vedo il vostro nome e questo Web site attraverso la rete continuamente - imparo dalle pagine che inviate, ma una domanda rimane: Perch non state conducendo la codificazione per lo GNOME?

    • Realmente, spendo il tempo o l'energia pochissimo sulle estensioni di GNOME. Non abbia semplicemente il tempo o l'inclinazione. Per quanto riguarda la conduzione della codificazione per lo GNOME, non sta andando accadere mentre sono in disaccordo con il disegno e la filosofia di esecuzione della squadra del centro di Shell di GNOME.

  • LONNIEFUTURE

    Ero curioso circa il vostro copyright. Il copyright significa il vostro lavoro non pu essere ridistribuito? Perch copyright FOSS?

    • L'autorizzazione ed il copyright sono due concetti differenti che sono confusi spesso nel mondo di FOSS. Il mio lavoro pu essere ridistribuito per GPL gli ha fornito il permesso il mio avviso di copyright su esso. Potete aggiungere il vostro proprio avviso di copyright se modificate il mio lavoro ma dovete lasciare il mio avviso di copyright sul posto.

      Negli S.U.A. e nella maggior parte dei paesi, avete automaticamente copyright a tutta l'opera pubblicata. Quello accade per difetto non appena l'opera pubblicata. Effettivamente, dovete disporre esplicitamente il vostro lavoro nel public domain se non volete il lavoro essere coperto da diritti di autore.

      Vedi http://www.gnu.org/licenses/gpl-faq.html#RequiredToClaimCopyright per ulteriori informazioni.

Lasci una risposta