Howto customize gnome-shell theme

GNOME 3.0 is just out of the corner. The major difference is the new shell replacement for gnome-panel, that is gnome-shell. GNOME Shell + Mutter brings the whole new experience for user interactivity. Unlike gnome-panel which is very limited in customization if you are not familiar with programming. gnome-shell is designed from ground-up with CSS and JS technology built-in. Every components of the shell are visible and customizable.

CSS is located under /usr/share/gnome-shell/theme/gnome-shell.css
JS for UI is located under /usr/share/gnome-shell/js/ui/

Just dig in and you can change pretty much everything of the shell.

I am in love with Mac menu style, so I make myself one, please see the screenshot. The Panel font is Fifth Leg font, you can find this font on Fedora Linux page. The application font is Droid Sans. The background is the Wooden Board, which you could download here. For my theme, I have to do a tweak for the AppDisplay, the font style is fixed and lack a CSS class for customization purpose. So I add a CSS class for it:

/usr/share/gnome-shell/js/ui/panel.js

TextShadower.prototype = {
    _init: function() {
        this.actor = new Shell.GenericContainer();
        this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
        this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
        this.actor.connect('allocate', Lang.bind(this, this._allocate));
        this._label = new St.Label({ style_class: 'label-app' }) // This is my new tweak

If you like my theme, you can get it here:
(Please make sure you have installed Droid Sans and Fifth Leg fonts)

/usr/share/gnome-shell/theme/gnome-shell.css

/* Copyright 2009, Red Hat, Inc.
 *
 * Portions adapted from Mx's data/style/default.css
 *   Copyright 2009 Intel Corporation
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU Lesser General Public License,
 * version 2.1, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 * more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 */

.label-app {
    font-family: "FifthLeg";
}

.shell-link {
    color: #0000ff;
    text-decoration: underline;
}

.shell-link:hover {
    color: #0000e0;
}

.label-shadow {
    color: rgba(255,255,255,0.5);
    font-family: "FifthLeg";
}

StScrollBar
{
  padding: 0px;
}

StScrollView
{
  scrollbar-width: 16px;
  scrollbar-height: 16px;
}

StScrollView > .top-shadow
{
    background-gradient-direction: vertical;
    background-gradient-start: rgba(0, 0, 0, 255);
    background-gradient-end: rgba(0, 0, 0, 0);
    height: 30px;
}

StScrollView > .bottom-shadow
{
    background-gradient-direction: vertical;
    background-gradient-start: rgba(0, 0, 0, 0);
    background-gradient-end: rgba(0, 0, 0, 255);
    height: 30px;
}

StScrollBar {
    background-color: #080808;
    border: 1px solid #2d2d2d;
    border-radius: 8px;
}

StScrollBar StButton#vhandle
{
    background-image: url("scroll-vhandle.svg");
    background-color: #252525;
    border: 1px solid #080808;
    border-radius: 8px;
}

StScrollBar StButton#hhandle
{
    background-image: url("scroll-hhandle.svg");
    background-color: #252525;
    border: 1px solid #080808;
    border-radius: 8px;
}

StScrollBar StButton#hhandle:hover,
StScrollBar StButton#vhandle:hover
{
    background-color: #292929;
}

StTooltip {
    border: 1px solid rgba(79,111,173,0.9);
    border-radius: 5px;
    padding: 4px;
    background-color: rgba(79,111,173,0.9);
    color: #ffffff;
}

/* Panel */

#panel {
    color: #000;
    font-size: 16px;
    background-gradient-direction: vertical;
    /* background-gradient-start: #C4C4C4;
    background-gradient-end: #979797; */
    background-gradient-start: rgba(255,255,255,0.8);
    background-gradient-end: rgba(222,219,226,0.8);
}

#panelLeft, #panelCenter, #panelRight {
    spacing: 4px;
}

#panelLeft {
    padding-right: 4px;
}

#panelRight {
    padding-left: 4px;
}

#appMenu {
    spacing: 4px;
}

.app-menu-icon {
    width: 24px;
    height: 24px;
}

.panel-button {
    padding: 2px 12px 3px;
    font: 16px "FifthLeg";
}

.panel-button:active, .panel-button:checked, .panel-button:pressed {
    background-gradient-direction: vertical;
    background-gradient-start: #5DA8E5;
    background-gradient-end: #006FD1;
    border-bottom: 1px solid #2E8ADB;
    color: #fff;
}

