翻譯

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
現代操作系统(第3編輯)的圖像
開始Google Maps的圖像API 3
先進編程在UNIX環境,再版(阿狄森-維斯利專家計算的系列)的圖像
Linux仁發展(第3編輯)的圖像

更换在地精殼3.2的活動按鈕

在地精殼(3.0 )的 原著修改活動的文本通過一個簡單的地精殼引伸按或增加像 是非常容易的

例如,這我在發行地精之後出版3.0使用戶 那的一個簡單的地精殼引伸的代碼。

const St = imports.gi.St;
const Main = imports.ui.main;
const Panel = imports.ui.panel;

const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;

function main() {

   let hotCornerButton = Main.panel.button;

   let box = new St.BoxLayout({ style_class: 'activities_box'});

   // change the text string if you want to display different text
   // for the activities button
   let label = new St.Label({ text: _("Activities"),
                              style_class: 'activities_text' });

   // change the icon_name if you want to display a different icon
   // the icon must exist in the appropriate directory
   let logo = new St.Icon({ icon_type: St.IconType.FULLCOLOR,
                            icon_size: hotCornerButton.height,
                            icon_name: 'fedora-logo-icon' });

   // comment out this line if you do not want an icon displayed
   box.add_actor(logo);

   // comment out this line if you do not want the label displayed
   box.add_actor(label);

   Main.panel.button.set_child(box);
}


這個地精殼引伸可能容易地被定做顯示或者像,正文串或兩個活動的按。 您必須做的所有是評論或或uncomment在原始代码的適當的線。

發行地精3.2,包括的地精殼3.2,在2011年9月,上述代碼不再运作。 生活变得複雜為地精殼引伸開發商由於新的要求支持三個作用: init使能並且失去能力,當編碼一個新的地精殼引伸或升級一個現有的引伸到支持地精殼3.2。 為 變動的详细描写對地精殼引伸基礎設施的看見這個崗位,我寫兩三個月前。

另外,與活動相關的Java語言代碼按显著被改變在地精殼3.0和3.2之間。 這從/usr/share/gnome-shell/js/ui/panel.js的相關的代碼與被去除的評論減少排数。

function ActivitiesButton() {
    this._init.apply(this, arguments);
}

