6

My power menu looks the following and I want to have a hibernate option:

power menu

In Freya I was able to activate the hibernate option by following the steps outlined in this answer. I tried the same steps in Loki, but this didn't add the hibernate option.

5 Answers 5

4

I wanted this functionality as well but couldn't find it online anywhere. It looks like the Hibernate option was removed a long time ago because it fails on some systems (which perhaps was the case a long time ago :-). On my Dell XPS 9350, hibernate works just fine with elementary OS (via 'sudo systemctl hibernate').

This aspect of elementary OS is handled by the "wingpanel", and more specifically, by the wingpanel's session indicator application (the specific indicator that provides the 'power button' icon on the top right corner of the screen).

In order to get this functionality, I had to download the latest source code for the wingpanel session indicator, learn how to compile and install it, and learn how to add the missing functionality. If you have a background in coding it's fairly straight forward, if not, hopefully this guideline will help you figure it out.

Note, in order to hibernate as my regular user (and not the root user) I added the following to /etc/sudoers (although now I'm not sure if that's entirely necessary or not, previously I wrote my own indicator app to perform hiberntaion but this alternative is more elegant):

  • devin ALL = (root) NOPASSWD: /bin/systemctl

(where devin is my regular user name)

The changes I had to make were as follows. Note that instructions for building are shown later in this post.

  • add a new file named HibernateDialog.vala in the folder src/Widgets (based on the existing EndSessionDialog.vala in the same folder), contents of which are as follows:
/*
 * Copyright (c) 2011-2015 Tom Beckmann
 *
 * 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., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA
 */

public class Session.Widgets.HibernateDialog : Gtk.Dialog {

    public HibernateDialog () {
        Object (
            title: "",
            deletable: false,
            resizable: false,
            skip_taskbar_hint: true,
            skip_pager_hint: true,
            type_hint: Gdk.WindowTypeHint.DIALOG
        );
    }

    construct {
        string icon_name, heading_text, button_text, content_text;

        icon_name = "system-log-out";
        heading_text = "Are you sure you want to Hibernate this computer?";
        content_text = "This will save the contents of RAM to disk and shut down the computer.";
        button_text = "Hibernate";

        set_position (Gtk.WindowPosition.CENTER_ALWAYS);
        set_keep_above (true);
        stick ();

        var image = new Gtk.Image.from_icon_name (icon_name, Gtk.IconSize.DIALOG);
        image.valign = Gtk.Align.START;

        var heading = new Gtk.Label (heading_text);
        heading.get_style_context ().add_class ("primary");
        heading.xalign = 0;

        var secondary_label = new Gtk.Label (content_text);
        secondary_label.xalign = 0;

        var grid = new Gtk.Grid ();
        grid.column_spacing = 12;
        grid.row_spacing = 6;
        grid.margin_left = grid.margin_right = grid.margin_bottom = 12;
        grid.attach (image, 0, 0, 1, 2);
        grid.attach (heading, 1, 0, 1, 1);
        grid.attach (secondary_label, 1, 1, 1, 1);

        var cancel = add_button (_("Cancel"), Gtk.ResponseType.CANCEL) as Gtk.Button;
        cancel.clicked.connect (() => { destroy (); });

        var confirm = add_button (button_text, Gtk.ResponseType.OK) as Gtk.Button;
        confirm.get_style_context ().add_class ("destructive-action");
        confirm.clicked.connect (() => {
            try {
                Posix.system("systemctl hibernate");
            } catch (IOError e) {
                stderr.printf ("%s\n", e.message);
            }

            destroy ();
        });

        set_default (confirm);

        get_content_area ().add (grid);

        var action_area = get_action_area ();
        action_area.margin = 6;
    }
}
  • Modify Indicator.vala to add a Hibernate button:
/*
 * Copyright (c) 2011-2017 elementary LLC. 
 *
 * 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., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA
 */

public class Session.Indicator : Wingpanel.Indicator {
    private const string ICON_NAME = "system-shutdown-symbolic";

    private SystemInterface suspend_interface;
    private LockInterface lock_interface;
    private SeatInterface seat_interface;

    private Wingpanel.IndicatorManager.ServerType server_type;
    private Wingpanel.Widgets.OverlayIcon indicator_icon;
    private Wingpanel.Widgets.Separator users_separator;
    private Wingpanel.Widgets.Button lock_screen;
    private Wingpanel.Widgets.Button log_out;
    private Wingpanel.Widgets.Button suspend;
    private Wingpanel.Widgets.Button shutdown;
    private Wingpanel.Widgets.Button hibernate;

    private Session.Services.UserManager manager;

    private Gtk.Grid main_grid;
    private Session.Widgets.EndSessionDialog? shutdown_dialog = null;
    private Session.Widgets.HibernateDialog? hibernate_dialog = null;