#panelActivities {
    border-radius-topleft: 0px;
}

#panelStatus {
    border-radius-topright: 0px;
}

#statusMenu {
    spacing: 4px;
}

/* Overview */

.overview {
    background-gradient-direction: vertical;
    background-gradient-start:rgba(0,0,0,1.0);
    background-gradient-end: rgba(0,0,0,0.3);

}

.info-bar {
    color: #fff;
    font-size: 14px;
    spacing: 20px;
}

.info-bar-link-button {
    background-color: #2d2d2d;
    padding: 2px 14px;
    border-radius: 10px;
    border: 1px solid #181818;
}

.info-bar-link-button:hover {
    border: 1px solid #666666;
}

.workspaces {
    color: #fff;
    font-family: "Droid Sans"
}

.workspaces.single {
    spacing: 25px;
}

.workspaces.mosaic {
    spacing: 15px;
}

.workspaces-bar {
    height: 48px;
}

.workspaces-bar, .workspaces-bar * {
    spacing: 5px;
}

.workspace-indicator {
    width: 24px;
    height: 16px;
    background: rgba(155,155,155,0.8);
    border-spacing: 16px;
}

.workspace-indicator.active {
    background: rgba(255,255,255,0.8);
}

.window-caption {
    background: rgba(0,0,0,0.8);
    border: 1px solid rgba(128,128,128,0.40);
    border-radius: 10px;
    font-size: 12px;
    padding: 2px 8px;
    -shell-caption-spacing: 4px;
}

.window-close {
    background-image: url("close-window.svg");
    height: 24px;
    width: 24px;
    -st-shadow: -2px 2px 6px rgba(0,0,0,0.5);
    -shell-close-overlap: 16px;
}

.single-view-controls {
    padding: 0px 15px;
}

.workspace-controls {
    width: 24px;
    height: 16px;
}

.workspace-controls.add {
    background-image: url("add-workspace.svg");
}

.workspace-controls.remove {
    background-image: url("remove-workspace.svg");
}

.workspace-controls.switch-single {
    background-image: url("single-view.svg");
}

.workspace-controls.switch-mosaic {
    background-image: url("mosaic-view.svg");
}

.workspace-controls.switch-single:checked {
    background-image: url("single-view-active.svg");
}

.workspace-controls.switch-mosaic:checked {
    background-image: url("mosaic-view-active.svg");
}

#SwitchScroll {
    height: 14px;
}

#SwitchScroll #hhandle {
    border-radius: 7px;
}

/* Dash */

#dash {
    color: #5f5f5f;
    font-size: 12px;
    padding: 0px 14px;
    font-family: "Droid Sans"
}

#dashSections {
    spacing: 12px;
}

#searchEntry {
    padding: 4px;
    border-bottom: 1px solid #262626;
}

#searchEntry:active {
    /* background-color: #c4c4c4; */
    background-color: #fff;
}

.dash-section {
    spacing: 8px;
}

.section-header {
}

.section-header-inner {
    spacing: 4px;
}

.section-text-content {
    padding: 4px 0px;
}

.section-header-back {
    padding: 0px 4px 0px 0px;
    border-right: 1px solid #262626;
}

.section-header-back-image {
    background-image: url("section-back.svg");
    width: 12px;
    height: 16px;
}

.section-count {
}

.dash-section-content {
    color: #ffffff;
    spacing: 8px;
}

.more-link {
}

.more-link-expander {
    background-image: url("section-more.svg");
    width: 9px;
    height: 9px;
}

.more-link-expander.open {
    background-image: url("section-more-open.svg");
    width: 9px;
    height: 9px;
}

.dash-pane {
    background-color: rgba(0,0,0,0.95);
    border: 1px solid #262626;
    padding: 4px;
    spacing: 4px;
}

.dash-pane-close {
    background-image: url("close.svg");
    width: 16px;
    height: 16px;
}

.dash-search-section-header {
    padding: 6px 0px;
    spacing: 4px;
}

.dash-search-section-results {
    color: #ffffff;
    padding-left: 4px;
}

.dash-search-section-list-results {
    spacing: 4px;
}

.dash-search-result-content {
    padding: 3px;
}

