1 #include <fcntl.h>
2 #include <math.h>
3 #include <pthread.h>
4 #include <stdio.h>
5 #include <string.h>
6 #include <time.h>
7 #include <unistd.h>
8
9 #include <sys/wait.h>
10 #include <sys/param.h>
11 #include <sys/types.h>
12
13 #include <X11/Xlib.h>
14 #include <X11/xpm.h>
15 #include <X11/extensions/shape.h>
16 #include <gtk/gtk.h>
17
18 #include "../wmgeneral/wmgeneral.h"
19 #include "../wmgeneral/misc.h"
20
21 #include "wmtimer.xpm"
22
23 #define CHAR_WIDTH 5
24 #define CHAR_HEIGHT 7
25 #define VERSION "2.92"
26 #define _MULTI_THREADED
27
28 typedef enum {NONE, ALARM, TIMER, TIMER_PAUSED, TIMER_DONE, CHRONO, CHRONO_PAUSED} modeType;
29 typedef struct {int bell, command;} actionType;
30 typedef enum {OUT, IN, RETURN} configState;
31
32 /*******************************************************************************
33 * Functions
34 ******************************************************************************/
35 // Misc functions
36 void execAct();
37 void parseArgs(int argc, char *argv[]);
38 void processEvent(XEvent *event);
39 void usage();
40
41 // Timer updates
42 void decrementTimer();
43 void incrementTimer();
44
45 // X11 Screen updates
46 void blitNum(int num, int x, int y);
47 void blitString(char *name, int x, int y);
48 void updateACT();
49 void updateClock(int clockHour, int clockMin, int clockSec);
50 void updateMain();
51
52 // GTK GUI functions
53 void *configure(void *);
54 void callback(GtkWidget *widget, gpointer data);
55 int delete_event(GtkWidget *widget, GdkEvent *event, gpointer data);
56 void destroy(GtkWidget *widget, gpointer data);
57
58 // Functions to avoid 'implicit declaration' warnings
59 int atoi();
60 char toupper();
61
62
63 /*******************************************************************************
64 * Globals
65 ******************************************************************************/
66 static GtkWidget *entry;
67 static GtkWidget *spinner1;
68 static GtkWidget *spinner2;
69 static GtkWidget *spinner3;
70
71 int timeSetToZero = 0;
72 int buttonStatus = -1;
73 int hour = 0, min = 0, sec = 0;
74 char *myName;
75 char command[256];
76 modeType mode, tmpMode;
77 actionType action, tmpAction;
78 configState configSt;
79
80
81 /*******************************************************************************
82 * main
83 ******************************************************************************/
main(int argc,char * argv[])84 int main(int argc, char *argv[])
85 {
86 int prevSec = 0;
87 long now;
88 struct tm *thisTime;
89 int wminet_mask_width = 64;
90 int wminet_mask_height = 64;
91 char wminet_mask_bits[64 * 64];
92 XEvent Event;
93
94 parseArgs(argc, argv);
95 gtk_init (&argc, &argv);
96
97 createXBMfromXPM(wminet_mask_bits, wmtimer_xpm,
98 wminet_mask_width, wminet_mask_height);
99
100 openXwindow(argc, argv, wmtimer_xpm, wminet_mask_bits,
101 wminet_mask_width, wminet_mask_height);
102
103 // setMaskXY(-64, 0);
104
105 AddMouseRegion(0, 18, 49, 45, 59); /* middle button */
106 AddMouseRegion(1, 5, 49, 17, 59); /* left button */
107 AddMouseRegion(2, 46, 49, 59, 59); /* right button */
108 AddMouseRegion(3, 2, 2, 58, 47); /* main area */
109 // AddMouseRegion(3, 6, 2, 60, 18); /* first bar */
110 // AddMouseRegion(4, 6, 20, 60, 34); /* second bar */
111 // AddMouseRegion(5, 6, 37, 60, 48); /* third bar */
112
113 updateMain();
114 updateACT();
115
116 // if (hour == 0 && min == 0 && sec == 0)
117 // timeSetToZero = 1;
118
119 while (1)
120 {
121 now = time(0);
122 waitpid(0, NULL, WNOHANG);
123 thisTime = localtime(&now);
124
125 updateClock(thisTime->tm_hour, thisTime->tm_min, thisTime->tm_sec);
126 RedrawWindow();
127
128 switch (mode)
129 {
130 case TIMER:
131 if (prevSec < thisTime->tm_sec)
132 {
133 decrementTimer();
134 updateACT();
135 if (hour == 0 && min == 0 && sec == 0 && !timeSetToZero)
136 execAct();
137 }
138 prevSec = thisTime->tm_sec;
139 break;
140 case CHRONO:
141 if (prevSec < thisTime->tm_sec)
142 {
143 incrementTimer();
144 updateACT();
145 }
146 prevSec = thisTime->tm_sec;
147 break;
148 case ALARM:
149 if (hour == thisTime->tm_hour &&
150 min == thisTime->tm_min &&
151 sec == thisTime->tm_sec)
152 execAct();
153 break;
154 case NONE:
155 case TIMER_DONE:
156 case TIMER_PAUSED:
157 case CHRONO_PAUSED:
158 break;
159 }
160
161 while (XPending(display)) // Handle X Events
162 {
163 XNextEvent(display, &Event);
164 processEvent(&Event);
165 }
166
167 // Since we have multi-thread, need to detect return from configure
168 if (configSt == RETURN)
169 {
170 configSt = OUT;
171 updateMain();
172 updateACT();
173 }
174
175 usleep(100000L);
176 }
177
178 return 0;
179 }
180
181
182 /*******************************************************************************
183 * execAct
184 ******************************************************************************/
execAct()185 void execAct()
186 {
187 if (action.command && strlen(command))
188 execCommand(command);
189 if (action.bell)
190 {
191 printf("\07");
192 fflush(stdout);
193 }
194
195 if (mode == TIMER)
196 mode = TIMER_DONE; // Don't want to keep doing the Timer event
197 else
198 mode = NONE;
199
200 }
201
202
203 /*******************************************************************************
204 * parseArgs
205 ******************************************************************************/
parseArgs(int argc,char * argv[])206 void parseArgs(int argc, char *argv[])
207 {
208 int argIndex;
209 int timeDelim = 0;
210 int timeParts[] = {0,0,0};
211 char *charPtr;
212
213 command[0] = '\0';
214 myName = argv[0];
215
216 for (argIndex = 1; argIndex < argc; argIndex++)
217 {
218 char *arg = argv[argIndex];
219
220 // Allow for the options that wmgeneral.c accepts
221 if (!strcmp(arg, "-color") ||
222 !strcmp(arg, "-display") ||
223 !strcmp(arg, "-geometry")) {
224 }
225 else if (*arg == '-')
226 {
227 switch (arg[1])
228 {
229 case 'a':
230 mode = ALARM;
231 break;
232 case 'c':
233 mode = TIMER;
234 break;
235 case 'r':
236 mode = CHRONO;
237 break;
238 case 'b':
239 action.bell = 1;
240 break;
241 case 'e':
242 strcpy(command, argv[argIndex+1]);
243 action.command = 1;
244 break;
245 case 't':
246 if (argv[argIndex+1])
247 {
248 // Check time argument for errors, dont want to segfault on strtok()
249 for (charPtr = argv[argIndex+1]; *charPtr; charPtr++)
250 {
251 if (*charPtr == ':')
252 timeDelim++;
253 else
254 {
255 if (timeDelim == 0)
256 timeParts[0]++;
257 else if (timeDelim == 1)
258 timeParts[1]++;
259 else if (timeDelim == 2)
260 timeParts[2]++;
261 }
262 }
263
264 // Need to have 2 :'s as time delimiter
265 // Need to have 1 or 2 digits for each part
266 if (timeDelim != 2 ||
267 !(timeParts[0] == 1 || timeParts[0] == 2) ||
268 !(timeParts[1] == 1 || timeParts[1] == 2) ||
269 !(timeParts[2] == 1 || timeParts[2] == 2) )
270 usage();
271
272 hour = atoi(strtok(argv[argIndex+1], ":"));
273 min = atoi(strtok(NULL, ":"));
274 sec = atoi(strtok(NULL, ":"));
275
276 if (hour == 0 && min == 0 && sec == 0)
277 timeSetToZero = 1;
278 }
279 else
280 usage();
281 break;
282 case 'v':
283 printf("WMTimer Version: %s\n", VERSION);
284 _exit(0);
285 break;
286 default:
287 usage();
288 break;
289 }
290 }
291 }
292
293 }
294
295
296 /*******************************************************************************
297 * processEvent
298 ******************************************************************************/
processEvent(XEvent * event)299 void processEvent(XEvent *event)
300 {
301
302 int tmpButtonStatus;
303 int threadId;
304 pthread_t thread;
305
306 switch (event->type)
307 {
308 case Expose:
309 RedrawWindow();
310 break;
311 case DestroyNotify:
312 XCloseDisplay(display);
313 _exit(0);
314 break;
315 case ButtonPress:
316 tmpButtonStatus = CheckMouseRegion(event->xbutton.x, event->xbutton.y);
317 buttonStatus = tmpButtonStatus;
318 if (buttonStatus == tmpButtonStatus && buttonStatus >= 0)
319 {
320 switch (buttonStatus)
321 {
322 case 0: // center button
323 break;
324 case 1: // left arrow button
325 break;
326 case 2: // right arrow button
327 break;
328 case 3: // main area
329 break;
330 default:
331 break;
332 }
333 }
334 break;
335 case ButtonRelease:
336 tmpButtonStatus = CheckMouseRegion(event->xbutton.x, event->xbutton.y);
337 if (buttonStatus == tmpButtonStatus && buttonStatus >= 0)
338 {
339 switch (buttonStatus)
340 {
341 case 0: // center button
342 if (mode == ALARM)
343 {
344 hour = min = sec = 0;
345 updateACT();
346 }
347 if (mode == CHRONO)
348 mode = CHRONO_PAUSED;
349 else if (mode == TIMER)
350 mode = TIMER_PAUSED;
351 updateMain();
352 break;
353 case 1: // left arrow button
354 if (mode == CHRONO)
355 mode = CHRONO_PAUSED;
356 else if (mode == TIMER)
357 mode = TIMER_PAUSED;
358 hour = min = sec = 0;
359 updateACT();
360 updateMain();
361 break;
362 case 2: // right arrow button
363 if (mode == ALARM)
364 {
365 hour = min = sec = 0;
366 updateACT();
367 timeSetToZero = 0;
368 mode = CHRONO;
369 }
370 else if (mode == TIMER || mode == TIMER_PAUSED)
371 mode = TIMER;
372 else
373 mode = CHRONO;
374
375 updateMain();
376 break;
377 case 3: // main area
378 if (configSt != IN) // Dont want to spawn multiple config threads
379 {
380 threadId = pthread_create(&thread, NULL, configure, NULL);
381 configSt = IN;
382 }
383 break;
384 default:
385 break;
386 }
387 }
388 buttonStatus = -1;
389 break;
390 }
391 }
392
393
394 /*******************************************************************************
395 * usage
396 ******************************************************************************/
usage(void)397 void usage(void)
398 {
399 fprintf(stderr, "\nWMTimer - Josh King <wmtimer@darkops.net>\n\n");
400
401 fprintf(stderr, "usage: %s -[a|c|r] -t <hh:mm:ss> -e <command>\n\n", myName);
402
403 fprintf(stderr, " -a alarm mode, wmtimer will beep/exec command\n");
404 fprintf(stderr, " at specified time\n");
405 fprintf(stderr, " -c countdowntimer mode, wmtimer will beep/exec\n");
406 fprintf(stderr, " command when specified time reaches 0 \n");
407 fprintf(stderr, " --color <color> as a word or as rgb:RR/GG/BB\n");
408 fprintf(stderr, " -b beep\n");
409 fprintf(stderr, " -e <command> exec command\n");
410 fprintf(stderr, " -r start in chronograph mode\n");
411 fprintf(stderr, " -t <hh:mm:ss>\n");
412 fprintf(stderr, " -h this help screen\n");
413 fprintf(stderr, " -v print the version number\n");
414 fprintf(stderr, "\n");
415
416 _exit(0);
417 }
418
419
420 /*******************************************************************************
421 * decrementTimer
422 ******************************************************************************/
decrementTimer()423 void decrementTimer()
424 {
425 if (!(hour == 0 && min == 0 && sec == 0)) // Don't want to go past 0:0:0
426 sec--;
427 if (sec == -1)
428 {
429 sec = 59;
430 min--;
431 if (min == -1)
432 {
433 min = 59;
434 hour--;
435 }
436 }
437 }
438
439
440 /*******************************************************************************
441 * incrementTimer
442 ******************************************************************************/
incrementTimer()443 void incrementTimer()
444 {
445 sec++;
446 if (sec == 60)
447 {
448 sec = 0;
449 min++;
450 if (min == 60)
451 {
452 min = 0;
453 hour++;
454 }
455 }
456 }
457
458
459 /*******************************************************************************
460 * blitNum Blits a number at given co-ordinates
461 ******************************************************************************/
blitNum(int num,int x,int y)462 void blitNum(int num, int x, int y)
463 {
464 char buf[1024];
465 int newx = x;
466
467 if (num > 99)
468 newx -= CHAR_WIDTH;
469
470 if (num > 999)
471 newx -= CHAR_WIDTH;
472
473 sprintf(buf, "%02i", num);
474 blitString(buf, newx, y);
475 }
476
477
478 /*******************************************************************************
479 * blitString Blits a string at given co-ordinates
480 ******************************************************************************/
blitString(char * name,int x,int y)481 void blitString(char *name, int x, int y)
482 {
483 // copyXPMArea(x_get_pos, y_get_pos, x_dist_from_x_pos, y_dist_from_y_pos,
484 // x_placement_pos, y_placement_pos);
485 // each char/num is 6u wide & 8u high, nums are 64u down, chars are 74u down
486
487 int i;
488 int c;
489 int k;
490 k = x;
491
492 for (i = 0; name[i]; i++)
493 {
494 c = toupper(name[i]);
495 if (c >= 'A' && c <= 'Z') // its a letter
496 {
497 c -= 'A';
498 copyXPMArea(c * 6, 74, 6, 8, k, y);
499 k += 6;
500 }
501 else // its a number or symbol
502 {
503 c -= '0';
504 copyXPMArea(c * 6, 64, 6, 8, k, y);
505 k += 6;
506 }
507 }
508
509 }
510
511
512 /*******************************************************************************
513 * updateACT (AlarmChronoTimer)
514 ******************************************************************************/
updateACT()515 void updateACT()
516 {
517 blitNum(hour, 7, 36);
518 blitString(":", 20, 36);
519 blitNum(min, 25, 36);
520 blitString(":", 38, 36);
521 blitNum(sec, 43, 36);
522 }
523
524
525 /*******************************************************************************
526 * updateClock
527 ******************************************************************************/
updateClock(int clockHour,int clockMin,int clockSec)528 void updateClock(int clockHour, int clockMin, int clockSec)
529 {
530 blitNum(clockHour, 7, 5);
531 blitString(":", 20, 5);
532 blitNum(clockMin, 25, 5);
533 blitString(":", 38, 5);
534 blitNum(clockSec, 43, 5);
535
536 }
537
538
539 /*******************************************************************************
540 * updateMain
541 ******************************************************************************/
updateMain()542 void updateMain()
543 {
544 copyXPMArea(13 * 6, 64, 8 * 6, 8, 6, 21);
545
546 switch (mode)
547 {
548 case ALARM:
549 blitString("ALARM:", 13, 21);
550 break;
551 case TIMER_PAUSED:
552 case TIMER:
553 blitString("TIMER:", 13, 21);
554 break;
555 case CHRONO_PAUSED:
556 case CHRONO:
557 blitString("CHRONO:", 12, 21);
558 break;
559 default:
560 blitString("WMTIMER", 10, 21);
561 break;
562 }
563 }
564
565
566 /*******************************************************************************
567 * callback
568 ******************************************************************************/
callback(GtkWidget * widget,gpointer data)569 void callback(GtkWidget * widget, gpointer data)
570 {
571 if ((char *) data == "alarm_button")
572 tmpMode = ALARM;
573 else if ((char *) data == "timer_button")
574 tmpMode = TIMER;
575 else if ((char *) data == "chrono_button")
576 tmpMode = CHRONO;
577 else if ((char *) data == "bell_button")
578 {
579 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
580 tmpAction.bell = 1;
581 else
582 tmpAction.bell = 0;
583 }
584 else if ((char *) data == "command_button")
585 {
586 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
587 {
588 tmpAction.command = 1;
589 gtk_entry_set_editable(GTK_ENTRY (entry), TRUE);
590 gtk_entry_set_text(GTK_ENTRY (entry), command);
591 }
592 else
593 {
594 tmpAction.command = 0;
595 gtk_entry_set_text(GTK_ENTRY (entry), "");
596 gtk_entry_set_editable(GTK_ENTRY (entry), FALSE);
597 }
598 }
599 else if ((char *) data == "ok")
600 {
601 if (tmpAction.command)
602 strcpy(command, gtk_entry_get_text(GTK_ENTRY (entry)));
603
604 hour = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON (spinner1));
605 min = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON (spinner2));
606 sec = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON (spinner3));
607 timeSetToZero = 0;
608
609 // If users presses 'ok' and we have not explicitly set the mode,
610 // then it was left on ALARM
611 if (!tmpMode)
612 tmpMode = ALARM;
613
614 mode = tmpMode;
615 // need to reset so that it can default to ALARM if timer not specified
616 tmpMode = NONE;
617 action.bell = tmpAction.bell;
618 action.command = tmpAction.command;
619 configSt = RETURN;
620 }
621 else if (!strcmp((char *) data, "clear"))
622 {
623 command[0] = '\0';
624 gtk_spin_button_set_value(GTK_SPIN_BUTTON (spinner1), 0);
625 gtk_spin_button_set_value(GTK_SPIN_BUTTON (spinner2), 0);
626 gtk_spin_button_set_value(GTK_SPIN_BUTTON (spinner3), 0);
627 gtk_entry_set_text(GTK_ENTRY (entry), command);
628 }
629 else if (!strcmp ((char *) data, "cancel"))
630 configSt = OUT;
631 }
632
633
634 /*******************************************************************************
635 * delete_event This callback quits the program
636 ******************************************************************************/
delete_event(GtkWidget * widget,GdkEvent * event,gpointer data)637 int delete_event(GtkWidget * widget, GdkEvent * event, gpointer data)
638 {
639 return(FALSE);
640 }
641
642
643 /*******************************************************************************
644 * destroy destroys the window
645 ******************************************************************************/
destroy(GtkWidget * widget,gpointer data)646 void destroy(GtkWidget * widget, gpointer data)
647 {
648 gtk_main_quit();
649 }
650
651
652 /*******************************************************************************
653 * configure
654 ******************************************************************************/
configure(void * arg)655 void *configure(void *arg)
656 {
657 GtkWidget *window;
658 GtkWidget *frame;
659 GtkWidget *button;
660 GtkWidget *alarm_button;
661 GtkWidget *timer_button;
662 GtkWidget *chrono_button;
663 GtkWidget *box1;
664 GtkWidget *box2;
665 GtkWidget *sub_vbox;
666 GtkWidget *label;
667 GtkAdjustment *adj;
668
669
670 // Create a new window
671 window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
672 gtk_window_set_title (GTK_WINDOW (window), "Configure");
673 gtk_window_set_wmclass (GTK_WINDOW (window), "wmtimerconf", "");
674
675 // Set a handler for delete_event that immediately exits GTK.
676 gtk_signal_connect (GTK_OBJECT (window), "destroy",
677 GTK_SIGNAL_FUNC (destroy), NULL);
678
679 // Sets the border width of the window.
680 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
681
682 // Create Vertical box
683 box1 = gtk_vbox_new (FALSE, 0);
684 // Add vertical box to main window
685 gtk_container_add (GTK_CONTAINER (window), box1);
686 gtk_widget_show (box1);
687
688 frame = gtk_frame_new ("Mode");
689 gtk_box_pack_start (GTK_BOX (box1), frame, TRUE, TRUE, 2);
690 gtk_widget_show (frame);
691
692 box2 = gtk_hbox_new (FALSE, 0);
693 gtk_container_add (GTK_CONTAINER (frame), box2);
694
695 // Create Alarm radio button
696 alarm_button = gtk_radio_button_new_with_label (NULL, "Alarm");
697 gtk_signal_connect (GTK_OBJECT (alarm_button), "clicked",
698 GTK_SIGNAL_FUNC (callback), (gpointer) "alarm_button");
699 gtk_box_pack_start (GTK_BOX (box2), alarm_button, FALSE, FALSE, 2);
700 gtk_widget_show (alarm_button);
701
702 // Create Timer radio button
703 timer_button = gtk_radio_button_new_with_label (gtk_radio_button_group
704 (GTK_RADIO_BUTTON (alarm_button)), "Timer");
705 gtk_signal_connect (GTK_OBJECT (timer_button), "clicked",
706 GTK_SIGNAL_FUNC (callback), (gpointer) "timer_button");
707 gtk_box_pack_start (GTK_BOX (box2), timer_button, FALSE, FALSE, 2);
708 gtk_widget_show (timer_button);
709 gtk_widget_show (box2);
710
711 // Create Chrono radio button
712 chrono_button = gtk_radio_button_new_with_label (gtk_radio_button_group
713 (GTK_RADIO_BUTTON (alarm_button)), "Chrono");
714 gtk_signal_connect (GTK_OBJECT (chrono_button), "clicked",
715 GTK_SIGNAL_FUNC (callback), (gpointer) "chrono_button");
716 gtk_box_pack_start (GTK_BOX (box2), chrono_button, FALSE, FALSE, 2);
717 gtk_widget_show (chrono_button);
718 gtk_widget_show (box2);
719
720 // If we are in timer mode, set toggle accordingly else default to alarm
721 // Set the button corresponding to the current mode
722 if (mode == TIMER || mode == TIMER_PAUSED || mode == TIMER_DONE)
723 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (timer_button), TRUE);
724 else if (mode == CHRONO || mode == CHRONO_PAUSED)
725 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (chrono_button), TRUE);
726 else
727 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (alarm_button), TRUE);
728
729 // Create frame for the time
730 frame = gtk_frame_new ("Time");
731 gtk_box_pack_start (GTK_BOX (box1), frame, TRUE, TRUE, 2);
732 gtk_widget_show (frame);
733
734 box2 = gtk_hbox_new (FALSE, 0);
735 gtk_container_add (GTK_CONTAINER (frame), box2);
736
737 // Create hours spinner
738 adj = (GtkAdjustment *) gtk_adjustment_new (hour, 0.0, 23.0, 1.0, 2.0, 0.0);
739 spinner1 = gtk_spin_button_new (adj, 0, 0);
740 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner1), TRUE);
741 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinner1), TRUE);
742 gtk_box_pack_start (GTK_BOX (box2), spinner1, FALSE, FALSE, 2);
743 gtk_widget_show (spinner1);
744
745 // Create separator label
746 label = gtk_label_new (" : ");
747 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
748 gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 2);
749 gtk_widget_show (label);
750
751 // Create minutes spinner
752 adj = (GtkAdjustment *) gtk_adjustment_new (min, 0.0, 59.0, 1.0, 5.0, 0.0);
753 spinner2 = gtk_spin_button_new (adj, 0, 0);
754 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner2), TRUE);
755 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinner2), TRUE);
756 gtk_box_pack_start (GTK_BOX (box2), spinner2, FALSE, FALSE, 2);
757 gtk_widget_show (spinner2);
758
759 // Create separator label
760 label = gtk_label_new (" : ");
761 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
762 gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 2);
763 gtk_widget_show (label);
764
765 // Create seconds spinner
766 adj = (GtkAdjustment *) gtk_adjustment_new (sec, 0.0, 59.0, 1.0, 5.0, 0.0);
767 spinner3 = gtk_spin_button_new (adj, 0, 0);
768 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spinner3), TRUE);
769 gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinner3), TRUE);
770 gtk_box_pack_start (GTK_BOX (box2), spinner3, FALSE, FALSE, 2);
771 gtk_widget_show (spinner3);
772 gtk_widget_show (box2);
773
774 // Create frame for 2 buttons and text entry box
775 frame = gtk_frame_new ("Action");
776 gtk_box_pack_start (GTK_BOX (box1), frame, TRUE, TRUE, 2);
777 gtk_widget_show (frame);
778
779 // Create vertical box
780 sub_vbox = gtk_vbox_new (FALSE, 0);
781 gtk_container_add (GTK_CONTAINER (frame), sub_vbox);
782 gtk_widget_show (sub_vbox);
783
784 // Create horizontal box
785 box2 = gtk_hbox_new (FALSE, 0);
786 gtk_box_pack_start (GTK_BOX (sub_vbox), box2, TRUE, TRUE, 2);
787
788 // Create Bell check button
789 button = gtk_check_button_new_with_label ("System Bell");
790 gtk_signal_connect (GTK_OBJECT (button), "clicked",
791 GTK_SIGNAL_FUNC (callback), (gpointer) "bell_button");
792 gtk_box_pack_start (GTK_BOX (box2), button, FALSE, FALSE, 2);
793 gtk_widget_show (button);
794
795 // If bell mode is active, toggle the button
796 if (action.bell)
797 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
798
799 // Create Command check button
800 button = gtk_check_button_new_with_label ("Command");
801 gtk_signal_connect (GTK_OBJECT (button), "clicked",
802 GTK_SIGNAL_FUNC (callback), (gpointer) "command_button");
803 gtk_box_pack_start (GTK_BOX (box2), button, FALSE, FALSE, 2);
804 gtk_widget_show (button);
805 gtk_widget_show (box2);
806
807 // Create horizontal box
808 box2 = gtk_hbox_new (FALSE, 0);
809 gtk_box_pack_start (GTK_BOX (sub_vbox), box2, TRUE, TRUE, 2);
810
811
812 // Create label for text entry box
813 label = gtk_label_new ("Command: ");
814 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
815 gtk_box_pack_start (GTK_BOX (box2), label, FALSE, FALSE, 2);
816 gtk_widget_show (label);
817
818 // Create "Command" text entry area
819 entry = gtk_entry_new_with_max_length (100);
820 gtk_entry_set_editable (GTK_ENTRY (entry), FALSE);
821 gtk_signal_connect (GTK_OBJECT (entry), "activate",
822 GTK_SIGNAL_FUNC (callback), entry);
823 gtk_box_pack_start (GTK_BOX (box2), entry, FALSE, FALSE, 2);
824 gtk_widget_show (entry);
825 gtk_widget_show (box2);
826
827 // If command mode is active, toggle the button and allow user to enter a
828 // command
829 if (action.command)
830 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
831
832 box2 = gtk_hbox_new (FALSE, 0);
833 gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 2);
834
835 // Create "Cancel" button
836 button = gtk_button_new_with_label ("Cancel");
837 gtk_signal_connect (GTK_OBJECT (button), "clicked",
838 GTK_SIGNAL_FUNC (callback), "cancel");
839 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
840 GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (window));
841 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 2);
842 gtk_widget_show (button);
843
844 // Create "Clear" button
845 button = gtk_button_new_with_label ("Clear");
846 gtk_signal_connect (GTK_OBJECT (button), "clicked",
847 GTK_SIGNAL_FUNC (callback), "clear");
848 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 2);
849 gtk_widget_show (button);
850
851 // Create "Ok" button
852 button = gtk_button_new_with_label ("Ok");
853 gtk_signal_connect (GTK_OBJECT (button), "clicked",
854 GTK_SIGNAL_FUNC (callback), "ok");
855 gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
856 GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT (window));
857 gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 2);
858 gtk_widget_show (button);
859
860 gtk_widget_show (box2);
861
862 gtk_widget_show (window);
863
864 gtk_main();
865
866 return 0;
867 }
868
869