1 /*
2
3 $Id$
4
5 X G N O K I I
6
7 A Linux/Unix GUI for the mobile phones.
8
9 This file is part of gnokii.
10
11 Gnokii is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 Gnokii is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with gnokii; if not, write to the Free Software
23 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24
25 Copyright (C) 1999 Tomi Ollila
26 Copyright (C) 2003 BORBELY Zoltan
27 Copyright (C) 2004 Pawel Kot
28 Copyright (C) 2005 Jan Derfinak
29
30
31 */
32
33 /*
34 * Id: xring.c
35 *
36 * Author: Tomi Ollila <Tomi.Ollila@iki.fi>
37 *
38 * Copyright (c) 1999 Tomi Ollila
39 * All rights reserved
40 *
41 * Created: Fri Aug 13 17:11:06 1999 too
42 * Last modified: Sun Aug 29 18:50:24 1999 too
43 *
44 * INFO
45 * This program is a quickly written GTK software to interactively create
46 * tunes for some purpote, like cellular phone ring tones.
47 *
48 * Currently the code looks like somebody is just learning (by doing) how
49 * to write GTK programs, and that is just what has happened. Expect
50 * more polished versions ACN
51 *
52 * HISTORY
53 */
54
55 #include "config.h"
56
57 #ifndef WIN32
58 # include <unistd.h>
59 #endif
60 #include <stdio.h>
61 #include <assert.h>
62 #include <errno.h>
63 #include <gtk/gtk.h>
64 #include <gdk/gdkkeysyms.h>
65
66 #include "misc.h"
67 #include "gnokii.h"
68 #include "xgnokii.h"
69 #include "xgnokii_common.h"
70 #include "xgnokii_lowlevel.h"
71
72 #include "xpm/New.xpm"
73 #include "xpm/Send.xpm"
74 #include "xpm/Read.xpm"
75 #include "xpm/Delete.xpm"
76 #include "xpm/Open.xpm"
77 #include "xpm/Save.xpm"
78 #include "xpm/Play.xpm"
79
80 static char *blackparts[] = {
81 ".+@@@@@@@@@@@@+.",
82 "+.+@@@@@@@@@@+.+",
83 "@+.+@@@@@@@@+.+@",
84 "@@+.+@@@@@@+.+@@",
85 "@@@+........+@@@",
86 "@@@@........@@@@"
87 };
88
89 static char *whitestarts[][3] = {
90 {" ++++++++++++++++",
91 " +..............+",
92 "+++++++++..............+"},
93 {
94 " ++++++++ ",
95 " +......+ ",
96 "+++++++++......+++++++++"},
97 {
98 "++++++++++++++++ ",
99 "+..............+ ",
100 "+..............+++++++++"}
101 };
102
103 static char *whiteend[] = {
104 "+......................+",
105 "+@....................@+",
106 "+@@..................@@+",
107 "++@@@..............@@@++",
108 "++++++++++++++++++++++++"
109 };
110
111
writecolors(char * buf0,char * col0,char * buf1,char * col1,char * buf2,char * col2)112 static void writecolors(char *buf0, char *col0,
113 char *buf1, char *col1,
114 char *buf2, char *col2)
115 {
116 sprintf(buf0, ". c #%s", col0);
117 sprintf(buf1, "+ c #%s", col1);
118 sprintf(buf2, "@ c #%s", col2);
119 }
120
121 typedef struct {
122 GdkPixmap *pixmap;
123 GdkBitmap *mask;
124 } PixmapAndMask;
125
126 static int createpixmap(GtkWidget * window, PixmapAndMask * pam, char **a);
127
greateWhitePixmap(GtkWidget * window,PixmapAndMask * pam,char * start[],char * color0,char * color1,char * color2)128 int greateWhitePixmap(GtkWidget * window, PixmapAndMask * pam, char *start[],
129 char *color0, char *color1, char *color2)
130 {
131 int i = 0, j = 0;
132 char *a[160 + 5];
133 char col0[20];
134 char col1[20];
135 char col2[20];
136
137 a[i++] = "24 160 4 1";
138 a[i++] = " c None";
139 writecolors(col0, color0, col1, color1, col2, color2);
140 a[i++] = col0;
141 a[i++] = col1;
142 a[i++] = col2;
143
144 a[i++] = start[0];
145 for (j = 0; j < 99; j++)
146 a[i++] = start[1];
147 a[i++] = start[2];
148
149 for (j = 0; j < 54; j++)
150 a[i++] = whiteend[0];
151
152 a[i++] = whiteend[1];
153 a[i++] = whiteend[1];
154 a[i++] = whiteend[2];
155 a[i++] = whiteend[3];
156 a[i++] = whiteend[4];
157
158 assert(i == 165);
159
160 return createpixmap(window, pam, a);
161 }
162
greateBlackPixmap(GtkWidget * window,PixmapAndMask * pam,char * color0,char * color1,char * color2)163 int greateBlackPixmap(GtkWidget * window, PixmapAndMask * pam,
164 char *color0, char *color1, char *color2)
165 {
166 int i = 0, j = 0;
167 char *a[160 + 4];
168 char col0[20];
169 char col1[20];
170 char col2[20];
171
172 a[i++] = "16 100 3 1";
173 writecolors(col0, color0, col1, color1, col2, color2);
174 a[i++] = col0;
175 a[i++] = col1;
176 a[i++] = col2;
177
178 for (j = 0; j < 5; j++)
179 a[i++] = blackparts[j];
180 for (j = 0; j < 90; j++)
181 a[i++] = blackparts[5];
182 for (j = 4; j >= 0; j--)
183 a[i++] = blackparts[j];
184
185 assert(i == 104);
186
187 return createpixmap(window, pam, a);
188 }
189
createpixmap(GtkWidget * window,PixmapAndMask * pam,char ** a)190 static int createpixmap(GtkWidget * window, PixmapAndMask * pam, char **a)
191 {
192 GtkStyle *style = gtk_widget_get_default_style();
193 pam->pixmap = gdk_pixmap_create_from_xpm_d(window->window,
194 &pam->mask,
195 &style->
196 bg[GTK_STATE_NORMAL],
197 a);
198 return (int) pam->pixmap; /* (to) NULL or not (to) NULL */
199 }
200
201 enum {
202 KIE_BLACK, KIE_BLACKSEL,
203 KIE_WHITEL, KIE_WHITELSEL,
204 KIE_WHITEM, KIE_WHITEMSEL,
205 KIE_WHITER, KIE_WHITERSEL,
206 KIE_COUNT
207 };
208
209 #define WHITE_COUNT 28 /* mit? on pianonkosketin englanniksi */
210
211 struct GUI {
212 GtkWidget *w;
213 GtkWidget *f;
214 GtkAccelGroup *accel;
215 GtkItemFactory *item_factory;
216 GtkWidget *menu;
217 GtkWidget *toolbar;
218 GtkWidget *vbox;
219 GtkWidget *rlist_combo;
220 GtkWidget *name;
221 GtkWidget *tempo_combo;
222 ErrorDialog error_dialog;
223 PixmapAndMask pam[KIE_COUNT];
224 GtkWidget *blacks[WHITE_COUNT - 1];
225 GtkWidget *whites[WHITE_COUNT];
226 int focus;
227 int pressed;
228 gint32 presstime;
229 gint32 releasetime;
230 gchar *file_name;
231 int volume;
232 gn_ringtone ringtone;
233 gn_ringtone_list ringtone_list;
234 };
235
236 static struct GUI gi = {0};
237 static char xwhi[] = {6, 4, 2, 6, 4, 4, 2};
238 static char *beats_per_minute[] = {
239 " 25", " 28", " 31", " 35", " 40", " 45", " 50", " 56", " 63", " 70",
240 " 80", " 90", "100", "112", "125", "140", "160", "180", "200", "225",
241 "250", "285", "320", "355", "400", "450", "500", "565", "635", "715",
242 "800", "900", NULL};
243
244 #define BLACK_PRESSED 64
245 #define WHITE_PRESSED 128
246
247
play_tone(int frequency,int volume,int usec)248 static void play_tone(int frequency, int volume, int usec)
249 {
250 PhoneEvent *e = g_malloc(sizeof(PhoneEvent));
251 D_PlayTone data;
252
253 /* prepare data for event */
254
255 data.frequency = frequency;
256 data.volume = volume;
257 data.usec = usec;
258 e->event = Event_PlayTone;
259 e->data = &data;
260
261 /* launch event and wait for completition */
262 GUI_InsertEvent(e);
263
264 if (usec > 0)
265 while (gtk_events_pending()) gtk_main_iteration_do(FALSE);
266
267 pthread_mutex_lock(&ringtoneMutex);
268 pthread_cond_wait(&ringtoneCond, &ringtoneMutex);
269 pthread_mutex_unlock(&ringtoneMutex);
270 }
271
ringtone_event(int event,gn_ringtone * ringtone)272 static gn_error ringtone_event(int event, gn_ringtone *ringtone)
273 {
274 PhoneEvent *e = g_malloc(sizeof(PhoneEvent));
275 D_Ringtone data;
276
277 /* prepare data for event */
278
279 data.ringtone = ringtone;
280 e->event = event;
281 e->data = &data;
282
283 /* launch event and wait for completition */
284 GUI_InsertEvent(e);
285
286 pthread_mutex_lock(&ringtoneMutex);
287 pthread_cond_wait(&ringtoneCond, &ringtoneMutex);
288 pthread_mutex_unlock(&ringtoneMutex);
289
290 return data.status;
291 }
292
get_ringtone_list(gn_ringtone_list * rlist)293 static void get_ringtone_list(gn_ringtone_list *rlist)
294 {
295 PhoneEvent *e = g_malloc(sizeof(PhoneEvent));
296
297 /* prepare data for event */
298
299 e->event = Event_GetRingtoneList;
300 e->data = rlist;
301
302 /* launch event and wait for completition */
303 GUI_InsertEvent(e);
304
305 pthread_mutex_lock(&ringtoneMutex);
306 pthread_cond_wait(&ringtoneCond, &ringtoneMutex);
307 pthread_mutex_unlock(&ringtoneMutex);
308 }
309
set_pixmap(struct GUI * gui,int flag)310 static void set_pixmap(struct GUI *gui, int flag)
311 {
312 int i = gui->pressed & ~(BLACK_PRESSED | WHITE_PRESSED);
313 int j;
314
315 if (gui->pressed & BLACK_PRESSED) {
316 j = flag ? KIE_BLACKSEL : KIE_BLACK;
317
318 gtk_pixmap_set(GTK_PIXMAP(gui->blacks[i]),
319 gui->pam[j].pixmap, gui->pam[j].mask);
320 } else {
321 j = xwhi[i % 7] + (flag ? 1 : 0);
322 gtk_pixmap_set(GTK_PIXMAP(gui->whites[i]),
323 gui->pam[j].pixmap, gui->pam[j].mask);
324 }
325 }
326
tone_stop(struct GUI * gui)327 static void tone_stop(struct GUI *gui)
328 {
329 int usec;
330
331 if (!gui->pressed) return;
332
333 usec = 1000 * (gui->releasetime - gui->presstime);
334
335 set_pixmap(gui, FALSE);
336 gui->pressed = 0;
337
338 play_tone(0, 0, -1);
339
340 if (gui->releasetime < gui->presstime) {
341 if (gui->ringtone.notes_count) gui->ringtone.notes_count--;
342 return;
343 }
344
345 gn_ringtone_set_duration(&gui->ringtone, gui->ringtone.notes_count ? gui->ringtone.notes_count - 1 : 0, usec);
346
347 #if 0
348 printf("%d %d %3d\n", gui->ringtone.notes[gui->ringtone.notes_count - 1].note / 14,
349 gui->ringtone.notes[gui->ringtone.notes_count - 1].note % 14,
350 gui->ringtone.notes[gui->ringtone.notes_count - 1].duration);
351 #endif
352 }
353
tone_start(struct GUI * gui)354 static void tone_start(struct GUI *gui)
355 {
356 int note, pressed, freq, usec;
357
358 if (!gui->pressed) return;
359
360 set_pixmap(gui, TRUE);
361
362 pressed = gui->pressed & ~(BLACK_PRESSED | WHITE_PRESSED);
363 if (gui->pressed & WHITE_PRESSED) {
364 note = 14 * (pressed / 7) + 2 * (pressed % 7);
365 } else {
366 note = 14 * (pressed / 7) + 2 * (pressed % 7) + 1;
367 }
368
369 gui->ringtone.notes[gui->ringtone.notes_count].note = note;
370 gui->ringtone.notes[gui->ringtone.notes_count].duration = 0;
371 gui->ringtone.notes_count++;
372
373 gn_ringtone_get_tone(&gui->ringtone, gui->ringtone.notes_count - 1, &freq, &usec);
374 play_tone(freq, gui->volume, -1);
375
376 if (gui->ringtone.notes_count >= GN_RINGTONE_MAX_NOTES - 1) {
377 gui->pressed = 0;
378 return;
379 }
380 }
381
load_ringtone_list(void)382 static void load_ringtone_list(void)
383 {
384 GList *list;
385 int i, uidx;
386 char **userdef;
387 gn_ringtone_info *ri;
388
389 get_ringtone_list(&gi.ringtone_list);
390 userdef = g_new0(char *, gi.ringtone_list.userdef_count);
391
392 list = NULL;
393 i = 0;
394 while (i < gi.ringtone_list.count) {
395 if (!gi.ringtone_list.ringtone[i].readable && !gi.ringtone_list.ringtone[i].writable) {
396 memmove(gi.ringtone_list.ringtone + i,
397 gi.ringtone_list.ringtone + i + 1,
398 (GN_RINGTONE_MAX_COUNT - i - 1) * sizeof(gn_ringtone_info));
399 gi.ringtone_list.count--;
400 continue;
401 }
402 uidx = gi.ringtone_list.ringtone[i].location - gi.ringtone_list.userdef_location;
403 if (uidx >= 0 && uidx < gi.ringtone_list.userdef_count) {
404 userdef[uidx] = g_strdup_printf(_("User #%d (%s)"), uidx, gi.ringtone_list.ringtone[i].name);
405 list = g_list_append(list, userdef[uidx]);
406 } else {
407 list = g_list_append(list, gi.ringtone_list.ringtone[i].name);
408 }
409 i++;
410 }
411
412 for (i = 0; i < gi.ringtone_list.userdef_count; i++) {
413 if (gi.ringtone_list.count >= GN_RINGTONE_MAX_COUNT) break;
414 if (userdef[i]) continue;
415
416 ri = gi.ringtone_list.ringtone + gi.ringtone_list.count++;
417 ri->location = gi.ringtone_list.userdef_location + i;
418 ri->name[0] = '\0';
419 ri->user_defined = 0;
420 ri->readable = 0;
421 ri->writable = 1;
422
423 userdef[i] = g_strdup_printf(_("User #%d (*EMPTY*)"), i);
424 list = g_list_append(list, userdef[i]);
425 }
426
427 gtk_combo_set_popdown_strings(GTK_COMBO(gi.rlist_combo), list);
428
429 for (i = 0; i < gi.ringtone_list.userdef_count; i++)
430 if (userdef[i]) g_free(userdef[i]);
431 }
432
get_selected_ringtone(void)433 gn_ringtone_info *get_selected_ringtone(void)
434 {
435 GtkList *list;
436 int pos = -1;
437
438 list = GTK_LIST(GTK_COMBO(gi.rlist_combo)->list);
439 if (list && list->selection)
440 pos = gtk_list_child_position(list, list->selection->data);
441
442 if (pos < 0 || pos > gi.ringtone_list.count) return NULL;
443
444 return gi.ringtone_list.ringtone + pos;
445 }
446
get_ringtone_info(gn_ringtone * ringtone)447 static void get_ringtone_info(gn_ringtone *ringtone)
448 {
449 gn_ringtone_info *ri;
450 char term;
451 int x;
452
453 if (!(ri = get_selected_ringtone())) return;
454 ringtone->location = ri->location;
455
456 snprintf(ringtone->name, sizeof(ringtone->name), "%s", gtk_entry_get_text(GTK_ENTRY(gi.name)));
457
458 if (sscanf(gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(gi.tempo_combo)->entry)), " %d %c", &x, &term) == 1)
459 ringtone->tempo = x;
460 }
461
set_ringtone_info(gn_ringtone * ringtone)462 static void set_ringtone_info(gn_ringtone *ringtone)
463 {
464 char buf[256];
465
466 gtk_entry_set_text(GTK_ENTRY(gi.name), ringtone->name);
467
468 snprintf(buf, sizeof(buf), "%3d", ringtone->tempo);
469 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(gi.tempo_combo)->entry), buf);
470 }
471
472 /* When invoked (via signal delete_event), terminates the application */
close_application(GtkWidget * widget,GdkEvent * event,gpointer data)473 static void close_application(GtkWidget * widget, GdkEvent * event, gpointer data)
474 {
475 if (gi.file_name) {
476 g_free(gi.file_name);
477 gi.file_name = NULL;
478 }
479 play_tone(0, 0, -1);
480
481 // gdk_key_repeat_restore();
482 gtk_widget_hide(gi.w);
483 }
484
key_map(gint keysym)485 static int key_map(gint keysym)
486 {
487 switch (keysym) {
488 case GDK_q: /* h-1 */
489 case GDK_a: return 6 | WHITE_PRESSED; /* h-1 in awerty -keyboard */
490 case GDK_w: return 7 | WHITE_PRESSED; /* c */
491 case GDK_e: return 8 | WHITE_PRESSED; /* d */
492 case GDK_r: return 9 | WHITE_PRESSED; /* e */
493 case GDK_t: return 10 | WHITE_PRESSED; /* f */
494 case GDK_y: /* g */
495 case GDK_z: return 11 | WHITE_PRESSED; /* g in qwertz -keyboard */
496 case GDK_u: return 12 | WHITE_PRESSED; /* a */
497 case GDK_i: return 13 | WHITE_PRESSED; /* h */
498 case GDK_o: return 14 | WHITE_PRESSED; /* c+1 */
499 case GDK_p: return 15 | WHITE_PRESSED; /* d+1 */
500
501 case GDK_1: return 5 | BLACK_PRESSED; /* a-1# */
502 case GDK_3: return 7 | BLACK_PRESSED; /* c# */
503 case GDK_4: return 8 | BLACK_PRESSED; /* d# */
504 case GDK_6: return 10 | BLACK_PRESSED; /* f# */
505 case GDK_7: return 11 | BLACK_PRESSED; /* g# */
506 case GDK_8: return 12 | BLACK_PRESSED; /* a# */
507 case GDK_0: return 14 | BLACK_PRESSED; /* c+1# */
508 }
509 return 0;
510 }
511
button_press(GtkWidget * widget,GdkEvent * event,gpointer data)512 static gboolean button_press(GtkWidget * widget, GdkEvent * event, gpointer data)
513 {
514 GdkEventButton *e = (GdkEventButton *) event;
515 int i;
516
517 if (!gi.focus) {
518 gtk_widget_grab_focus(gi.f);
519 gi.focus = TRUE;
520 }
521
522 if (!gi.pressed) {
523 guint x = e->x;
524 guint y = e->y;
525
526 gi.presstime = e->time;
527
528 if (y < 100) /* a possible black */
529 for (i = 0; i < WHITE_COUNT - 1; i++)
530 if (gi.blacks[i] && x - 16 - 24 * i < 16) {
531 gi.pressed = i | BLACK_PRESSED;
532 tone_start(&gi);
533 return TRUE; /* this a subroutine and we can do more... */
534 }
535 for (i = 0; i < WHITE_COUNT; i++) /* whites ? */
536 if (x - 24 * i < 24) {
537 gi.pressed = i | WHITE_PRESSED;
538 tone_start(&gi);
539 return TRUE;
540 }
541 }
542 return TRUE;
543 }
544
button_release(GtkWidget * widget,GdkEvent * event,gpointer data)545 static gboolean button_release(GtkWidget * widget, GdkEvent * event, gpointer data)
546 {
547 gi.releasetime = event->button.time;
548
549 tone_stop(&gi);
550
551 return TRUE;
552 }
553
focus_in(GtkWidget * widget,GdkEvent * event,gpointer data)554 static gboolean focus_in(GtkWidget * widget, GdkEvent * event, gpointer data)
555 {
556 gi.focus = TRUE;
557 // gdk_key_repeat_disable();
558
559 return TRUE;
560 }
561
focus_out(GtkWidget * widget,GdkEvent * event,gpointer data)562 static gboolean focus_out(GtkWidget * widget, GdkEvent * event, gpointer data)
563 {
564 tone_stop(&gi);
565
566 gi.focus = FALSE;
567 // gdk_key_repeat_restore();
568
569 return TRUE;
570 }
571
key_press(GtkWidget * widget,GdkEvent * event,gpointer data)572 static gboolean key_press(GtkWidget * widget, GdkEvent * event, gpointer data)
573 {
574 int press = key_map(event->key.keyval);
575 /* printf("key press %d\n", press); */
576
577 if (press && !gi.pressed && gi.focus) {
578 gi.presstime = event->key.time;
579 gi.pressed = press;
580 tone_start(&gi);
581 }
582
583 return TRUE;
584 }
585
key_release(GtkWidget * widget,GdkEvent * event,gpointer data)586 static gboolean key_release(GtkWidget * widget, GdkEvent * event, gpointer data)
587 {
588 int press = key_map(event->key.keyval);
589 /* printf("key release %d\n", press); */
590
591 if (press && gi.pressed == press) {
592 gi.releasetime = event->key.time;
593 tone_stop(&gi);
594 }
595
596 return TRUE;
597 }
598
read_ringtone(GtkWidget * w,GtkFileSelection * fs)599 static void read_ringtone(GtkWidget *w, GtkFileSelection *fs)
600 {
601 gchar *file_name;
602 gn_error err;
603
604 if (gi.file_name) {
605 g_free(gi.file_name);
606 gi.file_name = NULL;
607 }
608
609 file_name = (gchar *) gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs));
610 gtk_widget_hide(GTK_WIDGET(fs));
611
612 if ((err = gn_file_ringtone_read(file_name, &gi.ringtone)) != GN_ERR_NONE) {
613 gchar *buf = g_strdup_printf(_("Error reading file\n%s"), gn_error_print(err));
614 gtk_label_set_text(GTK_LABEL(gi.error_dialog.text), buf);
615 gtk_widget_show(gi.error_dialog.dialog);
616 g_free(buf);
617 return;
618 }
619
620 gi.file_name = g_strdup(file_name);
621 set_ringtone_info(&gi.ringtone);
622 }
623
open_ringtone(GtkWidget * w)624 static void open_ringtone(GtkWidget *w)
625 {
626 GtkWidget *file_select;
627
628 file_select = gtk_file_selection_new(_("Open ringtone..."));
629
630 gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(file_select)->ok_button),
631 "clicked", (GtkSignalFunc)read_ringtone, file_select);
632
633 gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(file_select)->cancel_button),
634 "clicked", (GtkSignalFunc)gtk_widget_destroy, GTK_OBJECT(file_select));
635
636 gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(file_select));
637
638 gtk_widget_show(file_select);
639 }
640
write_ringtone(GtkWidget * w,GtkFileSelection * fs)641 static void write_ringtone(GtkWidget *w, GtkFileSelection *fs)
642 {
643 gchar *file_name;
644 gn_error err;
645
646 file_name = (gchar *) gtk_file_selection_get_filename(GTK_FILE_SELECTION(fs));
647 gtk_widget_hide(GTK_WIDGET(fs));
648
649 if ((err = gn_file_ringtone_save(file_name, &gi.ringtone)) != GN_ERR_NONE) {
650 gchar *buf = g_strdup_printf(_("Error writing file\n%s"), gn_error_print(err));
651 gtk_label_set_text(GTK_LABEL(gi.error_dialog.text), buf);
652 gtk_widget_show(gi.error_dialog.dialog);
653 g_free(buf);
654 return;
655 }
656
657 if (gi.file_name) {
658 g_free(gi.file_name);
659 gi.file_name = NULL;
660 }
661 gi.file_name = g_strdup(file_name);
662 }
663
save_ringtone_as(GtkWidget * w)664 static void save_ringtone_as(GtkWidget *w)
665 {
666 GtkWidget *file_select;
667
668 get_ringtone_info(&gi.ringtone);
669
670 file_select = gtk_file_selection_new(_("Save ringtone as..."));
671
672 gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(file_select)->ok_button),
673 "clicked", (GtkSignalFunc)write_ringtone, file_select);
674
675 gtk_signal_connect_object(GTK_OBJECT(GTK_FILE_SELECTION(file_select)->cancel_button),
676 "clicked", (GtkSignalFunc)gtk_widget_destroy, GTK_OBJECT(file_select));
677
678 gtk_widget_show(file_select);
679 }
680
save_ringtone(GtkWidget * w)681 static void save_ringtone(GtkWidget *w)
682 {
683 gn_error err;
684
685 get_ringtone_info(&gi.ringtone);
686
687 if (!gi.file_name) {
688 save_ringtone_as(w);
689 return;
690 }
691
692 if ((err = gn_file_ringtone_save(gi.file_name, &gi.ringtone)) != GN_ERR_NONE) {
693 gchar *buf = g_strdup_printf(_("Error writing file\n%s"), gn_error_print(err));
694 gtk_label_set_text(GTK_LABEL(gi.error_dialog.text), buf);
695 gtk_widget_show(gi.error_dialog.dialog);
696 g_free(buf);
697 return;
698 }
699 }
700
play_ringtone(GtkWidget * w)701 static void play_ringtone(GtkWidget *w)
702 {
703 int i, freq, usec;
704
705 get_ringtone_info(&gi.ringtone);
706
707 set_pixmap(&gi, FALSE);
708 for (i = 0; i < gi.ringtone.notes_count; i++) {
709 if (gi.ringtone.notes[i].note == 255) {
710 gn_ringtone_get_tone(&gi.ringtone, i, &freq, &usec);
711 play_tone(freq, gi.volume, usec - 10000);
712 continue;
713 }
714 if (gi.ringtone.notes[i].note & 1)
715 gi.pressed = BLACK_PRESSED + gi.ringtone.notes[i].note / 2;
716 else
717 gi.pressed = WHITE_PRESSED + gi.ringtone.notes[i].note / 2;
718 set_pixmap(&gi, TRUE);
719 gn_ringtone_get_tone(&gi.ringtone, i, &freq, &usec);
720 play_tone(freq, gi.volume, usec - 30000);
721 set_pixmap(&gi, FALSE);
722 while (gtk_events_pending()) gtk_main_iteration_do(FALSE);
723 usleep(20000);
724 }
725
726 play_tone(0, 0, 0);
727 }
728
get_ringtone(GtkWidget * w)729 static void get_ringtone(GtkWidget *w)
730 {
731 gn_error err;
732 gn_ringtone_info *ri;
733
734 ri = get_selected_ringtone();
735 if (!ri) {
736 gchar *buf = g_strdup_printf(_("Empty ringtone list"));
737 gtk_label_set_text(GTK_LABEL(gi.error_dialog.text), buf);
738 gtk_widget_show(gi.error_dialog.dialog);
739 g_free(buf);
740 return;
741 }
742
743 gi.ringtone.location = ri->location;
744
745 if ((err = ringtone_event(Event_GetRingtone, &gi.ringtone)) != GN_ERR_NONE) {
746 gchar *buf = g_strdup_printf(_("Error getting ringtone\n%s"), gn_error_print(err));
747 gtk_label_set_text(GTK_LABEL(gi.error_dialog.text), buf);
748 gtk_widget_show(gi.error_dialog.dialog);
749 g_free(buf);
750 return;
751 }
752
753 set_ringtone_info(&gi.ringtone);
754 }
755
set_ringtone(GtkWidget * w)756 static void set_ringtone(GtkWidget *w)
757 {
758 gn_error err;
759
760 get_ringtone_info(&gi.ringtone);
761
762 if ((err = ringtone_event(Event_SetRingtone, &gi.ringtone)) != GN_ERR_NONE) {
763 gchar *buf = g_strdup_printf(_("Error setting ringtone\n%s"), gn_error_print(err));
764 gtk_label_set_text(GTK_LABEL(gi.error_dialog.text), buf);
765 gtk_widget_show(gi.error_dialog.dialog);
766 g_free(buf);
767 return;
768 }
769
770 load_ringtone_list();
771 }
772
delete_ringtone(GtkWidget * w)773 static void delete_ringtone(GtkWidget *w)
774 {
775 gn_error err;
776 gn_ringtone ringtone;
777
778 memset(&ringtone, 0, sizeof(ringtone));
779 get_ringtone_info(&ringtone);
780
781 if ((err = ringtone_event(Event_DeleteRingtone, &ringtone)) != GN_ERR_NONE) {
782 gchar *buf = g_strdup_printf(_("Error deleting ringtone\n%s"), gn_error_print(err));
783 gtk_label_set_text(GTK_LABEL(gi.error_dialog.text), buf);
784 gtk_widget_show(gi.error_dialog.dialog);
785 g_free(buf);
786 return;
787 }
788
789 load_ringtone_list();
790 }
791
clear_ringtone(GtkWidget * w)792 static void clear_ringtone(GtkWidget *w)
793 {
794 gi.volume = 1;
795 if (gi.file_name) {
796 g_free(gi.file_name);
797 gi.file_name = NULL;
798 }
799 memset(&gi.ringtone, 0, sizeof(gn_ringtone));
800 gi.ringtone.tempo = 120;
801
802 set_ringtone_info(&gi.ringtone);
803 }
804
805
GUI_CreateXringWindow(void)806 void GUI_CreateXringWindow(void)
807 {
808 int i;
809 GList *list;
810 GtkItemFactoryEntry menu_items[] = {
811 {NULL, NULL, NULL, 0, "<Branch>"},
812 {NULL, "<control>O", open_ringtone, 0, NULL},
813 {NULL, "<control>S", save_ringtone, 0, NULL},
814 {NULL, NULL, save_ringtone_as, 0, NULL},
815 {NULL, NULL, NULL, 0, "<Separator>"},
816 {NULL, NULL, get_ringtone, 0, NULL},
817 {NULL, NULL, set_ringtone, 0, NULL},
818 {NULL, NULL, delete_ringtone, 0, NULL},
819 {NULL, NULL, play_ringtone, 0, NULL},
820 {NULL, NULL, NULL, 0, "<Separator>"},
821 {NULL, "<control>W", close_application,0, NULL},
822 {NULL, NULL, NULL, 0, "<Branch>"},
823 {NULL, NULL, clear_ringtone, 0, NULL}
824 };
825
826 menu_items[0].path = _("/_File");
827 menu_items[1].path = _("/File/_Open");
828 menu_items[2].path = _("/File/_Save");
829 menu_items[3].path = _("/File/Save _as ...");
830 menu_items[4].path = _("/File/S1");
831 menu_items[5].path = _("/File/_Get ringtone");
832 menu_items[6].path = _("/File/Se_t ringtone");
833 menu_items[7].path = _("/File/Delete ringtone");
834 menu_items[8].path = _("/File/_Play");
835 menu_items[9].path = _("/File/S2");
836 menu_items[10].path = _("/File/_Close");
837 menu_items[11].path = _("/_Edit");
838 menu_items[12].path = _("/Edit/_Clear");
839
840 /* create toplevel window */
841
842 gi.w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
843 gtk_window_set_wmclass(GTK_WINDOW(gi.w), "RingtoneWindow", "Xgnokii");
844 gtk_window_set_policy(GTK_WINDOW(gi.w), FALSE, FALSE, TRUE);
845 gtk_window_set_title(GTK_WINDOW(gi.w), _("Ringtone"));
846 gtk_container_set_border_width(GTK_CONTAINER(gi.w), 4);
847
848 gtk_signal_connect(GTK_OBJECT(gi.w), "delete_event",
849 GTK_SIGNAL_FUNC(close_application), &gi);
850
851 gtk_widget_realize(gi.w);
852
853 /* create vbox */
854
855 gi.vbox = gtk_vbox_new(FALSE, 1);
856 gtk_container_add(GTK_CONTAINER(gi.w), gi.vbox);
857
858 /* create menubar */
859
860 gi.accel = gtk_accel_group_new();
861 gtk_window_add_accel_group(GTK_WINDOW(gi.w), gi.accel);
862 gi.item_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<main>", gi.accel);
863 gtk_item_factory_create_items(gi.item_factory, sizeof(menu_items) / sizeof(menu_items[0]), menu_items, NULL);
864 gi.menu = gtk_item_factory_get_widget(gi.item_factory, "<main>");
865
866 gtk_box_pack_start(GTK_BOX(gi.vbox), gi.menu, FALSE, FALSE, 0);
867
868 /* create toolbar */
869
870 gi.toolbar = gtk_toolbar_new();
871 gtk_toolbar_set_style(GTK_TOOLBAR(gi.toolbar), GTK_TOOLBAR_ICONS);
872 gtk_toolbar_set_orientation(GTK_TOOLBAR(gi.toolbar), GTK_ORIENTATION_HORIZONTAL);
873
874 gtk_toolbar_append_item(GTK_TOOLBAR(gi.toolbar), NULL, _("Clear ringtone"), NULL,
875 NewPixmap(New_xpm, gi.w->window, &gi.w->style->bg[GTK_STATE_NORMAL]),
876 (GtkSignalFunc)clear_ringtone, gi.toolbar);
877
878 gtk_toolbar_append_space(GTK_TOOLBAR(gi.toolbar));
879
880 gtk_toolbar_append_item(GTK_TOOLBAR(gi.toolbar), NULL, _("Get ringtone"), NULL,
881 NewPixmap(Read_xpm, gi.w->window, &gi.w->style->bg[GTK_STATE_NORMAL]),
882 (GtkSignalFunc)get_ringtone, gi.toolbar);
883
884 gtk_toolbar_append_item(GTK_TOOLBAR(gi.toolbar), NULL, _("Set ringtone"), NULL,
885 NewPixmap(Send_xpm, gi.w->window, &gi.w->style->bg[GTK_STATE_NORMAL]),
886 (GtkSignalFunc)set_ringtone, gi.toolbar);
887
888 gtk_toolbar_append_item(GTK_TOOLBAR(gi.toolbar), NULL, _("Delete ringtone"), NULL,
889 NewPixmap(Delete_xpm, gi.w->window, &gi.w->style->bg[GTK_STATE_NORMAL]),
890 (GtkSignalFunc)delete_ringtone, gi.toolbar);
891
892 gtk_toolbar_append_space(GTK_TOOLBAR(gi.toolbar));
893
894 gtk_toolbar_append_item(GTK_TOOLBAR(gi.toolbar), NULL, _("Import from file"), NULL,
895 NewPixmap(Open_xpm, gi.w->window, &gi.w->style->bg[GTK_STATE_NORMAL]),
896 (GtkSignalFunc)open_ringtone, gi.toolbar);
897
898 gtk_toolbar_append_item(GTK_TOOLBAR(gi.toolbar), NULL, _("Export to file"), NULL,
899 NewPixmap(Save_xpm, gi.w->window, &gi.w->style->bg[GTK_STATE_NORMAL]),
900 (GtkSignalFunc)save_ringtone, gi.toolbar);
901
902 gtk_toolbar_append_space(GTK_TOOLBAR(gi.toolbar));
903
904 gtk_toolbar_append_item(GTK_TOOLBAR(gi.toolbar), NULL, _("Play"), NULL,
905 NewPixmap(Play_xpm, gi.w->window, &gi.w->style->bg[GTK_STATE_NORMAL]),
906 (GtkSignalFunc)play_ringtone, gi.toolbar);
907
908 gtk_toolbar_append_space(GTK_TOOLBAR(gi.toolbar));
909
910 gi.rlist_combo = gtk_combo_new();
911 gtk_combo_set_use_arrows_always(GTK_COMBO(gi.rlist_combo), 1);
912 gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(gi.rlist_combo)->entry), FALSE);
913 gtk_toolbar_append_widget(GTK_TOOLBAR(gi.toolbar), gi.rlist_combo, _("Select ringtone"), NULL);
914
915 gtk_toolbar_append_space(GTK_TOOLBAR(gi.toolbar));
916
917 gi.name = gtk_entry_new();
918 gtk_toolbar_append_widget(GTK_TOOLBAR(gi.toolbar), gi.name, _("Ringtone name"), NULL);
919
920 gtk_toolbar_append_space(GTK_TOOLBAR(gi.toolbar));
921
922 gi.tempo_combo = gtk_combo_new();
923 gtk_combo_set_use_arrows_always(GTK_COMBO(gi.tempo_combo), 1);
924 gtk_widget_set_usize(gi.tempo_combo, 60, -1);
925 gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(gi.tempo_combo)->entry), TRUE);
926 gtk_entry_set_max_length(GTK_ENTRY(GTK_COMBO(gi.tempo_combo)->entry), 3);
927 for (list = NULL, i = 0; beats_per_minute[i]; i++)
928 list = g_list_append(list, beats_per_minute[i]);
929 gtk_combo_set_popdown_strings(GTK_COMBO(gi.tempo_combo), list);
930 gtk_toolbar_append_widget(GTK_TOOLBAR(gi.toolbar), gi.tempo_combo, _("Set tempo"), NULL);
931
932 gtk_box_pack_start(GTK_BOX(gi.vbox), gi.toolbar, FALSE, FALSE, 0);
933
934 /* create fixed */
935
936 gi.f = gtk_fixed_new();
937 gtk_fixed_set_has_window(GTK_FIXED(gi.f), TRUE);
938 gtk_widget_set_usize(gi.f, 672, 160);
939 gtk_box_pack_start(GTK_BOX(gi.vbox), gi.f, FALSE, FALSE, 0);
940
941 gtk_widget_add_events(gi.f, GDK_FOCUS_CHANGE_MASK |
942 GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
943 GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK |
944 GDK_BUTTON_PRESS_MASK |
945 GDK_BUTTON_RELEASE_MASK);
946
947 GTK_WIDGET_SET_FLAGS(gi.f, GTK_CAN_FOCUS);
948
949 gtk_signal_connect(GTK_OBJECT(gi.f), "key_press_event",
950 GTK_SIGNAL_FUNC(key_press), &gi);
951 gtk_signal_connect(GTK_OBJECT(gi.f), "key_release_event",
952 GTK_SIGNAL_FUNC(key_release), &gi);
953
954 /*
955 gtk_signal_connect(GTK_OBJECT(gi.f), "focus_in_event",
956 GTK_SIGNAL_FUNC(focus_in), &gi);
957 gtk_signal_connect(GTK_OBJECT(gi.f), "focus_out_event",
958 GTK_SIGNAL_FUNC(focus_out), &gi);
959 */
960 gtk_signal_connect(GTK_OBJECT(gi.f), "enter_notify_event",
961 GTK_SIGNAL_FUNC(focus_in), &gi);
962 gtk_signal_connect(GTK_OBJECT(gi.f), "leave_notify_event",
963 GTK_SIGNAL_FUNC(focus_out), &gi);
964
965 gtk_signal_connect(GTK_OBJECT(gi.f), "button_press_event",
966 GTK_SIGNAL_FUNC(button_press), &gi);
967 gtk_signal_connect(GTK_OBJECT(gi.f), "button_release_event",
968 GTK_SIGNAL_FUNC(button_release), &gi);
969
970 greateBlackPixmap(gi.w, &gi.pam[KIE_BLACK], "333333", "666666",
971 "999999");
972 greateBlackPixmap(gi.w, &gi.pam[KIE_BLACKSEL], "000000", "333333",
973 "666666");
974
975 for (i = 0; i < 6; i += 2) {
976 greateWhitePixmap(gi.w, &gi.pam[KIE_WHITEL + i],
977 whitestarts[i / 2], "FFFFFF", "999999",
978 "CCCCCC");
979 greateWhitePixmap(gi.w, &gi.pam[KIE_WHITELSEL + i],
980 whitestarts[i / 2], "CCCCCC", "666666",
981 "999999");
982 }
983
984 for (i = 0; i < WHITE_COUNT - 1; i++) {
985 PixmapAndMask *b = &gi.pam[KIE_BLACK];
986 if (xwhi[i % 7] == 2)
987 continue;
988 gi.blacks[i] = gtk_pixmap_new(b->pixmap, b->mask);
989 gtk_fixed_put(GTK_FIXED(gi.f), gi.blacks[i], 16 + 24 * i,
990 0);
991 }
992
993 for (i = 0; i < WHITE_COUNT; i++) {
994 int j = xwhi[i % 7];
995 gi.whites[i] =
996 gtk_pixmap_new(gi.pam[j].pixmap, gi.pam[j].mask);
997 gtk_fixed_put(GTK_FIXED(gi.f), gi.whites[i], 24 * i, 0);
998 }
999
1000 CreateErrorDialog(&gi.error_dialog, gi.w);
1001 }
1002
GUI_ShowXring(void)1003 void GUI_ShowXring(void)
1004 {
1005 clear_ringtone(NULL);
1006
1007 load_ringtone_list();
1008
1009 gi.focus = FALSE;
1010 gi.pressed = 0;
1011
1012 gtk_widget_show_all(gi.w);
1013 gtk_window_present(GTK_WINDOW(gi.w));
1014 gtk_widget_grab_focus(gi.f);
1015 }
1016