.dash-search-result-content:selected {
    padding: 2px;
    border: 1px solid #5c5c5c;
    border-radius: 2px;
    background-color: #1e1e1e;
}

/* GenericDisplay */

.generic-display-container {
    spacing: 4px;
}

.generic-display-item {
    height: 50px;
    border-radius: 4px;
    color: #ffffff;
    font-size: 14px;
    spacing: 4px;
}

.generic-display-item:selected {
    background-color: rgba(79,111,173,0.66);
}

.generic-display-item-text {
    spacing: 4px;
}

.generic-display-item-description {
    font-size: 12px;
    color: #bababa;
}

.generic-display-details {
    font-size: 14px;
    color: #ffffff;
}

.generic-display-details-name {
    font-weight: bold;
}

/* Apps */

.overview-pane {
    width: 440px;
}

#dashAppWell {
    spacing: 6px;
    -shell-grid-item-size: 70px;
}

.all-app {
    border-radius: 10px;
    background-color: rgba(0,0,0,0.95);
    border: 1px solid #262626;
    color: #ffffff;
    height: 400px;
}

.all-app-controls-panel {
    height: 30px;
}

.all-app-scroll-view {
    padding-right: 10px;
    padding-left: 10px;
    padding-bottom: 10px;
}

.app-well-app {
    border: 1px solid #181818;
    border-radius: 4px;
    padding: 2px;
    width: 70px;
    height: 70px;
    font-size: 10px;
}

.app-well-app.running {
    background-gradient-direction: vertical;
    background-gradient-start: #3d3d3d;
    background-gradient-end: #181818;
}

.app-well-app:hover {
    border: 1px solid #666666;
}

.app-well-app:active {
    background-color: #1e1e1e;
    border: 1px solid #5f5f5f;
}

.app-well-menu {
    border: 1px solid #5f5f5f;
    border-radius: 4px;
    padding: 4px;
    background-color: rgba(0,0,0,0.9);
    color: #ffffff;
    -shell-arrow-width: 12px;
    -shell-menu-spacing: 4px;
}

.app-well-menu-item:hover {
    background-color: #1e1e1e;
}

.app-well-menu-separator {
    padding-top: 1px;
    border-bottom: 1px solid #5f5f5f;
    height: 1px;
}

/* Places */

.places-actions {
    spacing: 4px;
}

#placesDevices {
    padding-top: 4px;
}

/* LookingGlass */

#LookingGlassDialog
{
  background-color: rgba(0,0,0,0.85);
  spacing: 4px;
  padding: 4px;
  border: 1px solid rgba(0,0,172,0.85);
  border-radius: 4px;

  color: #88ff66;
}

#LookingGlassDialog > #Toolbar
{
  border: 1px solid grey;
  border-radius: 4px;
}

#LookingGlassDialog .labels {
  spacing: 4px;
}

#LookingGlassDialog .notebook-tab {
  padding: 2px;
}

#LookingGlassDialog .notebook-tab:selected {
  border: 1px solid #88ff66;
  padding: 1px;
}

#LookingGlassDialog StLabel
{
  color: #88ff66;
}

#LookingGlassDialog StEntry
{
  color: #88ff66;
}

#LookingGlassDialog StBoxLayout#EvalBox
{
  padding: 4px;
  spacing: 4px;
}

#lookingGlassExtensions {
    padding: 4px;
}

.lg-extension-list {
    padding: 4px;
    spacing: 6px;
}

.lg-extension {
    border: 1px solid #6f6f6f;
    border-radius: 4px;
    padding: 4px;
}

.lg-extension-name {
    font-weight: bold;
}

.lg-extension-actions {
    spacing: 6px;
}

/* Calendar popup */

#calendarPopup {
    background: rgba(255,255,255,0.9);
    border: 1px solid rgba(128,128,128,0.45);
    color: #000;
    font-family: "FifthLeg";
}

#calendarPopup .calendar {
    padding: 10px;
}

.calendar {
    spacing-rows: 5px;
    spacing-columns: 3px;
}

.calendar-change-month {
    padding: 2px;
}

.calendar-change-month:hover {
    /* background: #314a6c;
    border-radius: 5px; */
    font-weight: bold;
}

.calendar-change-month:active {
    /* background: #213050;
    border-radius: 5px; */
    font-weight: bold;
}