ActivitiesButton.prototype = {
    __proto__: PanelMenu.Button.prototype,

    _init: function() {
        PanelMenu.Button.prototype._init.call(this, 0.0);

        let container = new Shell.GenericContainer();
        container.connect('get-preferred-width', Lang.bind(this, this._containerGetPreferredWidth));
        container.connect('get-preferred-height', Lang.bind(this, this._containerGetPreferredHeight));
        container.connect('allocate', Lang.bind(this, this._containerAllocate));
        this.actor.add_actor(container);
        this.actor.name = 'panelActivities';

        this._label = new St.Label({ text: _("Activities") });
        container.add_actor(this._label);

        this._hotCorner = new Layout.HotCorner();
        container.add_actor(this._hotCorner.actor);

        this.menu.open = Lang.bind(this, this._onMenuOpenRequest);
        this.menu.close = Lang.bind(this, this._onMenuCloseRequest);
        this.menu.toggle = Lang.bind(this, this._onMenuToggleRequest);

        this.actor.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
        this.actor.connect_after('button-release-event', Lang.bind(this, this._onButtonRelease));
        this.actor.connect_after('key-release-event', Lang.bind(this, this._onKeyRelease));

        Main.overview.connect('showing', Lang.bind(this, function() {
            this.actor.add_style_pseudo_class('overview');
            this._escapeMenuGrab();
        }));
        Main.overview.connect('hiding', Lang.bind(this, function() {
            this.actor.remove_style_pseudo_class('overview');
            this._escapeMenuGrab();
        }));

        this._xdndTimeOut = 0;
    },
    _containerGetPreferredWidth: function(actor, forHeight, alloc) {
        [alloc.min_size, alloc.natural_size] = this._label.get_preferred_width(forHeight);
    },

    _containerGetPreferredHeight: function(actor, forWidth, alloc) {
        [alloc.min_size, alloc.natural_size] = this._label.get_preferred_height(forWidth);
    },

    _containerAllocate: function(actor, box, flags) {
        this._label.allocate(box, flags);

        let primary = Main.layoutManager.primaryMonitor;
        let hotBox = new Clutter.ActorBox();
        let ok, x, y;
        if (actor.get_direction() == St.TextDirection.LTR) {
            [ok, x, y] = actor.transform_stage_point(primary.x, primary.y)
        } else {
            [ok, x, y] = actor.transform_stage_point(primary.x + primary.width, primary.y);
        }

        hotBox.x1 = Math.round(x);
        hotBox.x2 = hotBox.x1 + this._hotCorner.actor.width;
        hotBox.y1 = Math.round(y);
        hotBox.y2 = hotBox.y1 + this._hotCorner.actor.height;
        this._hotCorner.actor.allocate(hotBox, flags);
    },


注意使用Shell.GenericContainer和它伴生的信號經理。 我將回到談論這個對象,並且這些后發信號經理崗位的。

這個崗位剩下的人通過一定數量的例子描述如何通过地精殼引伸修改上述代碼為了改變被顯示的(文本)標籤,顯示像而不是標籤或同時顯示像和標籤。 這個崗位假设,您熟悉地精殼引伸發展; 它不試圖解釋寫引伸基本。

例子1 :

這個地精殼引伸顯示活動的一個供選擇的標籤按,當使能並且恢復回到原始的標籤,即活動,當失去能力。 地方化支持供選擇的標籤不是包括的,而是可能容易地增加。

const Main = imports.ui.main;

// Replace this string constant with your text
const ACTIVITIES_BUTTON_TEXT = "Change Me";

function ChangeActivitiesButtonText() {
    this._init();
}

ChangeActivitiesButtonText.prototype = {

    _init: function() {
        this._label = Main.panel._activitiesButton._label;
        this._originalText = this._label.get_text();
    },

    enable: function() {
        this._label.set_text(ACTIVITIES_BUTTON_TEXT);
    },

    disable: function() {
        this._label.set_text(this._originalText);
    }
};

function init(extensionMeta) {
    return new ChangeActivitiesButtonText();
}


您能看到,這個地精殼引伸的代碼是十分簡單的。 當安裝时引伸, _init被祈求。 當引伸使能时,使能被祈求,並且在活動按鈕的標籤被改變到ACTIVITIES_BUTTON_TEXT常數的內容。 當引伸是殘疾时,原始的標籤,即活動,被顯示。

某些人民更喜歡非樣本写作方式地精殼引伸。 如果您是那些人民之一,這什麼這個引伸看上去象,當寫提供三個必須的作用:

const Main = imports.ui.main;

// Replace this string constant with your text
const ACTIVITIES_BUTTON_TEXT = "Change Me";

let _label;
let _originalText;

function init() {
    _label = Main.panel._activitiesButton._label;
    _originalText = _label.get_text();
}

function enable() {
    _label.set_text(ACTIVITIES_BUTTON_TEXT);
}

function disable() {
    _label.set_text(this._originalText);
}

例子2 :

當您想要增加像到活動按鈕或用像时,替换文本事变得更加複雜。 這归结于事實實施的按鈕在地精殼3.2被更换使用殼GenericContainer對象的活動代碼。 這這個 對象的 C原始代码。

/**
 * SECTION:shell-generic-container
 * @short_description: A container class with signals for allocation
 *
 * #ShellGenericContainer is mainly a workaround for the current
 * lack of GObject subclassing + vfunc overrides in gjs.  We
 * implement the container interface, but proxy the virtual functions
 * into signals, which gjs can catch.
 *
 * #ShellGenericContainer is an #StWidget, and automatically takes its
 * borders and padding into account during size request and allocation.
 */

#include "config.h"

#include "shell-generic-container.h"

#include <clutter/clutter.h>
#include <gtk/gtk.h>
#include <girepository.h>

static void shell_generic_container_iface_init (ClutterContainerIface *iface);

G_DEFINE_TYPE_WITH_CODE(ShellGenericContainer,
                        shell_generic_container,
                        ST_TYPE_CONTAINER,
                        G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_CONTAINER,
                                               shell_generic_container_iface_init));

struct _ShellGenericContainerPrivate {
  GHashTable *skip_paint;
};

/* Signals */
enum
{
  GET_PREFERRED_WIDTH,
  GET_PREFERRED_HEIGHT,
  ALLOCATE,
  LAST_SIGNAL
};

static guint shell_generic_container_signals [LAST_SIGNAL] = { 0 };

static gpointer
shell_generic_container_allocation_ref (ShellGenericContainerAllocation *alloc)
{
  alloc->_refcount++;
  return alloc;
}

