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