.calendar-day {
    padding: 1px 2px;
}

.calendar-today {
    font-weight: bold;
    background: #161616;
    color: #fff;
    border-radius: 5px;
}

.calendar-other-month-day {
    color: #cccccc;
}

/* Message Tray */
#message-tray {
    background-gradient-direction: vertical;
    background-gradient-start: rgba(0,0,0,0.01);
    background-gradient-end: rgba(0,0,0,0.95);
    height: 28px;
}

#notification {
    font-size: 16px;
    border-radius: 5px;
    background: rgba(0,0,0,0.9);
    color: white;
    padding: 2px 10px 10px 10px;
    spacing-rows: 5px;
    spacing-columns: 10px;
    max-width: 40em;
}

#notification-actions {
    spacing: 5px;
}

.notification-button {
    border: 2px rgba(0,0,0,0.0);
    border-radius: 5px;
    padding: 5px;
    background: #c0c0c0;
    color: black;
    font-weight: bold;
}

.notification-button:hover {
    border: 2px solid white;
}

.notification-button:active {
    border: 2px solid white;
    background: #808080;
}

#summary-mode {
    spacing: 10px;
    padding: 2px 4px;
}

/* App Switcher */
.switcher-list {
    background: rgba(0,0,0,0.8);
    border: 1px solid rgba(128,128,128,0.40);
    border-radius: 8px;
    padding: 18px;

    font: 12px "Droid Sans";
    color: white;
}

.switcher-list .item-box {
    padding: 8px;
    border-radius: 4px;
}

.switcher-list .thumbnail-box {
    padding: 2px;
    spacing: 4px;
}

.switcher-list .thumbnail {
    width:  256px;
    height: 256px;
}

.switcher-list .outlined-item-box {
    padding: 6px;
    border: 2px solid rgba(85,85,85,1.0);
    border-radius: 4px;
}

.switcher-list .selected-item-box {
    padding: 8px;
    border-radius: 4px;
    background: rgba(255,255,255,0.33);
}

.switcher-list .separator {
    width: 1px;
    background: rgba(255,255,255,0.33);
}

.ripple-box {
    width: 52px;
    height: 52px;
    background-image: url("corner-ripple.png");
}

/* Workspace Switcher */
.workspace-switcher-container {
    background: rgba(0,0,0,0.8);
    border: 1px solid rgba(128,128,128,0.40);
    border-radius: 8px;
    padding: 12px;
}

.workspace-switcher {
    background: transparent;
    border: 0px;
    border-radius: 0px;
    padding: 4px;
}

.ws-switcher-active-left {
    height: 98px;
    border: 0px;
    background: rgba(255,255,255,0.5);
    background-image: url("ws-switch-arrow-left.svg");
    border-radius: 4px;
}

.ws-switcher-active-right {
    height: 98px;
    border: 0px;
    background: rgba(255,255,255,0.5);
    background-image: url("ws-switch-arrow-right.svg");
    border-radius: 4px;
}

.ws-switcher-spacer {
    width: 0.5px;
    height: 96px;
    border: 0px;
    background: transparent;
    padding: 4px;
}

.ws-switcher-box {
    height: 96px;
    border: 2px solid rgba(85,85,85,0.5);
    background: transparent;
    border-radius: 4px;
}

/usr/share/gnome-shell/js/ui/panel.js

/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */

const Big = imports.gi.Big;
const Clutter = imports.gi.Clutter;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Meta = imports.gi.Meta;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Tweener = imports.ui.tweener;
const Signals = imports.signals;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;

const AppDisplay = imports.ui.appDisplay;
const Calendar = imports.ui.calendar;
const Main = imports.ui.main;
const StatusMenu = imports.ui.statusMenu;

const PANEL_HEIGHT = 26;
const DEFAULT_PADDING = 4;

const PANEL_ICON_SIZE = 24;

// See comments around _recomputeTraySize
const TRAY_SPACING = 14;
const TRAY_SPACING_MIN = 8;

// Used for the tray icon container with gtk pre-2.16, which doesn't
// fully support tray icon transparency
const TRAY_BACKGROUND_COLOR = new Clutter.Color();
TRAY_BACKGROUND_COLOR.from_pixel(0x0b0b0bff);
const TRAY_BORDER_COLOR = new Clutter.Color();
TRAY_BORDER_COLOR.from_pixel(0x00000033);
const TRAY_CORNER_RADIUS = 5;
const TRAY_BORDER_WIDTH = 0;

