Mercurial > audlegacy-plugins
comparison src/alarm/alarm.c @ 121:b59bca84e3cd trunk
[svn] - add xmms-alarm port
author | nenolod |
---|---|
date | Thu, 26 Oct 2006 00:10:28 -0700 |
parents | |
children | 96fc1ef32c99 |
comparison
equal
deleted
inserted
replaced
120:7ce296248b5c | 121:b59bca84e3cd |
---|---|
1 /* | |
2 * Copyright (C) Adam Feakin <adamf@snika.uklinux.net> | |
3 * | |
4 * modified by Daniel Stodden <stodden@in.tum.de> | |
5 * | |
6 * This program is free software; you can redistribute it and/or | |
7 * modify it under the terms of the GNU General Public License | |
8 * as published by the Free Software Foundation; either version 2 | |
9 * of the License, or (at your option) any later version. | |
10 * | |
11 * This program is distributed in the hope that it will be useful, | |
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 * GNU General Public License for more details. | |
15 * | |
16 * You should have received a copy of the GNU General Public License | |
17 * along with this program; if not, write to the Free Software | |
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
19 */ | |
20 | |
21 /* | |
22 * xmms-alarm.c - a XMMS plugin which allows you to set a time for it to | |
23 * start playing a playlist with the volume fading up and more things | |
24 * the next time I get bored | |
25 */ | |
26 | |
27 /* this file really should get split/cleaned up sometime ;) */ | |
28 #include "config.h" | |
29 | |
30 #if STDC_HEADERS | |
31 # include <stdlib.h> | |
32 #endif | |
33 | |
34 #include <time.h> | |
35 #if TM_IN_SYS_TIME | |
36 # include <sys/time.h> | |
37 #endif | |
38 | |
39 #include <string.h> | |
40 #include <stdio.h> | |
41 #include <audacious/plugin.h> | |
42 #include <audacious/beepctrl.h> | |
43 #include <audacious/configdb.h> | |
44 #include <gdk/gdk.h> | |
45 #include <gtk/gtk.h> | |
46 #include <pthread.h> | |
47 #include <assert.h> | |
48 #include <math.h> | |
49 | |
50 #include "alarm.h" | |
51 #include "interface.h" | |
52 #include "callbacks.h" | |
53 | |
54 static pthread_t start_tid; /* thread id of alarm loop */ | |
55 static pthread_t stop_tid; /* thread id of stop loop */ | |
56 static pthread_mutex_t fader_lock = PTHREAD_MUTEX_INITIALIZER; | |
57 | |
58 static GeneralPlugin alarm_plugin; | |
59 | |
60 /* string tokens to allow loops and shorten code */ | |
61 static char day_cb[7][7] = {"sun_cb", "mon_cb", "tue_cb", | |
62 "wed_cb", "thu_cb", "fri_cb", "sat_cb"}; | |
63 | |
64 static char day_flags[7][10] = {"sun_flags", "mon_flags", "tue_flags", | |
65 "wed_flags", "thu_flags", "fri_flags", "sat_flags"}; | |
66 | |
67 static char day_h[7][6] = {"sun_h", "mon_h", "tue_h", | |
68 "wed_h", "thu_h", "fri_h", "sat_h"}; | |
69 | |
70 static char day_m[7][6] = {"sun_m", "mon_m", "tue_m", | |
71 "wed_m", "thu_m", "fri_m", "sat_m"}; | |
72 | |
73 static char day_def[7][8] = {"sun_def", "mon_def", "tue_def", | |
74 "wed_def", "thu_def", "fri_def", "sat_def"}; | |
75 | |
76 static struct | |
77 { | |
78 GtkSpinButton *alarm_h; | |
79 GtkSpinButton *alarm_m; | |
80 | |
81 GtkToggleButton *stop_on; | |
82 GtkSpinButton *stop_h; | |
83 GtkSpinButton *stop_m; | |
84 | |
85 GtkRange *volume; | |
86 GtkRange *quietvol; | |
87 | |
88 GtkSpinButton *fading; | |
89 | |
90 GtkEntry *cmdstr; | |
91 GtkToggleButton *cmd_on; | |
92 | |
93 GtkEntry *playlist; | |
94 | |
95 int default_hour; | |
96 int default_min; | |
97 | |
98 // array allows looping of days | |
99 alarmday day[7]; | |
100 | |
101 | |
102 GtkEntry *reminder; | |
103 GtkToggleButton *reminder_cb; | |
104 gchar *reminder_msg; | |
105 gboolean reminder_on; | |
106 } | |
107 alarm_conf; | |
108 | |
109 static gint alarm_h, alarm_m; | |
110 | |
111 static gboolean stop_on; | |
112 static gint stop_h, stop_m; | |
113 | |
114 static gint volume, quietvol; | |
115 | |
116 static gint fading; | |
117 | |
118 static gchar *cmdstr = NULL; | |
119 static gboolean cmd_on; | |
120 | |
121 static gchar *playlist = NULL; | |
122 | |
123 static GtkWidget *config_dialog = NULL; | |
124 static GtkWidget *alarm_dialog = NULL; | |
125 | |
126 static GtkWidget *lookup_widget(GtkWidget *w, const gchar *name) | |
127 { | |
128 GtkWidget *widget; | |
129 | |
130 widget = (GtkWidget*) gtk_object_get_data(GTK_OBJECT(w), | |
131 name); | |
132 g_return_val_if_fail(widget != NULL, NULL); | |
133 | |
134 return widget; | |
135 } | |
136 | |
137 static void dialog_destroyed(GtkWidget *dialog, gpointer data) | |
138 { | |
139 DEBUG("dialog destroyed\n"); | |
140 *(GtkObject**)data = NULL; | |
141 } | |
142 | |
143 static inline gboolean dialog_visible(GtkWidget *dialog) | |
144 { | |
145 return(((dialog != NULL) && GTK_WIDGET_VISIBLE(dialog))); | |
146 } | |
147 | |
148 /* | |
149 * tell the user about that bug | |
150 */ | |
151 static void alarm_warning(void) | |
152 { | |
153 | |
154 static GtkWidget *warning_dialog = NULL; | |
155 | |
156 if(dialog_visible(warning_dialog)) | |
157 return; | |
158 | |
159 warning_dialog = create_warning_dialog(); | |
160 | |
161 gtk_signal_connect(GTK_OBJECT(warning_dialog), "destroy", | |
162 GTK_SIGNAL_FUNC(dialog_destroyed), &warning_dialog); | |
163 | |
164 gtk_widget_show_all(warning_dialog); | |
165 | |
166 return; | |
167 } | |
168 | |
169 /* | |
170 * the callback function that is called when the save button is | |
171 * pressed saves configuration to ~/.bmp/alarmconfig | |
172 */ | |
173 void alarm_save(GtkButton *w, gpointer data) | |
174 { | |
175 int daynum = 0; // used to identify day number | |
176 ConfigDb *conf; | |
177 | |
178 DEBUG("alarm_save\n"); | |
179 | |
180 conf = bmp_cfg_db_open(); | |
181 | |
182 /* | |
183 * update the live values and write them out | |
184 */ | |
185 alarm_h = alarm_conf.default_hour = | |
186 gtk_spin_button_get_value_as_int(alarm_conf.alarm_h); | |
187 bmp_cfg_db_set_int(conf, "alarm", "alarm_h", alarm_h); | |
188 | |
189 alarm_m = alarm_conf.default_min = | |
190 gtk_spin_button_get_value_as_int(alarm_conf.alarm_m); | |
191 bmp_cfg_db_set_int(conf, "alarm", "alarm_m", alarm_m); | |
192 | |
193 | |
194 stop_h = | |
195 gtk_spin_button_get_value_as_int( alarm_conf.stop_h); | |
196 | |
197 stop_m = | |
198 gtk_spin_button_get_value_as_int(alarm_conf.stop_m); | |
199 | |
200 stop_on = | |
201 gtk_toggle_button_get_active(alarm_conf.stop_on); | |
202 | |
203 /* days of the week */ | |
204 for(; daynum < 7; daynum++) | |
205 { | |
206 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(alarm_conf.day[daynum].cb))) | |
207 alarm_conf.day[daynum].flags = 0; | |
208 else | |
209 alarm_conf.day[daynum].flags = ALARM_OFF; | |
210 | |
211 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(alarm_conf.day[daynum].cb_def))) | |
212 alarm_conf.day[daynum].flags |= ALARM_DEFAULT; | |
213 | |
214 alarm_conf.day[daynum].hour = | |
215 gtk_spin_button_get_value_as_int(alarm_conf.day[daynum].spin_hr); | |
216 alarm_conf.day[daynum].min = | |
217 gtk_spin_button_get_value_as_int(alarm_conf.day[daynum].spin_min); | |
218 | |
219 bmp_cfg_db_set_int(conf, "alarm", day_flags[daynum], alarm_conf.day[daynum].flags); | |
220 bmp_cfg_db_set_int(conf, "alarm", day_h[daynum], alarm_conf.day[daynum].hour); | |
221 bmp_cfg_db_set_int(conf, "alarm", day_m[daynum], alarm_conf.day[daynum].min); | |
222 } | |
223 | |
224 /* END: days of week */ | |
225 | |
226 volume = | |
227 gtk_range_get_adjustment(alarm_conf.volume)->value; | |
228 bmp_cfg_db_set_int(conf, "alarm", "volume", volume); | |
229 | |
230 quietvol = | |
231 gtk_range_get_adjustment(alarm_conf.quietvol)->value; | |
232 bmp_cfg_db_set_int(conf, "alarm", "quietvol", quietvol); | |
233 | |
234 fading = | |
235 gtk_spin_button_get_value_as_int(alarm_conf.fading); | |
236 //xmms_cfg_write_int(conf, "alarm", "fading", fading); | |
237 | |
238 /* lets check to see if we need to show the bug warning */ | |
239 if((stop_on == TRUE) && | |
240 ((((stop_h * 60) + stop_m) * 60) < (fading + 65))) | |
241 { | |
242 DEBUG("Displaying bug warning, stop %dh %dm, fade %d\n", | |
243 stop_h, stop_m, fading); | |
244 alarm_warning(); | |
245 } | |
246 else if((stop_on == TRUE) && (fading < 10)) | |
247 { | |
248 DEBUG("Displaying bug warning, stop %dh %dm, fade %d\n", | |
249 stop_h, stop_m, fading); | |
250 alarm_warning(); | |
251 } | |
252 else | |
253 { | |
254 /* write the new values */ | |
255 bmp_cfg_db_set_int(conf, "alarm", "stop_h", stop_h); | |
256 bmp_cfg_db_set_int(conf, "alarm", "stop_m", stop_m); | |
257 bmp_cfg_db_set_int(conf, "alarm", "fading", fading); | |
258 bmp_cfg_db_set_bool(conf, "alarm", "stop_on", stop_on); | |
259 } | |
260 | |
261 | |
262 g_free(cmdstr); | |
263 cmdstr = gtk_editable_get_chars(GTK_EDITABLE(alarm_conf.cmdstr), | |
264 0, -1); | |
265 bmp_cfg_db_set_string(conf, "alarm", "cmdstr", cmdstr); | |
266 | |
267 cmd_on = | |
268 gtk_toggle_button_get_active(alarm_conf.cmd_on); | |
269 bmp_cfg_db_set_bool(conf, "alarm", "cmd_on", cmd_on); | |
270 | |
271 g_free(playlist); | |
272 playlist = gtk_editable_get_chars(GTK_EDITABLE(alarm_conf.playlist), | |
273 0, -1); | |
274 bmp_cfg_db_set_string(conf, "alarm", "playlist", playlist); | |
275 | |
276 /* reminder */ | |
277 g_free(alarm_conf.reminder_msg); | |
278 alarm_conf.reminder_msg = gtk_editable_get_chars(GTK_EDITABLE(alarm_conf.reminder), | |
279 0, -1); | |
280 bmp_cfg_db_set_string(conf, "alarm", "reminder_msg", alarm_conf.reminder_msg); | |
281 | |
282 alarm_conf.reminder_on = | |
283 gtk_toggle_button_get_active(alarm_conf.reminder_cb); | |
284 bmp_cfg_db_set_bool(conf, "alarm", "reminder_on", alarm_conf.reminder_on); | |
285 | |
286 bmp_cfg_db_close(conf); | |
287 } | |
288 | |
289 /* | |
290 * read the current configuration from the file | |
291 */ | |
292 static void alarm_read_config() | |
293 { | |
294 int daynum = 0; // used for day number | |
295 ConfigDb *conf; | |
296 | |
297 DEBUG("alarm_read_config\n"); | |
298 | |
299 conf = bmp_cfg_db_open(); | |
300 | |
301 if(!bmp_cfg_db_get_int(conf, "alarm", "alarm_h", &alarm_h)) | |
302 alarm_h = DEFAULT_ALARM_HOUR; | |
303 if(!bmp_cfg_db_get_int(conf, "alarm", "alarm_m", &alarm_m)) | |
304 alarm_m = DEFAULT_ALARM_MIN; | |
305 | |
306 /* save them here too */ | |
307 alarm_conf.default_hour = alarm_h; | |
308 alarm_conf.default_min = alarm_m; | |
309 | |
310 if(!bmp_cfg_db_get_int( conf, "alarm", "stop_h", &stop_h)) | |
311 stop_h = DEFAULT_STOP_HOURS; | |
312 if(!bmp_cfg_db_get_int( conf, "alarm", "stop_m", &stop_m)) | |
313 stop_m = DEFAULT_STOP_MINS; | |
314 if(!bmp_cfg_db_get_bool(conf, "alarm", "stop_on", &stop_on)) | |
315 stop_on = TRUE; | |
316 | |
317 if(!bmp_cfg_db_get_int(conf, "alarm", "volume", &volume)) | |
318 volume = DEFAULT_VOLUME; | |
319 if(!bmp_cfg_db_get_int(conf, "alarm", "quietvol", &quietvol)) | |
320 quietvol = DEFAULT_QUIET_VOL; | |
321 | |
322 if(!bmp_cfg_db_get_int(conf, "alarm", "fading", &fading)) | |
323 fading = DEFAULT_FADING; | |
324 | |
325 if(!bmp_cfg_db_get_string(conf, "alarm", "cmdstr", &cmdstr)) | |
326 cmdstr = g_strdup(""); | |
327 if(!bmp_cfg_db_get_bool(conf, "alarm", "cmd_on", &cmd_on)) | |
328 cmd_on = FALSE; | |
329 | |
330 if(!bmp_cfg_db_get_string(conf, "alarm", "playlist", &playlist)) | |
331 playlist = g_strdup(""); | |
332 | |
333 if(!bmp_cfg_db_get_string(conf, "alarm", "reminder_msg", &alarm_conf.reminder_msg)) | |
334 alarm_conf.reminder_msg = g_strdup(""); | |
335 if(!bmp_cfg_db_get_bool(conf, "alarm", "reminder_on", &alarm_conf.reminder_on)) | |
336 alarm_conf.reminder_on = FALSE; | |
337 | |
338 /* day flags and times */ | |
339 for(; daynum < 7; daynum++) | |
340 { | |
341 /* read the flags */ | |
342 if(!bmp_cfg_db_get_int(conf, "alarm", day_flags[daynum], &alarm_conf.day[daynum].flags)) { | |
343 // only turn alarm off by default on a sunday | |
344 if(daynum != 0) | |
345 alarm_conf.day[daynum].flags = DEFAULT_FLAGS; | |
346 else | |
347 alarm_conf.day[daynum].flags = DEFAULT_FLAGS | ALARM_OFF; | |
348 } | |
349 | |
350 /* read the times */ | |
351 if(!bmp_cfg_db_get_int(conf, "alarm", day_h[daynum], &alarm_conf.day[daynum].hour)) | |
352 alarm_conf.day[daynum].hour = DEFAULT_ALARM_HOUR; | |
353 | |
354 if(!bmp_cfg_db_get_int(conf, "alarm", day_m[daynum], &alarm_conf.day[daynum].min)) | |
355 alarm_conf.day[daynum].min = DEFAULT_ALARM_MIN; | |
356 } | |
357 | |
358 DEBUG("END alarm_read_config\n"); | |
359 } | |
360 | |
361 /* | |
362 * display an about box | |
363 */ | |
364 static void alarm_about() | |
365 { | |
366 static GtkWidget *about_dialog = NULL; | |
367 | |
368 DEBUG("alarm_about\n"); | |
369 | |
370 if(dialog_visible(about_dialog)) | |
371 return; | |
372 | |
373 about_dialog = create_about_dialog(); | |
374 | |
375 gtk_signal_connect(GTK_OBJECT(about_dialog), "destroy", | |
376 GTK_SIGNAL_FUNC(dialog_destroyed), &about_dialog); | |
377 | |
378 gtk_widget_show_all(about_dialog); | |
379 | |
380 return; | |
381 } | |
382 | |
383 /* | |
384 * create a playlist file selection dialog | |
385 */ | |
386 static void alarm_playlist_browse(GtkButton *button, gpointer data) | |
387 { | |
388 GtkWidget *fs; | |
389 gchar *dirname, *path; | |
390 | |
391 dirname = g_dirname(playlist); | |
392 DEBUG("dirname = %s\n", dirname); | |
393 path = g_strdup_printf("%s/", dirname); | |
394 DEBUG("path = %s\n", path); | |
395 g_free(dirname); | |
396 | |
397 fs = create_playlist_fileselection(); | |
398 | |
399 gtk_file_selection_set_filename(GTK_FILE_SELECTION(fs), path); | |
400 g_free(path); | |
401 | |
402 gtk_widget_show_all(fs); | |
403 } | |
404 | |
405 /* | |
406 * save selected playlist to the corresponding text entry | |
407 */ | |
408 void alarm_store_playlistname(GtkButton *button, gpointer data) | |
409 { | |
410 GtkFileSelection *fs = GTK_FILE_SELECTION(data); | |
411 gchar *plist; | |
412 | |
413 DEBUG("alarm_store_playlistname\n"); | |
414 | |
415 plist = gtk_file_selection_get_filename(fs); | |
416 | |
417 gtk_entry_set_text(alarm_conf.playlist, plist); | |
418 } | |
419 | |
420 /* | |
421 * displays the configuration window and opens the config file. | |
422 */ | |
423 static void alarm_configure(void) | |
424 { | |
425 int daynum = 0; // used to loop days | |
426 GtkWidget *w; | |
427 | |
428 DEBUG("alarm_configure\n"); | |
429 | |
430 /* | |
431 * dont want to show more than one config window | |
432 */ | |
433 if(dialog_visible(config_dialog)) | |
434 return; | |
435 | |
436 alarm_read_config(); | |
437 | |
438 /* | |
439 * Create the widgets | |
440 */ | |
441 config_dialog = create_config_dialog(); | |
442 | |
443 w = lookup_widget(config_dialog, "alarm_h_spin"); | |
444 alarm_conf.alarm_h = GTK_SPIN_BUTTON(w); | |
445 gtk_spin_button_set_value(alarm_conf.alarm_h, alarm_h); | |
446 | |
447 w = lookup_widget(config_dialog, "alarm_m_spin"); | |
448 alarm_conf.alarm_m = GTK_SPIN_BUTTON(w); | |
449 gtk_spin_button_set_value(alarm_conf.alarm_m, alarm_m); | |
450 | |
451 w = lookup_widget(config_dialog, "stop_h_spin"); | |
452 alarm_conf.stop_h = GTK_SPIN_BUTTON(w); | |
453 gtk_spin_button_set_value(alarm_conf.stop_h, stop_h); | |
454 | |
455 w = lookup_widget(config_dialog, "stop_m_spin"); | |
456 alarm_conf.stop_m = GTK_SPIN_BUTTON(w); | |
457 gtk_spin_button_set_value(alarm_conf.stop_m, stop_m); | |
458 | |
459 w = lookup_widget(config_dialog, "stop_checkb"); | |
460 alarm_conf.stop_on = GTK_TOGGLE_BUTTON(w); | |
461 gtk_toggle_button_set_active(alarm_conf.stop_on, stop_on); | |
462 | |
463 w = lookup_widget(config_dialog, "vol_scale"); | |
464 alarm_conf.volume = GTK_RANGE(w); | |
465 gtk_range_set_adjustment(alarm_conf.volume, | |
466 GTK_ADJUSTMENT(gtk_adjustment_new(volume, | |
467 0, | |
468 100, 1, | |
469 5, 0))); | |
470 | |
471 w = lookup_widget(config_dialog, "quiet_vol_scale"); | |
472 alarm_conf.quietvol = GTK_RANGE(w); | |
473 gtk_range_set_adjustment(alarm_conf.quietvol, | |
474 GTK_ADJUSTMENT(gtk_adjustment_new(quietvol, | |
475 0, | |
476 100, 1, | |
477 5, 0))); | |
478 | |
479 /* days of week */ | |
480 for(; daynum < 7; daynum++) | |
481 { | |
482 w = lookup_widget(config_dialog, day_cb[daynum]); | |
483 alarm_conf.day[daynum].cb = GTK_CHECK_BUTTON(w); | |
484 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(alarm_conf.day[daynum].cb), | |
485 !(alarm_conf.day[daynum].flags & ALARM_OFF)); | |
486 | |
487 w = lookup_widget(config_dialog, day_def[daynum]); | |
488 alarm_conf.day[daynum].cb_def = GTK_CHECK_BUTTON(w); | |
489 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(alarm_conf.day[daynum].cb_def), | |
490 alarm_conf.day[daynum].flags & ALARM_DEFAULT); | |
491 | |
492 | |
493 /* Changed to show default time instead of set time when ALARM_DEFAULT set, | |
494 * as suggested by Mark Brown | |
495 */ | |
496 /* w = lookup_widget(config_dialog, day_h[daynum]); | |
497 alarm_conf.day[daynum].spin_hr = GTK_SPIN_BUTTON(w); | |
498 gtk_spin_button_set_value(alarm_conf.day[daynum].spin_hr, alarm_conf.day[daynum].hour); | |
499 | |
500 w = lookup_widget(config_dialog, day_m[daynum]); | |
501 alarm_conf.day[daynum].spin_min = GTK_SPIN_BUTTON(w); | |
502 gtk_spin_button_set_value(alarm_conf.day[daynum].spin_min, alarm_conf.day[daynum].min); | |
503 */ | |
504 if(alarm_conf.day[daynum].flags & ALARM_DEFAULT) | |
505 { | |
506 w = lookup_widget(config_dialog, day_h[daynum]); | |
507 alarm_conf.day[daynum].spin_hr = GTK_SPIN_BUTTON(w); | |
508 gtk_spin_button_set_value(alarm_conf.day[daynum].spin_hr, alarm_conf.default_hour); | |
509 | |
510 w = lookup_widget(config_dialog, day_m[daynum]); | |
511 alarm_conf.day[daynum].spin_min = GTK_SPIN_BUTTON(w); | |
512 gtk_spin_button_set_value(alarm_conf.day[daynum].spin_min, alarm_conf.default_min); | |
513 | |
514 gtk_widget_set_sensitive((GtkWidget *)alarm_conf.day[daynum].spin_hr, FALSE); | |
515 gtk_widget_set_sensitive((GtkWidget *)alarm_conf.day[daynum].spin_min, FALSE); | |
516 } | |
517 else | |
518 { | |
519 w = lookup_widget(config_dialog, day_h[daynum]); | |
520 alarm_conf.day[daynum].spin_hr = GTK_SPIN_BUTTON(w); | |
521 gtk_spin_button_set_value(alarm_conf.day[daynum].spin_hr, alarm_conf.day[daynum].hour); | |
522 | |
523 w = lookup_widget(config_dialog, day_m[daynum]); | |
524 alarm_conf.day[daynum].spin_min = GTK_SPIN_BUTTON(w); | |
525 gtk_spin_button_set_value(alarm_conf.day[daynum].spin_min, alarm_conf.day[daynum].min); | |
526 | |
527 gtk_widget_set_sensitive((GtkWidget *)alarm_conf.day[daynum].spin_hr, TRUE); | |
528 gtk_widget_set_sensitive((GtkWidget *)alarm_conf.day[daynum].spin_min, TRUE); | |
529 } | |
530 } | |
531 | |
532 /* END: days of week */ | |
533 | |
534 w = lookup_widget(config_dialog,"fading_spin"); | |
535 alarm_conf.fading = GTK_SPIN_BUTTON(w); | |
536 gtk_spin_button_set_value(alarm_conf.fading, fading); | |
537 | |
538 w = lookup_widget(config_dialog, "cmd_entry"); | |
539 alarm_conf.cmdstr = GTK_ENTRY(w); | |
540 gtk_entry_set_text(alarm_conf.cmdstr, cmdstr); | |
541 | |
542 w = lookup_widget(config_dialog, "cmd_checkb"); | |
543 alarm_conf.cmd_on = GTK_TOGGLE_BUTTON(w); | |
544 gtk_toggle_button_set_active(alarm_conf.cmd_on, cmd_on); | |
545 | |
546 w = lookup_widget(config_dialog, "playlist"); | |
547 alarm_conf.playlist = GTK_ENTRY(w); | |
548 gtk_entry_set_text(alarm_conf.playlist, playlist); | |
549 | |
550 w = lookup_widget(config_dialog, "reminder_text"); | |
551 alarm_conf.reminder = GTK_ENTRY(w); | |
552 gtk_entry_set_text(alarm_conf.reminder, alarm_conf.reminder_msg); | |
553 | |
554 w = lookup_widget(config_dialog, "reminder_cb"); | |
555 alarm_conf.reminder_cb = GTK_TOGGLE_BUTTON(w); | |
556 gtk_toggle_button_set_active(alarm_conf.reminder_cb, alarm_conf.reminder_on); | |
557 | |
558 w = lookup_widget(config_dialog, "playlist_browse_button"); | |
559 gtk_signal_connect(GTK_OBJECT(w), "clicked", | |
560 GTK_SIGNAL_FUNC(alarm_playlist_browse), NULL); | |
561 | |
562 gtk_signal_connect(GTK_OBJECT(config_dialog), "destroy", | |
563 GTK_SIGNAL_FUNC(dialog_destroyed), &config_dialog); | |
564 | |
565 gtk_widget_show_all(config_dialog); | |
566 | |
567 DEBUG("END alarm_configure\n"); | |
568 } | |
569 | |
570 /* functions for greying out the time for days */ | |
571 void on_day_def_toggled(GtkToggleButton *togglebutton, gpointer user_data, int daynum) | |
572 { | |
573 GtkWidget *w; | |
574 | |
575 /* change the time shown too */ | |
576 w = lookup_widget(config_dialog, day_h[daynum]); | |
577 if(w == NULL) | |
578 return; | |
579 | |
580 if(gtk_toggle_button_get_active(togglebutton) == TRUE) | |
581 { | |
582 gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), alarm_conf.default_hour); | |
583 gtk_widget_set_sensitive(w, FALSE); | |
584 } | |
585 else | |
586 { | |
587 gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), alarm_conf.day[daynum].hour); | |
588 gtk_widget_set_sensitive(w, TRUE); | |
589 } | |
590 | |
591 w = lookup_widget(config_dialog, day_m[daynum]); | |
592 if(gtk_toggle_button_get_active(togglebutton) == TRUE) | |
593 { | |
594 gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), alarm_conf.default_min); | |
595 gtk_widget_set_sensitive(w, FALSE); | |
596 } | |
597 else | |
598 { | |
599 gtk_spin_button_set_value(GTK_SPIN_BUTTON(w), alarm_conf.day[daynum].min); | |
600 gtk_widget_set_sensitive(w, TRUE); | |
601 } | |
602 } | |
603 | |
604 void on_sun_def_toggled(GtkToggleButton *togglebutton, gpointer user_data) | |
605 { | |
606 on_day_def_toggled(togglebutton, user_data, 0); | |
607 } | |
608 | |
609 void on_mon_def_toggled(GtkToggleButton *togglebutton, gpointer user_data) | |
610 { | |
611 on_day_def_toggled(togglebutton, user_data, 1); | |
612 } | |
613 | |
614 void on_tue_def_toggled(GtkToggleButton *togglebutton, gpointer user_data) | |
615 { | |
616 on_day_def_toggled(togglebutton, user_data, 2); | |
617 } | |
618 | |
619 void on_wed_def_toggled(GtkToggleButton *togglebutton, gpointer user_data) | |
620 { | |
621 on_day_def_toggled(togglebutton, user_data, 3); | |
622 } | |
623 | |
624 void on_thu_def_toggled(GtkToggleButton *togglebutton, gpointer user_data) | |
625 { | |
626 on_day_def_toggled(togglebutton, user_data, 4); | |
627 } | |
628 | |
629 void on_fri_def_toggled(GtkToggleButton *togglebutton, gpointer user_data) | |
630 { | |
631 on_day_def_toggled(togglebutton, user_data, 5); | |
632 } | |
633 | |
634 void on_sat_def_toggled(GtkToggleButton *togglebutton, gpointer user_data) | |
635 { | |
636 on_day_def_toggled(togglebutton, user_data, 6); | |
637 } | |
638 | |
639 /* END: greying things */ | |
640 | |
641 void alarm_current_volume(GtkButton *button, gpointer data) | |
642 { | |
643 gint vol; | |
644 GtkAdjustment *adj; | |
645 | |
646 DEBUG("on_current_button_clicked\n"); | |
647 | |
648 vol = xmms_remote_get_main_volume(alarm_plugin.xmms_session); | |
649 | |
650 adj = gtk_range_get_adjustment(alarm_conf.volume); | |
651 gtk_adjustment_set_value(adj, (gfloat)vol); | |
652 } | |
653 | |
654 GeneralPlugin *get_gplugin_info() | |
655 { | |
656 return &alarm_plugin; | |
657 } | |
658 | |
659 /* | |
660 * a thread safe sleeping function - | |
661 * and it even works in solaris (I think) | |
662 */ | |
663 static void threadsleep(float x) | |
664 { | |
665 struct timespec rqtp, rmtp; | |
666 | |
667 DEBUG("threadsleep: waiting %f seconds\n", x); | |
668 | |
669 rqtp.tv_sec = x; | |
670 rqtp.tv_nsec = (int)((float)(x - (int)x) * 1000000000.0); | |
671 | |
672 nanosleep(&rqtp, &rmtp); | |
673 | |
674 return; | |
675 } | |
676 | |
677 static inline pthread_t alarm_thread_create(void *(*start_routine)(void *), void *args, unsigned int detach) | |
678 { | |
679 pthread_t tid; | |
680 pthread_attr_t attr; | |
681 | |
682 pthread_attr_init(&attr); | |
683 | |
684 if(detach != 0) | |
685 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); | |
686 | |
687 pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); | |
688 pthread_attr_setschedpolicy(&attr, SCHED_OTHER); | |
689 pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); | |
690 | |
691 pthread_create(&tid, &attr, start_routine, args); | |
692 | |
693 return(tid); | |
694 } | |
695 | |
696 static void *alarm_fade(void *arg) | |
697 { | |
698 fader *vols = (fader *)arg; | |
699 guint i; | |
700 gint inc, diff, adiff; | |
701 | |
702 /* lock */ | |
703 pthread_mutex_lock(&fader_lock); | |
704 | |
705 /* slide volume */ | |
706 /* the Kaspar Giger way of fading, check the current mixer volume and | |
707 * increment from there so that if you have some other app lowering the | |
708 * volume at the same time xmms-alarm will not ignore it. If you have some | |
709 * other app increasing the volume, then it could get louder that you expect | |
710 * though - because the loop does not recalculate the difference each time. | |
711 */ | |
712 | |
713 /* difference between the 2 volumes */ | |
714 diff = vols->end - vols->start; | |
715 adiff = abs(diff); | |
716 | |
717 /* Are we going up or down? */ | |
718 if(diff < 0) | |
719 inc = -1; | |
720 else | |
721 inc = 1; | |
722 | |
723 xmms_remote_set_main_volume(alarm_plugin.xmms_session, (gint)vols->start); | |
724 //for(i=0;i<(vols->end - vols->start);i++) | |
725 for(i=0;i<adiff;i++) | |
726 { | |
727 //threadsleep((gfloat)fading / (vols->end - vols->start)); | |
728 threadsleep((gfloat)fading / (gfloat)adiff); | |
729 xmms_remote_set_main_volume(alarm_plugin.xmms_session, | |
730 (gint)(xmms_remote_get_main_volume(alarm_plugin.xmms_session) + inc)); | |
731 } | |
732 /* Setting the volume to the end volume sort of defeats the point if having | |
733 * the code in there to allow other apps to control volume too :) | |
734 */ | |
735 //xmms_remote_set_main_volume(alarm_plugin.xmms_session, (gint)vols->end); | |
736 | |
737 /* and */ | |
738 pthread_mutex_unlock(&fader_lock); | |
739 | |
740 DEBUG("volume = %f%%\n", (gdouble)vols->end); | |
741 return(0); | |
742 } | |
743 | |
744 static void *alarm_stop_thread( void *args ) | |
745 { | |
746 gint currvol; | |
747 fader fade_vols; | |
748 pthread_t f_tid; | |
749 | |
750 DEBUG("alarm_stop_thread\n"); | |
751 | |
752 | |
753 /* sleep for however long we are meant to be sleeping for until | |
754 * its time to shut up | |
755 */ | |
756 threadsleep(((stop_h * 60) + stop_m) * 60); | |
757 | |
758 DEBUG("alarm_stop triggered\n"); | |
759 | |
760 if (dialog_visible(alarm_dialog)) | |
761 gtk_widget_destroy(alarm_dialog); | |
762 | |
763 currvol = xmms_remote_get_main_volume(alarm_plugin.xmms_session), | |
764 | |
765 /* fade back to zero */ | |
766 fade_vols.start = currvol; | |
767 fade_vols.end = 0; | |
768 | |
769 /* The fader thread locks the fader_mutex now */ | |
770 f_tid = alarm_thread_create(alarm_fade, &fade_vols, 0); | |
771 | |
772 pthread_join(f_tid, NULL); | |
773 xmms_remote_stop(alarm_plugin.xmms_session); | |
774 | |
775 /* might as well set the volume to something higher than zero so we | |
776 * dont confuse the poor people who just woke up and cant work out why | |
777 * theres no music playing when they press the little play button :) | |
778 */ | |
779 xmms_remote_set_main_volume(alarm_plugin.xmms_session, currvol); | |
780 | |
781 DEBUG("alarm_stop done\n"); | |
782 return(NULL); | |
783 } | |
784 | |
785 void alarm_stop_cancel(GtkButton *w, gpointer data) | |
786 { | |
787 DEBUG("alarm_stop_cancel\n"); | |
788 pthread_cancel(stop_tid); | |
789 } | |
790 | |
791 /* the main alarm thread */ | |
792 static void *alarm_start_thread(void *args) | |
793 { | |
794 struct tm *currtime; | |
795 time_t timenow; | |
796 unsigned int play_start = 0; | |
797 guint today; | |
798 | |
799 /* give it time to set start_tid to something */ | |
800 threadsleep(1); | |
801 | |
802 while(start_tid != 0) | |
803 { | |
804 /* sit around and wait for the faders to not be doing anything */ | |
805 DEBUG("Waiting for fader to be unlocked.."); | |
806 pthread_mutex_lock(&fader_lock); | |
807 DEBUG("Ok\n"); | |
808 pthread_mutex_unlock(&fader_lock); | |
809 | |
810 DEBUG("Getting time\n"); | |
811 timenow = time(NULL); | |
812 currtime = localtime(&timenow); | |
813 today = currtime->tm_wday; | |
814 DEBUG("Today is %d\n", today); | |
815 | |
816 /* see if its time to do something */ | |
817 DEBUG("Checking Day\n"); | |
818 | |
819 /* Had to put something here so I put the hour string. | |
820 ** Its only debug stuff anyway */ | |
821 DEBUG(day_h[today]); | |
822 | |
823 if(alarm_conf.day[today].flags & ALARM_OFF) | |
824 { | |
825 threadsleep(8.5); | |
826 continue; | |
827 } | |
828 else | |
829 { | |
830 /* set the alarm_h and alarm_m for today, if not default */ | |
831 if(!(alarm_conf.day[today].flags & ALARM_DEFAULT)) | |
832 { | |
833 alarm_h = alarm_conf.day[today].hour; | |
834 alarm_m = alarm_conf.day[today].min; | |
835 } | |
836 else | |
837 { | |
838 alarm_h = alarm_conf.default_hour; | |
839 alarm_m = alarm_conf.default_min; | |
840 } | |
841 } | |
842 | |
843 DEBUG("Alarm time is %d:%d (def: %d:%d)\n", alarm_h, alarm_m, | |
844 alarm_conf.default_hour, alarm_conf.default_min); | |
845 | |
846 DEBUG("Checking time (%d:%d)\n", currtime->tm_hour, currtime->tm_min); | |
847 if((currtime->tm_hour != alarm_h) || (currtime->tm_min != alarm_m)) | |
848 { | |
849 threadsleep(8.5); | |
850 continue; | |
851 } | |
852 | |
853 if(cmd_on == TRUE) | |
854 { | |
855 DEBUG("Executing %s, cmd_on is true\n", cmdstr); | |
856 system(cmdstr); | |
857 } | |
858 | |
859 DEBUG("strcmp playlist, playlist is [%s]\n", playlist); | |
860 if(strcmp(playlist, "")) | |
861 { | |
862 DEBUG("playlist is not blank, aparently\n"); | |
863 /* Is this a url? */ | |
864 /* Thanks Thomer */ | |
865 if(!strncmp(playlist, "http://", 7)) | |
866 { | |
867 /* Yes */ | |
868 DEBUG("This looks like a URL to me...\n"); | |
869 /* If I just add the url and it turns out to be a playlist then xmms | |
870 * will sort that out.. It should also work for radio streams, I guess | |
871 */ | |
872 xmms_remote_playlist_clear(alarm_plugin.xmms_session); | |
873 xmms_remote_playlist_add_url_string(alarm_plugin.xmms_session, playlist); | |
874 } | |
875 else | |
876 { | |
877 /* No, its probably a local file */ | |
878 /* Does that mean we want to go through it and add files to the list | |
879 * properly, or just use this semi-hack to let xmms do the playlist | |
880 * parsing? | |
881 */ | |
882 xmms_remote_playlist_clear(alarm_plugin.xmms_session); | |
883 xmms_remote_playlist(alarm_plugin.xmms_session, | |
884 &playlist, 1, TRUE); | |
885 } | |
886 } | |
887 | |
888 if(fading) | |
889 { | |
890 fader fade_vols; | |
891 | |
892 DEBUG("Fading is true\n"); | |
893 xmms_remote_set_main_volume(alarm_plugin.xmms_session, quietvol); | |
894 | |
895 /* start playing */ | |
896 play_start = time(NULL); | |
897 xmms_remote_play(alarm_plugin.xmms_session); | |
898 | |
899 /* fade volume */ | |
900 fade_vols.start = quietvol; | |
901 fade_vols.end = volume; | |
902 | |
903 //alarm_fade(quietvol, volume); | |
904 alarm_thread_create(alarm_fade, &fade_vols, 0); | |
905 } | |
906 else | |
907 { | |
908 /* no fading */ | |
909 | |
910 /* set volume */ | |
911 xmms_remote_set_main_volume(alarm_plugin.xmms_session, volume); | |
912 | |
913 /* start playing */ | |
914 play_start = time(NULL); | |
915 xmms_remote_play(alarm_plugin.xmms_session); | |
916 } | |
917 | |
918 if(alarm_conf.reminder_on == TRUE) | |
919 { | |
920 GtkWidget *reminder_dialog; | |
921 DEBUG("Showing reminder '%s'\n", alarm_conf.reminder_msg); | |
922 | |
923 GDK_THREADS_ENTER(); | |
924 reminder_dialog = create_reminder_dialog(alarm_conf.reminder_msg); | |
925 gtk_signal_connect(GTK_OBJECT(reminder_dialog), "destroy", | |
926 GTK_SIGNAL_FUNC(dialog_destroyed), &reminder_dialog); | |
927 gtk_widget_show_all(reminder_dialog); | |
928 GDK_THREADS_LEAVE(); | |
929 } | |
930 | |
931 /* bring up the wakeup call dialog if stop_on is set TRUE, this | |
932 * has been moved to after making xmms play so that it doesnt | |
933 * get in the way for people with manual window placement turned on | |
934 * | |
935 * this means that the dialog doesnt get shown until the volume has | |
936 * finished fading though !, so thats something else to fix | |
937 */ | |
938 if(stop_on == TRUE) | |
939 { | |
940 /* ok, so when we want to open dialogs in threaded programs | |
941 * we use this do we? | |
942 * anyone? | |
943 */ | |
944 GDK_THREADS_ENTER(); | |
945 { | |
946 DEBUG("stop_on is true\n"); | |
947 alarm_dialog = create_alarm_dialog(); | |
948 DEBUG("created alarm dialog, %p\n", alarm_dialog); | |
949 | |
950 gtk_signal_connect(GTK_OBJECT(alarm_dialog), "destroy", | |
951 GTK_SIGNAL_FUNC(dialog_destroyed), &alarm_dialog); | |
952 DEBUG("attached destroy signal to alarm dialog, %p\n", alarm_dialog); | |
953 gtk_widget_show_all(alarm_dialog); | |
954 DEBUG("dialog now showing\n"); | |
955 | |
956 DEBUG("now starting stop thread\n"); | |
957 stop_tid = alarm_thread_create(alarm_stop_thread, NULL, 0); | |
958 DEBUG("Created wakeup dialog and started stop thread(%d)\n", (int)stop_tid); | |
959 | |
960 } | |
961 GDK_THREADS_LEAVE(); | |
962 | |
963 /* now wait for the stop thread */ | |
964 DEBUG("Waiting for stop to stop.... (%d)", (int)stop_tid); | |
965 pthread_join(stop_tid, NULL); | |
966 /* loop until we are out of the starting minute */ | |
967 while(time(NULL) < (play_start + 61)) | |
968 { | |
969 DEBUG("Waiting until out of starting minute\n"); | |
970 threadsleep(5.0); | |
971 } | |
972 DEBUG("OK\n"); | |
973 } | |
974 /* loop until we are out of the starting minute */ | |
975 while(time(NULL) < (play_start + 61)) | |
976 { | |
977 threadsleep(5.0); | |
978 } | |
979 threadsleep(fading); | |
980 } | |
981 | |
982 DEBUG("Main thread has gone...\n"); | |
983 return NULL; | |
984 } | |
985 | |
986 /* | |
987 * initialization | |
988 * opens the config file and reads the value, creates a new | |
989 * config in memory if the file doesnt exist and sets default vals | |
990 */ | |
991 static void alarm_init() | |
992 { | |
993 DEBUG("alarm_init\n"); | |
994 | |
995 alarm_read_config(); | |
996 | |
997 /* start the main thread running */ | |
998 start_tid = alarm_thread_create(alarm_start_thread, NULL, 1); | |
999 } | |
1000 | |
1001 /* | |
1002 * kill the main thread | |
1003 */ | |
1004 static void alarm_cleanup() | |
1005 { | |
1006 DEBUG("alarm_cleanup\n"); | |
1007 | |
1008 pthread_cancel(start_tid); | |
1009 start_tid = 0; | |
1010 if(stop_tid) | |
1011 pthread_cancel(stop_tid); | |
1012 } | |
1013 | |
1014 /* | |
1015 * for xmms to get the function names | |
1016 */ | |
1017 static GeneralPlugin alarm_plugin = | |
1018 { | |
1019 NULL, | |
1020 NULL, | |
1021 -1, | |
1022 "Alarm "VERSION, | |
1023 alarm_init, | |
1024 alarm_about, | |
1025 alarm_configure, | |
1026 alarm_cleanup, | |
1027 }; | |
1028 | |
1029 /* | |
1030 * vi:ai:expandtab:ts=2 sts=2 shiftwidth=2:nowrap: | |
1031 */ |