static void
shell_generic_container_allocation_unref (ShellGenericContainerAllocation *alloc)
{
  if (--alloc->_refcount == 0)
    g_slice_free (ShellGenericContainerAllocation, alloc);
}

static void
shell_generic_container_allocate (ClutterActor           *self,
                                  const ClutterActorBox  *box,
                                  ClutterAllocationFlags  flags)
{
  StThemeNode *theme_node;
  ClutterActorBox content_box;

  CLUTTER_ACTOR_CLASS (shell_generic_container_parent_class)->allocate (self, box, flags);

  theme_node = st_widget_get_theme_node (ST_WIDGET (self));
  st_theme_node_get_content_box (theme_node, box, &content_box);

  g_signal_emit (G_OBJECT (self), shell_generic_container_signals[ALLOCATE], 0,
                 &content_box, flags);
}

static void
shell_generic_container_get_preferred_width (ClutterActor *actor,
                                             gfloat        for_height,
                                             gfloat       *min_width_p,
                                             gfloat       *natural_width_p)
{
  ShellGenericContainerAllocation *alloc = g_slice_new0 (ShellGenericContainerAllocation);
  StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));

  st_theme_node_adjust_for_height (theme_node, &for_height);

  alloc->_refcount = 1;
  g_signal_emit (G_OBJECT (actor), shell_generic_container_signals[GET_PREFERRED_WIDTH], 0,
                 for_height, alloc);
  if (min_width_p)
    *min_width_p = alloc->min_size;
  if (natural_width_p)
    *natural_width_p = alloc->natural_size;
  shell_generic_container_allocation_unref (alloc);

  st_theme_node_adjust_preferred_width (theme_node, min_width_p, natural_width_p);
}

static void
shell_generic_container_get_preferred_height (ClutterActor *actor,
                                              gfloat        for_width,
                                              gfloat       *min_height_p,
                                              gfloat       *natural_height_p)
{
  ShellGenericContainerAllocation *alloc = g_slice_new0 (ShellGenericContainerAllocation);
  StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));

  st_theme_node_adjust_for_width (theme_node, &for_width);

  alloc->_refcount = 1;
  g_signal_emit (G_OBJECT (actor), shell_generic_container_signals[GET_PREFERRED_HEIGHT], 0,
                 for_width, alloc);
  if (min_height_p)
    *min_height_p = alloc->min_size;
  if (natural_height_p)
    *natural_height_p = alloc->natural_size;
  shell_generic_container_allocation_unref (alloc);

  st_theme_node_adjust_preferred_height (theme_node, min_height_p, natural_height_p);
}

static void
shell_generic_container_paint (ClutterActor  *actor)
{
  ShellGenericContainer *self = (ShellGenericContainer*) actor;
  GList *iter, *children;

  CLUTTER_ACTOR_CLASS (shell_generic_container_parent_class)->paint (actor);

  children = st_container_get_children_list (ST_CONTAINER (actor));
  for (iter = children; iter; iter = iter->next)
    {
      ClutterActor *child = iter->data;

      if (g_hash_table_lookup (self->priv->skip_paint, child))
        continue;

      clutter_actor_paint (child);
    }
}

static void
shell_generic_container_pick (ClutterActor        *actor,
                              const ClutterColor  *color)
{
  ShellGenericContainer *self = (ShellGenericContainer*) actor;
  GList *iter, *children;

  CLUTTER_ACTOR_CLASS (shell_generic_container_parent_class)->pick (actor, color);

  children = st_container_get_children_list (ST_CONTAINER (actor));
  for (iter = children; iter; iter = iter->next)
    {
      ClutterActor *child = iter->data;

      if (g_hash_table_lookup (self->priv->skip_paint, child))
        continue;

      clutter_actor_paint (child);
    }
}

static GList *
shell_generic_container_get_focus_chain (StContainer *container)
{
  ShellGenericContainer *self = SHELL_GENERIC_CONTAINER (container);
  GList *children, *focus_chain;

  focus_chain = NULL;
  for (children = st_container_get_children_list (container); children; children = children->next)
    {
      ClutterActor *child = children->data;

      if (CLUTTER_ACTOR_IS_VISIBLE (child) &&
          !shell_generic_container_get_skip_paint (self, child))
        focus_chain = g_list_prepend (focus_chain, child);
    }

  return g_list_reverse (focus_chain);
}