    public Indicator (Wingpanel.IndicatorManager.ServerType server_type) {
        Object (code_name: Wingpanel.Indicator.SESSION,
                display_name: _("Session"),
                description: _("The session indicator"));
        this.server_type = server_type;
    }

    public override Gtk.Widget get_display_widget () {
        if (indicator_icon == null) {
            indicator_icon = new Wingpanel.Widgets.OverlayIcon (ICON_NAME);

            indicator_icon.button_press_event.connect ((e) => {
                if (e.button == Gdk.BUTTON_MIDDLE) {
                    close ();
                    show_shutdown_dialog ();
                    return Gdk.EVENT_STOP;
                }

                return Gdk.EVENT_PROPAGATE;
            });
        }

        return indicator_icon;
    }

    public override Gtk.Widget? get_widget () {
        if (main_grid == null) {
            init_interfaces ();

            main_grid = new Gtk.Grid ();
            main_grid.set_orientation (Gtk.Orientation.VERTICAL);

            log_out = new Wingpanel.Widgets.Button (_("Log Out…"));
            lock_screen = new Wingpanel.Widgets.Button (_("Lock"));
            shutdown = new Wingpanel.Widgets.Button (_("Shut Down…"));
            suspend = new Wingpanel.Widgets.Button (_("Suspend"));
            hibernate = new Wingpanel.Widgets.Button ("Hibernate");

            if (server_type == Wingpanel.IndicatorManager.ServerType.SESSION) {
                users_separator = new Wingpanel.Widgets.Separator ();
                manager = new Session.Services.UserManager (users_separator);

                var scrolled_box = new Wingpanel.Widgets.AutomaticScrollBox (null, null);
                scrolled_box.max_height = 300;
                scrolled_box.set_policy (Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC);
                scrolled_box.add (manager.user_grid);

                main_grid.add (scrolled_box);

                if (manager.has_guest) {
                    manager.add_guest (false);
                }

                main_grid.add (users_separator);
                main_grid.add (lock_screen);
                main_grid.add (log_out);
                main_grid.add (new Wingpanel.Widgets.Separator ());
            }

            main_grid.add (suspend);
            main_grid.add (hibernate);
            main_grid.add (shutdown);
            main_grid.margin_top = 6;

            connections ();
        }

        this.visible = true;

        return main_grid;
    }

    private void init_interfaces () {
        try {
            suspend_interface = Bus.get_proxy_sync (BusType.SYSTEM,"org.freedesktop.login1", "/org/freedesktop/login1");
        } catch (IOError e) {
            stderr.printf ("%s\n", e.message);
            suspend.set_sensitive (false);
        }

        if (server_type == Wingpanel.IndicatorManager.ServerType.SESSION) {
            try {
                lock_interface = Bus.get_proxy_sync(BusType.SESSION, "org.freedesktop.ScreenSaver", "/org/freedesktop/ScreenSaver");
            } catch (IOError e) {
                stderr.printf ("%s\n", e.message);
                lock_screen.set_sensitive (false);
            }

            try {
                seat_interface = Bus.get_proxy_sync (BusType.SESSION, "org.freedesktop.DisplayManager","/org/freedesktop/DisplayManager/Seat0");
            } catch (IOError e) {
                stderr.printf ("%s\n", e.message);
                lock_screen.set_sensitive (false);
            }
        }
    }

    public void connections () {
        manager.close.connect (() => close ());

        lock_screen.clicked.connect (() => {
            close ();
            try {
                lock_interface.lock ();
            } catch (IOError e) {
                stderr.printf ("%s\n", e.message);
            }
        });

        log_out.clicked.connect (() => {
            close ();
            var dialog = new Session.Widgets.EndSessionDialog (Session.Widgets.EndSessionDialogType.LOGOUT);
            dialog.set_transient_for (indicator_icon.get_toplevel () as Gtk.Window);
            dialog.show_all ();
        });

        shutdown.clicked.connect (() => {
            close ();
            show_shutdown_dialog ();
        });

        hibernate.clicked.connect (() => {
            close ();
            show_hibernate_dialog ();
        });

        suspend.clicked.connect (() => {
            close ();
            try {
                suspend_interface.suspend (true);
            } catch (IOError e) {
                stderr.printf ("%s\n", e.message);
            }
        });
    }

    public override void opened () {
        manager.update_all ();
    }

    public override void closed () {}

    private void show_shutdown_dialog () {
        if (shutdown_dialog == null) {
            shutdown_dialog = new Session.Widgets.EndSessionDialog (Session.Widgets.EndSessionDialogType.RESTART);
            shutdown_dialog.destroy.connect (() => { shutdown_dialog = null; });
            shutdown_dialog.set_transient_for (indicator_icon.get_toplevel () as Gtk.Window);
            shutdown_dialog.show_all ();
        }

        shutdown_dialog.present ();
    }