const HOT_CORNER_ACTIVATION_TIMEOUT = 0.5;

const STANDARD_TRAY_ICON_ORDER = ['keyboard', 'volume', 'bluetooth', 'network', 'battery']
const STANDARD_TRAY_ICON_IMPLEMENTATIONS = {
    'bluetooth-applet': 'bluetooth',
    'gnome-volume-control-applet': 'volume',
    'nm-applet': 'network',
    'gnome-power-manager': 'battery'
};

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

TextShadower.prototype = {
    _init: function() {
        this.actor = new Shell.GenericContainer();
        this.actor.connect('get-preferred-width', Lang.bind(this, this._getPreferredWidth));
        this.actor.connect('get-preferred-height', Lang.bind(this, this._getPreferredHeight));
        this.actor.connect('allocate', Lang.bind(this, this._allocate));

        this._label = new St.Label({ style_class: 'label-app' });
        this.actor.add_actor(this._label);
        for (let i = 0; i < 4; i++) {
            let actor = new St.Label({ style_class: 'label-shadow' });
            this.actor.add_actor(actor);
        }
        this._label.raise_top();
    },

    setText: function(text) {
        let children = this.actor.get_children();
        for (let i = 0; i < children.length; i++)
            children[i].set_text(text);
    },

    _getPreferredWidth: function(actor, forHeight, alloc) {
        let [minWidth, natWidth] = this._label.get_preferred_width(forHeight);
        alloc.min_size = minWidth;
        alloc.natural_size = natWidth;
    },

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

    _allocate: function(actor, box, flags) {
        let children = this.actor.get_children();

        let availWidth = box.x2 - box.x1;
        let availHeight = box.y2 - box.y1;

        let [minChildWidth, minChildHeight, natChildWidth, natChildHeight] =
            this._label.get_preferred_size();

        let childWidth = Math.min(natChildWidth, availWidth);
        let childHeight = Math.min(natChildHeight, availHeight);

        for (let i = 0; i  0)
                lastSequence = sequences[sequences.length - 1];
        }

        // If the currently focused app hasn't changed and the current
        // startup sequence hasn't changed, we have nothing to do
        if (focusedApp == this._focusedApp
            && ((lastSequence == null && this._activeSequence == null)
                || (lastSequence != null && this._activeSequence != null
                    && lastSequence.get_id() == this._activeSequence.get_id())))
            return;

        this._focusedApp = focusedApp;
        this._activeSequence = lastSequence;

        if (this._iconBox.child != null)
            this._iconBox.child.destroy();
        this._iconBox.hide();
        this._label.setText('');
        let icon;
        if (this._focusedApp != null) {
            icon = this._focusedApp.create_icon_texture(AppDisplay.APPICON_SIZE);
            this._label.setText(this._focusedApp.get_name());
        } else if (this._activeSequence != null) {
            icon = this._activeSequence.create_icon(AppDisplay.APPICON_SIZE);
            this._label.setText(this._activeSequence.get_name());
        } else {
            icon = null;
        }
        
        if (icon != null) {
            let faded = Shell.fade_app_icon(icon); /* TODO consider caching */
            this._iconBox.set_child(faded);
            this._iconBox.show();
        }
        this._repositionLabel();

        this.emit('changed');
    }
}

Signals.addSignalMethods(AppPanelMenu.prototype);

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