/**
 * shell_generic_container_get_n_skip_paint:
 * @self:  A #ShellGenericContainer
 *
 * Returns: Number of children which will not be painted.
 */
guint
shell_generic_container_get_n_skip_paint (ShellGenericContainer  *self)
{
  return g_hash_table_size (self->priv->skip_paint);
}

/**
 * shell_generic_container_get_skip_paint:
 * @self: A #ShellGenericContainer
 * @child: Child #ClutterActor
 *
 * Gets whether or not @actor is skipped when painting.
 *
 * Return value: %TRUE or %FALSE
 */
gboolean
shell_generic_container_get_skip_paint (ShellGenericContainer  *self,
                                        ClutterActor           *child)
{
  return g_hash_table_lookup (self->priv->skip_paint, child) != NULL;
}

/**
 * shell_generic_container_set_skip_paint:
 * @self: A #ShellGenericContainer
 * @child: Child #ClutterActor
 * @skip: %TRUE if we should skip painting
 *
 * Set whether or not we should skip painting @actor.  Workaround for
 * lack of gjs ability to override _paint vfunc.
 */
void
shell_generic_container_set_skip_paint (ShellGenericContainer  *self,
                                        ClutterActor           *child,
                                        gboolean                skip)
{
  gboolean currently_skipping;

  currently_skipping = g_hash_table_lookup (self->priv->skip_paint, child) != NULL;
  if (!!skip == currently_skipping)
    return;

  if (!skip)
    g_hash_table_remove (self->priv->skip_paint, child);
  else
    g_hash_table_insert (self->priv->skip_paint, child, child);

  clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
}

static void
shell_generic_container_finalize (GObject *object)
{
  ShellGenericContainer *self = (ShellGenericContainer*) object;

  g_hash_table_destroy (self->priv->skip_paint);

  G_OBJECT_CLASS (shell_generic_container_parent_class)->finalize (object);
}

static void
shell_generic_container_class_init (ShellGenericContainerClass *klass)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
  ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
  StContainerClass *container_class = ST_CONTAINER_CLASS (klass);

  gobject_class->finalize = shell_generic_container_finalize;

  actor_class->get_preferred_width = shell_generic_container_get_preferred_width;
  actor_class->get_preferred_height = shell_generic_container_get_preferred_height;
  actor_class->allocate = shell_generic_container_allocate;
  actor_class->paint = shell_generic_container_paint;
  actor_class->pick = shell_generic_container_pick;

  container_class->get_focus_chain = shell_generic_container_get_focus_chain;

  /**
   * ShellGenericContainer::get-preferred-width:
   * @self: the #ShellGenericContainer
   * @for_height: as in clutter_actor_get_preferred_width()
   * @alloc: a #ShellGenericContainerAllocation to be filled in
   *
   * Emitted when clutter_actor_get_preferred_width() is called
   * on @self. You should fill in the fields of @alloc with the
   * your minimum and natural widths. #ShellGenericContainer
   * will deal with taking its borders and padding into account
   * for you.
   *
   * @alloc's fields are initialized to 0, so unless you have a fixed
   * width specified (via #ClutterActor:width or CSS), you must
   * connect to this signal and fill in the values.
   */
  shell_generic_container_signals[GET_PREFERRED_WIDTH] =
    g_signal_new ("get-preferred-width",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_LAST,
                  0,
                  NULL, NULL,
                  gi_cclosure_marshal_generic,
                  G_TYPE_NONE, 2, G_TYPE_FLOAT, SHELL_TYPE_GENERIC_CONTAINER_ALLOCATION);

  /**
   * ShellGenericContainer::get-preferred-height:
   * @self: the #ShellGenericContainer
   * @for_width: as in clutter_actor_get_preferred_height()
   * @alloc: a #ShellGenericContainerAllocation to be filled in
   *
   * Emitted when clutter_actor_get_preferred_height() is called
   * on @self. You should fill in the fields of @alloc with the
   * your minimum and natural heights. #ShellGenericContainer
   * will deal with taking its borders and padding into account
   * for you.
   *
   * @alloc's fields are initialized to 0, so unless you have a fixed
   * height specified (via #ClutterActor:height or CSS), you must
   * connect to this signal and fill in the values.
   */
  shell_generic_container_signals[GET_PREFERRED_HEIGHT] =
    g_signal_new ("get-preferred-height",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_LAST,
                  0,
                  NULL, NULL,
                  gi_cclosure_marshal_generic,
                  G_TYPE_NONE, 2, G_TYPE_FLOAT, SHELL_TYPE_GENERIC_CONTAINER_ALLOCATION);

  /**
   * ShellGenericContainer::allocate:
   * @self: the #ShellGenericContainer
   * @box: @self's content box
   * @flags: the allocation flags.
   *
   * Emitted when @self is allocated, after chaining up to the parent
   * allocate method.
   *
   * Note that @box is @self's content box (qv
   * st_theme_node_get_content_box()), NOT its allocation.
   */
  shell_generic_container_signals[ALLOCATE] =
    g_signal_new ("allocate",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_LAST,
                  0,
                  NULL, NULL,
                  gi_cclosure_marshal_generic,
                  G_TYPE_NONE, 2, CLUTTER_TYPE_ACTOR_BOX, CLUTTER_TYPE_ALLOCATION_FLAGS);

  g_type_class_add_private (gobject_class, sizeof (ShellGenericContainerPrivate));
}