    private void show_hibernate_dialog () {
        if (hibernate_dialog == null) {
            hibernate_dialog = new Session.Widgets.HibernateDialog ();
            hibernate_dialog.destroy.connect (() => { hibernate_dialog = null; });
            hibernate_dialog.set_transient_for (indicator_icon.get_toplevel () as Gtk.Window);
            hibernate_dialog.show_all ();
        }

        hibernate_dialog.present ();
    }

}

public Wingpanel.Indicator? get_indicator (Module module, Wingpanel.IndicatorManager.ServerType server_type) {
    debug ("Activating Sample Indicator");
    var indicator = new Session.Indicator (server_type);

    return indicator;
}
  • Modify src/CMakeLists.txt and add Widgets/EndSessionDialog.vala and posix package dependency, my src/CMakeLists.txt now looks like this:
find_package (PkgConfig)

# Add all your dependencies to the list below
pkg_check_modules (DEPS REQUIRED gthread-2.0 gtk+-3.0 gio-2.0 accountsservice wingpanel-2.0 granite)

add_definitions (${DEPS_CFLAGS})
link_directories (${DEPS_LIBRARY_DIRS})

find_package (Vala REQUIRED)
include (ValaVersion)
ensure_vala_version ("0.22.0" MINIMUM)

include (ValaPrecompile)
# Add all your vala files and requires packages to the List below to include them in the build
vala_precompile (VALA_C ${CMAKE_PROJECT_NAME}
  Indicator.vala
  Widgets/UserBox.vala
  Widgets/UserListBox.vala
  Widgets/EndSessionDialog.vala
  Widgets/HibernateDialog.vala
  Services/UserManager.vala
  Services/DbusInterfaces.vala
  ${CMAKE_CURRENT_BINARY_DIR}/config.vala
PACKAGES
  gio-2.0
  gtk+-3.0
  wingpanel-2.0
  granite
  AccountsService-1.0
  posix
OPTIONS
  --thread
)

add_library (${CMAKE_PROJECT_NAME} MODULE ${VALA_C})
target_link_libraries(${CMAKE_PROJECT_NAME} ${DEPS_LIBRARIES})

# Installation
install (TARGETS ${CMAKE_PROJECT_NAME} DESTINATION ${PKGDATADIR})

Rough guideline for recompiling and installing a new wingpanel session indicator is as follows. You'll likely need to install several missing libraries for it to compile to completion.

For example, if you get an error about a dependency missing, then use "sudo apt-cache search dependency_name" to find it. It was fairly straight forward when I tried this. I think there was one exception though, which was 'sudo apt-get install elementary-sdk' (for "GObject").

  • download the latest wingpanel session indicator here: wingpanel session indicator
  • extract the .tar.xf file via 'tar xf wingpanel-indicator-session-2.0.3.tar.xz'
  • cd wingpanel-indicator-session-2.0.3
  • mkdir build
  • cd build
  • cmake .. -DCMAKE_INSTALL_PREFIX=/usr
  • make (and when get dependency errors, then use 'sudo apt-cache search '
  • WARNING: this last step with "sudo make install" will replace your current wingpanel session indicator with this one (and likely can't get it back), this should be fine as long as you're using a recent elementary OS (I think the latest is Loki as of this writing, so don't try this with older versions)
  • sudo make install

Note: I replaced the shutdown logo with my own logo. To do this, find all "system-shutdown-symbolic" icons in /usr/share and replace them with your own .svg icon file. For example, find the existing ones via:

  • find /usr/share -name '*system-shutdown-symbolic*'

Note: I didn't care about the various translations for i18n so I just used hard coded English strings instead of _("string"). I didn't feel like learning about i18n for this as I'm only ever using my PC in English.

example hibernate option

2
0

a simple solution may be: 1. go to system settings -> power. 2. enable hibernate for power button.

everytime you want to hibernate the system, just press power button.

1
  • 1
    Doesn't work on my computer.
    – Arif
    Commented May 5, 2017 at 17:03
0

You could install pm-utils (sudo apt install pm-utils). It worked for me, although it doesn't appear in the power menu, I could hibernate by calling:

sudo pm-hibernate

And it will hibernate.

0

You could assign your power button to hibernate the system by going to system settings -> Power -> select "Hibernate" next to "power button" like so:

enter image description here

Hope that helps.

Cheers!

0

Setting up a swapfile, and adding pm-utils and uswsusp worked for me just fine with sudo pm-hibernate, but no way to add it in the power menu without rebuilding wingpanel....ouch.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.