[gnome-shell] Port ShellStatusMenu to javascript
- From: Dan Winship <danw src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnome-shell] Port ShellStatusMenu to javascript
- Date: Fri, 13 Nov 2009 19:22:24 +0000 (UTC)
commit 985d7077884fa7670de906e2db31383fd28f73cf
Author: Dan Winship <danw gnome org>
Date: Tue Nov 10 12:13:58 2009 -0500
Port ShellStatusMenu to javascript
https://bugzilla.gnome.org/show_bug.cgi?id=601458
data/theme/gnome-shell.css | 7 +
js/ui/Makefile.am | 1 +
js/ui/panel.js | 12 +-
js/ui/statusMenu.js | 202 ++++++++++++
src/Makefile.am | 2 -
src/shell-global.c | 33 ++
src/shell-global.h | 4 +
src/shell-status-menu.c | 732 --------------------------------------------
src/shell-status-menu.h | 45 ---
9 files changed, 253 insertions(+), 785 deletions(-)
---
diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css
index 3e02884..351b4aa 100644
--- a/data/theme/gnome-shell.css
+++ b/data/theme/gnome-shell.css
@@ -348,3 +348,10 @@ StTooltip {
width: 1px;
background: rgba(255,255,255,0.33);
}
+
+/* Status Menu */
+#StatusMenu {
+ spacing: 4px;
+ font: 16px sans-serif;
+ color: white;
+}
diff --git a/js/ui/Makefile.am b/js/ui/Makefile.am
index ebc7f53..a74fb86 100644
--- a/js/ui/Makefile.am
+++ b/js/ui/Makefile.am
@@ -23,6 +23,7 @@ dist_jsui_DATA = \
runDialog.js \
shellDBus.js \
sidebar.js \
+ statusMenu.js \
tweener.js \
widget.js \
widgetBox.js \
diff --git a/js/ui/panel.js b/js/ui/panel.js
index 447bb85..9e2fdb4 100644
--- a/js/ui/panel.js
+++ b/js/ui/panel.js
@@ -16,6 +16,7 @@ const _ = Gettext.gettext;
const Button = imports.ui.button;
const Calendar = imports.ui.calendar;
const Main = imports.ui.main;
+const StatusMenu = imports.ui.statusMenu;
const PANEL_HEIGHT = 26;
const TRAY_HEIGHT = PANEL_HEIGHT - 1;
@@ -176,6 +177,8 @@ Panel.prototype = {
this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL
});
+ this.actor._delegate = this;
+
let backgroundGradient = Shell.create_vertical_gradient(BACKGROUND_TOP,
BACKGROUND_BOTTOM);
this.actor.connect('notify::allocation', Lang.bind(this, function () {
@@ -371,11 +374,8 @@ Panel.prototype = {
this._traymanager.manage_stage(global.stage);
let statusbox = new Big.Box();
- let statusmenu = this._statusmenu = new Shell.StatusMenu();
- statusmenu.get_icon().hide();
- statusmenu.get_name().fontName = DEFAULT_FONT;
- statusmenu.get_name().color = PANEL_FOREGROUND_COLOR;
- statusbox.append(this._statusmenu, Big.BoxPackFlags.NONE);
+ let statusmenu = this._statusmenu = new StatusMenu.StatusMenu();
+ statusbox.append(this._statusmenu.actor, Big.BoxPackFlags.NONE);
let statusbutton = new Button.Button(statusbox,
PANEL_BUTTON_COLOR,
PRESSED_BUTTON_BACKGROUND_COLOR,
@@ -385,7 +385,7 @@ Panel.prototype = {
if (e.get_button() == 1 && e.get_click_count() == 1) {
statusmenu.toggle(e);
// The statusmenu might not pop up if it couldn't get a pointer grab
- if (statusmenu.is_active())
+ if (statusmenu.isActive())
statusbutton.actor.active = true;
return true;
} else {
diff --git a/js/ui/statusMenu.js b/js/ui/statusMenu.js
new file mode 100644
index 0000000..a4de8bf
--- /dev/null
+++ b/js/ui/statusMenu.js
@@ -0,0 +1,202 @@
+/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
+
+const Gdm = imports.gi.Gdm;
+const GLib = imports.gi.GLib;
+const Gtk = imports.gi.Gtk;
+const Lang = imports.lang;
+const Shell = imports.gi.Shell;
+const St = imports.gi.St;
+const Signals = imports.signals;
+const Gettext = imports.gettext.domain('gnome-shell');
+const _ = Gettext.gettext;
+
+const Panel = imports.ui.panel;
+
+// Adapted from gdm/gui/user-switch-applet/applet.c
+//
+// Copyright (C) 2004-2005 James M. Cape <jcape ignore-your tv>.
+// Copyright (C) 2008,2009 Red Hat, Inc.
+
+const SIDEBAR_VISIBLE_KEY = 'sidebar/visible';
+
+function StatusMenu() {
+ this._init();
+}
+
+StatusMenu.prototype = {
+ _init: function() {
+ this._gdm = Gdm.UserManager.ref_default();
+ this._user = this._gdm.get_user(GLib.get_user_name());
+
+ this.actor = new St.BoxLayout({ name: 'StatusMenu' });
+ this.actor.connect('destroy', Lang.bind(this, this._onDestroy));
+
+ this._name = new St.Label({ text: this._user.get_real_name() });
+ this.actor.add(this._name, { expand: true, y_align: St.Align.MIDDLE });
+ this._userNameChangedId = this._user.connect('notify::display-name', Lang.bind(this, this._updateUserName));
+
+ this._createSubMenu();
+ this._gdm.connect('users-loaded', Lang.bind(this, this._updateSwitchUser));
+ this._gdm.connect('user-added', Lang.bind(this, this._updateSwitchUser));
+ this._gdm.connect('user-removed', Lang.bind(this, this._updateSwitchUser));
+ },
+
+ _onDestroy: function() {
+ this._user.disconnect(this._userNameChangedId);
+ },
+
+ _updateUserName: function() {
+ this._name.set_text(this._user.get_real_name());
+ },
+
+ _updateSwitchUser: function() {
+ let users = this._gdm.list_users();
+ if (users.length > 1)
+ this._loginScreenItem.show();
+ else
+ this._loginScreenItem.hide();
+ },
+
+ // The menu
+
+ _createImageMenuItem: function(label, iconName) {
+ let image = new Gtk.Image();
+ let item = new Gtk.ImageMenuItem({ label: label,
+ image: image });
+ item.connect('style-set', Lang.bind(this,
+ function() {
+ image.set_from_icon_name(iconName, Gtk.IconSize.MENU);
+ }));
+
+ return item;
+ },
+
+ _createSubMenu: function() {
+ this._menu = new Gtk.Menu();
+ this._menu.connect('deactivate', Lang.bind(this, function() { this.emit('deactivated'); }));
+
+ let item;
+
+ item = this._createImageMenuItem(_('Account Information...'), 'user-info');
+ item.connect('activate', Lang.bind(this, this._onAccountInformationActivate));
+ this._menu.append(item);
+ item.show();
+
+ let gconf = Shell.GConf.get_default();
+ item = new Gtk.CheckMenuItem({ label: _('Sidebar'),
+ active: gconf.get_boolean(SIDEBAR_VISIBLE_KEY) });
+ item.connect('activate', Lang.bind(this,
+ function() {
+ gconf.set_boolean(SIDEBAR_VISIBLE_KEY, this._sidebarItem.active);
+ }));
+ this._menu.append(item);
+ item.show();
+
+ item = this._createImageMenuItem(_('System Preferences...'), 'preferences-desktop');
+ item.connect('activate', Lang.bind(this, this._onPreferencesActivate));
+ this._menu.append(item);
+ item.show();
+
+ item = new Gtk.SeparatorMenuItem();
+ this._menu.append(item);
+ item.show();
+
+ item = this._createImageMenuItem(_('Lock Screen'), 'system-lock-screen');
+ item.connect('activate', Lang.bind(this, this._onLockScreenActivate));
+ this._menu.append(item);
+ item.show();
+
+ item = this._createImageMenuItem(_('Switch User'), 'system-users');
+ item.connect('activate', Lang.bind(this, this._onLoginScreenActivate));
+ this._menu.append(item);
+ item.show();
+ this._loginScreenItem = item;
+
+ item = this._createImageMenuItem(_('Log Out...'), 'system-log-out');
+ item.connect('activate', Lang.bind(this, this._onQuitSessionActivate));
+ this._menu.append(item);
+ item.show();
+
+ item = this._createImageMenuItem(_('Shut Down...'), 'system-shutdown');
+ item.connect('activate', Lang.bind(this, this._onShutDownActivate));
+ this._menu.append(item);
+ item.show();
+ },
+
+ _onAccountInformationActivate: function() {
+ this._spawn(['gnome-about-me']);
+ },
+
+ _onPreferencesActivate: function() {
+ this._spawn(['gnome-control-center']);
+ },
+
+ _onLockScreenActivate: function() {
+ this._spawn(['gnome-screensaver-command', '--lock']);
+ },
+
+ _onLoginScreenActivate: function() {
+ this._gdm.goto_login_session();
+ this._onLockScreenActivate();
+ },
+
+ _onQuitSessionActivate: function() {
+ this._spawn(['gnome-session-save', '--logout-dialog']);
+ },
+
+ _onShutDownActivate: function() {
+ this._spawn(['gnome-session-save', '--shutdown-dialog']);
+ },
+
+ _spawn: function(args) {
+ // FIXME: once Shell.Process gets support for signalling
+ // errors we should pop up an error dialog or something here
+ // on failure
+ let p = new Shell.Process({'args' : args});
+ p.run();
+ },
+
+ // shell_status_menu_toggle:
+ // @event: event causing the toggle
+ //
+ // If the menu is not currently up, pops it up. Otherwise, hides it.
+ // Popping up may fail if another grab is already active; check with
+ // isActive().
+ toggle: function(event) {
+ if (this._menu.visible)
+ this._menu.popdown();
+ else {
+ // We don't want to overgrab a Mutter grab with the grab
+ // that GTK+ uses on menus.
+ if (global.display_is_grabbed())
+ return;
+
+ let [menuWidth, menuHeight] = this._menu.get_size_request ();
+
+ let panel;
+ for (panel = this.actor; panel; panel = panel.get_parent()) {
+ if (panel._delegate instanceof Panel.Panel)
+ break;
+ }
+
+ let [panelX, panelY] = panel.get_transformed_position();
+ let [panelWidth, panelHeight] = panel.get_transformed_size();
+
+ let menuX = Math.round(panelX + panelWidth - menuWidth);
+ let menuY = Math.round(panelY + panelHeight);
+
+ Shell.popup_menu(this._menu, event.get_button(), event.get_time(),
+ menuX, menuY);
+ }
+ },
+
+ // isActive:
+ //
+ // Gets whether the menu is currently popped up
+ //
+ // Return value: %true if the menu is currently popped up
+ isActive: function() {
+ return this._menu.visible;
+ }
+};
+Signals.addSignalMethods(StatusMenu.prototype);
diff --git a/src/Makefile.am b/src/Makefile.am
index 1970e85..4b11e83 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -87,8 +87,6 @@ libgnome_shell_la_SOURCES = \
shell-global.c \
shell-global.h \
shell-global-private.h \
- shell-status-menu.c \
- shell-status-menu.h \
shell-stack.c \
shell-stack.h \
shell-tray-manager.c \
diff --git a/src/shell-global.c b/src/shell-global.c
index b07d090..5bb7e69 100644
--- a/src/shell-global.c
+++ b/src/shell-global.c
@@ -1026,3 +1026,36 @@ shell_get_event_state (ClutterEvent *event)
ClutterModifierType state = clutter_event_get_state (event);
return state & CLUTTER_MODIFIER_MASK;
}
+
+static void
+shell_popup_menu_position_func (GtkMenu *menu,
+ int *x,
+ int *y,
+ gboolean *push_in,
+ gpointer user_data)
+{
+ *x = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menu), "shell-menu-x"));
+ *y = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (menu), "shell-menu-y"));
+}
+
+/**
+ * shell_popup_menu:
+ * @menu: a #GtkMenu
+ * @button: mouse button that triggered the menu
+ * @time: timestamp of event that triggered the menu
+ * @menu_x: x coordinate to display the menu at
+ * @menu_y: y coordinate to display the menu at
+ *
+ * Wraps gtk_menu_popup(), but using @menu_x, @menu_y for the location
+ * rather than needing a callback.
+ **/
+void
+shell_popup_menu (GtkMenu *menu, int button, guint32 time,
+ int menu_x, int menu_y)
+{
+ g_object_set_data (G_OBJECT (menu), "shell-menu-x", GINT_TO_POINTER (menu_x));
+ g_object_set_data (G_OBJECT (menu), "shell-menu-y", GINT_TO_POINTER (menu_y));
+
+ gtk_menu_popup (menu, NULL, NULL, shell_popup_menu_position_func, NULL,
+ button, time);
+}
diff --git a/src/shell-global.h b/src/shell-global.h
index 55844a3..60b9cb5 100644
--- a/src/shell-global.h
+++ b/src/shell-global.h
@@ -79,6 +79,10 @@ GdkModifierType shell_global_get_modifier_keys (ShellGlobal *global);
ClutterModifierType shell_get_event_state (ClutterEvent *event);
+void shell_popup_menu (GtkMenu *menu, int button, guint32 time,
+ int menu_x, int menu_y);
+
+
G_END_DECLS
#endif /* __SHELL_GLOBAL_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]