static void
shell_generic_container_actor_removed (ClutterContainer *container,
                                       ClutterActor     *actor)
{
  ShellGenericContainerPrivate *priv = SHELL_GENERIC_CONTAINER (container)->priv;

  g_hash_table_remove (priv->skip_paint, actor);
}

static void
shell_generic_container_iface_init (ClutterContainerIface *iface)
{
  iface->actor_removed = shell_generic_container_actor_removed;
}

static void
shell_generic_container_init (ShellGenericContainer *area)
{
  area->priv = G_TYPE_INSTANCE_GET_PRIVATE (area, SHELL_TYPE_GENERIC_CONTAINER,
                                            ShellGenericContainerPrivate);
  area->priv->skip_paint = g_hash_table_new (NULL, NULL);
}

GType
shell_generic_container_allocation_get_type (void)
{
  static GType gtype = G_TYPE_INVALID;
  if (gtype == G_TYPE_INVALID)
    {
      gtype = g_boxed_type_register_static ("ShellGenericContainerAllocation",
         (GBoxedCopyFunc)shell_generic_container_allocation_ref,
         (GBoxedFreeFunc)shell_generic_container_allocation_unref);
    }
  return gtype;
}

一種方式在殼GenericContainer問題附近工作將使用 CSS活動按顯示像而不是缺省標籤如下所示的restyle :

const St = imports.gi.St;
const Shell = imports.gi.Shell;
const Main = imports.ui.main;

function ThemeActivitiesButton(meta) {
    this._init(meta)
}

ThemeActivitiesButton.prototype = {
    _init: function(meta) {
        this._defaultStylesheet = Main._defaultCssStylesheet;
        this._patchStylesheet = meta.path + '/activitiesbutton.css';
        this._themeContext = St.ThemeContext.get_for_stage(global.stage);
    },

    enable: function() {
        let theme = new St.Theme ({ application_stylesheet: this._patchStylesheet,
                                    theme_stylesheet: this._defaultStylesheet });
        try {
            this._themeContext.set_theme(theme);
        } catch (e) {
            global.logError('Stylesheet parse error: ' + e);
        }
    },

    disable: function() {
        let theme = new St.Theme ({ theme_stylesheet: this._defaultStylesheet });
        try {
            this._themeContext.set_theme(theme);
        } catch (e) {
            global.logError('Stylesheet parse error: ' + e);
        }
    }

};

function init(meta) {
    return new ThemeActivitiesButton(meta);
}


這對應的stylesheet.css

/* activitiesbutton.png should be 24x24 PNG icon */

#panelActivities {
    border: none;
    background-image: url("activitiesbutton.png");
    background-position: 4 0;
    width: 24px;
    height: 24px;
    padding-left: 12px;
    padding-right: 0px;
    color: rgba(0,0,0,0.0);
    transition-duration: 100;
}

#panelActivities:hover {
    border-image: url("activitiesbutton-border.svg") 10 10 0 2;
}


這種方法的問題是(1)您不可能顯示文本,並且在活動的一個像按,並且(2)那裡為稱呼是潛在的地精殼成為迷茫由于在多個地精殼引伸的多stylesheets。 這是在地精殼的一個已知的問題。 它是可能容易地發生與非常书面殼引伸做關於的事什麼的無保證的假定他們能和不能做。

