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",
123 GTK_ICON_SIZE_BUTTON
);
126 gtk_box_pack_start(GTK_BOX(hdaps
->hvbox
),
127 GTK_WIDGET(hdaps
->icon
),
131 gtk_widget_show(hdaps
->icon
);
138 void hdaps_set_tooltip(HdapsPlugin
*hdaps
, int status
) {
139 if (status
== HDAPS_ERROR
) {
140 gtk_widget_set_tooltip_text(GTK_WIDGET(hdaps
->eventbox
), "HDAPS Error");
142 else if (status
== HDAPS_OFF
) {
143 gtk_widget_set_tooltip_text(GTK_WIDGET(hdaps
->eventbox
), "HDAPS Off");
146 gtk_widget_set_tooltip_text(GTK_WIDGET(hdaps
->eventbox
), "HDAPS On");
151 static void hdaps_set_defaults(HdapsPlugin
*hdaps
) {
152 DBG("Configuring all settings to defaults.");
154 /* Here we determine the default device name. There are essentially
155 two "defaults," one soft, and the other hard. The soft default
156 is to choose the first supported HDAPS device in the system. This
157 would benefit users who, for example, only have one supported drive
158 named hda. If we can't find any supported HDAPS devices, we use the
159 hard default of DEFAULT_DEVICE_NAME. */
160 char hdaps_devices
[MAX_HDAPS_DEVICES
][FILENAME_MAX
];
161 int found_devices
= get_hdaps_device_list(hdaps_devices
);
163 if (found_devices
> 0) {
164 hdaps
->device_name
= g_strdup(hdaps_devices
[0]);
167 hdaps
->device_name
= g_strdup(DEFAULT_DEVICE_NAME
);
170 snprintf(hdaps
->sysfs_file
,
175 /* The other default is easier. */
176 hdaps
->poll_frequency
= DEFAULT_POLL_FREQUENCY
;
180 static void hdaps_read(HdapsPlugin
*hdaps
) {
184 const gchar
*saved_device_name
;
186 /* Get the plugin config file location. XFCE should know this. */
187 file
= xfce_panel_plugin_save_location(hdaps
->plugin
, TRUE
);
189 if (G_UNLIKELY(file
== NULL
)) {
190 DBG("Something went wrong getting the configuration file location.");
191 DBG("Retaining default settings.");
195 /* Open the config file read-only. */
196 rc
= xfce_rc_simple_open(file
, TRUE
);
198 /* Don't need this anymore if we've got a file handle. */
201 if (G_UNLIKELY(rc
== NULL
)) {
202 DBG("There was an error opening the configuration file.");
203 DBG("Retaining default settings.");
207 /* Read the settings, one at a time. */
209 /* We use saved_device_name here because we need
210 to dupe the string after we read it in from the
212 saved_device_name
= xfce_rc_read_entry(rc
,
214 DEFAULT_DEVICE_NAME
);
215 hdaps
->device_name
= g_strdup(saved_device_name
);
216 snprintf(hdaps
->sysfs_file
,
221 /* Integers are easier. */
222 hdaps
->poll_frequency
= xfce_rc_read_int_entry(rc
,
224 DEFAULT_POLL_FREQUENCY
);
226 /* And close the config file. */
233 static HdapsPlugin
*hdaps_new(XfcePanelPlugin
*plugin
) {
235 GtkOrientation orientation
;
237 /* Allocate memory for the plugin struct, and zero it. */
238 hdaps
= g_slice_new0(HdapsPlugin
);
240 /* The HdapsPlugin gets a copy of the XfcePanelPlugin. */
241 hdaps
->plugin
= plugin
;
243 /* Set default values right before reading in the user's settings.
244 This way, hdaps_read() doesn't have to set defaults on error
246 hdaps_set_defaults(hdaps
);
248 /* Read any user settings into the HdapsPlugin. */
251 /* Get the current orientation. Magic. */
252 orientation
= xfce_panel_plugin_get_orientation(plugin
);
254 /* This creates the event box and shows it. This
258 b) Interact with it via right-click, etc.
260 hdaps
->eventbox
= gtk_event_box_new();
261 gtk_widget_show(hdaps
->eventbox
);
263 /* Make the event box transparent. In newer versions of xfce4-panel
264 users can make the panel transparent, so we don't want to stick a
265 big opaque box on it. */
266 gtk_event_box_set_visible_window(GTK_EVENT_BOX(hdaps
->eventbox
), FALSE
);
268 /* Set up the hvbox for the widget, which supports
269 both horizontal and vertical (hv) orientations. */
270 hdaps
->hvbox
= gtk_box_new(orientation
, 2);
271 gtk_widget_show(hdaps
->hvbox
);
272 gtk_container_add(GTK_CONTAINER(hdaps
->eventbox
), hdaps
->hvbox
);
274 /* We only change the icon when the status has changed,
275 so it's important that they start out n*sync. */
276 hdaps
->previous_status
= HDAPS_OFF
;
277 hdaps_set_icon(hdaps
, HDAPS_OFF
);
278 hdaps_set_tooltip(hdaps
, HDAPS_OFF
);
285 static void hdaps_free(XfcePanelPlugin
*plugin
,
286 HdapsPlugin
*hdaps
) {
290 /* Destroy the dialog if it's still open. */
291 dialog
= g_object_get_data(G_OBJECT(plugin
), "dialog");
293 if (G_UNLIKELY(dialog
!= NULL
)) {
294 gtk_widget_destroy(dialog
);
297 /* Destroy the panel widgets. When dumb comments like these
298 are left over, they're from the sample panel applet,
300 gtk_widget_destroy(hdaps
->hvbox
);
302 /* Remove the timeout that was set during creation. */
303 if (hdaps
->timeout
) {
304 g_source_remove(hdaps
->timeout
);
307 /* And free the string (if any) containing
309 if (G_LIKELY(hdaps
->device_name
!= NULL
)) {
310 g_free(hdaps
->device_name
);
313 /* ...and finally free the plugin structure. */
314 g_slice_free(HdapsPlugin
, hdaps
);
319 static void hdaps_orientation_changed(XfcePanelPlugin
*plugin
,
320 GtkOrientation orientation
,
321 HdapsPlugin
*hdaps
) {
323 /* Change the plugin's orientation. Basically magic to me. */
324 gtk_orientable_set_orientation(GTK_ORIENTABLE(hdaps
->hvbox
), orientation
);
329 static gboolean
hdaps_size_changed(XfcePanelPlugin
*plugin
,
331 HdapsPlugin
*hdaps
) {
333 GtkOrientation orientation
;
335 /* Get the current orientation of the plugin. */
336 orientation
= xfce_panel_plugin_get_orientation(plugin
);
338 /* We want to make the widget "bigger" in the direction
339 of its orientation. Or is it the other way around? */
340 if (orientation
== GTK_ORIENTATION_HORIZONTAL
) {
341 gtk_widget_set_size_request(GTK_WIDGET(plugin
), -1, size
);
344 gtk_widget_set_size_request(GTK_WIDGET(plugin
), size
, -1);
347 /* This fixes an issue where the initial icon size is too small. */
348 hdaps_set_icon(hdaps
, hdaps
->previous_status
);
350 /* We handled the change, so we're supposed to return TRUE. */
356 static gboolean
hdaps_update_status(HdapsPlugin
*hdaps
) {
357 /* This checks the status of HDAPS and updates the
358 widget accordingly. */
360 /* This just gets the status. */
361 int status
= parse_int_from_file(hdaps
->sysfs_file
);
363 /* The value in the sysfs_file represents the number of milliseconds
364 * that the drive heads will be parked. Of course, this will
365 * generally count down, and appear different each time we poll.
367 * So, to determine whether or not HDAPS has gone from "on"
368 * to "off," we treat all values greater than zero the same.
374 if (status
!= hdaps
->previous_status
) {
375 /* And we only update the icon if we need to. */
376 hdaps_set_icon(hdaps
, status
);
377 hdaps_set_tooltip(hdaps
, status
);
378 hdaps
->previous_status
= status
;
386 void hdaps_reset_timeout(HdapsPlugin
*hdaps
) {
387 /* Remove, and then re-set the timeout function. Useful
388 for changing the poll frequency. */
389 if (hdaps
->timeout
) {
390 g_source_remove(hdaps
->timeout
);
393 hdaps
->timeout
= g_timeout_add(hdaps
->poll_frequency
,
394 (GSourceFunc
)hdaps_update_status
,
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
);