Panel.prototype = {
    _init : function() {

        this.actor = new St.BoxLayout({ name: 'panel' });
        this.actor._delegate = this;

        this._leftBox = new St.BoxLayout({ name: 'panelLeft' });
        this._centerBox = new St.BoxLayout({ name: 'panelCenter' });
        this._rightBox = new St.BoxLayout({ name: 'panelRight' });

        /* This box container ensures that the centerBox is positioned in the *absolute*
         * center, but can be pushed aside if necessary. */
        this._boxContainer = new Shell.GenericContainer();
        this.actor.add(this._boxContainer, { expand: true });
        this._boxContainer.add_actor(this._leftBox);
        this._boxContainer.add_actor(this._centerBox);
        this._boxContainer.add_actor(this._rightBox);
        this._boxContainer.connect('get-preferred-width', Lang.bind(this, function(box, forHeight, alloc) {
            let children = box.get_children();
            for (let i = 0; i < children.length; i++) {
                let [childMin, childNatural] = children[i].get_preferred_width(forHeight);
                alloc.min_size += childMin;
                alloc.natural_size += childNatural;
            }
        }));
        this._boxContainer.connect('get-preferred-height', Lang.bind(this, function(box, forWidth, alloc) {
            let children = box.get_children();
            for (let i = 0; i  alloc.min_size)
                    alloc.min_size = childMin;
                if (childNatural > alloc.natural_size)
                    alloc.natural_size = childNatural;
            }
        }));
        this._boxContainer.connect('allocate', Lang.bind(this, function(container, box, flags) {
            let allocWidth = box.x2 - box.x1;
            let allocHeight = box.y2 - box.y1;
            let [leftMinWidth, leftNaturalWidth] = this._leftBox.get_preferred_width(-1);
            let [centerMinWidth, centerNaturalWidth] = this._centerBox.get_preferred_width(-1);
            let [rightMinWidth, rightNaturalWidth] = this._rightBox.get_preferred_width(-1);
            let leftWidth, centerWidth, rightWidth;
            if (allocWidth < (leftNaturalWidth + centerNaturalWidth + rightNaturalWidth)) {
                leftWidth = leftMinWidth;
                centerWidth = centerMinWidth;
                rightWidth = rightMinWidth;
            } else {
                leftWidth = leftNaturalWidth;
                centerWidth = centerNaturalWidth;
                rightWidth = rightNaturalWidth;
            }

            let x;
            let childBox = new Clutter.ActorBox();
            childBox.x1 = box.x1;
            childBox.y1 = box.y1;
            childBox.x2 = x = childBox.x1 + leftWidth;
            childBox.y2 = box.y2;
            this._leftBox.allocate(childBox, flags);

            let centerNaturalX = Math.floor((box.x2 - box.x1) / 2 - (centerWidth / 2));
            /* Check left side */
            if (x  (box.x2 - rightWidth)) {
                x = box.x2 - rightWidth - centerWidth;
            }
            childBox = new Clutter.ActorBox();
            childBox.x1 = x;
            childBox.y1 = box.y1;
            childBox.x2 = x = childBox.x1 + centerWidth;
            childBox.y2 = box.y2;
            this._centerBox.allocate(childBox, flags);

            childBox = new Clutter.ActorBox();
            childBox.x1 = box.x2 - rightWidth;
            childBox.y1 = box.y1;
            childBox.x2 = box.x2;
            childBox.y2 = box.y2;
            this._rightBox.allocate(childBox, flags);
        }));

        /* Button on the left side of the panel. */
        /* Translators: If there is no suitable word for "Activities" in your language, you can use the word for "Overview". */
        let label = new St.Label({ text: _("Activities") });
        this.button = new St.Clickable({ name: 'panelActivities',
                                          style_class: 'panel-button',
                                          reactive: true });
        this.button.set_child(label);
        this.button.height = PANEL_HEIGHT;

        this._leftBox.add(this.button);

        // We use this flag to mark the case where the user has entered the
        // hot corner and has not left both the hot corner and a surrounding
        // guard area (the "environs"). This avoids triggering the hot corner
        // multiple times due to an accidental jitter.
        this._hotCornerEntered = false;

        this._hotCornerEnvirons = new Clutter.Rectangle({ x: 0,
                                                          y: 0,
                                                          width: 3,
                                                          height: 3,
                                                          opacity: 0,
                                                          reactive: true });

        this._hotCorner = new Clutter.Rectangle({ x: 0,
                                                  y: 0,
                                                  width: 1,
                                                  height: 1,
                                                  opacity: 0,
                                                  reactive: true });

        this._hotCornerActivationTime = 0;

        this._hotCornerEnvirons.connect('leave-event',
                                        Lang.bind(this, this._onHotCornerEnvironsLeft));
        // Clicking on the hot corner environs should result in the same bahavior
        // as clicking on the hot corner.
        this._hotCornerEnvirons.connect('button-release-event',
                                        Lang.bind(this, this._onHotCornerClicked));

        // In addition to being triggered by the mouse enter event, the hot corner
        // can be triggered by clicking on it. This is useful if the user wants to 
        // undo the effect of triggering the hot corner once in the hot corner.
        this._hotCorner.connect('enter-event',
                                Lang.bind(this, this._onHotCornerEntered));
        this._hotCorner.connect('button-release-event',
                                Lang.bind(this, this._onHotCornerClicked));
        this._hotCorner.connect('leave-event',
                                Lang.bind(this, this._onHotCornerLeft));

        this._leftBox.add(this._hotCornerEnvirons);
        this._leftBox.add(this._hotCorner);

        let appMenu = new AppPanelMenu();
        this._leftBox.add(appMenu.actor);

        /* center */

        let clockButton = new St.Button({ style_class: "panel-button",
                                          toggle_mode: true,
                                          x_fill: true,
                                          y_fill: true });
        this._centerBox.add(clockButton, { y_fill: false });
        clockButton.connect('clicked', Lang.bind(this, this._toggleCalendar));

        this._clock = new St.Label();
        clockButton.set_child(this._clock);
        this._clockButton = clockButton;

        this._calendarPopup = null;

        /* right */

        // The tray icons live in trayBox within trayContainer.
        // The trayBox is hidden when there are no tray icons.
        let trayContainer = new Big.Box({ orientation: Big.BoxOrientation.VERTICAL,
                                          y_align: Big.BoxAlignment.CENTER });
        this._rightBox.add(trayContainer);
        let trayBox = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL,
                                    height: PANEL_ICON_SIZE,
                                    spacing: TRAY_SPACING });
        this._trayBox = trayBox;

        // gtk+ < 2.16 doesn't have fully-working icon transparency,
        // so we want trayBox to be opaque in that case (the icons
        // will at least pick up its background color).
        if (Gtk.MAJOR_VERSION == 2 && Gtk.MINOR_VERSION = 0; i--) {
                let rolePosition = children[i]._rolePosition;
                if (!rolePosition || position > rolePosition) {
                    this._trayBox.insert_after(icon, children[i], Big.BoxPackFlags.NONE);
                    break;
                }
            }
            if (i == -1) {
                // If we didn't find a position, we must be first
                this._trayBox.prepend(icon, Big.BoxPackFlags.NONE);
            }
        }

        // Make sure the trayBox is shown.
        this._trayBox.show();
        this._recomputeTraySize();
    },

    // By default, tray icons have a spacing of TRAY_SPACING.  However this
    // starts to fail if we have too many as can sadly happen; just jump down
    // to a spacing of 8 if we're over 6.
    // http://bugzilla.gnome.org/show_bug.cgi?id=590495
    _recomputeTraySize: function () {
        if (this._trayBox.get_children().length > 6)
            this._trayBox.spacing = TRAY_SPACING_MIN;
        else
            this._trayBox.spacing = TRAY_SPACING;
    },

    _updateClock: function() {
        let displayDate = new Date();
        let msecRemaining = 60000 - (1000 * displayDate.getSeconds() +
                                     displayDate.getMilliseconds());
        if (msecRemaining  scale opacity
                this._addRipple(0.0,   0.83,  0.25,  1.0,    1.5,  0.0);
                this._addRipple(0.05,  1.0,   0.0,   0.7,    1.25, 0.0);
                this._addRipple(0.35,  1.0,   0.0,   0.3,    1,    0.0);
                Main.overview.toggle();
            }
        }
        return false;
    },

    _onHotCornerClicked : function() {
         if (!Main.overview.animationInProgress) {
             this._maybeToggleOverviewOnClick();
         }
         return false;
    },

    _onHotCornerLeft : function(actor, event) {
        if (event.get_related() != this._hotCornerEnvirons) {
            this._hotCornerEntered = false;
        }
        return false;
    },

    _onHotCornerEnvironsLeft : function(actor, event) {
        if (event.get_related() != this._hotCorner) {
            this._hotCornerEntered = false;
        }
        return false;
    },

    // Toggles the overview unless this is the first click on the Activities button within the HOT_CORNER_ACTIVATION_TIMEOUT time
    // of the hot corner being triggered. This check avoids opening and closing the overview if the user both triggered the hot corner
    // and clicked the Activities button.
    _maybeToggleOverviewOnClick: function() {
        if (this._hotCornerActivationTime == 0 || Date.now() / 1000 - this._hotCornerActivationTime > HOT_CORNER_ACTIVATION_TIMEOUT)
            Main.overview.toggle();
        this._hotCornerActivationTime = 0;
    }
};

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

