1 /*
2 * Copyright (C) 1990 Regents of the University of California.
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and
5 * its documentation for any purpose is hereby granted without fee,
6 * provided that the above copyright notice appear in all copies and that
7 * both that copyright notice and this permission notice appear in
8 * supporting documentation, and that the name of the University of
9 * California not be used in advertising or publicity pertaining to
10 * distribution of the software without specific, written prior
11 * permission. the University of California makes no representations
12 * about the suitability of this software for any purpose. It is provided
13 * "as is" without express or implied warranty.
14 */
15
16 # include <X11/Intrinsic.h>
17 # include <X11/StringDefs.h>
18 # include <X11/Xaw/Form.h>
19 # include <X11/Xaw/Toggle.h>
20
21 # include <stdio.h>
22
23 # include "debug.h"
24 # include "cdrom_globs.h"
25 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
26 # include "cdrom_freebsd.h"
27 #endif
28 #ifdef sun
29 # include "cdrom_sun.h"
30 #endif
31 #ifdef sgi
32 # include "cdrom_sgi.h"
33 #endif
34
35 extern AppData app_data;
36
37 void cdrom_new_disc();
38
39 /*
40 * cb_cdrom_play checks to see if we're playing; if so do nothing.
41 * if not playing turns on playing. if paused then return.
42 * otherwise start cd playing.
43 */
44 /*ARGSUSED*/
45 void
cb_cdrom_play(widget,client_data,call_data)46 cb_cdrom_play(widget, client_data, call_data)
47 Widget widget;
48 XtPointer client_data;
49 XtPointer call_data;
50 {
51 if (cdrom_open() == -1) {
52 debug_printf(1, "cb_cdrom_play: error from cdrom_open\n");
53 /* Turn the play button back off */
54 play_button_reset();
55 eject_button_set();
56 return;
57 }
58
59 if (cdi.state & CDROM_STATE_EJECTED) {
60 cdrom_new_disc(widget);
61 }
62
63 /*
64 * toggle button weirdness; play and stop are radio toggles, ie. if
65 * you hit stop, and you are playing, play is supposed to stop, so
66 * toggle buttons automatically invoke the notify procedure of other
67 * members of a toggle group when another member of the toggle group
68 * is activated, before the requested notification takes place.
69 * The practical upshot of this is that this routine can be called
70 * even if you didn't press play, and so it really takes no action.
71 */
72 if (cdi.state & CDROM_STATE_PLAY) {
73 debug_printf(1, "cb_cdrom_play: already playing track %d\n",
74 cdi.curtrack);
75 return;
76 }
77
78 if (cdi.curtrack == 0) /* (no track selected) */
79 {
80 cdi.curtrack = cdi.mintrack;
81 track_button_update();
82 }
83
84 cdi.state |= CDROM_STATE_PLAY;
85
86 if (cdi.state & CDROM_STATE_PAUSE) {
87 debug_printf(1, "cb_cdrom_play: paused on track %d\n",
88 cdi.curtrack);
89 return;
90 }
91
92 timer_fsecs = 0;
93 cdi.duration = 0;
94
95 if (cdi.state & CDROM_STATE_SHUFFLE)
96 cdi.curtrack = shuffle_next_track();
97
98 else if (cdi.state & CDROM_STATE_PROGRAM)
99 {
100 if ((cdi.curtrack = program_resume()) == 0) {
101
102 /* cancel program */
103 debug_printf(1, "cb_cdrom_play: cancelling program\n");
104 program_cancel();
105 cdi.curtrack = cdi.mintrack;
106 }
107 else {
108 debug_printf(1, "cb_cdrom_play: resetting timer button\n");
109 timer_button_reset();
110 }
111 }
112
113 if (cdrom_play() != -1) {
114 cdi.state &= ~CDROM_STATE_STOP;
115 }
116
117 timer_button_update();
118 }
119
120 /*
121 * cb_cdrom_pause toggles pausing on or off.
122 */
123 /*ARGSUSED*/
124 void
cb_cdrom_pause(widget,client_data,call_data)125 cb_cdrom_pause(widget, client_data, call_data)
126 Widget widget;
127 XtPointer client_data;
128 XtPointer call_data;
129
130 {
131 if (cdrom_open() == -1) {
132 debug_printf(1, "cb_cdrom_pause: error from cdrom_open\n");
133 pause_button_reset();
134 return;
135 }
136
137 #ifdef sgi
138 if (cdrom_status() == CDROM_NO_STATUS) {
139 cdi.state |= CDROM_STATE_EJECTED;
140 buttons_reset();
141 pause_button_reset();
142 return;
143 }
144 #endif
145
146 if (cdi.state & CDROM_STATE_EJECTED) {
147 cdrom_new_disc(widget);
148 }
149
150 if (cdi.state & CDROM_STATE_PAUSE) {
151 cdi.state &= ~CDROM_STATE_PAUSE;
152
153 if (cdi.state & CDROM_STATE_PROGRAM)
154 cdi.curtrack = program_resume();
155
156 else if (cdi.curtrack == 0) /* (no track selected) */
157 {
158 cdi.curtrack = cdi.mintrack;
159 track_button_update();
160 }
161
162 debug_printf(1, "cb_cdrom_pause: resuming track %d\n",
163 cdi.curtrack);
164
165 /*
166 * if we use next or prev after a pause we can't
167 * just resume but have to move to the track.
168 */
169 if ((cdi.curtrack == cdrom_get_curtrack()) &&
170 (cdi.duration > 0))
171 {
172 if (cdrom_resume() != -1) {
173 cdi.state &= ~CDROM_STATE_EJECTED;
174 eject_button_reset();
175 cdi.state &= ~CDROM_STATE_STOP;
176 }
177
178 cdrom_timer_on();
179
180 return;
181 }
182
183 if (cdrom_play() != -1) {
184 cdi.state &= ~CDROM_STATE_EJECTED;
185 eject_button_reset();
186 cdi.state &= ~CDROM_STATE_STOP;
187 }
188
189 return;
190 }
191
192 cdi.state |= CDROM_STATE_PAUSE;
193
194 debug_printf(1, "cb_cdrom_pause: pausing on track %d\n",
195 cdi.curtrack);
196
197 if (cdrom_pause() != -1) {
198 cdi.state &= ~CDROM_STATE_STOP;
199 cdi.state |= CDROM_STATE_PLAY;
200 eject_button_reset();
201 play_button_set();
202 }
203
204 cdrom_timer_off();
205 }
206
207 /*
208 * cb_cdrom_stop checks to see if we're playing; if not then
209 * do nothing. sets the current track to the first audio track.
210 * turns off play, pause, stops the cd, and closes it so that the
211 * disc can be ejected with the eject button on the drive.
212 */
213 /*ARGSUSED*/
214 void
cb_cdrom_stop(widget,client_data,call_data)215 cb_cdrom_stop(widget, client_data, call_data)
216 Widget widget;
217 XtPointer client_data;
218 XtPointer call_data;
219 {
220 Arg args[1];
221 Boolean state;
222
223 if (cdrom_open() == -1) {
224 debug_printf(1, "cb_cdrom_stop: error from cdrom_open\n");
225 /* Turn the stop button back off */
226 stop_button_reset();
227 eject_button_set();
228 return;
229 }
230
231 #ifdef sgi
232 if (cdrom_status() == CDROM_NO_STATUS) {
233 cdi.state |= CDROM_STATE_EJECTED;
234 buttons_reset();
235 /* Turn the stop button back off */
236 stop_button_reset();
237 return;
238 }
239 #endif
240
241 /* toggle button weirdness; see comment in cb_cdrom_play for details */
242 XtSetArg(args[0], XtNstate, &state);
243 XtGetValues(widget, args, 1);
244
245 if (state == False) {
246 debug_printf(1, "cb_cdrom_stop: already stopped\n");
247 return;
248 }
249
250 debug_printf(1, "cb_cdrom_stop: resetting disc\n");
251
252 cdrom_reset();
253
254 if (cdi.state & CDROM_STATE_SHUFFLE) {
255 debug_printf(1, "cb_cdrom_shuffle: shuffle on\n");
256 cdi.state |= CDROM_STATE_SHUFFLE;
257 shuffle_setup();
258 }
259 }
260
261 /*
262 * cb_cdrom_previous decrments the current track. if paused or stopped
263 * then return. otherwise start playing the (new) current track.
264 */
265 /*ARGSUSED*/
266 void
cb_cdrom_previous(widget,client_data,call_data)267 cb_cdrom_previous(widget, client_data, call_data)
268 Widget widget;
269 XtPointer client_data;
270 XtPointer call_data;
271 {
272 if (cdrom_open() == -1) {
273 debug_printf(1, "cb_cdrom_previous: error from cdrom_open\n");
274 return;
275 }
276
277 #ifdef sgi
278 if (cdrom_status() == CDROM_NO_STATUS) {
279 cdi.state |= CDROM_STATE_EJECTED;
280 buttons_reset();
281 return;
282 }
283 #endif
284
285 cdi.state &= ~CDROM_STATE_EJECTED;
286 eject_button_reset();
287 cdi.state &= ~CDROM_STATE_STOP;
288
289 cdrom_timer_off();
290
291 /*
292 * if playing less than replayThreshold seconds, back up to
293 * previous track; otherwise start at beginning of current track:
294 */
295 if (cdi.duration < app_data.replayThreshold)
296 {
297 if ((cdi.program != NULL) &&
298 (cdi.state & CDROM_STATE_PLAY) &&
299 ((cdi.state & CDROM_STATE_PAUSE) == 0))
300 {
301 if (program_prev_track() == 0)
302 debug_printf(1, "cb_cdrom_previous: no previous selections in program\n");
303 else
304 {
305 debug_printf(1, "cb_cdrom_previous: going to prev selection\n");
306 cdi.curtrack = program_goto_prev_track();
307 }
308 }
309 else if (cdi.curtrack > cdi.mintrack) /* can't go below 1st track:*/
310 cdi.curtrack--;
311 }
312
313 timer_fsecs = 0;
314 cdi.duration = 0;
315
316 if (cdi.state & CDROM_STATE_SHUFFLE)
317 cdi.curtrack = shuffle_prev_track();
318
319 track_button_update();
320 timer_button_update();
321
322 if (cdi.state & CDROM_STATE_PAUSE) {
323 debug_printf(1, "cb_cdrom_previous: paused on track %d\n",
324 cdi.curtrack);
325 if (cdrom_play() != -1) {
326 cdi.state &= ~CDROM_STATE_STOP;
327 }
328 if (cdrom_pause() != -1) {
329 cdi.state &= ~CDROM_STATE_STOP;
330 }
331 cdrom_timer_off();
332 return;
333 }
334
335 if ((cdi.state & CDROM_STATE_PLAY) == 0) {
336 debug_printf(1, "cb_cdrom_previous: stopped on track %d\n",
337 cdi.curtrack);
338 return;
339 }
340
341 debug_printf(1, "cb_cdrom_previous: playing track %d\n",
342 cdi.curtrack);
343
344
345 /* restart playing if not paused and currently playing */
346 (void) cdrom_play();
347 }
348
349
350 /*
351 * cb_cdrom_next incrments the current track. if paused or stopped
352 * then return. otherwise start playing the (new) current track.
353 */
354 /*ARGSUSED*/
355 void
cb_cdrom_next(widget,client_data,call_data)356 cb_cdrom_next(widget, client_data, call_data)
357 Widget widget;
358 XtPointer client_data;
359 XtPointer call_data;
360 {
361 if (cdrom_open() == -1) {
362 debug_printf(1, "cb_cdrom_next: error from cdrom_open\n");
363 return;
364 }
365
366 #ifdef sgi
367 if (cdrom_status() == CDROM_NO_STATUS) {
368 cdi.state |= CDROM_STATE_EJECTED;
369 buttons_reset();
370 return;
371 }
372 #endif
373
374 if (cdi.state & CDROM_STATE_EJECTED) {
375 cdrom_new_disc(widget);
376 }
377
378 cdi.state &= ~CDROM_STATE_EJECTED;
379 eject_button_reset();
380 cdi.state &= ~CDROM_STATE_STOP;
381
382 if (cdi.state & CDROM_STATE_SHUFFLE) {
383 if (cdi.currand == cdi.ntracks) {
384 debug_printf(1, "cb_cdrom_next: at last track\n");
385 return;
386 }
387 }
388 else if ((cdi.program != NULL) &&
389 (cdi.state & CDROM_STATE_PLAY) &&
390 ((cdi.state & CDROM_STATE_PAUSE) == 0))
391 {
392 if (program_next_track() == 0)
393 debug_printf(1, "cb_cdrom_next: no further selections in program\n");
394 else
395 {
396 debug_printf(1, "cb_cdrom_next: going to next selection\n");
397 cdi.curtrack = program_goto_next_track();
398 }
399 }
400 else {
401 if (cdi.curtrack >= cdi.maxtrack) {
402 debug_printf(1, "cb_cdrom_next: at last track\n");
403 return;
404 }
405 else
406 cdi.curtrack++;
407 }
408
409 cdrom_timer_off();
410
411 timer_fsecs = 0;
412 cdi.duration = 0;
413
414
415 track_button_update();
416 timer_button_update();
417
418 if (cdi.state & CDROM_STATE_PAUSE) {
419 debug_printf(1, "cb_cdrom_next: paused on track %d\n",
420 cdi.curtrack);
421 if (cdrom_play() != -1) {
422 cdi.state &= ~CDROM_STATE_STOP;
423 }
424 if (cdrom_pause() != -1) {
425 cdi.state &= ~CDROM_STATE_STOP;
426 }
427 cdrom_timer_off();
428 return;
429 }
430
431 if ((cdi.state & CDROM_STATE_PLAY) == 0) {
432 debug_printf(1, "cb_cdrom_next: stopped on track %d\n",
433 cdi.curtrack);
434 return;
435 }
436
437 if (cdi.state & CDROM_STATE_SHUFFLE)
438 cdi.curtrack = shuffle_next_track();
439
440 debug_printf(1, "cb_cdrom_next: playing track %d\n",
441 cdi.curtrack);
442
443 /* restart playing if not paused and currently playing */
444 (void) cdrom_play();
445 }
446
447
448 /*ARGSUSED*/
449 void
cb_cdrom_eject(widget,client_data,call_data)450 cb_cdrom_eject(widget, client_data, call_data)
451 Widget widget;
452 XtPointer client_data;
453 XtPointer call_data;
454 {
455 Arg args[1];
456 Boolean state;
457
458 if (cdrom_open() == -1) {
459 debug_printf(1, "cb_cdrom_eject: error from cdrom_open\n");
460 return;
461 }
462
463 #ifdef sgi
464 if (cdrom_status() == CDROM_NO_STATUS) {
465 cdi.state |= CDROM_STATE_EJECTED;
466 buttons_reset();
467 return;
468 }
469 #endif
470
471 /* Check if this is just a toggle event. If so, do nothing */
472 XtSetArg(args[0], XtNstate, &state);
473 XtGetValues(widget, args, 1);
474 if (state == False) {
475 return;
476 }
477
478 /* toggle button weirdness; see comment in cb_cdrom_play for details */
479 if (cdi.state & CDROM_STATE_EJECTED) {
480 debug_printf(1, "cb_cdrom_eject: already ejected\n");
481 return;
482 }
483
484 debug_printf(1, "cb_cdrom_eject: ejecting on track %d\n",
485 cdi.curtrack);
486
487 cdrom_reset();
488 cdi.maxtrack = 0;
489
490 program_cancel();
491 cdrom_eject();
492 cdi.state |= CDROM_STATE_EJECTED;
493 cdrom_close();
494
495 disc_title = NODISCSTR;
496 update_title();
497 }
498
499 #ifdef sgi
500 /*ARGSUSED*/
501 void
cb_cdrom_audio(widget,client_data,call_data)502 cb_cdrom_audio(widget, client_data, call_data)
503 Widget widget;
504 XtPointer client_data;
505 XtPointer call_data;
506 {
507 if (cdrom_open() == -1) {
508 debug_printf(1, "cb_cdrom_audio: error from cdrom_open\n");
509 return;
510 }
511
512 if (cdi.state & CDROM_STATE_PLAY) {
513 XBell(XtDisplay(widget), 100);
514 if (cdi.scsi_audio) {
515 audio_button_set();
516 } else {
517 audio_button_reset();
518 }
519 return;
520 }
521
522 if (cdi.scsi_audio) {
523 debug_printf(1, "cb_cdrom_audio: toggling audio off\n");
524 cdrom_toggle_audio();
525 audio_button_reset();
526 return;
527 }
528
529 /* Check if it's available before turning it on */
530 if ( cdrom_audio_avail() ) {
531 debug_printf(1, "cb_cdrom_audio: toggling audio on\n");
532 cdrom_toggle_audio();
533 audio_button_set();
534 return;
535 }
536 XBell(XtDisplay(widget), 100);
537 audio_button_reset();
538 }
539 #endif /* sgi */
540
541 /*ARGSUSED*/
542 void
cb_cdrom_cycle(widget,client_data,call_data)543 cb_cdrom_cycle(widget, client_data, call_data)
544 Widget widget;
545 XtPointer client_data;
546 XtPointer call_data;
547 {
548 if (cdi.state & CDROM_STATE_CYCLE) {
549 debug_printf(1, "cb_cdrom_cycle: cycle off\n");
550 cdi.state &= ~CDROM_STATE_CYCLE;
551
552 return;
553 }
554
555 debug_printf(1, "cb_cdrom_cycle: cycle on\n");
556 cdi.state |= CDROM_STATE_CYCLE;
557 }
558
559 /*ARGSUSED*/
560 void
cb_cdrom_shuffle(widget,client_data,call_data)561 cb_cdrom_shuffle(widget, client_data, call_data)
562 Widget widget;
563 XtPointer client_data;
564 XtPointer call_data;
565 {
566 if (cdi.state & CDROM_STATE_SHUFFLE) {
567
568 debug_printf(1, "cb_cdrom_shuffle: shuffle off\n");
569 cdi.state &= ~CDROM_STATE_SHUFFLE;
570
571 return;
572 }
573
574 if (cdi.state & CDROM_STATE_PLAY) {
575 XBell(XtDisplay(widget), 100);
576 shuffle_button_reset();
577 return;
578 }
579
580 if (cdi.state & CDROM_STATE_PROGRAM) {
581 debug_printf(1, "cb_cdrom_shuffle: cancelling program\n");
582 program_cancel();
583 }
584
585 debug_printf(1, "cb_cdrom_shuffle: shuffle on\n");
586 cdi.state |= CDROM_STATE_SHUFFLE;
587 shuffle_setup();
588 }
589
590 /*ARGSUSED*/
591 void
cb_cdrom_quit(widget,client_data,call_data)592 cb_cdrom_quit(widget, client_data, call_data)
593 Widget widget;
594 XtPointer client_data;
595 XtPointer call_data;
596 {
597 debug_printf(1, "cb_cdrom_quit: bye\n");
598
599 cdrom_timer_off();
600 cdrom_close();
601
602 exit(0);
603 }
604
605
606 /*ARGSUSED*/
607 void
cb_cdrom_rewind(widget,client_data,call_data)608 cb_cdrom_rewind(widget, client_data, call_data)
609 Widget widget;
610 XtPointer client_data;
611 XtPointer call_data;
612 {
613 if (cdrom_open() == -1) {
614 debug_printf(1, "cb_cdrom_rew: error from cdrom_open\n");
615 return;
616 }
617
618 if ((cdi.state & CDROM_STATE_PLAY) || (cdi.state & CDROM_STATE_PAUSE)) {
619 debug_printf(1, "cb_cdrom_rew: moving backward in track %d\n",
620 cdi.curtrack);
621
622 cdrom_rewind();
623 }
624 }
625
626
627 /*ARGSUSED*/
628 void
cb_cdrom_ff(widget,client_data,call_data)629 cb_cdrom_ff(widget, client_data, call_data)
630 Widget widget;
631 XtPointer client_data;
632 XtPointer call_data;
633 {
634 if (cdrom_open() == -1) {
635 debug_printf(1, "cb_cdrom_ff: error from cdrom_open\n");
636 return;
637 }
638
639
640 if ((cdi.state & CDROM_STATE_PLAY) || (cdi.state & CDROM_STATE_PAUSE)) {
641 debug_printf(1, "cb_cdrom_ff: moving forward in track %d\n",
642 cdi.curtrack);
643
644 cdrom_ff();
645 }
646 }
647
648 static Boolean pgmButtonUp = False;
649
650 /*ARGSUSED*/
651 void
cb_cdrom_program(widget,topLevel,call_data)652 cb_cdrom_program(widget, topLevel, call_data)
653 Widget widget;
654 Widget topLevel;
655 XtPointer call_data;
656 {
657 if (pgmButtonUp)
658 {
659 track_button_reset();
660 pgm_button_set();
661
662 /*
663 * have to keep track of button position internally, since toggle
664 * widgets screw up when you mess with their state programatically,
665 * in that if you set the state to false when notified on a button
666 * press, if you also notify on button release, the state is
667 * auto-reset to true prior to notification, so there is no
668 * longer any way to tell if it's a button release:
669 * THIS IS A HACK! (necessary, but *still* a hack.)
670 */
671 pgmButtonUp = False;
672
673 return;
674 }
675
676 if ((cdi.state & CDROM_STATE_PROGRAM) == 0)
677 {
678 if (cdrom_open() == -1) {
679 debug_printf(1, "cb_cdrom_play: error from cdrom_open\n");
680 return;
681 }
682 if (cdi.state & CDROM_STATE_EJECTED) {
683 cdrom_new_disc(widget);
684 }
685 if (cdi.state & CDROM_STATE_SHUFFLE) {
686 debug_printf(1, "cb_cdrom_program: cancelling shuffle mode\n");
687 cdi.state &= ~CDROM_STATE_SHUFFLE;
688 shuffle_button_reset();
689 }
690 cdi.state &= ~CDROM_STATE_EJECTED;
691 eject_button_reset();
692 cdi.state &= ~CDROM_STATE_STOP;
693
694 debug_printf(1, "cb_cdrom_program: program on\n");
695 cdi.state |= CDROM_STATE_PROGRAM;
696 timer_button_set();
697 popup_program_form (widget, topLevel, call_data);
698 /*
699 * have to keep track of button position internally, since command
700 * widgets screw up if you mess with their state programatically:
701 */
702 pgmButtonUp = True;
703 return;
704 }
705
706 if (((cdi.state & CDROM_STATE_PAUSE) ||
707 ((cdi.state & CDROM_STATE_PLAY) == 0)) &&
708 (cdi.curtrack != 0))
709 {
710 /* indicate to user he's programmed a track: */
711 pgm_button_reset();
712 track_button_set();
713 timer_button_update();
714
715 debug_printf(1, "cb_cdrom_program: adding track %d to program list\n",
716 cdi.curtrack);
717 program_add_track (cdi.curtrack);
718 }
719 /*
720 * have to keep track of button position internally, since command
721 * widgets screw up if you mess with their state programatically:
722 */
723 pgmButtonUp = True;
724
725 }
726
727
728 void
cdrom_new_disc(widget)729 cdrom_new_disc(widget)
730 Widget widget;
731 {
732 Arg args[1];
733 Boolean state;
734
735 debug_printf(1, "cdrom_new_disc: resetting disc\n");
736
737 cdrom_reset();
738
739 cdi.state &= ~CDROM_STATE_EJECTED;
740 eject_button_reset();
741
742 /* toggle button weirdness; see comment in cb_cdrom_play for details */
743 XtSetArg(args[0], XtNstate, &state);
744 XtGetValues(widget, args, 1);
745 if (state == False) {
746 XtSetArg(args[0], XtNstate, True);
747 XtSetValues(widget, args, 1);
748 }
749
750 if (cdi.state & CDROM_STATE_SHUFFLE) {
751 debug_printf(1, "cb_cdrom_shuffle: shuffle on\n");
752 cdi.state |= CDROM_STATE_SHUFFLE;
753 shuffle_setup();
754 }
755 }
756