]> gitweb.michael.orlitzky.com - xfce4-hdaps.git/blob - panel-plugin/xfce4-hdaps.c
e5a781e3b7cd50915f5a7136caeee63ad13d0c79
[xfce4-hdaps.git] / panel-plugin / xfce4-hdaps.c
1 /*
2 * xfce4-hdaps, an XFCE4 panel plugin for the HDAPS system.
3 *
4 * Copyright (C) 2019 Michael Orlitzky
5 *
6 * http://michael.orlitzky.com/
7 *
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.
12 *
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:
17 *
18 * https://www.gnu.org/licenses/agpl-3.0.html
19 *
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include "hdaps.h"
27 #include "xfce4-hdaps.h"
28 #include "xfce4-hdaps-dialogs.h"
29
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"
34
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
38
39
40 /* Prototype, needed to register below. */
41 static void hdaps_construct(XfcePanelPlugin *plugin);
42
43 /* Register the plugin with the panel. */
44 XFCE_PANEL_PLUGIN_REGISTER(hdaps_construct);
45
46
47 void hdaps_save(XfcePanelPlugin *plugin, HdapsPlugin *hdaps) {
48
49 XfceRc *rc;
50 gchar *file;
51
52 /* Get the config file location. XFCE should know this. */
53 file = xfce_panel_plugin_save_location(plugin, TRUE);
54
55 if (G_UNLIKELY(file == NULL)) {
56 DBG("Failed to find the configuration file. Bailing.");
57 return;
58 }
59
60 /* Open the config file read/write. */
61 rc = xfce_rc_simple_open(file, FALSE);
62
63 /* And we can free the file path now that we've
64 opened the file. */
65 g_free(file);
66
67 if (G_UNLIKELY(rc == NULL)) {
68 DBG("Failed to open the configuration file. Bailing.");
69 return;
70 }
71
72
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);
76 }
77
78 xfce_rc_write_int_entry(rc, "poll_frequency", hdaps->poll_frequency);
79
80 /* close the rc file */
81 xfce_rc_close(rc);
82 }
83
84
85
86 void hdaps_set_icon(HdapsPlugin *hdaps, int status) {
87 GdkPixbuf *icon;
88 gint size;
89
90 /* Panel info magic. */
91 size = xfce_panel_plugin_get_size(hdaps->plugin) - 6;
92
93 /* Try to load an icon from the current icon theme. */
94 if (status == HDAPS_ERROR) {
95 /* Error */
96 icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(),
97 "emblem-noread",
98 size, 0, NULL);
99 }
100 else if (status == HDAPS_OFF) {
101 icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(),
102 "drive-harddisk",
103 size, 0, NULL);
104 }
105 else {
106 /* status > HDAPS_OFF means it's on. */
107 icon = gtk_icon_theme_load_icon(gtk_icon_theme_get_default(),
108 "emblem-nowrite",
109 size, 0, NULL);
110 }
111
112 /* Get rid of the previous icon. */
113 if (hdaps->icon) {
114 gtk_widget_destroy(hdaps->icon);
115 }
116
117 if (icon) {
118 hdaps->icon = gtk_image_new_from_pixbuf(icon);
119 g_object_unref(G_OBJECT(icon));
120 }
121 else {
122 hdaps->icon = gtk_image_new_from_icon_name("dialog-warning", GTK_ICON_SIZE_BUTTON);
123 }
124
125 gtk_box_pack_start(GTK_BOX(hdaps->hvbox), GTK_WIDGET(hdaps->icon), FALSE, FALSE, 0);
126 gtk_widget_show(hdaps->icon);
127
128 return;
129 }
130
131
132
133 void hdaps_set_tooltip(HdapsPlugin *hdaps, int status) {
134 if (status == HDAPS_ERROR) {
135 gtk_widget_set_tooltip_text(GTK_WIDGET(hdaps->eventbox), "HDAPS Error");
136 }
137 else if (status == HDAPS_OFF) {
138 gtk_widget_set_tooltip_text(GTK_WIDGET(hdaps->eventbox), "HDAPS Off");
139 }
140 else {
141 gtk_widget_set_tooltip_text(GTK_WIDGET(hdaps->eventbox), "HDAPS On");
142 }
143 }
144
145
146 static void hdaps_set_defaults(HdapsPlugin *hdaps) {
147 DBG("Configuring all settings to defaults.");
148
149 /* Here we determine the default device name. There are essentially
150 two "defaults," one soft, and the other hard. The soft default
151 is to choose the first supported HDAPS device in the system. This
152 would benefit users who, for example, only have one supported drive
153 named hda. If we can't find any supported HDAPS devices, we use the
154 hard default of DEFAULT_DEVICE_NAME. */
155 char hdaps_devices[MAX_HDAPS_DEVICES][FILENAME_MAX];
156 int found_devices = get_hdaps_device_list(hdaps_devices);
157
158 if (found_devices > 0) {
159 hdaps->device_name = g_strdup(hdaps_devices[0]);
160 }
161 else {
162 hdaps->device_name = g_strdup(DEFAULT_DEVICE_NAME);
163 }
164
165 snprintf(hdaps->sysfs_file, FILENAME_MAX, UNLOAD_HEADS_FMT, hdaps->device_name);
166
167 /* The other default is easier. */
168 hdaps->poll_frequency = DEFAULT_POLL_FREQUENCY;
169 }
170
171
172 static void hdaps_read(HdapsPlugin *hdaps) {
173
174 XfceRc *rc;
175 gchar *file;
176 const gchar *saved_device_name;
177
178 /* Get the plugin config file location. XFCE should know this. */
179 file = xfce_panel_plugin_save_location(hdaps->plugin, TRUE);
180
181 if (G_UNLIKELY(file == NULL)) {
182 DBG("Something went wrong getting the configuration file location.");
183 DBG("Retaining default settings.");
184 return;
185 }
186
187 /* Open the config file read-only. */
188 rc = xfce_rc_simple_open(file, TRUE);
189
190 /* Don't need this anymore if we've got a file handle. */
191 g_free(file);
192
193 if (G_UNLIKELY(rc == NULL)) {
194 DBG("There was an error opening the configuration file.");
195 DBG("Retaining default settings.");
196 return;
197 }
198
199 /* Read the settings, one at a time. */
200
201 /* We use saved_device_name here because we need
202 to dupe the string after we read it in from the
203 config file. */
204 saved_device_name = xfce_rc_read_entry(rc,
205 "device_name",
206 DEFAULT_DEVICE_NAME);
207 hdaps->device_name = g_strdup(saved_device_name);
208 snprintf(hdaps->sysfs_file, FILENAME_MAX, UNLOAD_HEADS_FMT, hdaps->device_name);
209
210 /* Integers are easier. */
211 hdaps->poll_frequency = xfce_rc_read_int_entry(rc,
212 "poll_frequency",
213 DEFAULT_POLL_FREQUENCY);
214
215 /* And close the config file. */
216 xfce_rc_close(rc);
217 }
218
219
220
221
222 static HdapsPlugin *hdaps_new(XfcePanelPlugin *plugin) {
223 HdapsPlugin *hdaps;
224 GtkOrientation orientation;
225
226 /* Allocate memory for the plugin struct, and zero it. */
227 hdaps = panel_slice_new0(HdapsPlugin);
228
229 /* The HdapsPlugin gets a copy of the XfcePanelPlugin. */
230 hdaps->plugin = plugin;
231
232 /* Set default values right before reading in the user's settings.
233 This way, hdaps_read() doesn't have to set defaults on error
234 conditions. */
235 hdaps_set_defaults(hdaps);
236
237 /* Read any user settings into the HdapsPlugin. */
238 hdaps_read(hdaps);
239
240 /* Get the current orientation. Magic. */
241 orientation = xfce_panel_plugin_get_orientation(plugin);
242
243 /* This creates the event box and shows it. This
244 is necessary to,
245
246 a) See the widget
247 b) Interact with it via right-click, etc.
248 */
249 hdaps->eventbox = gtk_event_box_new();
250 gtk_widget_show(hdaps->eventbox);
251
252 /* Make the event box transparent. In newer versions of xfce4-panel
253 users can make the panel transparent, so we don't want to stick a
254 big opaque box on it. */
255 gtk_event_box_set_visible_window(GTK_EVENT_BOX(hdaps->eventbox), FALSE);
256
257 /* Set up the hvbox for the widget, which supports
258 both horizontal and vertical (hv) orientations. */
259 hdaps->hvbox = gtk_box_new(orientation, 2);
260 gtk_widget_show(hdaps->hvbox);
261 gtk_container_add(GTK_CONTAINER(hdaps->eventbox), hdaps->hvbox);
262
263 /* We only change the icon when the status has changed,
264 so it's important that they start out n*sync. */
265 hdaps->previous_status = HDAPS_OFF;
266 hdaps_set_icon(hdaps, HDAPS_OFF);
267 hdaps_set_tooltip(hdaps, HDAPS_OFF);
268
269 return hdaps;
270 }
271
272
273
274 static void hdaps_free(XfcePanelPlugin *plugin,
275 HdapsPlugin *hdaps) {
276
277 GtkWidget *dialog;
278
279 /* Destroy the dialog if it's still open. */
280 dialog = g_object_get_data(G_OBJECT(plugin), "dialog");
281
282 if (G_UNLIKELY(dialog != NULL)) {
283 gtk_widget_destroy(dialog);
284 }
285
286 /* Destroy the panel widgets. When dumb comments like these
287 are left over, they're from the sample panel applet,
288 I swear. */
289 gtk_widget_destroy(hdaps->hvbox);
290
291 /* Remove the timeout that was set during creation. */
292 if (hdaps->timeout) {
293 g_source_remove(hdaps->timeout);
294 }
295
296 /* And free the string (if any) containing
297 the device name. */
298 if (G_LIKELY(hdaps->device_name != NULL)) {
299 g_free(hdaps->device_name);
300 }
301
302 /* ...and finally free the plugin structure. */
303 panel_slice_free(HdapsPlugin, hdaps);
304 }
305
306
307
308 static void hdaps_orientation_changed(XfcePanelPlugin *plugin,
309 GtkOrientation orientation,
310 HdapsPlugin *hdaps) {
311
312 /* Change the plugin's orientation. Basically magic to me. */
313 gtk_orientable_set_orientation(GTK_ORIENTABLE(hdaps->hvbox), orientation);
314 }
315
316
317
318 static gboolean hdaps_size_changed(XfcePanelPlugin *plugin,
319 gint size,
320 HdapsPlugin *hdaps) {
321
322 GtkOrientation orientation;
323
324 /* Get the current orientation of the plugin. */
325 orientation = xfce_panel_plugin_get_orientation(plugin);
326
327 /* We want to make the widget "bigger" in the direction
328 of its orientation. Or is it the other way around? */
329 if (orientation == GTK_ORIENTATION_HORIZONTAL) {
330 gtk_widget_set_size_request(GTK_WIDGET(plugin), -1, size);
331 }
332 else {
333 gtk_widget_set_size_request(GTK_WIDGET(plugin), size, -1);
334 }
335
336 /* This fixes an issue where the initial icon size is too small. */
337 hdaps_set_icon(hdaps, hdaps->previous_status);
338
339 /* We handled the change, so we're supposed to return TRUE. */
340 return TRUE;
341 }
342
343
344
345 static gboolean hdaps_update_status(HdapsPlugin *hdaps) {
346 /* This checks the status of HDAPS and updates the
347 widget accordingly. */
348
349 /* This just gets the status. */
350 int status = parse_int_from_file(hdaps->sysfs_file);
351
352 /* The value in the sysfs_file represents the number of milliseconds
353 * that the drive heads will be parked. Of course, this will
354 * generally count down, and appear different each time we poll.
355 *
356 * So, to determine whether or not HDAPS has gone from "on"
357 * to "off," we treat all values greater than zero the same.
358 */
359 if (status > 0) {
360 status = HDAPS_ON;
361 }
362
363 if (status != hdaps->previous_status) {
364 /* And we only update the icon if we need to. */
365 hdaps_set_icon(hdaps, status);
366 hdaps_set_tooltip(hdaps, status);
367 hdaps->previous_status = status;
368 }
369
370 return TRUE;
371 }
372
373
374
375 void hdaps_reset_timeout(HdapsPlugin *hdaps) {
376 /* Remove, and then re-set the timeout function. Useful
377 for changing the poll frequency. */
378 if (hdaps->timeout) {
379 g_source_remove(hdaps->timeout);
380 }
381
382 hdaps->timeout = g_timeout_add(hdaps->poll_frequency, (GSourceFunc)hdaps_update_status, hdaps);
383 }
384
385
386
387 static void hdaps_construct(XfcePanelPlugin *plugin) {
388 HdapsPlugin *hdaps;
389
390 /* Set the "translation domain". I don't know what that does. */
391 xfce_textdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR, "UTF-8");
392
393 /* First, create the plugin. */
394 hdaps = hdaps_new(plugin);
395
396 /* Add the plugin's eventbox to the panel. */
397 gtk_container_add(GTK_CONTAINER(plugin), hdaps->eventbox);
398
399 /* This configures the right-click menu to appear
400 on the plugin's eventbox. */
401 xfce_panel_plugin_add_action_widget(plugin, hdaps->eventbox);
402
403 /* Connect the common event handlers. */
404 g_signal_connect(G_OBJECT(plugin), "free-data",
405 G_CALLBACK(hdaps_free), hdaps);
406
407 g_signal_connect (G_OBJECT(plugin), "save",
408 G_CALLBACK(hdaps_save), hdaps);
409
410 g_signal_connect (G_OBJECT(plugin), "size-changed",
411 G_CALLBACK(hdaps_size_changed), hdaps);
412
413 g_signal_connect (G_OBJECT(plugin), "orientation-changed",
414 G_CALLBACK(hdaps_orientation_changed), hdaps);
415
416 /* Show the "configure" right-click menu item, and
417 connect its event handler. */
418 xfce_panel_plugin_menu_show_configure(plugin);
419 g_signal_connect(G_OBJECT(plugin), "configure-plugin",
420 G_CALLBACK(hdaps_configure), hdaps);
421
422 /* Show the "about" right-click menu item, and
423 connect its event handler. */
424 xfce_panel_plugin_menu_show_about(plugin);
425 g_signal_connect(G_OBJECT(plugin), "about",
426 G_CALLBACK(hdaps_about), hdaps);
427
428 /* Set the timeout for the function which checks the
429 HDAPS status. */
430 hdaps_reset_timeout(hdaps);
431
432 return;
433 }