CalendarPopup.prototype = {
    _init: function() {
        let panelActor = Main.panel.actor;

        this.actor = new St.BoxLayout({ name: 'calendarPopup' });

        this.calendar = new Calendar.Calendar();
        this.actor.add(this.calendar.actor);

        Main.chrome.addActor(this.actor, { visibleInOverview: true,
                                           affectsStruts: false });
        this.actor.y = (panelActor.y + panelActor.height - this.actor.height);
    },

    show: function() {
        let panelActor = Main.panel.actor;

        // Reset the calendar to today's date
        this.calendar.setDate(new Date());

        this.actor.x = Math.round(panelActor.x + (panelActor.width - this.actor.width) / 2);
        this.actor.lower(panelActor);
        this.actor.show();
        Tweener.addTween(this.actor,
                         { y: panelActor.y + panelActor.height,
                           time: 0.2,
                           transition: "easeOutQuad"
                         });
    },

    hide: function() {
        let panelActor = Main.panel.actor;

        Tweener.addTween(this.actor,
                         { y: panelActor.y + panelActor.height - this.actor.height,
                           time: 0.2,
                           transition: "easeOutQuad",
                           onComplete: function() { this.actor.hide(); },
                           onCompleteScope: this
                         });
    }
};

About Jones Lee

Nothing much about me..