更好的方法將瞭解殼GenericContainer怎麼运作。 要瞭解的可能最重要的事關於這個對象是您不可能分配高度或寬度,當您創造這個對象时事例。 如以下例子所顯示,反而您必須使用三個不同信號:

// create the new shell generic container object
let container = new Shell.GenericContainer();

// set up the three signals
container.connect('get-preferred-width', Lang.bind(this, this._containerGetPreferredWidth));
container.connect('get-preferred-height', Lang.bind(this, this._containerGetPreferredHeight));
container.connect('allocate', Lang.bind(this, this._containerAllocate));

// signal code
_containerGetPreferredWidth: function(actor, forHeight, alloc) {
    [alloc.min_size, alloc.natural_size] = this._label.get_preferred_width(forHeight);
},

_containerGetPreferredHeight: function(actor, forWidth, alloc) {
    [alloc.min_size, alloc.natural_size] = this._label.get_preferred_height(forWidth);
},

_containerAllocate: function(actor, box, flags) {
    this._label.allocate(box, flags);
    ....
},


這顯示在活動的淺頂軟呢帽項目商標按,當使能的完全extension.js。 在這個崗位的所有剩余的例子根据這個代碼。

const Clutter = imports.gi.Clutter;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Layout = imports.ui.layout;
const PanelMenu = imports.ui.panelMenu;
const Main = imports.ui.main;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Signals = imports.signals;

// ------------ change to suit -----------
const ACTIVITIES_BUTTON_ICON_SIZE    = 20;
const ACTIVITIES_BUTTON_ICON_NAME    = 'fedora-logo-icon';  

function ActivitiesButtonIcon() {
    this._init.apply(this, arguments);
}

