1 /*
2 TiMidity++ -- MIDI to WAVE converter and player
3 Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
4 Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 gtk_i.c - Glenn Trigg 29 Oct 1998
21
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif /* HAVE_CONFIG_H*/
27
28 #include <string.h>
29 #ifdef HAVE_GLOB_H
30 #include <glob.h>
31 #endif
32 #if HAVE_SYS_PARAM_H
33 #include <sys/param.h>
34 #endif
35 #include <gtk/gtk.h>
36
37 #include "timidity.h"
38 #include "common.h"
39 #include "output.h"
40 #include "gtk_h.h"
41
42 #include "pixmaps/playpaus.xpm"
43 #include "pixmaps/prevtrk.xpm"
44 #include "pixmaps/nexttrk.xpm"
45 #include "pixmaps/rew.xpm"
46 #include "pixmaps/ff.xpm"
47 #include "pixmaps/restart.xpm"
48 #include "pixmaps/quit.xpm"
49 #include "pixmaps/quiet.xpm"
50 #include "pixmaps/loud.xpm"
51 #include "pixmaps/open.xpm"
52 #include "pixmaps/keyup.xpm"
53 #include "pixmaps/keydown.xpm"
54 #include "pixmaps/slow.xpm"
55 #include "pixmaps/fast.xpm"
56 #include "pixmaps/timidity.xpm"
57
58 static GtkWidget *create_menubar(void);
59 static GtkWidget *create_button_with_pixmap(GtkWidget *, gchar **, gint, gchar *);
60 static GtkWidget *create_pixmap_label(GtkWidget *, gchar **);
61 static gint delete_event(GtkWidget *, GdkEvent *, gpointer);
62 static void destroy (GtkWidget *, gpointer);
63 static GtkTooltips *create_yellow_tooltips(void);
64 static void handle_input(gpointer, gint, GdkInputCondition);
65 static void generic_cb(GtkWidget *, gpointer);
66 static void generic_scale_cb(GtkAdjustment *, gpointer);
67 static void open_file_cb(GtkWidget *, gpointer);
68 static void playlist_cb(GtkWidget *, guint);
69 static void playlist_op(GtkWidget *, guint);
70 static void file_list_cb(GtkWidget *, gint, gint, GdkEventButton *, gpointer);
71 static void clear_all_cb(GtkWidget *, gpointer);
72 static void filer_cb(GtkWidget *, gpointer);
73 static void tt_toggle_cb(GtkWidget *, gpointer);
74 static void locate_update_cb(GtkWidget *, GdkEventButton *, gpointer);
75 static void my_adjustment_set_value(GtkAdjustment *, gint);
76 static void set_icon_pixmap(GtkWidget *, gchar **);
77
78 static GtkWidget *window, *clist, *text, *vol_scale, *locator;
79 static GtkWidget *filesel = NULL, *plfilesel = NULL;
80 static GtkWidget *tot_lbl, *cnt_lbl, *auto_next, *ttshow;
81 static GtkTooltips *ttip;
82 static int file_number_to_play; /* Number of the file we're playing in the list */
83 static int max_sec, is_quitting = 0, locating = 0, local_adjust = 0;
84
85 static GtkItemFactoryEntry ife[] = {
86 {"/File/Open", "<control>O", open_file_cb, 0, NULL},
87 {"/File/sep", NULL, NULL, 0, "<Separator>"},
88 {"/File/Load Playlist", "<control>L", playlist_cb,
89 'l', NULL},
90 {"/File/Save Playlist", "<control>S", playlist_cb,
91 's', NULL},
92 {"/File/sep", NULL, NULL, 0, "<Separator>"},
93 {"/File/Quit", "<control>Q", generic_cb, GTK_QUIT, NULL},
94 {"/Options/Auto next", "<control>A", NULL, 0, "<CheckItem>"},
95 {"/Options/Show tooltips", "<control>T", tt_toggle_cb, 0, "<CheckItem>"},
96 {"/Options/Clear All", "<control>C", clear_all_cb, 0, NULL}
97 };
98
99 #ifdef HAVE_GTK_2
100 static GtkTextBuffer *textbuf;
101 static GtkTextIter iter, start_iter, end_iter;
102 static GtkTextMark *mark;
103 #endif
104
105 /*----------------------------------------------------------------------*/
106
107 static void
generic_cb(GtkWidget * widget,gpointer data)108 generic_cb(GtkWidget *widget, gpointer data)
109 {
110 gtk_pipe_int_write(GPOINTER_TO_INT(data));
111 if(GPOINTER_TO_INT(data) == GTK_PAUSE) {
112 gtk_label_set(GTK_LABEL(cnt_lbl), "Pause");
113 }
114 }
115
116 static void
tt_toggle_cb(GtkWidget * widget,gpointer data)117 tt_toggle_cb(GtkWidget *widget, gpointer data)
118 {
119 if( GTK_CHECK_MENU_ITEM(ttshow)->active ) {
120 gtk_tooltips_enable(ttip);
121 }
122 else {
123 gtk_tooltips_disable(ttip);
124 }
125 }
126
127 static void
open_file_cb(GtkWidget * widget,gpointer data)128 open_file_cb(GtkWidget *widget, gpointer data)
129 {
130 if( ! filesel ) {
131 filesel = gtk_file_selection_new("Open File");
132 gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(filesel));
133
134 #ifdef HAVE_GTK_2
135 gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(filesel)->ok_button),
136 "clicked",
137 G_CALLBACK (filer_cb), GINT_TO_POINTER(1));
138 #else
139 gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(filesel)->ok_button),
140 "clicked",
141 GTK_SIGNAL_FUNC (filer_cb), GINT_TO_POINTER(1));
142 #endif
143 #ifdef HAVE_GTK_2
144 gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(filesel)->cancel_button),
145 "clicked",
146 G_CALLBACK (filer_cb), GINT_TO_POINTER(0));
147 #else
148 gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(filesel)->cancel_button),
149 "clicked",
150 GTK_SIGNAL_FUNC (filer_cb), GINT_TO_POINTER(0));
151 #endif
152 }
153
154 gtk_widget_show(GTK_WIDGET(filesel));
155 }
156
157 static void
filer_cb(GtkWidget * widget,gpointer data)158 filer_cb(GtkWidget *widget, gpointer data)
159 {
160 gchar *filenames[2];
161 #ifdef GLOB_BRACE
162 int i;
163 #ifdef HAVE_GTK_2
164 const gchar *patt;
165 #else
166 gchar *patt;
167 #endif
168 glob_t pglob;
169
170 if(GPOINTER_TO_INT(data) == 1) {
171 patt = gtk_file_selection_get_filename(GTK_FILE_SELECTION(filesel));
172 if(glob(patt, GLOB_BRACE|GLOB_NOMAGIC|GLOB_TILDE, NULL, &pglob))
173 return;
174 for( i = 0; i < pglob.gl_pathc; i++) {
175 filenames[0] = pglob.gl_pathv[i];
176 filenames[1] = NULL;
177 gtk_clist_append(GTK_CLIST(clist), filenames);
178 }
179 globfree(&pglob);
180 }
181 #else
182 if((int)data == 1) {
183 filenames[0] = gtk_file_selection_get_filename(GTK_FILE_SELECTION(filesel));
184 filenames[1] = NULL;
185 gtk_clist_append(GTK_CLIST(clist), filenames);
186 }
187 #endif
188 gtk_widget_hide(filesel);
189 gtk_clist_columns_autosize(GTK_CLIST(clist));
190 }
191
192 static void
generic_scale_cb(GtkAdjustment * adj,gpointer data)193 generic_scale_cb(GtkAdjustment *adj, gpointer data)
194 {
195 if(local_adjust)
196 return;
197
198 gtk_pipe_int_write(GPOINTER_TO_INT(data));
199
200 /* This is a bit of a hack as the volume scale (a GtkVScale) seems
201 to have it's minimum at the top which is counter-intuitive. */
202 if(GPOINTER_TO_INT(data) == GTK_CHANGE_VOLUME) {
203 gtk_pipe_int_write(MAX_AMPLIFICATION - adj->value);
204 }
205 else {
206 gtk_pipe_int_write((int)adj->value*100);
207 }
208 }
209
210 static void
file_list_cb(GtkWidget * widget,gint row,gint column,GdkEventButton * event,gpointer data)211 file_list_cb(GtkWidget *widget, gint row, gint column,
212 GdkEventButton *event, gpointer data)
213 {
214 gint retval;
215 gchar *fname;
216
217 if(event && (event->button == 3)) {
218 if(event->type == GDK_2BUTTON_PRESS) {
219 gtk_clist_remove(GTK_CLIST(clist), row);
220 }
221 else {
222 return;
223 }
224 }
225 retval = gtk_clist_get_text(GTK_CLIST(widget), row, 0, &fname);
226 if(retval) {
227 gtk_pipe_int_write(GTK_PLAY_FILE);
228 gtk_pipe_string_write(fname);
229 file_number_to_play=row;
230 }
231 }
232
233 static void
playlist_cb(GtkWidget * widget,guint data)234 playlist_cb(GtkWidget *widget, guint data)
235 {
236 const gchar *pldir;
237 gchar *plpatt;
238
239 if( ! plfilesel ) {
240 plfilesel = gtk_file_selection_new("");
241 gtk_file_selection_hide_fileop_buttons(GTK_FILE_SELECTION(plfilesel));
242
243 pldir = g_getenv("TIMIDITY_PLAYLIST_DIR");
244 if(pldir != NULL) {
245 plpatt = g_strconcat(pldir, "/*.tpl", NULL);
246 gtk_file_selection_set_filename(GTK_FILE_SELECTION(plfilesel),
247 plpatt);
248 g_free(plpatt);
249 }
250
251 gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(plfilesel)->ok_button),
252 "clicked",
253 GTK_SIGNAL_FUNC (playlist_op), (gpointer)1);
254 gtk_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(plfilesel)->cancel_button),
255 "clicked",
256 GTK_SIGNAL_FUNC (playlist_op), NULL);
257 }
258
259 gtk_window_set_title(GTK_WINDOW(plfilesel), ((char)data == 'l')?
260 "Load Playlist":
261 "Save Playlist");
262 gtk_object_set_user_data(GTK_OBJECT(plfilesel), GINT_TO_POINTER(data));
263 gtk_file_selection_complete(GTK_FILE_SELECTION(plfilesel), "*.tpl");
264
265 gtk_widget_show(plfilesel);
266 } /* playlist_cb */
267
268 static void
playlist_op(GtkWidget * widget,guint data)269 playlist_op(GtkWidget *widget, guint data)
270 {
271 int i;
272 const gchar *filename[2];
273 gchar action, *rowdata, fname[BUFSIZ], *tmp;
274 FILE *plfp;
275
276 gtk_widget_hide(plfilesel);
277
278 if(!data)
279 return;
280
281 action = GPOINTER_TO_INT(gtk_object_get_user_data(GTK_OBJECT(plfilesel)));
282 filename[0] = gtk_file_selection_get_filename(GTK_FILE_SELECTION(plfilesel));
283
284 if(action == 'l') {
285 if((plfp = fopen(filename[0], "r")) == NULL) {
286 g_error("Can't open %s for reading.", filename[0]);
287 return;
288 }
289 while(fgets(fname, BUFSIZ, plfp) != NULL) {
290 gchar *filename[2];
291 if(fname[strlen(fname) - 1] == '\n')
292 fname[strlen(fname) - 1] = '\0';
293 filename[0] = fname;
294 filename[1] = NULL;
295 gtk_clist_append(GTK_CLIST(clist), filename);
296 }
297 fclose(plfp);
298 gtk_clist_columns_autosize(GTK_CLIST(clist));
299 }
300 else if(action == 's') {
301 if((plfp = fopen(filename[0], "w")) == NULL) {
302 g_error("Can't open %s for writing.", filename[0]);
303 return;
304 }
305 for(i = 0; i < GTK_CLIST(clist)->rows; i++) {
306 gtk_clist_get_text(GTK_CLIST(clist), i, 0, &rowdata);
307 /* Make sure we have an absolute path. */
308 if(*rowdata != '/') {
309 tmp = g_get_current_dir();
310 rowdata = g_strconcat(tmp, "/", rowdata, NULL);
311 fprintf(plfp, "%s\n", rowdata);
312 g_free(rowdata);
313 g_free(tmp);
314 }
315 else {
316 fprintf(plfp, "%s\n", rowdata);
317 }
318 }
319 fclose(plfp);
320 }
321 else {
322 g_error("Invalid playlist action!.");
323 }
324 } /* playlist_op */
325
326 static void
clear_all_cb(GtkWidget * widget,gpointer data)327 clear_all_cb(GtkWidget *widget, gpointer data)
328 {
329 gtk_clist_clear(GTK_CLIST(clist));
330 } /* clear_all_cb */
331
332 static gint
delete_event(GtkWidget * widget,GdkEvent * event,gpointer data)333 delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
334 {
335 return (FALSE);
336 }
337
338 static void
destroy(GtkWidget * widget,gpointer data)339 destroy (GtkWidget *widget, gpointer data)
340 {
341 is_quitting = 1;
342 gtk_pipe_int_write(GTK_QUIT);
343 }
344
345 static void
locate_update_cb(GtkWidget * widget,GdkEventButton * ev,gpointer data)346 locate_update_cb (GtkWidget *widget, GdkEventButton *ev, gpointer data)
347 {
348 if( (ev->button == 1) || (ev->button == 2)) {
349 if( ev->type == GDK_BUTTON_RELEASE ) {
350 locating = 0;
351 }
352 else {
353 locating = 1;
354 }
355 }
356 }
357
358 static void
my_adjustment_set_value(GtkAdjustment * adj,gint value)359 my_adjustment_set_value(GtkAdjustment *adj, gint value)
360 {
361 local_adjust = 1;
362 gtk_adjustment_set_value(adj, (gfloat)value);
363 local_adjust = 0;
364 }
365
366 void
Launch_Gtk_Process(int pipe_number)367 Launch_Gtk_Process(int pipe_number)
368 {
369 int argc = 0;
370 gchar **argv = NULL;
371 GtkWidget *button, *mbar, *swin;
372 GtkWidget *table, *align, *handlebox;
373 GtkWidget *vbox, *hbox, *vbox2, *scrolled_win;
374 GtkObject *adj;
375
376 /* enable locale */
377 gtk_set_locale ();
378
379 gtk_init (&argc, &argv);
380
381 ttip = create_yellow_tooltips();
382 window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
383 gtk_widget_set_name(window, "TiMidity");
384 gtk_window_set_title(GTK_WINDOW(window), "TiMidity - MIDI Player");
385 gtk_window_set_wmclass(GTK_WINDOW(window), "timidity", "TiMidity");
386
387 gtk_signal_connect(GTK_OBJECT(window), "delete_event",
388 GTK_SIGNAL_FUNC (delete_event), NULL);
389
390 gtk_signal_connect(GTK_OBJECT(window), "destroy",
391 GTK_SIGNAL_FUNC (destroy), NULL);
392
393 vbox = gtk_vbox_new(FALSE, 0);
394 gtk_container_add(GTK_CONTAINER(window), vbox);
395
396 mbar = create_menubar();
397 gtk_box_pack_start(GTK_BOX(vbox), mbar, FALSE, FALSE, 0);
398
399 scrolled_win = gtk_scrolled_window_new(NULL, NULL);
400 gtk_box_pack_start(GTK_BOX(vbox), scrolled_win, TRUE, TRUE ,0);
401 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_win),GTK_POLICY_NEVER, GTK_POLICY_ALWAYS);
402 gtk_widget_show(scrolled_win);
403
404 #ifdef HAVE_GTK_2
405 text = gtk_text_view_new();
406 gtk_text_view_set_editable(GTK_TEXT_VIEW(text), FALSE);
407 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(text), GTK_WRAP_WORD);
408 #else
409 text = gtk_text_new(NULL, NULL);
410 #endif
411 gtk_widget_show(text);
412 gtk_container_add(GTK_CONTAINER(scrolled_win), text);
413
414 hbox = gtk_hbox_new(FALSE, 4);
415 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 4);
416 gtk_widget_show(hbox);
417
418 adj = gtk_adjustment_new(0., 0., 100., 1., 20., 0.);
419 locator = gtk_hscale_new(GTK_ADJUSTMENT(adj));
420 gtk_scale_set_draw_value(GTK_SCALE(locator), TRUE);
421 gtk_signal_connect(GTK_OBJECT(adj), "value_changed",
422 GTK_SIGNAL_FUNC(generic_scale_cb),
423 (gpointer)GTK_CHANGE_LOCATOR);
424 gtk_signal_connect(GTK_OBJECT(locator), "button_press_event",
425 GTK_SIGNAL_FUNC(locate_update_cb),
426 NULL);
427 gtk_signal_connect(GTK_OBJECT(locator), "button_release_event",
428 GTK_SIGNAL_FUNC(locate_update_cb),
429 NULL);
430 gtk_range_set_update_policy(GTK_RANGE(locator),
431 GTK_UPDATE_DISCONTINUOUS);
432 gtk_scale_set_digits(GTK_SCALE(locator), 0);
433 gtk_widget_show(locator);
434 gtk_box_pack_start(GTK_BOX(hbox), locator, TRUE, TRUE, 4);
435
436 align = gtk_alignment_new(0., 1., 1., 0.);
437 gtk_widget_show(align);
438 cnt_lbl = gtk_label_new("00:00");
439 gtk_widget_show(cnt_lbl);
440 gtk_container_add(GTK_CONTAINER(align), cnt_lbl);
441 gtk_box_pack_start(GTK_BOX(hbox), align, FALSE, TRUE, 0);
442
443 align = gtk_alignment_new(0., 1., 1., 0.);
444 gtk_widget_show(align);
445 tot_lbl = gtk_label_new("/00:00");
446 gtk_widget_show(tot_lbl);
447 gtk_container_add(GTK_CONTAINER(align), tot_lbl);
448 gtk_box_pack_start(GTK_BOX(hbox), align, FALSE, TRUE, 0);
449
450 hbox = gtk_hbox_new(FALSE, 4);
451 gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 4);
452
453 swin = gtk_scrolled_window_new(NULL, NULL);
454 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin),
455 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
456 clist = gtk_clist_new(1);
457 gtk_container_add(GTK_CONTAINER(swin), clist);
458 gtk_widget_show(swin);
459 gtk_widget_show(clist);
460 gtk_widget_set_usize(clist, 200, 10);
461 gtk_clist_set_reorderable(GTK_CLIST(clist), TRUE);
462 gtk_clist_set_button_actions(GTK_CLIST(clist), 0, GTK_BUTTON_SELECTS);
463 gtk_clist_set_button_actions(GTK_CLIST(clist), 1, GTK_BUTTON_DRAGS);
464 gtk_clist_set_button_actions(GTK_CLIST(clist), 2, GTK_BUTTON_SELECTS);
465 gtk_clist_set_selection_mode(GTK_CLIST(clist), GTK_SELECTION_SINGLE);
466 gtk_clist_set_column_auto_resize(GTK_CLIST(clist), 1, TRUE);
467 gtk_signal_connect(GTK_OBJECT(clist), "select_row",
468 GTK_SIGNAL_FUNC(file_list_cb), NULL);
469
470 gtk_box_pack_start(GTK_BOX(hbox), swin, TRUE, TRUE, 0);
471
472 vbox2 = gtk_vbox_new(FALSE, 0);
473 gtk_box_pack_start(GTK_BOX(hbox), vbox2, FALSE, FALSE, 0);
474 gtk_widget_show(vbox2);
475
476 /* This is so the pixmap creation works properly. */
477 gtk_widget_realize(window);
478 set_icon_pixmap(window, timidity_xpm);
479
480 gtk_box_pack_start(GTK_BOX(vbox2),
481 create_pixmap_label(window, loud_xpm),
482 FALSE, FALSE, 0);
483
484 adj = gtk_adjustment_new(30., 0., (gfloat)MAX_AMPLIFICATION, 1., 20., 0.);
485 vol_scale = gtk_vscale_new(GTK_ADJUSTMENT(adj));
486 gtk_scale_set_draw_value(GTK_SCALE(vol_scale), FALSE);
487 gtk_signal_connect (GTK_OBJECT(adj), "value_changed",
488 GTK_SIGNAL_FUNC(generic_scale_cb),
489 (gpointer)GTK_CHANGE_VOLUME);
490 gtk_range_set_update_policy(GTK_RANGE(vol_scale),
491 GTK_UPDATE_DELAYED);
492 gtk_widget_show(vol_scale);
493 gtk_tooltips_set_tip(ttip, vol_scale, "Volume control", NULL);
494
495 gtk_box_pack_start(GTK_BOX(vbox2), vol_scale, TRUE, TRUE, 0);
496
497 gtk_box_pack_start(GTK_BOX(vbox2),
498 create_pixmap_label(window, quiet_xpm),
499 FALSE, FALSE, 0);
500
501 handlebox = gtk_handle_box_new();
502 gtk_box_pack_start(GTK_BOX(hbox), handlebox, FALSE, FALSE, 0);
503
504 table = gtk_table_new(7, 2, TRUE);
505 gtk_container_add(GTK_CONTAINER(handlebox), table);
506
507 button = create_button_with_pixmap(window, playpaus_xpm, GTK_PAUSE,
508 "Play/Pause");
509 gtk_table_attach_defaults(GTK_TABLE(table), button,
510 0, 2, 0, 1);
511
512 button = create_button_with_pixmap(window, prevtrk_xpm, GTK_PREV,
513 "Previous file");
514 gtk_table_attach_defaults(GTK_TABLE(table), button,
515 0, 1, 1, 2);
516
517 button = create_button_with_pixmap(window, nexttrk_xpm, GTK_NEXT,
518 "Next file");
519 gtk_table_attach_defaults(GTK_TABLE(table), button,
520 1, 2, 1, 2);
521
522 button = create_button_with_pixmap(window, rew_xpm, GTK_RWD,
523 "Rewind");
524 gtk_table_attach_defaults(GTK_TABLE(table), button,
525 0, 1, 2, 3);
526
527 button = create_button_with_pixmap(window, ff_xpm, GTK_FWD,
528 "Fast forward");
529 gtk_table_attach_defaults(GTK_TABLE(table), button,
530 1, 2, 2, 3);
531
532 button = create_button_with_pixmap(window, keydown_xpm, GTK_KEYDOWN,
533 "Lower pitch");
534 gtk_table_attach_defaults(GTK_TABLE(table), button,
535 0, 1, 3, 4);
536
537 button = create_button_with_pixmap(window, keyup_xpm, GTK_KEYUP,
538 "Raise pitch");
539 gtk_table_attach_defaults(GTK_TABLE(table), button,
540 1, 2, 3, 4);
541
542 button = create_button_with_pixmap(window, slow_xpm, GTK_SLOWER,
543 "Decrease tempo");
544 gtk_table_attach_defaults(GTK_TABLE(table), button,
545 0, 1, 4, 5);
546
547 button = create_button_with_pixmap(window, fast_xpm, GTK_FASTER,
548 "Increase tempo");
549 gtk_table_attach_defaults(GTK_TABLE(table), button,
550 1, 2, 4, 5);
551
552 button = create_button_with_pixmap(window, restart_xpm, GTK_RESTART,
553 "Restart");
554 gtk_table_attach_defaults(GTK_TABLE(table), button,
555 0, 1, 5, 6);
556
557 button = create_button_with_pixmap(window, open_xpm, 0,
558 "Open");
559 #ifdef HAVE_GTK_2
560 gtk_signal_disconnect_by_func(GTK_OBJECT(button), G_CALLBACK(generic_cb), 0);
561 #else
562 gtk_signal_disconnect_by_func(GTK_OBJECT(button), generic_cb, 0);
563 #endif
564 gtk_signal_connect(GTK_OBJECT(button), "clicked",
565 GTK_SIGNAL_FUNC(open_file_cb), 0);
566 gtk_table_attach_defaults(GTK_TABLE(table), button,
567 1, 2, 5, 6);
568
569 button = create_button_with_pixmap(window, quit_xpm, GTK_QUIT,
570 "Quit");
571 gtk_table_attach_defaults(GTK_TABLE(table), button,
572 0, 2, 6, 7);
573
574 gtk_widget_show(hbox);
575 gtk_widget_show(vbox);
576 gtk_widget_show(table);
577 gtk_widget_show(handlebox);
578 gtk_widget_show(window);
579
580 gdk_input_add(pipe_number, GDK_INPUT_READ, handle_input, NULL);
581
582 gtk_main();
583 }
584
585 static GtkWidget *
create_button_with_pixmap(GtkWidget * window,gchar ** bits,gint data,gchar * thelp)586 create_button_with_pixmap(GtkWidget *window, gchar **bits, gint data, gchar *thelp)
587 {
588 GtkWidget *pw, *button;
589 GdkPixmap *pixmap;
590 GdkBitmap *mask;
591 GtkStyle *style;
592
593 style = gtk_widget_get_style(window);
594 pixmap = gdk_pixmap_create_from_xpm_d(window->window,
595 &mask,
596 &style->bg[GTK_STATE_NORMAL],
597 bits);
598 pw = gtk_pixmap_new(pixmap, mask);
599 gtk_widget_show(pw);
600
601 button = gtk_button_new();
602 gtk_container_add(GTK_CONTAINER(button), pw);
603 gtk_signal_connect(GTK_OBJECT(button), "clicked",
604 GTK_SIGNAL_FUNC(generic_cb),
605 GINT_TO_POINTER(data));
606 gtk_widget_show(button);
607 gtk_tooltips_set_tip(ttip, button, thelp, NULL);
608
609 return button;
610 }
611
612 static GtkWidget *
create_pixmap_label(GtkWidget * window,gchar ** bits)613 create_pixmap_label(GtkWidget *window, gchar **bits)
614 {
615 GtkWidget *pw;
616 GdkPixmap *pixmap;
617 GdkBitmap *mask;
618 GtkStyle *style;
619
620 style = gtk_widget_get_style(window);
621 pixmap = gdk_pixmap_create_from_xpm_d(window->window,
622 &mask,
623 &style->bg[GTK_STATE_NORMAL],
624 bits);
625 pw = gtk_pixmap_new(pixmap, mask);
626 gtk_widget_show(pw);
627
628 return pw;
629 }
630
631 static void
set_icon_pixmap(GtkWidget * window,gchar ** bits)632 set_icon_pixmap(GtkWidget *window, gchar **bits)
633 {
634 GdkPixmap *pixmap;
635 GdkBitmap *mask;
636 GtkStyle *style;
637
638 style = gtk_widget_get_style(window);
639 pixmap = gdk_pixmap_create_from_xpm_d(window->window,
640 &mask,
641 &style->bg[GTK_STATE_NORMAL],
642 bits);
643 gdk_window_set_icon(window->window, NULL, pixmap, mask);
644 gdk_window_set_icon_name(window->window, "TiMidity");
645 }
646
647 static GtkWidget *
create_menubar(void)648 create_menubar(void)
649 {
650 GtkItemFactory *ifactory;
651 GtkAccelGroup *ag;
652
653 #ifdef HAVE_GTK_2
654 ag = gtk_accel_group_new();
655 #else
656 ag = gtk_accel_group_get_default();
657 #endif
658 ifactory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<Main>", ag);
659 gtk_item_factory_create_items(ifactory,
660 sizeof(ife) / sizeof(GtkItemFactoryEntry),
661 ife, NULL);
662 gtk_widget_show(ifactory->widget);
663
664 auto_next = gtk_item_factory_get_widget(ifactory, "/Options/Auto next");
665 gtk_check_menu_item_set_state(GTK_CHECK_MENU_ITEM(auto_next), TRUE);
666 ttshow = gtk_item_factory_get_widget(ifactory, "/Options/Show tooltips");
667 gtk_check_menu_item_set_state(GTK_CHECK_MENU_ITEM(ttshow), TRUE);
668
669 return ifactory->widget;
670 }
671
672 /* Following function curtesy of the gtk mailing list. */
673
674 static GtkTooltips *
create_yellow_tooltips()675 create_yellow_tooltips()
676 {
677 GtkTooltips *tip;
678
679 /* First create a default Tooltip */
680 tip = gtk_tooltips_new();
681
682 #ifndef HAVE_GTK_2
683 GdkColor *t_back;
684
685 t_back = (GdkColor*)g_malloc( sizeof(GdkColor));
686
687 /* Try to get the colors */
688 if ( gdk_color_parse("linen", t_back)){
689 if(gdk_colormap_alloc_color(gdk_colormap_get_system(),
690 t_back,
691 FALSE, TRUE)) {
692 gtk_tooltips_set_colors(tip, t_back, NULL);
693 }
694 }
695 #endif
696
697 return tip;
698 }
699
700 /* Receive DATA sent by the application on the pipe */
701
702 static void
handle_input(gpointer client_data,gint source,GdkInputCondition ic)703 handle_input(gpointer client_data, gint source, GdkInputCondition ic)
704 {
705 int message;
706
707 gtk_pipe_int_read(&message);
708
709 switch (message) {
710 case REFRESH_MESSAGE:
711 g_warning("REFRESH MESSAGE IS OBSOLETE !!!");
712 break;
713
714 case TOTALTIME_MESSAGE:
715 {
716 int tt;
717 int minutes,seconds;
718 char local_string[20];
719 GtkObject *adj;
720
721 gtk_pipe_int_read(&tt);
722
723 seconds=max_sec=tt/play_mode->rate;
724 minutes=seconds/60;
725 seconds-=minutes*60;
726 sprintf(local_string,"/ %i:%02i",minutes,seconds);
727 gtk_label_set(GTK_LABEL(tot_lbl), local_string);
728
729 /* Readjust the time scale */
730 adj = gtk_adjustment_new(0., 0., (gfloat)max_sec,
731 1., 10., 0.);
732 gtk_signal_connect(GTK_OBJECT(adj), "value_changed",
733 GTK_SIGNAL_FUNC(generic_scale_cb),
734 (gpointer)GTK_CHANGE_LOCATOR);
735 gtk_range_set_adjustment(GTK_RANGE(locator),
736 GTK_ADJUSTMENT(adj));
737 }
738 break;
739
740 case MASTERVOL_MESSAGE:
741 {
742 int volume;
743 GtkAdjustment *adj;
744
745 gtk_pipe_int_read(&volume);
746 adj = gtk_range_get_adjustment(GTK_RANGE(vol_scale));
747 my_adjustment_set_value(adj, MAX_AMPLIFICATION - volume);
748 }
749 break;
750
751 case FILENAME_MESSAGE:
752 {
753 char filename[255], title[255];
754 char *pc;
755
756 gtk_pipe_string_read(filename);
757
758 /* Extract basename of the file */
759 pc = strrchr(filename, '/');
760 if (pc == NULL)
761 pc = filename;
762 else
763 pc++;
764
765 sprintf(title, "Timidity %s - %s", timidity_version, pc);
766 gtk_window_set_title(GTK_WINDOW(window), title);
767
768 /* Clear the text area. */
769 #ifdef HAVE_GTK_2
770 textbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(text));
771 gtk_text_buffer_get_start_iter(textbuf, &start_iter);
772 gtk_text_buffer_get_end_iter(textbuf, &end_iter);
773 iter = start_iter;
774 #else
775 gtk_text_freeze(GTK_TEXT(text));
776 gtk_text_set_point(GTK_TEXT(text), 0);
777 gtk_text_forward_delete(GTK_TEXT(text),
778 gtk_text_get_length(GTK_TEXT(text)));
779 gtk_text_thaw(GTK_TEXT(text));
780 #endif
781 }
782 break;
783
784 case FILE_LIST_MESSAGE:
785 {
786 gchar filename[255], *fnames[2];
787 gint i, number_of_files;
788
789 /* reset the playing list : play from the start */
790 file_number_to_play = -1;
791
792 gtk_pipe_int_read(&number_of_files);
793 for (i = 0; i < number_of_files; i++)
794 {
795 gtk_pipe_string_read(filename);
796 fnames[0] = filename;
797 fnames[1] = NULL;
798 gtk_clist_append(GTK_CLIST(clist), fnames);
799 }
800 gtk_clist_columns_autosize(GTK_CLIST(clist));
801 }
802 break;
803
804 case NEXT_FILE_MESSAGE:
805 case PREV_FILE_MESSAGE:
806 case TUNE_END_MESSAGE:
807 {
808 int nbfile;
809
810 /* When a file ends, launch next if auto_next toggle */
811 if ( (message==TUNE_END_MESSAGE) &&
812 !GTK_CHECK_MENU_ITEM(auto_next)->active )
813 return;
814
815 /* Total number of file to play in the list */
816 nbfile = GTK_CLIST(clist)->rows;
817
818 if (message == PREV_FILE_MESSAGE)
819 file_number_to_play--;
820 else
821 file_number_to_play++;
822
823 /* Do nothing if requested file is before first one */
824 if (file_number_to_play < 0) {
825 file_number_to_play = 0;
826 return;
827 }
828
829 /* Stop after playing the last file */
830 if (file_number_to_play >= nbfile) {
831 file_number_to_play = nbfile - 1;
832 return;
833 }
834
835 if(gtk_clist_row_is_visible(GTK_CLIST(clist),
836 file_number_to_play) !=
837 GTK_VISIBILITY_FULL) {
838 gtk_clist_moveto(GTK_CLIST(clist), file_number_to_play,
839 -1, 1.0, 0.0);
840 }
841 gtk_clist_select_row(GTK_CLIST(clist), file_number_to_play, 0);
842 }
843 break;
844
845 case CURTIME_MESSAGE:
846 {
847 int seconds, minutes;
848 int nbvoice;
849 char local_string[20];
850
851 gtk_pipe_int_read(&seconds);
852 gtk_pipe_int_read(&nbvoice);
853
854 if( is_quitting )
855 return;
856
857 minutes=seconds/60;
858
859 sprintf(local_string,"%2d:%02d", minutes, (int)(seconds % 60));
860
861 gtk_label_set(GTK_LABEL(cnt_lbl), local_string);
862
863 /* Readjust the time scale if not dragging the scale */
864 if( !locating && (seconds <= max_sec)) {
865 GtkAdjustment *adj;
866
867 adj = gtk_range_get_adjustment(GTK_RANGE(locator));
868 my_adjustment_set_value(adj, (gfloat)seconds);
869 }
870 }
871 break;
872
873 case NOTE_MESSAGE:
874 {
875 int channel;
876 int note;
877
878 gtk_pipe_int_read(&channel);
879 gtk_pipe_int_read(¬e);
880 g_warning("NOTE chn%i %i", channel, note);
881 }
882 break;
883
884 case PROGRAM_MESSAGE:
885 {
886 int channel;
887 int pgm;
888
889 gtk_pipe_int_read(&channel);
890 gtk_pipe_int_read(&pgm);
891 g_warning("NOTE chn%i %i", channel, pgm);
892 }
893 break;
894
895 case VOLUME_MESSAGE:
896 {
897 int channel;
898 int volume;
899
900 gtk_pipe_int_read(&channel);
901 gtk_pipe_int_read(&volume);
902 g_warning("VOLUME= chn%i %i", channel, volume);
903 }
904 break;
905
906
907 case EXPRESSION_MESSAGE:
908 {
909 int channel;
910 int express;
911
912 gtk_pipe_int_read(&channel);
913 gtk_pipe_int_read(&express);
914 g_warning("EXPRESSION= chn%i %i", channel, express);
915 }
916 break;
917
918 case PANNING_MESSAGE:
919 {
920 int channel;
921 int pan;
922
923 gtk_pipe_int_read(&channel);
924 gtk_pipe_int_read(&pan);
925 g_warning("PANNING= chn%i %i", channel, pan);
926 }
927 break;
928
929 case SUSTAIN_MESSAGE:
930 {
931 int channel;
932 int sust;
933
934 gtk_pipe_int_read(&channel);
935 gtk_pipe_int_read(&sust);
936 g_warning("SUSTAIN= chn%i %i", channel, sust);
937 }
938 break;
939
940 case PITCH_MESSAGE:
941 {
942 int channel;
943 int bend;
944
945 gtk_pipe_int_read(&channel);
946 gtk_pipe_int_read(&bend);
947 g_warning("PITCH BEND= chn%i %i", channel, bend);
948 }
949 break;
950
951 case RESET_MESSAGE:
952 g_warning("RESET_MESSAGE");
953 break;
954
955 case CLOSE_MESSAGE:
956 gtk_exit(0);
957 break;
958
959 case CMSG_MESSAGE:
960 {
961 int type;
962 char message[1000];
963 #ifdef HAVE_GTK_2
964 gchar *message_u8;
965 #endif
966
967 gtk_pipe_int_read(&type);
968 gtk_pipe_string_read(message);
969 #ifdef HAVE_GTK_2
970 message_u8 = g_locale_to_utf8( message, -1, NULL, NULL, NULL );
971 gtk_text_buffer_get_bounds(textbuf, &start_iter, &end_iter);
972 gtk_text_buffer_insert(textbuf, &end_iter,
973 message_u8, -1);
974 gtk_text_buffer_insert(textbuf, &end_iter,
975 "\n", 1);
976 gtk_text_buffer_get_bounds(textbuf, &start_iter, &end_iter);
977
978 mark = gtk_text_buffer_create_mark(textbuf, NULL, &end_iter, 1);
979 gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(text), mark, 0.0, 0, 0.0, 1.0);
980 gtk_text_buffer_delete_mark(textbuf, mark);
981 g_free( message_u8 );
982 #else
983 gtk_text_insert(GTK_TEXT(text), NULL, NULL, NULL,
984 message, -1);
985 gtk_text_insert(GTK_TEXT(text), NULL, NULL, NULL,
986 "\n", 1);
987 #endif
988 }
989 break;
990 case LYRIC_MESSAGE:
991 {
992 char message[1000];
993 #ifdef HAVE_GTK_2
994 gchar *message_u8;
995 #endif
996
997 gtk_pipe_string_read(message);
998
999 #ifdef HAVE_GTK_2
1000 message_u8 = g_locale_to_utf8( message, -1, NULL, NULL, NULL );
1001 gtk_text_buffer_get_bounds(textbuf, &start_iter, &end_iter);
1002 gtk_text_buffer_insert(textbuf, &iter,
1003 message_u8, -1);
1004 gtk_text_buffer_get_bounds(textbuf, &start_iter, &end_iter);
1005
1006 mark = gtk_text_buffer_create_mark(textbuf, NULL, &end_iter, 1);
1007 gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(text), mark, 0.0, 0, 0.0, 1.0);
1008 gtk_text_buffer_delete_mark(textbuf, mark);
1009 #else
1010 gtk_text_insert(GTK_TEXT(text), NULL, NULL, NULL,
1011 message, -1);
1012 #endif
1013 }
1014 break;
1015 default:
1016 g_warning("UNKNOWN Gtk+ MESSAGE %i", message);
1017 }
1018 }
1019