/* * xfce4-hdaps, an XFCE4 panel plugin for the HDAPS system. * * Copyright (C) 2019 Michael Orlitzky * * http://michael.orlitzky.com/ * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 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 Affero General Public License for more details: * * https://www.gnu.org/licenses/agpl-3.0.html * */ #ifdef HAVE_CONFIG_H #include #endif #include "hdaps.h" #include "xfce4-hdaps.h" #include "xfce4-hdaps-dialogs.h" /* We need a default device. Since we require kernels newer than 2.6.28, it's probably sdX, and I'm guessing that sda is most likely. */ #define DEFAULT_DEVICE_NAME "sda" /* How often do we poll, in milliseconds? This should be configured, but we set the default here. */ #define DEFAULT_POLL_FREQUENCY 500 /* Prototype, needed to register below. */ static void hdaps_construct(XfcePanelPlugin *plugin); /* Register the plugin with the panel. */ XFCE_PANEL_PLUGIN_REGISTER(hdaps_construct); void hdaps_save(XfcePanelPlugin *plugin, HdapsPlugin *hdaps) { XfceRc *rc; gchar *file; /* Get the config file location. XFCE should know this. */ file = xfce_panel_plugin_save_location(plugin, TRUE); if (G_UNLIKELY(file == NULL)) { DBG("Failed to find the configuration file. Bailing."); return; } /* Open the config file read/write. */ rc = xfce_rc_simple_open(file, FALSE); /* And we can free the file path now that we've opened the file. */ g_free(file); if (G_UNLIKELY(rc == NULL)) { DBG("Failed to open the configuration file. Bailing."); return; } /* Write any user-configured values to the resource file. */ if (hdaps->device_name) { xfce_rc_write_entry(rc, "device_name", hdaps->device_name); } xfce_rc_write_int_entry(rc, "poll_frequency", hdaps->poll_frequency); /* close the rc file */ xfce_rc_close(rc); } void hdaps_set_icon(HdapsPlugin *hdaps, int status) { GdkPixbuf *icon; gint size; /* Panel info magic. */ size = xfce_panel_plugin_get_size(hdaps->plugin) - 6; /* Try to load an icon from the current icon theme. */ if (status == HDAPS_ERROR) { /* Error */ icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "emblem-noread", size, 0, NULL); } else if (status == HDAPS_OFF) { icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "drive-harddisk", size, 0, NULL); } else { /* status > HDAPS_OFF means it's on. */ icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(), "emblem-nowrite", size, 0, NULL); } /* Get rid of the previous icon. */ if (hdaps->icon) { gtk_widget_destroy(hdaps->icon); } if (icon) { hdaps->icon = gtk_image_new_from_pixbuf(icon); g_object_unref(G_OBJECT(icon)); } else { hdaps->icon = gtk_image_new_from_icon_name("dialog-warning", GTK_ICON_SIZE_BUTTON); } gtk_box_pack_start(GTK_BOX(hdaps->hvbox), GTK_WIDGET(hdaps->icon), FALSE, FALSE, 0); gtk_widget_show(hdaps->icon); return; } void hdaps_set_tooltip(HdapsPlugin *hdaps, int status) { if (status == HDAPS_ERROR) { gtk_tooltips_set_tip(hdaps->tooltip, hdaps->eventbox, "HDAPS Error", NULL); } else if (status == HDAPS_OFF) { gtk_tooltips_set_tip(hdaps->tooltip, hdaps->eventbox, "HDAPS Off", NULL); } else { gtk_tooltips_set_tip(hdaps->tooltip, hdaps->eventbox, "HDAPS On", NULL); } } static void hdaps_set_defaults(HdapsPlugin *hdaps) { DBG("Configuring all settings to defaults."); /* Here we determine the default device name. There are essentially two "defaults," one soft, and the other hard. The soft default is to choose the first supported HDAPS device in the system. This would benefit users who, for example, only have one supported drive named hda. If we can't find any supported HDAPS devices, we use the hard default of DEFAULT_DEVICE_NAME. */ char hdaps_devices[MAX_HDAPS_DEVICES][FILENAME_MAX]; int found_devices = get_hdaps_device_list(hdaps_devices); if (found_devices > 0) { hdaps->device_name = g_strdup(hdaps_devices[0]); } else { hdaps->device_name = g_strdup(DEFAULT_DEVICE_NAME); } snprintf(hdaps->sysfs_file, FILENAME_MAX, UNLOAD_HEADS_FMT, hdaps->device_name); /* The other default is easier. */ hdaps->poll_frequency = DEFAULT_POLL_FREQUENCY; } static void hdaps_read(HdapsPlugin *hdaps) { XfceRc *rc; gchar *file; const gchar *saved_device_name; /* Get the plugin config file location. XFCE should know this. */ file = xfce_panel_plugin_save_location(hdaps->plugin, TRUE); if (G_UNLIKELY(file == NULL)) { DBG("Something went wrong getting the configuration file location."); DBG("Retaining default settings."); return; } /* Open the config file read-only. */ rc = xfce_rc_simple_open(file, TRUE); /* Don't need this anymore if we've got a file handle. */ g_free(file); if (G_UNLIKELY(rc == NULL)) { DBG("There was an error opening the configuration file."); DBG("Retaining default settings."); return; } /* Read the settings, one at a time. */ /* We use saved_device_name here because we need to dupe the string after we read it in from the config file. */ saved_device_name = xfce_rc_read_entry(rc, "device_name", DEFAULT_DEVICE_NAME); hdaps->device_name = g_strdup(saved_device_name); snprintf(hdaps->sysfs_file, FILENAME_MAX, UNLOAD_HEADS_FMT, hdaps->device_name); /* Integers are easier. */ hdaps->poll_frequency = xfce_rc_read_int_entry(rc, "poll_frequency", DEFAULT_POLL_FREQUENCY); /* And close the config file. */ xfce_rc_close(rc); } static HdapsPlugin *hdaps_new(XfcePanelPlugin *plugin) { HdapsPlugin *hdaps; GtkOrientation orientation; /* Allocate memory for the plugin struct, and zero it. */ hdaps = panel_slice_new0(HdapsPlugin); /* The HdapsPlugin gets a copy of the XfcePanelPlugin. */ hdaps->plugin = plugin; /* Set default values right before reading in the user's settings. This way, hdaps_read() doesn't have to set defaults on error conditions. */ hdaps_set_defaults(hdaps); /* Read any user settings into the HdapsPlugin. */ hdaps_read(hdaps); /* Get the current orientation. Magic. */ orientation = xfce_panel_plugin_get_orientation(plugin); /* This creates the event box and shows it. This is necessary to, a) See the widget b) Interact with it via right-click, etc. */ hdaps->eventbox = gtk_event_box_new(); gtk_widget_show(hdaps->eventbox); /* Make the event box transparent. In newer versions of xfce4-panel users can make the panel transparent, so we don't want to stick a big opaque box on it. */ gtk_event_box_set_visible_window(GTK_EVENT_BOX(hdaps->eventbox), FALSE); /* Set up the hvbox for the widget, which supports both horizontal and vertical (hv) orientations. */ hdaps->hvbox = xfce_hvbox_new(orientation, FALSE, 2); gtk_widget_show(hdaps->hvbox); gtk_container_add(GTK_CONTAINER(hdaps->eventbox), hdaps->hvbox); /* We only change the icon when the status has changed, so it's important that they start out n*sync. */ hdaps->previous_status = HDAPS_OFF; hdaps_set_icon(hdaps, HDAPS_OFF); /* Create the tooltip widget, and set its initial value. * The first couple of lines are stolen from the battery * status plugin. I make no claim as to their correctness. */ hdaps->tooltip = gtk_tooltips_new(); g_object_ref(G_OBJECT(hdaps->tooltip)); gtk_object_sink(GTK_OBJECT(hdaps->tooltip)); hdaps_set_tooltip(hdaps, HDAPS_OFF); return hdaps; } static void hdaps_free(XfcePanelPlugin *plugin, HdapsPlugin *hdaps) { GtkWidget *dialog; /* Destroy the dialog if it's still open. */ dialog = g_object_get_data(G_OBJECT(plugin), "dialog"); if (G_UNLIKELY(dialog != NULL)) { gtk_widget_destroy(dialog); } /* Destroy the panel widgets. When dumb comments like these are left over, they're from the sample panel applet, I swear. */ gtk_widget_destroy(hdaps->hvbox); /* Remove the timeout that was set during creation. */ if (hdaps->timeout) { g_source_remove(hdaps->timeout); } /* And free the string (if any) containing the device name. */ if (G_LIKELY(hdaps->device_name != NULL)) { g_free(hdaps->device_name); } /* Goodbye, tooltips. */ gtk_tooltips_set_tip(hdaps->tooltip, hdaps->eventbox, NULL, NULL); g_object_unref(G_OBJECT(hdaps->tooltip)); /* ...and finally free the plugin structure. */ panel_slice_free(HdapsPlugin, hdaps); } static void hdaps_orientation_changed(XfcePanelPlugin *plugin, GtkOrientation orientation, HdapsPlugin *hdaps) { /* Change the plugin's orientation. Basically magic to me. */ xfce_hvbox_set_orientation(XFCE_HVBOX(hdaps->hvbox), orientation); } static gboolean hdaps_size_changed(XfcePanelPlugin *plugin, gint size, HdapsPlugin *hdaps) { GtkOrientation orientation; /* Get the current orientation of the plugin. */ orientation = xfce_panel_plugin_get_orientation(plugin); /* We want to make the widget "bigger" in the direction of its orientation. Or is it the other way around? */ if (orientation == GTK_ORIENTATION_HORIZONTAL) { gtk_widget_set_size_request(GTK_WIDGET(plugin), -1, size); } else { gtk_widget_set_size_request(GTK_WIDGET(plugin), size, -1); } /* This fixes an issue where the initial icon size is too small. */ hdaps_set_icon(hdaps, hdaps->previous_status); /* We handled the change, so we're supposed to return TRUE. */ return TRUE; } static gboolean hdaps_update_status(HdapsPlugin *hdaps) { /* This checks the status of HDAPS and updates the widget accordingly. */ /* This just gets the status. */ int status = parse_int_from_file(hdaps->sysfs_file); /* The value in the sysfs_file represents the number of milliseconds * that the drive heads will be parked. Of course, this will * generally count down, and appear different each time we poll. * * So, to determine whether or not HDAPS has gone from "on" * to "off," we treat all values greater than zero the same. */ if (status > 0) { status = HDAPS_ON; } if (status != hdaps->previous_status) { /* And we only update the icon if we need to. */ hdaps_set_icon(hdaps, status); hdaps_set_tooltip(hdaps, status); hdaps->previous_status = status; } return TRUE; } void hdaps_reset_timeout(HdapsPlugin *hdaps) { /* Remove, and then re-set the timeout function. Useful for changing the poll frequency. */ if (hdaps->timeout) { g_source_remove(hdaps->timeout); } hdaps->timeout = g_timeout_add(hdaps->poll_frequency, (GSourceFunc)hdaps_update_status, hdaps); } static void hdaps_construct(XfcePanelPlugin *plugin) { HdapsPlugin *hdaps; /* Set the "translation domain". I don't know what that does. */ xfce_textdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR, "UTF-8"); /* First, create the plugin. */ hdaps = hdaps_new(plugin); /* Add the plugin's eventbox to the panel. */ gtk_container_add(GTK_CONTAINER(plugin), hdaps->eventbox); /* This configures the right-click menu to appear on the plugin's eventbox. */ xfce_panel_plugin_add_action_widget(plugin, hdaps->eventbox); /* Connect the common event handlers. */ g_signal_connect(G_OBJECT(plugin), "free-data", G_CALLBACK(hdaps_free), hdaps); g_signal_connect (G_OBJECT(plugin), "save", G_CALLBACK(hdaps_save), hdaps); g_signal_connect (G_OBJECT(plugin), "size-changed", G_CALLBACK(hdaps_size_changed), hdaps); g_signal_connect (G_OBJECT(plugin), "orientation-changed", G_CALLBACK(hdaps_orientation_changed), hdaps); /* Show the "configure" right-click menu item, and connect its event handler. */ xfce_panel_plugin_menu_show_configure(plugin); g_signal_connect(G_OBJECT(plugin), "configure-plugin", G_CALLBACK(hdaps_configure), hdaps); /* Show the "about" right-click menu item, and connect its event handler. */ xfce_panel_plugin_menu_show_about(plugin); g_signal_connect(G_OBJECT(plugin), "about", G_CALLBACK(hdaps_about), hdaps); /* Set the timeout for the function which checks the HDAPS status. */ hdaps_reset_timeout(hdaps); return; }