// ----- most of this code came straight from panel.js
ActivitiesButtonIcon.prototype = {
    __proto__: PanelMenu.Button.prototype,

    _init: function() {
        PanelMenu.Button.prototype._init.call(this, 0.0);

        this.actor.name = 'panelActivities';

        let container = new Shell.GenericContainer();
        container.connect('get-preferred-width', Lang.bind(this, this._containerGetPreferredWidth));
        container.connect('get-preferred-height', Lang.bind(this, this._containerGetPreferredHeight));
        container.connect('allocate', Lang.bind(this, this._containerAllocate));
        this.actor.add_actor(container);

        // ---------------- icon code -----------------
        this._iconBox = new St.Bin({ width: ACTIVITIES_BUTTON_ICON_SIZE,
                                     height: ACTIVITIES_BUTTON_ICON_SIZE,
                                     x_fill: true,
                                     y_fill: true });
        this._logo = new St.Icon({ icon_type: St.IconType.FULLCOLOR,
                                   icon_size: ACTIVITIES_BUTTON_ICON_SIZE,
                                   icon_name: ACTIVITIES_BUTTON_ICON_NAME });
        this._iconBox.child = this._logo;
        container.add_actor(this._iconBox);

        this._hotCorner = new Layout.HotCorner();
        container.add_actor(this._hotCorner.actor);

        // Hack up our menu...
        this.menu.open = Lang.bind(this, this._onMenuOpenRequest);
        this.menu.close = Lang.bind(this, this._onMenuCloseRequest);
        this.menu.toggle = Lang.bind(this, this._onMenuToggleRequest);

        this.actor.connect('captured-event', Lang.bind(this, this._onCapturedEvent));
        this.actor.connect_after('button-release-event', Lang.bind(this, this._onButtonRelease));
        this.actor.connect_after('key-release-event', Lang.bind(this, this._onKeyRelease));

        Main.overview.connect('showing', Lang.bind(this, function() {
            this.actor.add_style_pseudo_class('overview');
            this._escapeMenuGrab();
        }));
        Main.overview.connect('hiding', Lang.bind(this, function() {
            this.actor.remove_style_pseudo_class('overview');
            this._escapeMenuGrab();
        }));

        this._xdndTimeOut = 0;
    },

    _containerGetPreferredWidth: function(actor, forHeight, alloc) {
        [alloc.min_size, alloc.natural_size] = this._iconBox.get_preferred_width(forHeight);
    },

    _containerGetPreferredHeight: function(actor, forWidth, alloc) {
        [alloc.min_size, alloc.natural_size] = this._iconBox.get_preferred_height(forWidth);
    },

    _containerAllocate: function(actor, box, flags) {
        this._iconBox.allocate(box, flags);

        let primary = Main.layoutManager.primaryMonitor;
        let hotBox = new Clutter.ActorBox();
        let ok, x, y;
        if (actor.get_direction() == St.TextDirection.LTR) {
            [ok, x, y] = actor.transform_stage_point(primary.x, primary.y)
        } else {
            [ok, x, y] = actor.transform_stage_point(primary.x + primary.width, primary.y);
        }

        hotBox.x1 = Math.round(x);
        hotBox.x2 = hotBox.x1 + this._hotCorner.actor.width;
        hotBox.y1 = Math.round(y);
        hotBox.y2 = hotBox.y1 + this._hotCorner.actor.height;
        this._hotCorner.actor.allocate(hotBox, flags);
    },

    handleDragOver: function(source, actor, x, y, time) {
        if (source != Main.xdndHandler)
            return;

        if (this._xdndTimeOut != 0)
            Mainloop.source_remove(this._xdndTimeOut);
        this._xdndTimeOut = Mainloop.timeout_add(BUTTON_DND_ACTIVATION_TIMEOUT,
                                                 Lang.bind(this, this._xdndShowOverview, actor));
    },

    _escapeMenuGrab: function() {
        if (this.menu.isOpen)
            this.menu.close();
    },

    _onCapturedEvent: function(actor, event) {
        if (event.type() == Clutter.EventType.BUTTON_PRESS) {
            if (!this._hotCorner.shouldToggleOverviewOnClick())
                return true;
        }
        return false;
    },

    _onMenuOpenRequest: function() {
        this.menu.isOpen = true;
        this.menu.emit('open-state-changed', true);
    },

    _onMenuCloseRequest: function() {
        this.menu.isOpen = false;
        this.menu.emit('open-state-changed', false);
    },

    _onMenuToggleRequest: function() {
        this.menu.isOpen = !this.menu.isOpen;
        this.menu.emit('open-state-changed', this.menu.isOpen);
    },

    _onButtonRelease: function() {
        if (this.menu.isOpen) {
            this.menu.close();
            Main.overview.toggle();
        }
    },

    _onKeyRelease: function(actor, event) {
        let symbol = event.get_key_symbol();
        if (symbol == Clutter.KEY_Return || symbol == Clutter.KEY_space) {
            if (this.menu.isOpen)
                this.menu.close();
            Main.overview.toggle();
        }
    },

    _xdndShowOverview: function(actor) {
        let [x, y, mask] = global.get_pointer();
        let pickedActor = global.stage.get_actor_at_pos(Clutter.PickMode.REACTIVE, x, y);

        if (pickedActor == this.actor) {
            if (!Main.overview.visible && !Main.overview.animationInProgress) {
                Main.overview.showTemporarily();
                Main.overview.beginItemDrag(actor);
            }
        }

        Mainloop.source_remove(this._xdndTimeOut);
        this._xdndTimeOut = 0;
    }

};

function ChangeActivitiesButton() {
    this._init();
}

ChangeActivitiesButton.prototype = {

    _init: function() {
        this._myActivitiesButton = new ActivitiesButtonIcon();
        this._orgActivitiesButton = Main.panel._activitiesButton;
    },

    enable: function() {
        Main.panel._leftBox.remove_actor(this._orgActivitiesButton.actor);
        Main.panel._leftBox.insert_actor(this._myActivitiesButton.actor, 0);
    },

    disable: function() {
        Main.panel._leftBox.remove_actor(this._myActivitiesButton.actor);
        Main.panel._leftBox.insert_actor(this._orgActivitiesButton.actor, 0);
    }
};

function init(extensionMeta) {
    return new ChangeActivitiesButton();
}


在地精殼3.0,我們可能使用了 修補的猴子 修補在/usr/share/gnome-shell/js/ui/panel.js的ActivitiesButton原型代碼。 當地精殼引伸被裝載並且使能时,這不再是可能的在地精殼3.2由于變動在。 因此需要提供在引伸的一個完全ActivitiesButton原型。

這個代碼可以被用于顯示是可利用的在Linux平臺的通常地方如指定由XDG 基本目录規格的所有像。 您在$HOME/.icons能也安置一個習慣像,並且它將顯示由地精殼引伸。 上述例子為 使用SVG,但是其他文件類型被接受。

例子3 :

在本例中,修改我們從例子2的新的地精殼引伸,以便包含像的文件讀,並且從容的像在其中在活動按鈕被顯示。