20 responses to “Howto customize gnome-shell theme

  1. steveacab

    can I have the theme?

  2. bmoore

    Any insight on where to change the font for the open application name?

  3. Kanderson

    What font are you using in the terminal window in the first graphic?

    thanks

  4. How do I change the font for “Activities”, and the username?

    • Jones Lee

      Checkout my /usr/share/gnome-shell/theme/gnome-shell.css, search for font-family: “FifthLeg”; and you know where that is

  5. Rame

    Is it possible to place the panel at the bottom?

  6. Animesh

    Unlike gnome-panel which is very limited in customization if you are not familiar with programming. gnome-shell is designed from ground-up with CSS and JS technology built-in.

    WTF DUDE
    think before you write

  7. Screw You

    All this wonderful CSS is useless without an element inspector so that you can figure out that the element you’re trying to edit is called “StBin,” and so that you have some hope of figuring out why in the fucking fuck gnome-shell is completely ignoring your edit. It’s probably because the element is inheriting from 50 different classes and having its style sheet dynamically modified by JS, which you’d be able to see if GNOME had an element inspector. Even Internet Explorer has an element inspector, but GNOME doesn’t.

    That’s what you get for trying to bolt a half-assed web browser onto a graphical shell.

  8. Screw You

    Furthermore, in old GNOME, you could change simple things like the appearance of the windows without having to close all of your windows and restart the shell. But the new GNOME 3 paradigm is that none of that matters, since all you people do with your computers is look at Facebook and Twitter.

  9. Thanks for trying, mate, but this is definitely not working at archlinux…nice try…

    • MS

      idiot. Gnome is gnome, it work the same on any distro.

      • sceptre

        Have you preformed this on every known Linux distro that uses Gnome? Probably not. Not all distros leave everything vanilla, so what works on one distro may not work on another, thats even true with different versions within the same distro. Not to mention this article was written in 2010 thats like 5 to 6 releases ago (for me anyway). So instead of name calling ask questions. Find out why it didnt work and offer a solution if you can, thats what made linux what it is.

  10. What is your GTK+ theme?

  11. joda

    I have Ubuntu 12.04 and gnome shell 3.4 and this theme does not work for me. I do not have this two fonts, so I changed the fonts to defaults in css file but after gnome shell restart nothing shows, only wallpaper. How can I debug to find where is the problem? It is a great customization, a lot better than default activities overview.

  12. Pingback: How To Change Font Size In Gnome-shell Panel | Click & Find Answer !

  13. Pingback: Resolved: How to change font size in gnome-shell panel #fix #programming #computers | StackCopy

  14. Pingback: How to change font size in gnome-shell panel - Boot Panic

Leave a comment