2 * xfce4-hdaps, an XFCE4 panel plugin for the HDAPS system.
4 * Copyright (C) 2019 Michael Orlitzky
6 * http://michael.orlitzky.com/
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Affero General Public License as
10 * published by the Free Software Foundation, either version 3 of the
11 * License, or (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Affero General Public License for more details:
18 * https://www.gnu.org/licenses/agpl-3.0.html
27 #include "xfce4-hdaps.h"
28 #include "xfce4-hdaps-dialogs.h"
30 /* We need a default device. Since we require kernels
31 newer than 2.6.28, it's probably sdX, and I'm guessing
32 that sda is most likely. */
33 #define DEFAULT_DEVICE_NAME "sda"
35 /* How often do we poll, in milliseconds?
36 This should be configured, but we set the default here. */
37 #define DEFAULT_POLL_FREQUENCY 500
40 /* Prototype, needed to register below. */
41 static void hdaps_construct(XfcePanelPlugin
*plugin
);
43 /* Register the plugin with the panel. */
44 XFCE_PANEL_PLUGIN_REGISTER(hdaps_construct
);
47 void hdaps_save(XfcePanelPlugin
*plugin
, HdapsPlugin
*hdaps
) {
52 /* Get the config file location. XFCE should know this. */
53 file
= xfce_panel_plugin_save_location(plugin
, TRUE
);
55 if (G_UNLIKELY(file
== NULL
)) {
56 DBG("Failed to find the configuration file. Bailing.");
60 /* Open the config file read/write. */
61 rc
= xfce_rc_simple_open(file
, FALSE
);
63 /* And we can free the file path now that we've
67 if (G_UNLIKELY(rc
== NULL
)) {
68 DBG("Failed to open the configuration file. Bailing.");
73 /* Write any user-configured values to the resource file. */
74 if (hdaps
->device_name
) {
75 xfce_rc_write_entry(rc
, "device_name", hdaps
->device_name
);
78 xfce_rc_write_int_entry(rc
, "poll_frequency", hdaps
->poll_frequency
);
80 /* close the rc file */
86 void hdaps_set_icon(HdapsPlugin
*hdaps
, int status
) {
90 /* Panel info magic. */
91 size
= xfce_panel_plugin_get_size(hdaps
->plugin
) - 6;
93 /* Try to load an icon from the current icon theme. */
94 if (status
== HDAPS_ERROR
) {
96 icon
= gtk_icon_theme_load_icon(gtk_icon_theme_get_default(),
100 else if (status
== HDAPS_OFF
) {
101 icon
= gtk_icon_theme_load_icon(gtk_icon_theme_get_default(),
106 /* status > HDAPS_OFF means it's on. */
107 icon
= gtk_icon_theme_load_icon(gtk_icon_theme_get_default(),
112 /* Get rid of the previous icon. */
114 gtk_widget_destroy(hdaps
->icon
);
118 hdaps
->icon
= gtk_image_new_from_pixbuf(icon
);
119 g_object_unref(G_OBJECT(icon
));
122 hdaps
->icon
= gtk_image_new_from_icon_name("dialog-warning", GTK_ICON_SIZE_BUTTON
);
125 gtk_box_pack_start(GTK_BOX(hdaps
->hvbox
), GTK_WIDGET(hdaps
->icon
), FALSE
, FALSE
, 0);
126 gtk_widget_show(hdaps
->icon
);
133 void hdaps_set_tooltip(HdapsPlugin
*hdaps
, int status
) {
135 if (status
== HDAPS_ERROR
) {
136 gtk_tooltips_set_tip(hdaps
->tooltip
, hdaps
->eventbox
, "HDAPS Error", NULL
);
138 else if (status
== HDAPS_OFF
) {
139 gtk_tooltips_set_tip(hdaps
->tooltip
, hdaps
->eventbox
, "HDAPS Off", NULL
);
142 gtk_tooltips_set_tip(hdaps
->tooltip
, hdaps
->eventbox
, "HDAPS On", NULL
);
147 static void hdaps_set_defaults(HdapsPlugin
*hdaps
) {
148 DBG("Configuring all settings to defaults.");
150 /* Here we determine the default device name. There are essentially
151 two "defaults," one soft, and the other hard. The soft default
152 is to choose the first supported HDAPS device in the system. This
153 would benefit users who, for example, only have one supported drive
154 named hda. If we can't find any supported HDAPS devices, we use the
155 hard default of DEFAULT_DEVICE_NAME. */
156 char hdaps_devices
[MAX_HDAPS_DEVICES
][FILENAME_MAX
];
157 int found_devices
= get_hdaps_device_list(hdaps_devices
);
159 if (found_devices
> 0) {
160 hdaps
->device_name
= g_strdup(hdaps_devices
[0]);
163 hdaps
->device_name
= g_strdup(DEFAULT_DEVICE_NAME
);
166 snprintf(hdaps
->sysfs_file
, FILENAME_MAX
, UNLOAD_HEADS_FMT
, hdaps
->device_name
);
168 /* The other default is easier. */
169 hdaps
->poll_frequency
= DEFAULT_POLL_FREQUENCY
;
173 static void hdaps_read(HdapsPlugin
*hdaps
) {
177 const gchar
*saved_device_name
;
179 /* Get the plugin config file location. XFCE should know this. */
180 file
= xfce_panel_plugin_save_location(hdaps
->plugin
, TRUE
);
182 if (G_UNLIKELY(file
== NULL
)) {
183 DBG("Something went wrong getting the configuration file location.");
184 DBG("Retaining default settings.");
188 /* Open the config file read-only. */
189 rc
= xfce_rc_simple_open(file
, TRUE
);
191 /* Don't need this anymore if we've got a file handle. */
194 if (G_UNLIKELY(rc
== NULL
)) {
195 DBG("There was an error opening the configuration file.");
196 DBG("Retaining default settings.");
200 /* Read the settings, one at a time. */
202 /* We use saved_device_name here because we need
203 to dupe the string after we read it in from the
205 saved_device_name
= xfce_rc_read_entry(rc
,
207 DEFAULT_DEVICE_NAME
);
208 hdaps
->device_name
= g_strdup(saved_device_name
);
209 snprintf(hdaps
->sysfs_file
, FILENAME_MAX
, UNLOAD_HEADS_FMT
, hdaps
->device_name
);
211 /* Integers are easier. */
212 hdaps
->poll_frequency
= xfce_rc_read_int_entry(rc
,
214 DEFAULT_POLL_FREQUENCY
);
216 /* And close the config file. */
223 static HdapsPlugin
*hdaps_new(XfcePanelPlugin
*plugin
) {
225 GtkOrientation orientation
;
227 /* Allocate memory for the plugin struct, and zero it. */
228 hdaps
= panel_slice_new0(HdapsPlugin
);
230 /* The HdapsPlugin gets a copy of the XfcePanelPlugin. */
231 hdaps
->plugin
= plugin
;
233 /* Set default values right before reading in the user's settings.
234 This way, hdaps_read() doesn't have to set defaults on error
236 hdaps_set_defaults(hdaps
);
238 /* Read any user settings into the HdapsPlugin. */
241 /* Get the current orientation. Magic. */
242 orientation
= xfce_panel_plugin_get_orientation(plugin
);
244 /* This creates the event box and shows it. This
248 b) Interact with it via right-click, etc.
250 hdaps
->eventbox
= gtk_event_box_new();
251 gtk_widget_show(hdaps
->eventbox
);
253 /* Make the event box transparent. In newer versions of xfce4-panel
254 users can make the panel transparent, so we don't want to stick a
255 big opaque box on it. */
256 gtk_event_box_set_visible_window(GTK_EVENT_BOX(hdaps
->eventbox
), FALSE
);
258 /* Set up the hvbox for the widget, which supports
259 both horizontal and vertical (hv) orientations. */
260 hdaps
->hvbox
= xfce_hvbox_new(orientation
, FALSE
, 2);
261 gtk_widget_show(hdaps
->hvbox
);
262 gtk_container_add(GTK_CONTAINER(hdaps
->eventbox
), hdaps
->hvbox
);
264 /* We only change the icon when the status has changed,
265 so it's important that they start out n*sync. */
266 hdaps
->previous_status
= HDAPS_OFF
;
267 hdaps_set_icon(hdaps
, HDAPS_OFF
);
269 /* Create the tooltip widget, and set its initial value.
270 * The first couple of lines are stolen from the battery
271 * status plugin. I make no claim as to their correctness.
273 hdaps
->tooltip
= gtk_tooltips_new();
274 g_object_ref(G_OBJECT(hdaps
->tooltip
));
275 gtk_object_sink(GTK_OBJECT(hdaps
->tooltip
));
276 hdaps_set_tooltip(hdaps
, HDAPS_OFF
);
283 static void hdaps_free(XfcePanelPlugin
*plugin
,
284 HdapsPlugin
*hdaps
) {
288 /* Destroy the dialog if it's still open. */
289 dialog
= g_object_get_data(G_OBJECT(plugin
), "dialog");
291 if (G_UNLIKELY(dialog
!= NULL
)) {
292 gtk_widget_destroy(dialog
);
295 /* Destroy the panel widgets. When dumb comments like these
296 are left over, they're from the sample panel applet,
298 gtk_widget_destroy(hdaps
->hvbox
);
300 /* Remove the timeout that was set during creation. */
301 if (hdaps
->timeout
) {
302 g_source_remove(hdaps
->timeout
);
305 /* And free the string (if any) containing
307 if (G_LIKELY(hdaps
->device_name
!= NULL
)) {
308 g_free(hdaps
->device_name
);
311 /* Goodbye, tooltips. */
312 gtk_tooltips_set_tip(hdaps
->tooltip
, hdaps
->eventbox
, NULL
, NULL
);
313 g_object_unref(G_OBJECT(hdaps
->tooltip
));
315 /* ...and finally free the plugin structure. */
316 panel_slice_free(HdapsPlugin
, hdaps
);
321 static void hdaps_orientation_changed(XfcePanelPlugin
*plugin
,
322 GtkOrientation orientation
,
323 HdapsPlugin
*hdaps
) {
325 /* Change the plugin's orientation. Basically magic to me. */
326 xfce_hvbox_set_orientation(XFCE_HVBOX(hdaps
->hvbox
), orientation
);
331 static gboolean
hdaps_size_changed(XfcePanelPlugin
*plugin
,
333 HdapsPlugin
*hdaps
) {
335 GtkOrientation orientation
;
337 /* Get the current orientation of the plugin. */
338 orientation
= xfce_panel_plugin_get_orientation(plugin
);
340 /* We want to make the widget "bigger" in the direction
341 of its orientation. Or is it the other way around? */
342 if (orientation
== GTK_ORIENTATION_HORIZONTAL
) {
343 gtk_widget_set_size_request(GTK_WIDGET(plugin
), -1, size
);
346 gtk_widget_set_size_request(GTK_WIDGET(plugin
), size
, -1);
349 /* This fixes an issue where the initial icon size is too small. */
350 hdaps_set_icon(hdaps
, hdaps
->previous_status
);
352 /* We handled the change, so we're supposed to return TRUE. */
358 static gboolean
hdaps_update_status(HdapsPlugin
*hdaps
) {
359 /* This checks the status of HDAPS and updates the
360 widget accordingly. */
362 /* This just gets the status. */
363 int status
= parse_int_from_file(hdaps
->sysfs_file
);
365 /* The value in the sysfs_file represents the number of milliseconds
366 * that the drive heads will be parked. Of course, this will
367 * generally count down, and appear different each time we poll.
369 * So, to determine whether or not HDAPS has gone from "on"
370 * to "off," we treat all values greater than zero the same.
376 if (status
!= hdaps
->previous_status
) {
377 /* And we only update the icon if we need to. */
378 hdaps_set_icon(hdaps
, status
);
379 hdaps_set_tooltip(hdaps
, status
);
380 hdaps
->previous_status
= status
;
388 void hdaps_reset_timeout(HdapsPlugin
*hdaps
) {
389 /* Remove, and then re-set the timeout function. Useful
390 for changing the poll frequency. */
391 if (hdaps
->timeout
) {
392 g_source_remove(hdaps
->timeout
);
395 hdaps
->timeout
= g_timeout_add(hdaps
->poll_frequency
, (GSourceFunc
)hdaps_update_status
, hdaps
);
400 static void hdaps_construct(XfcePanelPlugin
*plugin
) {
403 /* Set the "translation domain". I don't know what that does. */
404 xfce_textdomain(GETTEXT_PACKAGE
, PACKAGE_LOCALE_DIR
, "UTF-8");
406 /* First, create the plugin. */
407 hdaps
= hdaps_new(plugin
);
409 /* Add the plugin's eventbox to the panel. */
410 gtk_container_add(GTK_CONTAINER(plugin
), hdaps
->eventbox
);
412 /* This configures the right-click menu to appear
413 on the plugin's eventbox. */
414 xfce_panel_plugin_add_action_widget(plugin
, hdaps
->eventbox
);
416 /* Connect the common event handlers. */
417 g_signal_connect(G_OBJECT(plugin
), "free-data",
418 G_CALLBACK(hdaps_free
), hdaps
);
420 g_signal_connect (G_OBJECT(plugin
), "save",
421 G_CALLBACK(hdaps_save
), hdaps
);
423 g_signal_connect (G_OBJECT(plugin
), "size-changed",
424 G_CALLBACK(hdaps_size_changed
), hdaps
);
426 g_signal_connect (G_OBJECT(plugin
), "orientation-changed",
427 G_CALLBACK(hdaps_orientation_changed
), hdaps
);
429 /* Show the "configure" right-click menu item, and
430 connect its event handler. */
431 xfce_panel_plugin_menu_show_configure(plugin
);
432 g_signal_connect(G_OBJECT(plugin
), "configure-plugin",
433 G_CALLBACK(hdaps_configure
), hdaps
);
435 /* Show the "about" right-click menu item, and
436 connect its event handler. */
437 xfce_panel_plugin_menu_show_about(plugin
);
438 g_signal_connect(G_OBJECT(plugin
), "about",
439 G_CALLBACK(hdaps_about
), hdaps
);
441 /* Set the timeout for the function which checks the
443 hdaps_reset_timeout(hdaps
);