const ACTIVITIES_BUTTON_ICON_FILENAME = 'activities_button_icon.svg';  

function ActivitiesButtonIcon() {
    this._init.apply(this, arguments);
}

// ----- most of this code came straight from panel.js
ActivitiesButtonIcon.prototype = {
    __proto__: PanelMenu.Button.prototype,

    _init: function(iconpath) {
        PanelMenu.Button.prototype._init.call(this, 0.0);

        this.actor.name = 'panelActivities';

        // ---------------- icon code -----------------
        let textureCache = St.TextureCache.get_default();
        this._iconActivitiesButton = textureCache.load_uri_async("file://" + iconpath + "/" + ACTIVITIES_BUTTON_ICON_FILENAME, -1, -1);

        this._iconBox = new St.Bin({ style_class: 'activities-button-icon',
                                     child: this._iconActivitiesButton });
        container.add_actor(this._iconBox);
        ....
    },

    _containerGetPreferredWidth: function(actor, forHeight, alloc) {
        [alloc.min_size, alloc.natural_size] = this._iconBox.get_preferred_width(forHeight);
    },

    _containerGetPreferredHeight: function(actor, forWidth, alloc) {
        [alloc.min_size, alloc.natural_size] = this._iconBox.get_preferred_height(forWidth);
    },

    _containerAllocate: function(actor, box, flags) {
        this._iconBox.allocate(box, flags);
        ...
    },

    ...
};

function init(extensionMeta) {
    return new ChangeActivitiesButton(extensionMeta.path);
}


在上述例子中,像文件必须位于目錄和扩展代码一样。 當它被裝載时,某些變數據通過對地精殼引伸。 的扩展代码找出的全路径嚮是可利用的變數據的一個組分。 使用extensionMeta.path,在上述例子中,這個道路被檢索。

例子4 :

在這個最後的例子中,修改我們從例子2的新的地精殼引伸,以便像和文本被顯示。

這相關的代碼變動:

        // ---------------- icon and text code -----------------
        let textureCache = St.TextureCache.get_default();
        this._iconActivitiesButton = textureCache.load_uri_async("file://" + iconpath + "/" + ACTIVITIES_BUTTON_ICON_FILENAME, -1, -1);

        this._boxIconText = new St.BoxLayout({ vertical: false });
        this._boxIconText.add_actor( new St.Bin({ style_class: 'activities-button-icon',
                                                  child: this._iconActivitiesButton }));
        this._boxIconText.add_actor(new St.Label({ text: _("Activities"),
                                                   style_class: 'activities-button-text' }));
        container.add_actor(this._boxIconText);

    ....

    _containerGetPreferredWidth: function(actor, forHeight, alloc) {
        [alloc.min_size, alloc.natural_size] = this._boxIconText.get_preferred_width(forHeight);
    },

    _containerGetPreferredHeight: function(actor, forWidth, alloc) {
        [alloc.min_size, alloc.natural_size] = this._boxIconText.get_preferred_height(forWidth);
    },

    _containerAllocate: function(actor, box, flags) {
        this._boxIconText.allocate(box, flags);
    ...


支持一額外CSS ruleset,活動按鈕文本,增加允許活動按鈕標籤被稱呼。

.activities-button-text {
    font-style: italic;
    font-size: 75%;
}


如果您審查上述screenshot,您看見活動標籤在一種更小的用斜體字印刷的字體被顯示。 沒有理由這樣支持不可能增加到例子1地精殼引伸。 我將離開作為您的一鍛煉能做。

那么,上述例子應該提供您以所有必要的知識和技能使您開发您自己的地精3.2殼引伸定做您的活動按鈕在您喜歡的任何方式。 所有上述例子可以從我的地精 殼引伸網頁 被下載作為运作的引伸。

P.S. 請給我發電子郵件有您的另外的題目的建議的與扩大地精殼相關您希望我寫。

對更换活動按鈕的1個評論在地精殼3.2

  • Awolf

    很好我安裝了此建议使用im使用ubuntu 11.10的方式我假設投入我想要設置的像的地方,當活動按? 我认识应该的im更改在扩展代码的像名字,但是怎么样像應該是的地方? 可以我設置像地點在
    const ACTIVITIES_BUTTON_ICON_NAME = `淺頂軟呢帽商標icon'

    PS : 我是沒有程序員,並且不知道編制程序im运作對此實際上自已學習任何幫助的我Thnx

留下回復