Port ShellStatusMenu to javascript
https://bugzilla.gnome.org/show_bug.cgi?id=601458
This commit is contained in:
parent
9ddebf0480
commit
985d707788
@ -348,3 +348,10 @@ StTooltip {
|
|||||||
width: 1px;
|
width: 1px;
|
||||||
background: rgba(255,255,255,0.33);
|
background: rgba(255,255,255,0.33);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Status Menu */
|
||||||
|
#StatusMenu {
|
||||||
|
spacing: 4px;
|
||||||
|
font: 16px sans-serif;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
@ -23,6 +23,7 @@ dist_jsui_DATA = \
|
|||||||
runDialog.js \
|
runDialog.js \
|
||||||
shellDBus.js \
|
shellDBus.js \
|
||||||
sidebar.js \
|
sidebar.js \
|
||||||
|
statusMenu.js \
|
||||||
tweener.js \
|
tweener.js \
|
||||||
widget.js \
|
widget.js \
|
||||||
widgetBox.js \
|
widgetBox.js \
|
||||||
|
@ -16,6 +16,7 @@ const _ = Gettext.gettext;
|
|||||||
const Button = imports.ui.button;
|
const Button = imports.ui.button;
|
||||||
const Calendar = imports.ui.calendar;
|
const Calendar = imports.ui.calendar;
|
||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
|
const StatusMenu = imports.ui.statusMenu;
|
||||||
|
|
||||||
const PANEL_HEIGHT = 26;
|
const PANEL_HEIGHT = 26;
|
||||||
const TRAY_HEIGHT = PANEL_HEIGHT - 1;
|
const TRAY_HEIGHT = PANEL_HEIGHT - 1;
|
||||||
@ -176,6 +177,8 @@ Panel.prototype = {
|
|||||||
|
|
||||||
this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL
|
this.actor = new Big.Box({ orientation: Big.BoxOrientation.HORIZONTAL
|
||||||
});
|
});
|
||||||
|
this.actor._delegate = this;
|
||||||
|
|
||||||
let backgroundGradient = Shell.create_vertical_gradient(BACKGROUND_TOP,
|
let backgroundGradient = Shell.create_vertical_gradient(BACKGROUND_TOP,
|
||||||
BACKGROUND_BOTTOM);
|
BACKGROUND_BOTTOM);
|
||||||
this.actor.connect('notify::allocation', Lang.bind(this, function () {
|
this.actor.connect('notify::allocation', Lang.bind(this, function () {
|
||||||
@ -371,11 +374,8 @@ Panel.prototype = {
|
|||||||
this._traymanager.manage_stage(global.stage);
|
this._traymanager.manage_stage(global.stage);
|
||||||
|
|
||||||
let statusbox = new Big.Box();
|
let statusbox = new Big.Box();
|
||||||
let statusmenu = this._statusmenu = new Shell.StatusMenu();
|
let statusmenu = this._statusmenu = new StatusMenu.StatusMenu();
|
||||||
statusmenu.get_icon().hide();
|
statusbox.append(this._statusmenu.actor, Big.BoxPackFlags.NONE);
|
||||||
statusmenu.get_name().fontName = DEFAULT_FONT;
|
|
||||||
statusmenu.get_name().color = PANEL_FOREGROUND_COLOR;
|
|
||||||
statusbox.append(this._statusmenu, Big.BoxPackFlags.NONE);
|
|
||||||
let statusbutton = new Button.Button(statusbox,
|
let statusbutton = new Button.Button(statusbox,
|
||||||
PANEL_BUTTON_COLOR,
|
PANEL_BUTTON_COLOR,
|
||||||
PRESSED_BUTTON_BACKGROUND_COLOR,
|
PRESSED_BUTTON_BACKGROUND_COLOR,
|
||||||
@ -385,7 +385,7 @@ Panel.prototype = {
|
|||||||
if (e.get_button() == 1 && e.get_click_count() == 1) {
|
if (e.get_button() == 1 && e.get_click_count() == 1) {
|
||||||
statusmenu.toggle(e);
|
statusmenu.toggle(e);
|
||||||
// The statusmenu might not pop up if it couldn't get a pointer grab
|
// 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;
|
statusbutton.actor.active = true;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
202
js/ui/statusMenu.js
Normal file
202
js/ui/statusMenu.js
Normal file
@ -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);
|
@ -87,8 +87,6 @@ libgnome_shell_la_SOURCES = \
|
|||||||
shell-global.c \
|
shell-global.c \
|
||||||
shell-global.h \
|
shell-global.h \
|
||||||
shell-global-private.h \
|
shell-global-private.h \
|
||||||
shell-status-menu.c \
|
|
||||||
shell-status-menu.h \
|
|
||||||
shell-stack.c \
|
shell-stack.c \
|
||||||
shell-stack.h \
|
shell-stack.h \
|
||||||
shell-tray-manager.c \
|
shell-tray-manager.c \
|
||||||
|
@ -1026,3 +1026,36 @@ shell_get_event_state (ClutterEvent *event)
|
|||||||
ClutterModifierType state = clutter_event_get_state (event);
|
ClutterModifierType state = clutter_event_get_state (event);
|
||||||
return state & CLUTTER_MODIFIER_MASK;
|
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);
|
||||||
|
}
|
||||||
|
@ -79,6 +79,10 @@ GdkModifierType shell_global_get_modifier_keys (ShellGlobal *global);
|
|||||||
|
|
||||||
ClutterModifierType shell_get_event_state (ClutterEvent *event);
|
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
|
G_END_DECLS
|
||||||
|
|
||||||
#endif /* __SHELL_GLOBAL_H__ */
|
#endif /* __SHELL_GLOBAL_H__ */
|
||||||
|
@ -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 <jcape@ignore-your.tv>.
|
|
||||||
* 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 <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
#include <glib/gi18n-lib.h>
|
|
||||||
#include <gdk/gdkkeysyms.h>
|
|
||||||
#include <gtk/gtk.h>
|
|
||||||
|
|
||||||
#include <gconf/gconf.h>
|
|
||||||
#include <gconf/gconf-client.h>
|
|
||||||
|
|
||||||
#include <dbus/dbus-glib.h>
|
|
||||||
|
|
||||||
#define GDMUSER_I_KNOW_THIS_IS_UNSTABLE
|
|
||||||
#include <gdmuser/gdm-user-manager.h>
|
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
@ -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 <clutter/clutter.h>
|
|
||||||
#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__ */
|
|
Loading…
Reference in New Issue
Block a user