diff --git a/data/theme/gnome-shell.css b/data/theme/gnome-shell.css index 3e0288477..351b4aadb 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 ebc7f53d3..a74fb862e 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 447bb854e..9e2fdb431 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 000000000..a4de8bf92 --- /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 . +// 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 1970e85f3..4b11e83f3 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 b07d0905f..5bb7e69d4 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 55844a3a4..60b9cb552 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__ */ diff --git a/src/shell-status-menu.c b/src/shell-status-menu.c deleted file mode 100644 index 4018faf3c..000000000 --- a/src/shell-status-menu.c +++ /dev/null @@ -1,732 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ -/* Adapted from gdm/gui/user-switch-applet/applet.c */ -/* - * - * Copyright (C) 2004-2005 James M. Cape . - * Copyright (C) 2008,2009 Red Hat, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "shell-status-menu.h" - -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include - -#define GDMUSER_I_KNOW_THIS_IS_UNSTABLE -#include - -#include "shell-global.h" -#include "shell-gconf.h" - -#define LOCKDOWN_DIR "/desktop/gnome/lockdown" -#define LOCKDOWN_KEY LOCKDOWN_DIR "/disable_user_switching" - -#define SIDEBAR_VISIBLE_KEY SHELL_GCONF_DIR "/sidebar/visible" - -struct _ShellStatusMenuPrivate { - GConfClient *client; - GdmUserManager *manager; - GdmUser *user; - - ClutterTexture *user_icon; - BigBox *name_box; - ClutterText *name; - - GtkWidget *menu; - GtkWidget *account_item; - GtkWidget *sidebar_item; - GtkWidget *control_panel_item; - GtkWidget *lock_screen_item; - GtkWidget *login_screen_item; - GtkWidget *quit_session_item; - GtkWidget *shut_down_item; - - guint client_notify_lockdown_id; - - guint current_status_state; - - guint user_icon_changed_id; - guint user_notify_id; - - gboolean has_other_users; - - GtkIconSize icon_size; - guint pixel_size; -}; - -enum { - PROP_0 -}; - -G_DEFINE_TYPE(ShellStatusMenu, shell_status_menu, BIG_TYPE_BOX); - -/* Signals */ -enum -{ - DEACTIVATED, - LAST_SIGNAL -}; - -static guint shell_status_menu_signals [LAST_SIGNAL] = { 0 }; - -static void -reset_icon (ShellStatusMenu *status) -{ - ShellStatusMenuPrivate *priv = status->priv; - GdkPixbuf *pixbuf; - - if (priv->user == NULL) - return; - - if (priv->user_icon != NULL) - { - pixbuf = gdm_user_render_icon (priv->user, 24); - - if (pixbuf == NULL) - return; - - shell_clutter_texture_set_from_pixbuf (priv->user_icon, pixbuf); - - g_object_unref (pixbuf); - } -} - -static void -update_name_text (ShellStatusMenu *status) -{ - ShellStatusMenuPrivate *priv = status->priv; - - clutter_text_set_text (priv->name, - gdm_user_get_real_name (GDM_USER (priv->user))); -} - -static void -on_user_icon_changed (GdmUser *user, - ShellStatusMenu *status) -{ - g_debug ("User icon changed"); - reset_icon (status); -} - -static void -user_notify_display_name_cb (GObject *object, - GParamSpec *pspec, - ShellStatusMenu *status) -{ - update_name_text (status); -} - -static void -setup_current_user (ShellStatusMenu *status) -{ - ShellStatusMenuPrivate *priv = status->priv; - const char *name; - - priv->user = gdm_user_manager_get_user_by_uid (priv->manager, getuid ()); - if (priv->user != NULL) - { - g_object_ref (priv->user); - name = gdm_user_get_real_name (priv->user); - } - else - { - name = _("Unknown"); - } - - update_name_text (status); - - if (priv->user != NULL) - { - reset_icon (status); - - priv->user_icon_changed_id = - g_signal_connect (priv->user, - "icon-changed", - G_CALLBACK (on_user_icon_changed), - status); - priv->user_notify_id = - g_signal_connect (priv->user, - "notify::display-name", - G_CALLBACK (user_notify_display_name_cb), - status); - } -} - -static void -maybe_lock_screen (ShellStatusMenu *status) -{ - char *args[3]; - GError *err; - GdkScreen *screen; - gboolean use_gscreensaver = TRUE; - gboolean res; - - g_debug ("Attempting to lock screen"); - - args[0] = g_find_program_in_path ("gnome-screensaver-command"); - if (args[0] == NULL) - { - args[0] = g_find_program_in_path ("xscreensaver-command"); - use_gscreensaver = FALSE; - } - - if (args[0] == NULL) - return; - - if (use_gscreensaver) - args[1] = "--lock"; - else - args[1] = "-lock"; - args[2] = NULL; - - screen = gdk_screen_get_default (); - - err = NULL; - res = gdk_spawn_on_screen (screen, g_get_home_dir (), args, NULL, 0, NULL, - NULL, NULL, &err); - if (!res) - { - g_warning (_("Can't lock screen: %s"), err->message); - g_error_free (err); - } - - if (use_gscreensaver) - args[1] = "--throttle"; - else - args[1] = "-throttle"; - - err = NULL; - res = gdk_spawn_on_screen (screen, g_get_home_dir (), args, NULL, - (G_SPAWN_STDERR_TO_DEV_NULL | G_SPAWN_STDOUT_TO_DEV_NULL), NULL, NULL, - NULL, &err); - if (!res) - { - g_warning (_("Can't temporarily set screensaver to blank screen: %s"), - err->message); - g_error_free (err); - } - - g_free (args[0]); -} - -static void -on_lock_screen_activate (GtkMenuItem *item, - ShellStatusMenu *status) -{ - maybe_lock_screen (status); -} - -static void -do_switch (ShellStatusMenu *status, - GdmUser *user) -{ - ShellStatusMenuPrivate *priv = status->priv; - guint num_sessions; - - g_debug ("Do user switch"); - - if (user == NULL) - { - gdm_user_manager_goto_login_session (priv->manager); - goto out; - } - - num_sessions = gdm_user_get_num_sessions (user); - if (num_sessions > 0) - gdm_user_manager_activate_user_session (priv->manager, user); - else - gdm_user_manager_goto_login_session (priv->manager); -out: - maybe_lock_screen (status); -} - -static void -on_login_screen_activate (GtkMenuItem *item, - ShellStatusMenu *status) -{ - GdmUser *user; - - user = NULL; - - do_switch (status, user); -} - -static void -spawn_external (ShellStatusMenu *status, const char *program) -{ - char *args[2]; - GError *error; - GdkScreen *screen; - gboolean res; - - args[0] = g_find_program_in_path (program); - if (args[0] == NULL) - return; - args[1] = NULL; - - screen = gdk_screen_get_default (); - - error = NULL; - res = gdk_spawn_on_screen (screen, g_get_home_dir (), args, NULL, 0, NULL, - NULL, NULL, &error); - if (!res) - { - g_warning ("Failed to exec %s: %s", program, error->message); - g_clear_error (&error); - } - - g_free (args[0]); - -} - -static void -on_control_panel_activate (GtkMenuItem *item, - ShellStatusMenu *status) -{ - spawn_external (status, "gnome-control-center"); -} - -static void -on_account_activate (GtkMenuItem *item, - ShellStatusMenu *status) -{ - spawn_external (status, "gnome-about-me"); -} - -static void -on_sidebar_toggled (GtkCheckMenuItem *item, - ShellStatusMenu *status) -{ - gconf_client_set_bool (status->priv->client, SIDEBAR_VISIBLE_KEY, - gtk_check_menu_item_get_active (item), NULL); -} - - -/* Calls 'gnome-session-save arg' */ -static void -gnome_session_save_command (const char *arg) -{ - char *args[3]; - GError *error; - GdkScreen *screen; - gboolean res; - - args[0] = g_find_program_in_path ("gnome-session-save"); - if (args[0] == NULL) - return; - - args[1] = (char *)arg; - args[2] = NULL; - - screen = gdk_screen_get_default (); - - error = NULL; - res = gdk_spawn_on_screen (screen, g_get_home_dir (), args, NULL, 0, NULL, - NULL, NULL, &error); - if (!res) - { - g_warning (_("Can't logout: %s"), error->message); - g_error_free (error); - } - - g_free (args[0]); -} - - -static void -on_quit_session_activate (GtkMenuItem *item, - ShellStatusMenu *status) -{ - gnome_session_save_command ("--logout-dialog"); -} - -static void -on_shut_down_activate (GtkMenuItem *item, - ShellStatusMenu *status) -{ - gnome_session_save_command ("--shutdown-dialog"); -} - -static void -update_switch_user (ShellStatusMenu *status) -{ - ShellStatusMenuPrivate *priv = status->priv; - GSList *users; - - users = gdm_user_manager_list_users (priv->manager); - priv->has_other_users = FALSE; - if (users != NULL) - priv->has_other_users = g_slist_length (users) > 1; - g_slist_free (users); - - if (priv->has_other_users) - gtk_widget_show (priv->login_screen_item); - else - gtk_widget_hide (priv->login_screen_item); -} - -static void -on_manager_user_added (GdmUserManager *manager, - GdmUser *user, - ShellStatusMenu *status) -{ - update_switch_user (status); -} - -static void -on_manager_user_removed (GdmUserManager *manager, - GdmUser *user, - ShellStatusMenu *status) -{ - update_switch_user (status); -} - -static void -on_manager_users_loaded (GdmUserManager *manager, - ShellStatusMenu *status) -{ - update_switch_user (status); -} - -static void -menu_style_set_cb (GtkWidget *menu, GtkStyle *old_style, - ShellStatusMenu *status) -{ - ShellStatusMenuPrivate *priv = status->priv; - GtkSettings *settings; - int width; - int height; - - priv->icon_size = gtk_icon_size_from_name ("panel-menu"); - if (priv->icon_size == GTK_ICON_SIZE_INVALID) - priv->icon_size = gtk_icon_size_register ("panel-menu", 24, 24); - - if (gtk_widget_has_screen (menu)) - settings = gtk_settings_get_for_screen (gtk_widget_get_screen (menu)); - else - settings = gtk_settings_get_default (); - - if (!gtk_icon_size_lookup_for_settings (settings, priv->icon_size, &width, - &height)) - priv->pixel_size = -1; - else - priv->pixel_size = MAX(width, height); -} - -static void -menuitem_style_set_cb (GtkWidget *menuitem, - GtkStyle *old_style, - ShellStatusMenu *status) -{ - GtkWidget *image; - const char *icon_name; - ShellStatusMenuPrivate *priv = status->priv; - - if (menuitem == priv->login_screen_item) - icon_name = "system-users"; - else if (menuitem == priv->lock_screen_item) - icon_name = "system-lock-screen"; - else if (menuitem == priv->quit_session_item) - icon_name = "system-log-out"; - else if (menuitem == priv->account_item) - icon_name = "user-info"; - else if (menuitem == priv->control_panel_item) - icon_name = "preferences-desktop"; - else if (menuitem == priv->shut_down_item) - icon_name = "system-shutdown"; - else - icon_name = GTK_STOCK_MISSING_IMAGE; - - image = gtk_image_menu_item_get_image (GTK_IMAGE_MENU_ITEM (menuitem)); - gtk_image_set_pixel_size (GTK_IMAGE (image), priv->pixel_size); - gtk_image_set_from_icon_name (GTK_IMAGE (image), icon_name, priv->icon_size); -} - -static void -on_deactivate (GtkMenuShell *menushell, gpointer user_data) -{ - ShellStatusMenu *status = SHELL_STATUS_MENU (user_data); - g_signal_emit (G_OBJECT (status), shell_status_menu_signals[DEACTIVATED], 0); -} - -static void -create_sub_menu (ShellStatusMenu *status) -{ - ShellStatusMenuPrivate *priv = status->priv; - GtkWidget *item; - - priv->menu = gtk_menu_new (); - g_signal_connect (priv->menu, "style-set", G_CALLBACK (menu_style_set_cb), - status); - - g_signal_connect (priv->manager, "users-loaded", - G_CALLBACK (on_manager_users_loaded), status); - g_signal_connect (priv->manager, "user-added", - G_CALLBACK (on_manager_user_added), status); - g_signal_connect (priv->manager, "user-removed", - G_CALLBACK (on_manager_user_removed), status); - - priv->account_item = gtk_image_menu_item_new_with_label (_("Account Information...")); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (priv->account_item), - gtk_image_new ()); - gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), priv->account_item); - g_signal_connect (priv->account_item, "style-set", - G_CALLBACK (menuitem_style_set_cb), status); - g_signal_connect (priv->account_item, "activate", - G_CALLBACK (on_account_activate), status); - gtk_widget_show (priv->account_item); - - priv->sidebar_item = gtk_check_menu_item_new_with_label (_("Sidebar")); - gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (priv->sidebar_item), - gconf_client_get_bool (priv->client, SIDEBAR_VISIBLE_KEY, NULL)); - gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), priv->sidebar_item); - g_signal_connect (priv->sidebar_item, "toggled", - G_CALLBACK (on_sidebar_toggled), status); - gtk_widget_show (priv->sidebar_item); - - priv->control_panel_item = gtk_image_menu_item_new_with_label (_("System Preferences...")); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (priv->control_panel_item), - gtk_image_new ()); - gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), priv->control_panel_item); - g_signal_connect (priv->control_panel_item, "style-set", - G_CALLBACK (menuitem_style_set_cb), status); - g_signal_connect (priv->control_panel_item, "activate", - G_CALLBACK (on_control_panel_activate), status); - gtk_widget_show (priv->control_panel_item); - - item = gtk_separator_menu_item_new (); - gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), item); - gtk_widget_show (item); - - priv->lock_screen_item - = gtk_image_menu_item_new_with_label (_("Lock Screen")); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (priv->lock_screen_item), - gtk_image_new ()); - gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), priv->lock_screen_item); - g_signal_connect (priv->lock_screen_item, "style-set", - G_CALLBACK (menuitem_style_set_cb), status); - g_signal_connect (priv->lock_screen_item, "activate", - G_CALLBACK (on_lock_screen_activate), status); - gtk_widget_show (priv->lock_screen_item); - - priv->login_screen_item = gtk_image_menu_item_new_with_label (_("Switch User")); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (priv->login_screen_item), - gtk_image_new ()); - gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), priv->login_screen_item); - g_signal_connect (priv->login_screen_item, "style-set", - G_CALLBACK (menuitem_style_set_cb), status); - g_signal_connect (priv->login_screen_item, "activate", - G_CALLBACK (on_login_screen_activate), status); - /* Only show switch user if there are other users */ - - /* Log Out */ - priv->quit_session_item = gtk_image_menu_item_new_with_label (_("Log Out...")); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (priv->quit_session_item), - gtk_image_new ()); - gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), priv->quit_session_item); - g_signal_connect (priv->quit_session_item, "style-set", - G_CALLBACK (menuitem_style_set_cb), status); - g_signal_connect (priv->quit_session_item, "activate", - G_CALLBACK (on_quit_session_activate), status); - gtk_widget_show (priv->quit_session_item); - - /* Shut down */ - priv->shut_down_item = gtk_image_menu_item_new_with_label (_("Shut Down...")); - gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (priv->shut_down_item), - gtk_image_new ()); - gtk_menu_shell_append (GTK_MENU_SHELL (priv->menu), priv->shut_down_item); - g_signal_connect (priv->shut_down_item, "style-set", - G_CALLBACK (menuitem_style_set_cb), status); - g_signal_connect (priv->shut_down_item, "activate", - G_CALLBACK (on_shut_down_activate), status); - gtk_widget_show (priv->shut_down_item); - - g_signal_connect (G_OBJECT (priv->menu), "deactivate", - G_CALLBACK (on_deactivate), status); -} - -static void -shell_status_menu_init (ShellStatusMenu *status) -{ - ShellStatusMenuPrivate *priv; - - status->priv = priv = G_TYPE_INSTANCE_GET_PRIVATE (status, SHELL_TYPE_STATUS_MENU, - ShellStatusMenuPrivate); - - g_object_set (G_OBJECT (status), - "orientation", BIG_BOX_ORIENTATION_HORIZONTAL, - NULL); - priv->client = gconf_client_get_default (); - - priv->user_icon = CLUTTER_TEXTURE (clutter_texture_new ()); - big_box_append (BIG_BOX (status), CLUTTER_ACTOR (status->priv->user_icon), 0); - - priv->name_box = BIG_BOX (big_box_new (BIG_BOX_ORIENTATION_VERTICAL)); - g_object_set (G_OBJECT (priv->name_box), "y-align", BIG_BOX_ALIGNMENT_CENTER, NULL); - big_box_append (BIG_BOX (status), CLUTTER_ACTOR (priv->name_box), BIG_BOX_PACK_EXPAND); - priv->name = CLUTTER_TEXT (clutter_text_new ()); - big_box_append (BIG_BOX (priv->name_box), CLUTTER_ACTOR (priv->name), BIG_BOX_PACK_EXPAND); - - priv->manager = gdm_user_manager_ref_default (); - setup_current_user (status); - - create_sub_menu (status); -} - -static void -shell_status_menu_finalize (GObject *object) -{ - ShellStatusMenu *status = SHELL_STATUS_MENU (object); - ShellStatusMenuPrivate *priv = status->priv; - - gconf_client_notify_remove (priv->client, priv->client_notify_lockdown_id); - - g_signal_handler_disconnect (priv->user, priv->user_notify_id); - g_signal_handler_disconnect (priv->user, priv->user_icon_changed_id); - - if (priv->user != NULL) { - g_object_unref (priv->user); - } - g_object_unref (priv->client); - g_object_unref (priv->manager); - - G_OBJECT_CLASS (shell_status_menu_parent_class)->finalize (object); -} - -static void -shell_status_menu_class_init (ShellStatusMenuClass *klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (ShellStatusMenuPrivate)); - - gobject_class->finalize = shell_status_menu_finalize; - - shell_status_menu_signals[DEACTIVATED] = - g_signal_new ("deactivated", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (ShellStatusMenuClass, deactivated), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); -} - -static void -position_menu (GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer user_data) -{ - ShellStatusMenu *status = SHELL_STATUS_MENU (user_data); - ClutterActor *parent; - float src_x, src_y; - float width, height; - int menu_width; - - gtk_widget_get_size_request (GTK_WIDGET (menu), &menu_width, NULL); - - /* Encapsulation breakage: it looks better if the menu is - * aligned with the bottom of the actor's grandparent - the - * panel, rather than with the bottom of the actor. We just - * assume what the hierarchy is and where we are positioned - * in the panel. - */ - parent = clutter_actor_get_parent (CLUTTER_ACTOR (status)); - parent = clutter_actor_get_parent (parent); - clutter_actor_get_transformed_position (parent, &src_x, &src_y); - clutter_actor_get_transformed_size (parent, &width, &height); - *x = (gint)(0.5 + src_x + width - menu_width); - *y = (gint)(0.5 + src_y + height); -} - -/** - * shell_status_menu_toggle: - * @menu: a #ShellStatusMenu - * - * 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 - * shell_status_menu_is_active(). - */ -void -shell_status_menu_toggle (ShellStatusMenu *status, ClutterEvent *event) -{ - ShellStatusMenuPrivate *priv = status->priv; - - if (GTK_WIDGET_VISIBLE (priv->menu)) - { - gtk_menu_popdown (GTK_MENU (priv->menu)); - } - else - { - /* We don't want to overgrab a Mutter grab with the grab that GTK+ - * uses on menus. - */ - ShellGlobal *global = shell_global_get (); - if (shell_global_display_is_grabbed (global)) - return; - - gtk_menu_popup (GTK_MENU (priv->menu), NULL, NULL, position_menu, - status, 1, event->button.time); - } -} - -/** - * shell_status_menu_is_active: - * @menu: a #ShellStatusMenu - * - * Gets whether the menu is currently popped up - * - * Return value: %TRUE if the menu is currently popped up - */ -gboolean -shell_status_menu_is_active (ShellStatusMenu *status) -{ - ShellStatusMenuPrivate *priv = status->priv; - - return GTK_WIDGET_VISIBLE (priv->menu); -} - -/** - * shell_status_menu_get_name: - * @menu: a #ShellStatusMenu - * - * Return value: (transfer none): the #ClutterText actor with the user's name. - */ -ClutterText * -shell_status_menu_get_name (ShellStatusMenu *menu) -{ - return menu->priv->name; -} - -/** - * shell_status_menu_get_icon: - * @menu: a #ShellStatusMenu - * - * Return value: (transfer none): the #ClutterTexture actor with the user icon. - */ -ClutterTexture * -shell_status_menu_get_icon (ShellStatusMenu *menu) -{ - return menu->priv->user_icon; -} diff --git a/src/shell-status-menu.h b/src/shell-status-menu.h deleted file mode 100644 index 9a7c2969f..000000000 --- a/src/shell-status-menu.h +++ /dev/null @@ -1,45 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ - -#ifndef __SHELL_STATUS_MENU_H__ -#define __SHELL_STATUS_MENU_H__ - -#include -#include "big/box.h" - -G_BEGIN_DECLS - -#define SHELL_TYPE_STATUS_MENU (shell_status_menu_get_type ()) -#define SHELL_STATUS_MENU(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SHELL_TYPE_STATUS_MENU, ShellStatusMenu)) -#define SHELL_STATUS_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SHELL_TYPE_STATUS_MENU, ShellStatusMenuClass)) -#define SHELL_IS_STATUS_MENU(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SHELL_TYPE_STATUS_MENU)) -#define SHELL_IS_STATUS_MENU_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SHELL_TYPE_STATUS_MENU)) -#define SHELL_STATUS_MENU_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SHELL_TYPE_STATUS_MENU, ShellStatusMenuClass)) - -typedef struct _ShellStatusMenu ShellStatusMenu; -typedef struct _ShellStatusMenuPrivate ShellStatusMenuPrivate; -typedef struct _ShellStatusMenuClass ShellStatusMenuClass; - -struct _ShellStatusMenu -{ - BigBox parent_instance; - - ShellStatusMenuPrivate *priv; -}; - -struct _ShellStatusMenuClass -{ - BigBoxClass parent_class; - - void (*deactivated) (ShellStatusMenu *status, gpointer user_data); -}; - -GType shell_status_menu_get_type (void); - -void shell_status_menu_toggle (ShellStatusMenu *menu, ClutterEvent *event); -gboolean shell_status_menu_is_active (ShellStatusMenu *menu); -ClutterText *shell_status_menu_get_name (ShellStatusMenu *menu); -ClutterTexture *shell_status_menu_get_icon (ShellStatusMenu *menu); - -G_END_DECLS - -#endif /* __SHELL_STATUS_MENU_H__ */