]> gitweb.michael.orlitzky.com - xfce4-hdaps.git/blob - panel-plugin/xfce4-hdaps.c
95f05eb5f90a14b014b94f6db7d496da45a84e07
[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
135 if (status == HDAPS_ERROR) {
136 gtk_tooltips_set_tip(hdaps->tooltip, hdaps->eventbox, "HDAPS Error", NULL);
137 }
138 else if (status == HDAPS_OFF) {
139 gtk_tooltips_set_tip(hdaps->tooltip, hdaps->eventbox, "HDAPS Off", NULL);
140 }
141 else {
142 gtk_tooltips_set_tip(hdaps->tooltip, hdaps->eventbox, "HDAPS On", NULL);
143 }
144 }
145
146
147 static void hdaps_set_defaults(HdapsPlugin *hdaps) {
148 DBG("Configuring all settings to defaults.");
149
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);
158
159 if (found_devices > 0) {
160 hdaps->device_name = g_strdup(hdaps_devices[0]);
161 }
162 else {
163 hdaps->device_name = g_strdup(DEFAULT_DEVICE_NAME);
164 }
165
166 snprintf(hdaps->sysfs_file, FILENAME_MAX, UNLOAD_HEADS_FMT, hdaps->device_name);
167
168 /* The other default is easier. */
169 hdaps->poll_frequency = DEFAULT_POLL_FREQUENCY;
170 }
171
172
173 static void hdaps_read(HdapsPlugin *hdaps) {
174
175 XfceRc *rc;
176 gchar *file;
177 const gchar *saved_device_name;
178
179 /* Get the plugin config file location. XFCE should know this. */
180 file = xfce_panel_plugin_save_location(hdaps->plugin, TRUE);
181
182 if (G_UNLIKELY(file == NULL)) {
183 DBG("Something went wrong getting the configuration file location.");
184 DBG("Retaining default settings.");
185 return;
186 }
187
188 /* Open the config file read-only. */
189 rc = xfce_rc_simple_open(file, TRUE);
190
191 /* Don't need this anymore if we've got a file handle. */
192 g_free(file);
193
194 if (G_UNLIKELY(rc == NULL)) {
195 DBG("There was an error opening the configuration file.");
196 DBG("Retaining default settings.");
197 return;
198 }
199
200 /* Read the settings, one at a time. */
201
202 /* We use saved_device_name here because we need
203 to dupe the string after we read it in from the
204 config file. */
205 saved_device_name = xfce_rc_read_entry(rc,
206 "device_name",
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);
210
211 /* Integers are easier. */
212 hdaps->poll_frequency = xfce_rc_read_int_entry(rc,
213 "poll_frequency",
214 DEFAULT_POLL_FREQUENCY);
215
216 /* And close the config file. */
217 xfce_rc_close(rc);
218 }
219
220
221
222
223 static HdapsPlugin *hdaps_new(XfcePanelPlugin *plugin) {
224 HdapsPlugin *hdaps;
225 GtkOrientation orientation;
226
227 /* Allocate memory for the plugin struct, and zero it. */
228 hdaps = panel_slice_new0(HdapsPlugin);
229
230 /* The HdapsPlugin gets a copy of the XfcePanelPlugin. */
231 hdaps->plugin = plugin;
232
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
235 conditions. */
236 hdaps_set_defaults(hdaps);
237
238 /* Read any user settings into the HdapsPlugin. */
239 hdaps_read(hdaps);
240
241 /* Get the current orientation. Magic. */
242 orientation = xfce_panel_plugin_get_orientation(plugin);
243
244 /* This creates the event box and shows it. This
245 is necessary to,
246
247 a) See the widget
248 b) Interact with it via right-click, etc.
249 */
250 hdaps->eventbox = gtk_event_box_new();
251 gtk_widget_show(hdaps->eventbox);
252
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);
257
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);
263
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);
268
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.
272 */
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);
277
278 return hdaps;
279 }
280
281
282
283 static void hdaps_free(XfcePanelPlugin *plugin,
284 HdapsPlugin *hdaps) {
285
286 GtkWidget *dialog;
287
288 /* Destroy the dialog if it's still open. */
289 dialog = g_object_get_data(G_OBJECT(plugin), "dialog");
290
291 if (G_UNLIKELY(dialog != NULL)) {
292 gtk_widget_destroy(dialog);
293 }
294
295 /* Destroy the panel widgets. When dumb comments like these
296 are left over, they're from the sample panel applet,
297 I swear. */
298 gtk_widget_destroy(hdaps->hvbox);
299
300 /* Remove the timeout that was set during creation. */
301 if (hdaps->timeout) {
302 g_source_remove(hdaps->timeout);
303 }
304
305 /* And free the string (if any) containing
306 the device name. */
307 if (G_LIKELY(hdaps->device_name != NULL)) {
308 g_free(hdaps->device_name);
309 }
310
311 /* Goodbye, tooltips. */
312 gtk_tooltips_set_tip(hdaps->tooltip, hdaps->eventbox, NULL, NULL);
313 g_object_unref(G_OBJECT(hdaps->tooltip));
314
315 /* ...and finally free the plugin structure. */
316 panel_slice_free(HdapsPlugin, hdaps);
317 }
318
319
320
321 static void hdaps_orientation_changed(XfcePanelPlugin *plugin,
322 GtkOrientation orientation,
323 HdapsPlugin *hdaps) {
324
325 /* Change the plugin's orientation. Basically magic to me. */
326 xfce_hvbox_set_orientation(XFCE_HVBOX(hdaps->hvbox), orientation);
327 }
328
329
330
331 static gboolean hdaps_size_changed(XfcePanelPlugin *plugin,
332 gint size,
333 HdapsPlugin *hdaps) {
334
335 GtkOrientation orientation;
336
337 /* Get the current orientation of the plugin. */
338 orientation = xfce_panel_plugin_get_orientation(plugin);
339
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);
344 }
345 else {
346 gtk_widget_set_size_request(GTK_WIDGET(plugin), size, -1);
347 }
348
349 /* This fixes an issue where the initial icon size is too small. */
350 hdaps_set_icon(hdaps, hdaps->previous_status);
351
352 /* We handled the change, so we're supposed to return TRUE. */
353 return TRUE;
354 }
355
356
357
358 static gboolean hdaps_update_status(HdapsPlugin *hdaps) {
359 /* This checks the status of HDAPS and updates the
360 widget accordingly. */
361
362 /* This just gets the status. */
363 int status = parse_int_from_file(hdaps->sysfs_file);
364
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.
368 *
369 * So, to determine whether or not HDAPS has gone from "on"
370 * to "off," we treat all values greater than zero the same.
371 */
372 if (status > 0) {
373 status = HDAPS_ON;
374 }
375
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;
381 }
382
383 return TRUE;
384 }
385
386
387
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);
393 }
394
395 hdaps->timeout = g_timeout_add(hdaps->poll_frequency, (GSourceFunc)hdaps_update_status, hdaps);
396 }
397
398
399
400 static void hdaps_construct(XfcePanelPlugin *plugin) {
401 HdapsPlugin *hdaps;
402
403 /* Set the "translation domain". I don't know what that does. */
404 xfce_textdomain(GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR, "UTF-8");
405
406 /* First, create the plugin. */
407 hdaps = hdaps_new(plugin);
408
409 /* Add the plugin's eventbox to the panel. */
410 gtk_container_add(GTK_CONTAINER(plugin), hdaps->eventbox);
411
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);
415
416 /* Connect the common event handlers. */
417 g_signal_connect(G_OBJECT(plugin), "free-data",
418 G_CALLBACK(hdaps_free), hdaps);
419
420 g_signal_connect (G_OBJECT(plugin), "save",
421 G_CALLBACK(hdaps_save), hdaps);
422
423 g_signal_connect (G_OBJECT(plugin), "size-changed",
424 G_CALLBACK(hdaps_size_changed), hdaps);
425
426 g_signal_connect (G_OBJECT(plugin), "orientation-changed",
427 G_CALLBACK(hdaps_orientation_changed), hdaps);
428
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);
434
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);
440
441 /* Set the timeout for the function which checks the
442 HDAPS status. */
443 hdaps_reset_timeout(hdaps);
444
445 return;
446 }