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     xskin_i.c
21 
22     Oct.06.1998  Daisuke Nagano
23 */
24 
25 #include "xskin.h"
26 
27 #include "timidity.h"
28 #include "common.h"
29 #include "instrum.h"
30 #include "playmidi.h"
31 #include "output.h"
32 #include "controls.h"
33 #include "miditrace.h"
34 
35 extern void xskin_pipe_write(char *);
36 extern int  xskin_pipe_read(char *,int);
37 
38 /* text positions */
39 
40 static int text_posx[] = {
41 /*     !   ""   #   $   %   &   '   (   )   *   +   ,   -   .   /  */
42   30, 17, 26, 30, 29, 26, 25, 16, 13, 14,  4, 19, 10, 15, 10, 21,
43 /* 0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?  */
44    0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 12, 12, 30, 28, 30,  3,
45   27,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
46   15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 22, 20, 23, 24, 18
47 };
48 static int text_posy[] = {
49    0,  1,  0,  1,  1,  1,  1,  1,  1,  1,  2,  1,  1,  1,  1,  1,
50    1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  1,  0,  2,
51    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
52    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  1,  1,  1,  1
53 };
54 
55 static char local_buf[300];
56 
57 static int load_skins( void );
58 static void xskin_jobs( int );
59 static void repaint( void );
60 
61 static void install_sighandler( void );
62 static void signal_vector( int );
63 static void delete_shm( void );
64 
65 static int fshuf,frep,fequ,fpll;
66 static int fplay,fpause;
67 static int fremain;
68 static int play_val, vol_val;
69 static char last_text[1024];
70 static int last_current_time;
71 static int total_time;
72 
73 static int shmid;
74 static unsigned char *speana_buf;
75 
76 Visual *xskin_vis;
77 unsigned int xskin_depth;
78 
79 Display *xskin_d;
80 Window xskin_r,xskin_w;
81 GC xskin_gc;
82 
83 Pixmap xskin_back,xskin_titlebar,xskin_playpaus,xskin_numbers,xskin_cbuttons;
84 Pixmap xskin_monoster,xskin_posbar,xskin_shufrep,xskin_text,xskin_volume;
85 
86 /* text */
87 
ts_puttext(int x0,int y0,char * message)88 void ts_puttext( int x0, int y0, char *message ) {
89   int i,l;
90   int c;
91   int x,px,py;
92 
93   if ( x0 == MESSAGE_X ) {
94     px=text_posx[0]*TEXT_W;
95     py=text_posy[0]*TEXT_H;
96     for ( i=0 ; i<31 ; i++ ) {
97       x = x0+i*TEXT_W;
98       XCopyArea( xskin_d, xskin_text, xskin_w, xskin_gc,
99 		 px, py, TEXT_W, TEXT_H, x, y0 );
100     }
101   } else if ( x0 == BITRATE_X ) {
102     XCopyArea( xskin_d, xskin_back, xskin_w, xskin_gc,
103 	       111, 43, 15, 6, 111, 43 );
104   } else if ( x0 == SAMPLE_X ) {
105     XCopyArea( xskin_d, xskin_back, xskin_w, xskin_gc,
106 	       156, 43, 10, 6, 156, 43 );
107   }
108 
109   l = strlen( message );
110   if ( l<=0 ) return;
111   for ( i=0 ; i<l ; i++ ) {
112     c = (int)(message[i]);
113     if ( (c>='a') && (c<='z') ) c = c-'a'+'A';
114     if ( c<' ' ) c = '.';
115     if ( c>'_' ) c = '.';
116 
117     c-=' ';
118     if ( c>=64 ) c=0;
119     px = text_posx[c]*TEXT_W;
120     py = text_posy[c]*TEXT_H;
121     x = x0+i*TEXT_W;
122     if (( x0 == MESSAGE_X && i<31 ) ||
123 	( x0 == BITRATE_X && i<3  ) ||
124 	( x0 == SAMPLE_X  && i<2  )) {
125       XCopyArea( xskin_d, xskin_text, xskin_w, xskin_gc,
126 		 px, py, TEXT_W, TEXT_H, x, y0 );
127     }
128   }
129   XSync( xskin_d, True ); /* discards any events in the queue */
130 
131   if ( x0 == MESSAGE_X )
132     strncpy( last_text, message, sizeof(last_text) );
133 
134   return;
135 }
136 
137 /* numbers */
138 
ts_putnum(int x,int y,int val)139 void ts_putnum( int x, int y, int val ) {
140 
141   int x0,y0;
142 
143   if ( (val>9) || (val<0 ) ) return;
144   x0=val*9;
145   y0=0;
146 
147   XCopyArea( xskin_d, xskin_numbers, xskin_w, xskin_gc,
148 	     x0, y0, NUM_W, NUM_H, x, y );
149 
150   return ;
151 }
152 
153 /* cbuttons */
154 
ts_prev(int i)155 void ts_prev( int i ) {
156 
157   XCopyArea( xskin_d, xskin_cbuttons, xskin_w, xskin_gc,
158 	     PREV_SX(i), PREV_SY(i), PREV_W, PREV_H, PREV_DX, PREV_DY );
159 
160   return;
161 }
162 
ts_play(int i)163 void ts_play( int i ) {
164 
165   XCopyArea( xskin_d, xskin_cbuttons, xskin_w, xskin_gc,
166 	     PLAY_SX(i), PLAY_SY(i), PLAY_W, PLAY_H, PLAY_DX, PLAY_DY );
167 
168   return;
169 }
170 
ts_pause(int i)171 void ts_pause( int i ) {
172 
173   XCopyArea( xskin_d, xskin_cbuttons, xskin_w, xskin_gc,
174 	     PAUSE_SX(i), PAUSE_SY(i), PAUSE_W, PAUSE_H, PAUSE_DX, PAUSE_DY);
175 
176   return;
177 }
178 
ts_stop(int i)179 void ts_stop ( int i ) {
180 
181   XCopyArea( xskin_d, xskin_cbuttons, xskin_w, xskin_gc,
182 	     STOP_SX(i), STOP_SY(i), STOP_W, STOP_H, STOP_DX, STOP_DY );
183 
184   return;
185 }
186 
ts_next(int i)187 void ts_next( int i ) {
188 
189   XCopyArea( xskin_d, xskin_cbuttons, xskin_w, xskin_gc,
190 	     NEXT_SX(i), NEXT_SY(i), NEXT_W, NEXT_H, NEXT_DX, NEXT_DY );
191 
192   return;
193 }
194 
ts_eject(int i)195 void ts_eject( int i ) {
196 
197   XCopyArea( xskin_d, xskin_cbuttons, xskin_w, xskin_gc,
198 	     EJECT_SX(i), EJECT_SY(i), EJECT_W, EJECT_H, EJECT_DX, EJECT_DY );
199   return;
200 }
201 
202 /* titlebar */
203 
ts_titlebar(int i)204 void ts_titlebar( int i ) {
205 
206   XCopyArea( xskin_d, xskin_titlebar, xskin_w, xskin_gc,
207 	     TITLEBAR_SX(i), TITLEBAR_SY(i),
208 	     TITLEBAR_W, TITLEBAR_H, TITLEBAR_DX, TITLEBAR_DY );
209   return;
210 }
211 
ts_exitbutton(int i)212 void ts_exitbutton( int i ) {
213 
214   XCopyArea( xskin_d, xskin_titlebar, xskin_w, xskin_gc,
215 	     EXITBUTTON_SX(i), EXITBUTTON_SY(i),
216 	     EXITBUTTON_W, EXITBUTTON_H, EXITBUTTON_DX, EXITBUTTON_DY );
217 
218   return;
219 }
220 
ts_menubutton(int i)221 void ts_menubutton( int i ) {
222 
223   XCopyArea( xskin_d, xskin_titlebar, xskin_w, xskin_gc,
224 	     MENUBUTTON_SX(i), MENUBUTTON_SY(i),
225 	     MENUBUTTON_W, MENUBUTTON_H, MENUBUTTON_DX, MENUBUTTON_DY );
226   return;
227 }
228 
ts_iconbutton(int i)229 void ts_iconbutton( int i ) {
230 
231   XCopyArea( xskin_d, xskin_titlebar, xskin_w, xskin_gc,
232 	     ICONBUTTON_SX(i), ICONBUTTON_SY(i),
233 	     ICONBUTTON_W, ICONBUTTON_H, ICONBUTTON_DX, ICONBUTTON_DY );
234   return;
235 }
236 
ts_minibutton(int i)237 void ts_minibutton( int i ) {
238 
239   XCopyArea( xskin_d, xskin_titlebar, xskin_w, xskin_gc,
240 	     MINIBUTTON_SX(i), MINIBUTTON_SY(i),
241 	     MINIBUTTON_W, MINIBUTTON_H, MINIBUTTON_DX, MINIBUTTON_DY );
242   return;
243 }
244 
245 /* monoster */
246 
ts_mono(int i)247 void ts_mono( int i ) {
248 
249   XCopyArea( xskin_d, xskin_monoster, xskin_w, xskin_gc,
250 	     MONO_SX(i), MONO_SY(i),
251 	     MONO_W, MONO_H, MONO_DX, MONO_DY );
252   return;
253 }
254 
ts_stereo(int i)255 void ts_stereo( int i ) {
256 
257   XCopyArea( xskin_d, xskin_monoster, xskin_w, xskin_gc,
258 	     STEREO_SX(i), STEREO_SY(i),
259 	     STEREO_W, STEREO_H, STEREO_DX, STEREO_DY );
260   return;
261 }
262 
263 /* playpaus */
264 
ts_pstate(int i)265 void ts_pstate( int i ) {
266 
267   XCopyArea( xskin_d, xskin_playpaus, xskin_w, xskin_gc,
268 	     PSTATE1_SX(i), PSTATE1_SY(i),
269 	     PSTATE1_W, PSTATE1_H, PSTATE1_DX, PSTATE1_DY );
270   XCopyArea( xskin_d, xskin_playpaus, xskin_w, xskin_gc,
271 	     PSTATE2_SX(i), PSTATE2_SY(i),
272 	     PSTATE2_W, PSTATE2_H, PSTATE2_DX, PSTATE2_DY );
273   return;
274 }
275 
276 /* shufrep */
277 
ts_shuf(int i)278 void ts_shuf( int i ) {
279 
280   XCopyArea( xskin_d, xskin_shufrep, xskin_w, xskin_gc,
281 	     SHUF_SX(i), SHUF_SY(i),
282 	     SHUF_W, SHUF_H, SHUF_DX, SHUF_DY );
283 
284   return;
285 }
286 
ts_rep(int i)287 void ts_rep( int i ) {
288 
289   XCopyArea( xskin_d, xskin_shufrep, xskin_w, xskin_gc,
290 	     REP_SX(i), REP_SY(i),
291 	     REP_W, REP_H, REP_DX, REP_DY );
292 
293   return;
294 }
295 
ts_equ(int i)296 void ts_equ( int i ) {
297 
298   XCopyArea( xskin_d, xskin_shufrep, xskin_w, xskin_gc,
299 	     EQU_SX(i), EQU_SY(i),
300 	     EQU_W, EQU_H, EQU_DX, EQU_DY );
301   return;
302 }
303 
ts_plist(int i)304 void ts_plist( int i ) {
305 
306   XCopyArea( xskin_d, xskin_shufrep, xskin_w, xskin_gc,
307 	     PLIST_SX(i), PLIST_SY(i),
308 	     PLIST_W, PLIST_H, PLIST_DX, PLIST_DY );
309   return;
310 }
311 
312 /* posbar */
313 
ts_pos(int i,int j)314 int ts_pos( int i, int j ) {
315 
316   int x,y;
317   int p;
318 
319   if ( j<0 ) p=-j;
320   else {
321     if (j<POS_MIN_DX) j=POS_MIN_DX;
322     if (j>POS_MAX_DX) j=POS_MAX_DX;
323     p = 100*(j-POS_MIN_DX)/(POS_MAX_DX-POS_MIN_DX);
324   }
325 
326   x = POS_MIN_DX + (POS_MAX_DX-POS_MIN_DX)*p/100;
327   y = POS_DY;
328 
329   XCopyArea( xskin_d, xskin_posbar, xskin_w, xskin_gc,
330 	     BAR_SX, BAR_SY, BAR_W, BAR_H, BAR_DX, BAR_DY );
331   XCopyArea( xskin_d, xskin_posbar, xskin_w, xskin_gc,
332 	     POS_SX(i), POS_SY(i), POS_W, POS_H, x, y );
333   return p;
334 }
335 
ts_volume(int i,int j)336 int ts_volume( int i, int j ) {
337 
338   int x,y;
339   int t,p;
340 
341   if ( j<0 ) p=-j;
342   else {
343     if (j<VOL_MIN_DX) j=VOL_MIN_DX;
344     if (j>VOL_MAX_DX) j=VOL_MAX_DX;
345     p = 100*(j-VOL_MIN_DX)/(VOL_MAX_DX-VOL_MIN_DX);
346   }
347 
348   x = VOL_MIN_DX + (VOL_MAX_DX-VOL_MIN_DX)*p/100;
349   y = VOL_DY;
350   t=27*(int)p/100;
351   XCopyArea( xskin_d, xskin_volume, xskin_w, xskin_gc,
352 	     VOLUME_SX, t*VOLUME_H,
353 	     VOLUME_W, VOLUME_H-2, VOLUME_DX, VOLUME_DY );
354   XCopyArea( xskin_d, xskin_volume, xskin_w, xskin_gc,
355 	     VOL_SX(i), VOL_SY(i), VOL_W, VOL_H, x, y );
356   return p;
357 }
358 
ts_pan(int i,int j)359 int ts_pan( int i, int j ) {
360 
361   int x,y;
362   int t,p;
363 
364   if ( j<0 ) p=-j;
365   else {
366     if (j<PAN_MIN_DX) j=PAN_MIN_DX;
367     if (j>PAN_MAX_DX) j=PAN_MAX_DX;
368     p = 100*(j-PAN_MIN_DX)/(PAN_MAX_DX-PAN_MIN_DX);
369   }
370 
371   x = PAN_MIN_DX + (PAN_MAX_DX-PAN_MIN_DX)*p/100;
372   y = PAN_DY;
373   t=27*((p>50)?((float)p-50)/50:(50-(float)p)/50);
374   if ( t<2 ) t=0;
375   XCopyArea( xskin_d, xskin_volume, xskin_w, xskin_gc,
376 	     PANPOT_SX, t*PANPOT_H,
377 	     PANPOT_W, PANPOT_H-2, PANPOT_DX, PANPOT_DY );
378   XCopyArea( xskin_d, xskin_volume, xskin_w, xskin_gc,
379 	     PAN_SX(i), PAN_SY(i),
380 	     PAN_W, PAN_H, x, y );
381   return p;
382 }
383 
pauseOn()384 static void pauseOn()
385 {
386     if(!fpause) {
387 	fpause = 1;
388 	xskin_pipe_write("U");
389     }
390 }
391 
pauseOff()392 static void pauseOff()
393 {
394     if(fpause) {
395 	fpause = 0;
396 	xskin_pipe_write("U");
397     }
398 }
399 
400 /* main loop */
401 
402 #define ISIN(x,y,x0,y0,w,h) ( (x>=x0)&&(x<x0+w)&&(y>=y0)&&(y<y0+h) )?1:0
403 
xskin_start_interface(int pipe_in)404 void xskin_start_interface( int pipe_in ) {
405 
406   int xskin_sc;
407   XEvent xskin_e;
408   XSetWindowAttributes xskin_attr;
409 
410   XSizeHints xskin_hint;
411   XClassHint xskin_chint;
412   XTextProperty ct;
413   char *namlist[2];
414 
415 
416   /* setup window */
417 
418   xskin_d     = XOpenDisplay( NULL );
419   xskin_sc    = DefaultScreen( xskin_d );
420   xskin_r     = RootWindow( xskin_d, xskin_sc );
421   xskin_gc    = DefaultGC( xskin_d, xskin_sc );
422   xskin_vis   = DefaultVisual( xskin_d, xskin_sc );
423   xskin_depth = DefaultDepth( xskin_d, xskin_sc );
424 
425   xskin_w = XCreateSimpleWindow( xskin_d, xskin_r, 0, 0,
426 				 skin_width, skin_height, 0,
427 				 WhitePixel( xskin_d, xskin_sc ),
428 				 BlackPixel( xskin_d, xskin_sc ) );
429 
430   xskin_attr.backing_store = True;
431   xskin_attr.override_redirect = False;
432   XChangeWindowAttributes( xskin_d, xskin_w,
433 			   CWBackingStore|CWOverrideRedirect, &xskin_attr );
434 
435   XSelectInput( xskin_d, xskin_w,
436 		KeyPressMask|ExposureMask|
437 		EnterWindowMask|LeaveWindowMask|
438 		ButtonPressMask|ButtonReleaseMask|
439 		Button1MotionMask );
440 
441   xskin_hint.flags = USSize | PMinSize | PMaxSize | USPosition;
442   xskin_hint.width = xskin_hint.min_width = xskin_hint.max_width
443     = skin_width;
444   xskin_hint.height = xskin_hint.min_height = xskin_hint.max_height
445     = skin_height;
446   XSetNormalHints( xskin_d, xskin_w, &xskin_hint );
447 
448   xskin_chint.res_name  = XSKIN_RES_NAME;
449   xskin_chint.res_class = XSKIN_RES_CLASS;
450   XSetClassHint( xskin_d, xskin_w, &xskin_chint );
451 
452   namlist[0]=(char *)safe_malloc(strlen(XSKIN_WINDOW_NAME)+1);
453   strcpy( namlist[0], XSKIN_WINDOW_NAME );
454   XmbTextListToTextProperty( xskin_d, namlist, 1, XCompoundTextStyle, &ct );
455   XSetWMName( xskin_d, xskin_w, &ct );
456   XSetWMIconName( xskin_d, xskin_w, &ct );
457   free(namlist[0]);
458 
459 
460   /* setup pixmaps */
461 
462   if ( load_skins()!=0 ) goto finish;
463 
464   XSetWindowBackgroundPixmap( xskin_d, xskin_w, xskin_back );
465   XClearWindow( xskin_d, xskin_w );
466 
467   XMapWindow( xskin_d, xskin_w );
468   while( 1 ) {
469     XNextEvent( xskin_d, &xskin_e );
470     if ( xskin_e.type == Expose ) break;
471   }
472 
473   fshuf=0;
474   frep=0;
475   fequ=1;
476   fpll=1;
477   fplay=0;
478   fpause=0;
479   fremain=0;
480   play_val=1;
481   vol_val=50;
482   last_current_time=0;
483   total_time=0;
484   speana_buf = NULL;
485   strcpy( last_text, "welcome to timidity" );
486 
487   install_sighandler();
488 
489   repaint();
490   ts_spectrum( -1, speana_buf );
491 
492   XFlush(xskin_d);
493 
494   xskin_jobs( pipe_in );   /* tskin main jobs */
495 
496 finish:
497   signal_vector(0);  /* finish */
498 }
499 
500 #define ISIN(x,y,x0,y0,w,h) ( (x>=x0)&&(x<x0+w)&&(y>=y0)&&(y<y0+h) )?1:0
501 
xskin_jobs(int pipe_in)502 static void xskin_jobs( int pipe_in ) {
503   XEvent e;
504   int x,y;
505   int window_x,window_y;
506   int fspe=0;
507   int pr=-1;
508   int z;
509   int p;
510   int master_volume=0;
511   char file_name[1024], tmp[1024];
512 
513   int last_puttext_time;
514   int last_window_x=-1, last_window_y=-1;
515 
516   int max_files;
517   int i;
518   fd_set fds;
519   static struct timeval tv;
520 
521   Window t_w;
522   unsigned int t_width, t_height, t_border, t_depth;
523 
524   xskin_pipe_write( "READY" );
525 
526   shmid = shmget( IPC_PRIVATE, sizeof(char)*SPE_W, IPC_CREAT|0600 );
527   if ( shmid<0 ) xskin_pipe_write( "ERROR" );
528   else {
529     sprintf( local_buf, "%d", shmid );
530     xskin_pipe_write( local_buf );
531     speana_buf = (unsigned char *)shmat( shmid, 0, 0 );
532   }
533 
534   xskin_pipe_read( local_buf, sizeof(local_buf) );
535   max_files = atoi( local_buf );
536   for ( i=0 ; i<max_files ; i++ ) {
537     xskin_pipe_read( local_buf, sizeof(local_buf) );
538   }
539 
540   z=1;
541   last_puttext_time=0;
542   last_current_time=0;
543 
544   XGetGeometry( xskin_d, xskin_w, &t_w,
545 		&window_x, &window_y,
546 		&t_width, &t_height, &t_border, &t_depth );
547 
548   while( z ) {
549 
550     XFlush( xskin_d );
551 
552     FD_ZERO( &fds );
553     FD_SET( pipe_in, &fds );
554     tv.tv_sec=0;
555     tv.tv_usec=20000L; /* 20 msec */
556     i=select( pipe_in+1, &fds, NULL, NULL, &tv );
557 
558     if ( i!=0 ) {
559       xskin_pipe_read( local_buf, sizeof(local_buf) );
560       switch (local_buf[0]) {
561 
562       case 'A': /* total time */
563 	total_time=atoi( local_buf+2 );
564 	last_current_time=0;
565 	last_puttext_time=0;
566 	break;
567 
568       case 'T': /* current time */
569 	{
570 	  int min,sec;
571 	  sscanf( local_buf+2, "%02d:%02d", &min, &sec );
572 	  i=min*60+sec;
573 	  if ( fremain==1 ) {
574 	    sec =total_time-i;
575 	    min =sec/60;
576 	    sec-=min*60;
577 	  }
578 	  if ( i != last_current_time ) {
579 	    ts_putnum( MIN_H_X, MIN_H_Y, min/10 );
580 	    ts_putnum( MIN_L_X, MIN_L_Y, min%10 );
581 	    ts_putnum( SEC_H_X, SEC_H_Y, sec/10 );
582 	    ts_putnum( SEC_L_X, SEC_L_Y, sec%10 );
583 	    p=100*i/total_time;
584 	    play_val=ts_pos( OFF, -p );
585 	    last_current_time=i;
586 
587 	    if ( last_current_time - last_puttext_time == 3 ) { /* 3 sec */
588 	      sprintf( tmp, "%s [%02d:%02d]",
589 		       file_name, total_time/60, total_time%60 );
590 	      ts_puttext( MESSAGE_X, MESSAGE_Y, tmp );
591 	    }
592 	  }
593 	}
594       break;
595 
596       case 'L': /* lylics/message */
597 	ts_puttext( MESSAGE_X, MESSAGE_Y, local_buf+2 );
598 	last_puttext_time=last_current_time;
599 	break;
600 
601       case 'F': /* filename */
602 	strncpy( file_name, local_buf+2, 1023 );
603 	file_name[1023]=0;
604 	break;
605 
606       case 'O': /* off the play button */
607 	fplay=0;
608 	ts_play(OFF);
609 	ts_spectrum(fspe, NULL); /* erase spectrums */
610 	break;
611 
612       case 'V': /* master volume */
613 	master_volume=atoi( local_buf+2 );
614 	p=100*((master_volume<200)?master_volume:200)/200; /* max:200% */
615 	vol_val=ts_volume( OFF, -p );
616 	break;
617 
618       case 'Q': /* quit */
619 	z=1;
620 	break;
621 
622       case 'W': /* wave form */
623 	ts_spectrum(fspe, speana_buf);
624 	break;
625 
626       default:
627 	break;
628       }
629     }
630 
631     if ( XPending( xskin_d )==0 ) continue;
632     XNextEvent( xskin_d, &e );
633 
634     switch ( e.type ) {
635       /*
636     case KeyPress:
637       z=0;
638       break;
639       */
640 
641     case Expose:
642       repaint();
643       break;
644 
645     case EnterNotify:
646       {
647 	Cursor cs;
648 	ts_titlebar(ON);
649 	cs = XCreateFontCursor( xskin_d, XC_top_left_arrow );
650 	XDefineCursor( xskin_d, xskin_w, cs );
651       }
652       break;
653 
654     case LeaveNotify:
655       ts_titlebar(OFF);
656       XUndefineCursor( xskin_d, xskin_w );
657       break;
658 
659     case MotionNotify:
660       while( XCheckMaskEvent( xskin_d, Button1MotionMask, &e ) ) {
661 	XNextEvent( xskin_d, &e );
662       }
663       x = e.xbutton.x;
664       y = e.xbutton.y;
665       switch( pr ) {
666 
667 	/*
668       case TS_POS:
669 	play_val=ts_pos( ON, x );break;
670 	*/
671       case TS_VOLUME:
672 	vol_val=ts_volume( ON, x );
673 	i=master_volume;
674 	master_volume=200*vol_val/100;
675 	sprintf( local_buf, "V %d", master_volume-i );
676 	xskin_pipe_write( local_buf );
677 
678 	sprintf( tmp, " volume: %d%%", vol_val );
679 	ts_puttext( MESSAGE_X, MESSAGE_Y, tmp );
680 	last_puttext_time=last_current_time;
681 	break;
682 	/*
683       case TS_PAN:
684 	pan_val=ts_pan( ON, x );break;
685 	*/
686 
687       default:
688 	if ( x != last_window_x || y != last_window_y ) {
689 	  window_x += x-last_window_x;
690 	  window_y += y-last_window_y;
691 	  XMoveWindow( xskin_d, xskin_w,
692 		       window_x, window_y );
693 	}
694 	break;
695       }
696       break;
697 
698     case ButtonPress:
699       x = e.xbutton.x;
700       y = e.xbutton.y;
701       last_window_x=x;
702       last_window_y=y;
703 
704              if ( ISIN( x, y,EXITBUTTON_DX,EXITBUTTON_DY,
705 			EXITBUTTON_W,EXITBUTTON_H ) ) {
706         ts_exitbutton(ON);pr=TS_EXITBUTTON;
707 
708       } else if ( ISIN( x, y, PREV_DX, PREV_DY, PREV_W, PREV_H ) ) {
709 	ts_prev(ON);pr=TS_PREV;
710       } else if ( ISIN( x, y, PLAY_DX, PLAY_DY, PLAY_W, PLAY_H ) ) {
711 	ts_play(ON);pr=TS_PLAY;
712       } else if ( ISIN( x, y, PAUSE_DX, PAUSE_DY, PAUSE_W, PAUSE_H ) ) {
713 	ts_pause(ON);pr=TS_PAUSE;
714       } else if ( ISIN( x, y, STOP_DX, STOP_DY, STOP_W, STOP_H ) ) {
715 	ts_stop(ON);pr=TS_STOP;
716       } else if ( ISIN( x, y, NEXT_DX, NEXT_DY, NEXT_W, NEXT_H ) ) {
717 	ts_next(ON);pr=TS_NEXT;
718       } else if ( ISIN( x, y, EJECT_DX, EJECT_DY, EJECT_W, EJECT_H ) ) {
719 	ts_eject(ON);pr=TS_EJECT;
720 
721       } else if ( ISIN( x, y,164, 89, 47, 15 ) ) {  /* shuffle */
722 	if ( fshuf==0 ) {
723 	  ts_shuf(OFFON);pr=TS_SHUFON;
724 	} else {
725 	  ts_shuf(ONOFF);pr=TS_SHUFOFF;
726 	}
727       } else if ( ISIN( x, y,210, 89, 28, 15 ) ) {  /* repeat */
728 	if ( frep==0 ) {
729 	  ts_rep(OFFON);pr=TS_REPON;
730 	} else {
731 	  ts_rep(ONOFF);pr=TS_REPOFF;
732 	}
733       } else if ( ISIN( x, y,219, 58, 23, 12 ) ) {  /* equalizer */
734 	if ( fequ==0 ) {
735 	  ts_equ(OFFON);pr=TS_EQUON;
736 	} else {
737 	  ts_equ(ONOFF);pr=TS_EQUOFF;
738 	}
739       } else if ( ISIN( x, y,242, 58, 23, 12 ) ) {  /* playlist */
740 	if ( fpll==0 ) {
741 	  ts_plist(OFFON);pr=TS_PLISTON;
742 	} else {
743 	  ts_plist(ONOFF);pr=TS_PLISTOFF;
744 	}
745 
746       } else if ( ISIN( x, y, MENUBUTTON_DX, MENUBUTTON_DY,
747 			MENUBUTTON_W, MENUBUTTON_H ) ) {
748 	ts_menubutton(ON);pr=TS_MENUBUTTON;
749       } else if ( ISIN( x, y, ICONBUTTON_DX, ICONBUTTON_DY,
750 			ICONBUTTON_W, ICONBUTTON_H ) ) {
751 	ts_iconbutton(ON);pr=TS_ICONBUTTON;
752       } else if ( ISIN( x, y, MINIBUTTON_DX, MINIBUTTON_DY,
753 			MINIBUTTON_W, MINIBUTTON_H ) ) {
754 	ts_minibutton(ON);pr=TS_MINIBUTTON;
755 
756 	/*
757       }	else if ( ISIN( x, y,POS_MIN_DX+(POS_MAX_DX-POS_MIN_DX)*play_val/100,
758 			POS_DY, POS_W, POS_H ) ) {
759 	ts_pos( ON, -play_val );pr=TS_POS;
760 	*/
761       } else if ( ISIN( x, y,VOL_MIN_DX+(VOL_MAX_DX-VOL_MIN_DX)*vol_val/100,
762 			VOL_DY, VOL_W, VOL_H ) ) {
763 	ts_volume( ON, -vol_val );pr=TS_VOLUME;
764 	sprintf( tmp, " volume: %d%%", vol_val );
765 	ts_puttext( MESSAGE_X, MESSAGE_Y, tmp );
766 	last_puttext_time=last_current_time;
767 
768 	/*
769       } else if ( ISIN( x, y,PAN_MIN_DX+(PAN_MAX_DX-PAN_MIN_DX)*pan_val/100,
770 			PAN_DY, PAN_W, PAN_H ) ) {
771 	ts_pan( ON, -pan_val );pr=TS_PAN;
772 	*/
773 
774       } else if ( ISIN( x, y, MIN_H_X, MIN_H_Y,
775 			SEC_L_X+NUM_W-MIN_H_X, NUM_H ) ) {
776 	int min,sec;
777 	fremain=(fremain==0)?1:0;
778 	sec=(fremain==0)?last_current_time:total_time-last_current_time;
779 	min =sec/60;
780 	sec-=min*60;
781 	ts_putnum( MIN_H_X, MIN_H_Y, min/10 );
782 	ts_putnum( MIN_L_X, MIN_L_Y, min%10 );
783 	ts_putnum( SEC_H_X, SEC_H_Y, sec/10 );
784 	ts_putnum( SEC_L_X, SEC_L_Y, sec%10 );
785 
786       } else if ( ISIN( x, y, SPE_SX, SPE_SY, SPE_W, SPE_H ) ) {
787 	pr=TS_SPECTRUM;
788       } else {
789 	XRaiseWindow( xskin_d, xskin_w );
790       }
791 	     break;
792 
793     case ButtonRelease:
794 
795       last_window_x = -1;
796       last_window_y = -1;
797 
798       switch( pr ) {
799 
800       case TS_EXITBUTTON:
801 	ts_exitbutton(OFF);
802 	xskin_pipe_write("Q");
803 	z=0;break;
804 
805       case TS_PREV:
806 	ts_prev(OFF);
807 	ts_spectrum( fspe, NULL );
808 	xskin_pipe_write("B");
809 	break;
810       case TS_PLAY:
811 	xskin_pipe_write("P");
812 	fplay=1;
813 	pauseOff();
814 	ts_play(OFF);ts_pause(OFF);
815 	ts_pstate( PSTATE_PLAY );
816 	break;
817       case TS_PAUSE:
818 	ts_pause(OFF);
819 	if ( fplay ==1 ) {
820 	  if ( fpause==0 ) {
821 	    ts_pstate( PSTATE_PAUSE );
822 	    ts_spectrum( fspe, NULL );
823 	    pauseOn();
824 	  } else {
825 	    ts_pstate( PSTATE_PLAY );
826 	    pauseOff();
827 	  }
828 	}
829 	break;
830       case TS_STOP:
831 	pauseOff();
832 	fplay=0;
833 	ts_pause(OFF);ts_play(OFF);ts_stop(OFF);
834 	ts_pstate( PSTATE_STOP );
835 	ts_spectrum( fspe, NULL );
836 	xskin_pipe_write("S");
837 	break;
838       case TS_NEXT:
839 	ts_next(OFF);
840 	ts_spectrum( fspe, NULL );
841 	xskin_pipe_write("N");
842 	break;
843       case TS_EJECT:
844 	ts_eject(OFF);break;
845 
846       case TS_SHUFON:
847 	ts_shuf(ON);fshuf=1;
848 	fplay=1;
849 	pauseOff();
850 	ts_pstate( PSTATE_PLAY );
851 	xskin_pipe_write("D 1");
852 	break;
853       case TS_SHUFOFF:
854 	ts_shuf(OFF);fshuf=0;
855 	fplay=0;
856 	pauseOff();
857 	ts_pstate( PSTATE_STOP );
858 	ts_spectrum( fspe, NULL );
859 	xskin_pipe_write("D 2");
860 	break;
861       case TS_REPON:
862 	ts_rep(ON);frep=1;
863 	xskin_pipe_write("R 1");
864 	break;
865       case TS_REPOFF:
866 	ts_rep(OFF);frep=0;
867 	xskin_pipe_write("R 0");
868 	break;
869 
870       case TS_EQUON:
871 	ts_equ(ON);fequ=1;break;
872       case TS_EQUOFF:
873 	ts_equ(OFF);fequ=0;break;
874 
875       case TS_PLISTON:
876 	ts_plist(ON);fpll=1;break;
877       case TS_PLISTOFF:
878 	ts_plist(OFF);fpll=0;break;
879 
880       case TS_MENUBUTTON:
881 	ts_menubutton(OFF);break;
882       case TS_ICONBUTTON:
883 	ts_iconbutton(OFF);break;
884       case TS_MINIBUTTON:
885 	ts_minibutton(OFF);break;
886 
887 	/*
888       case TS_POS:
889 	ts_pos( OFF, -play_val );break;
890 	*/
891       case TS_VOLUME:
892 	ts_volume( OFF, -vol_val );break;
893 	/*
894       case TS_PAN:
895 	ts_pan( OFF, -pan_val );break;
896 	*/
897 
898       case TS_SPECTRUM:
899 #ifdef SUPPORT_SOUNDSPEC
900 	fspe = (fspe+1)%3;
901 	if ( fspe==1 ) xskin_pipe_write("W");      /* on */
902 	else if ( fspe==0 ) {
903 	  xskin_pipe_write("W"); /* off */
904 	  ts_spectrum(0,speana_buf);
905 	}
906 #endif /* SUPPORT_SOUNDSPEC */
907 	break;
908 
909       default:
910 	break;
911       }
912       pr=-1;
913       break;
914 
915     default:
916       break;
917     }
918   }
919 
920   return;
921 }
922 
load_skins(void)923 static int load_skins( void ) {
924 
925   char **files;
926   char *tmp[2];
927   int nfiles;
928   int i,pixmaps;
929   char *p,*p0;
930   char *skin_name;
931   int width, height;
932 
933   skin_name = getenv( "TIMIDITY_SKIN" );
934   if ( skin_name == NULL ) {
935     skin_name = getenv( "timidity_skin" );
936     if ( skin_name == NULL ) {
937 #ifdef	DEFAULT_SKIN
938       skin_name = DEFAULT_SKIN;
939 #else
940       fprintf(stderr, "Undefined environment `timidity_skin'\n");
941       return -1;
942 #endif
943     }
944   }
945 
946   tmp[0]=skin_name;
947   files=tmp;
948   nfiles=1;
949   files = expand_file_archives( files, &nfiles );
950 
951   pixmaps=0;
952 
953   xskin_loadviscolor( xskin_d, xskin_w, NULL );
954 
955   for ( i=0 ; i<nfiles ; i++ ) {
956 
957     /*printf("%s\n",files[i]);fflush(stdout);*/
958     p0=strrchr( files[i], '#' );
959     if ( p0==NULL ) p0=files[i];
960     else p0++;
961     p=strrchr( p0, PATH_SEP );
962     if ( p==NULL ) p=p0;
963     else p++;
964 
965            if ( strcasecmp( p, "viscolor.txt" )==0 ) {
966 	     xskin_loadviscolor( xskin_d, xskin_w, files[i] );
967 
968     } else if ( strcasecmp( p, "main.bmp" )==0 ) {
969       xskin_back =
970 	xskin_loadBMP( xskin_d, xskin_w, files[i], &width, &height );
971       pixmaps++;
972 
973     } else if ( strcasecmp( p, "titlebar.bmp" )==0 ) {
974       xskin_titlebar =
975 	xskin_loadBMP( xskin_d, xskin_w, files[i], &width, &height );
976       pixmaps++;
977 
978     } else if ( strcasecmp( p, "playpaus.bmp" )==0 ) {
979       xskin_playpaus =
980 	xskin_loadBMP( xskin_d, xskin_w, files[i], &width, &height );
981       pixmaps++;
982 
983     } else if ( strcasecmp( p, "cbuttons.bmp" )==0 ) {
984       xskin_cbuttons =
985 	xskin_loadBMP( xskin_d, xskin_w, files[i], &width, &height );
986       pixmaps++;
987 
988     } else if ( strcasecmp( p, "monoster.bmp" )==0 ) {
989       xskin_monoster =
990 	xskin_loadBMP( xskin_d, xskin_w, files[i], &width, &height );
991       pixmaps++;
992 
993     } else if ( strcasecmp( p, "posbar.bmp" )==0 ) {
994       xskin_posbar =
995 	xskin_loadBMP( xskin_d, xskin_w, files[i], &width, &height );
996       pixmaps++;
997 
998     } else if ( strcasecmp( p, "shufrep.bmp" )==0 ) {
999       xskin_shufrep =
1000 	xskin_loadBMP( xskin_d, xskin_w, files[i], &width, &height );
1001       pixmaps++;
1002 
1003     } else if ( strcasecmp( p, "text.bmp" )==0 ) {
1004       xskin_text =
1005 	xskin_loadBMP( xskin_d, xskin_w, files[i], &width, &height );
1006       pixmaps++;
1007 
1008     } else if ( strcasecmp( p, "volume.bmp" )==0 ) {
1009       xskin_volume =
1010 	xskin_loadBMP( xskin_d, xskin_w, files[i], &width, &height );
1011       pixmaps++;
1012 
1013     } else if ( strcasecmp( p, "numbers.bmp" )==0 ) {
1014       xskin_numbers =
1015 	xskin_loadBMP( xskin_d, xskin_w, files[i], &width, &height );
1016       pixmaps++;
1017 
1018     } else {
1019       width=1;
1020     }
1021     if ( width<0 ) return -1;
1022   }
1023 
1024   if(files != tmp)
1025       free(files);
1026 
1027   if ( pixmaps<10 ) {
1028     fprintf(stderr, "some of bmp file might be missed.\n");
1029     return -1;
1030   }
1031 
1032   return 0;
1033 }
1034 
repaint(void)1035 static void repaint( void ) {
1036 
1037   char tmp[64];
1038   int min,sec;
1039 
1040   /* static values */
1041 
1042   XClearWindow( xskin_d, xskin_w );
1043 
1044   ts_titlebar(OFF);
1045 
1046   ts_prev(OFF);
1047   ts_play(OFF);
1048   ts_pause(OFF);
1049   ts_stop(OFF);
1050   ts_next(OFF);
1051   ts_eject(OFF);
1052 
1053   if ( (play_mode->encoding & PE_MONO)==0 ) {
1054     ts_mono(OFF);
1055     ts_stereo(ON);
1056   } else {
1057     ts_mono(ON);
1058     ts_stereo(OFF);
1059   }
1060 
1061   ts_pan(OFF,-50);
1062   ts_puttext( BITRATE_X, BITRATE_Y, "---" ); /* bit-rate */
1063 
1064   sprintf( tmp, "%d", (int)play_mode->rate/1000 );
1065   ts_puttext( SAMPLE_X,  SAMPLE_Y,  tmp  ); /* sample-rate */
1066 
1067   /* volatile values */
1068 
1069   if ( fshuf==0 ) ts_shuf(OFF);
1070   else ts_shuf(ON);
1071 
1072   if ( frep==0 ) ts_rep(OFF);
1073   else ts_rep(ON);
1074 
1075   if ( fequ==0 ) ts_equ(OFF);
1076   else ts_equ(ON);
1077 
1078   if ( fpll==0 ) ts_plist(OFF);
1079   else ts_plist(ON);
1080 
1081   if ( fplay==1 ) {
1082     if ( fpause==0 ) ts_pstate( PSTATE_PLAY );
1083     else  ts_pstate( PSTATE_PAUSE );
1084   } else ts_pstate( PSTATE_STOP );
1085 
1086   ts_volume( OFF, -vol_val );
1087   ts_pos( OFF, -play_val );
1088 
1089   ts_puttext( MESSAGE_X, MESSAGE_Y, last_text );
1090 
1091   if ( fremain==0 ) {
1092     sec=last_current_time;
1093   } else {
1094     sec=total_time-last_current_time;
1095   }
1096   min =sec/60;
1097   sec-=min*60;
1098 
1099   ts_putnum( MIN_H_X, MIN_H_Y, min/10 );
1100   ts_putnum( MIN_L_X, MIN_L_Y, min%10 );
1101   ts_putnum( SEC_H_X, SEC_H_Y, sec/10 );
1102   ts_putnum( SEC_L_X, SEC_L_Y, sec%10 );
1103 
1104   XFlush(xskin_d);
1105   return;
1106 }
1107 
1108 /* signal handler calls are ported from xmasl
1109    and thanks to takawata@shidahara1.planet.kobe-u.ac.jp */
1110 
delete_shm(void)1111 void delete_shm( void ) {
1112 
1113   if ( speana_buf != NULL ) {
1114     shmdt( (char *)speana_buf );
1115     shmctl( shmid, IPC_RMID, 0 );
1116   }
1117   return;
1118 }
1119 
1120 static const int signals[]={SIGHUP,SIGINT,SIGQUIT,SIGILL,SIGABRT,SIGFPE,
1121 			    SIGBUS,SIGSEGV,SIGPIPE,SIGALRM,SIGTERM,0};
1122 
install_sighandler(void)1123 void install_sighandler( void ) {
1124   int i;
1125   for ( i=0 ; signals[i]!=0 ; i++ ) {
1126     signal( signals[i], signal_vector );
1127   }
1128 }
1129 
signal_vector(int sig)1130 void signal_vector( int sig ) {
1131 
1132   delete_shm();
1133 
1134   XUnmapWindow( xskin_d, xskin_w );
1135   XFlush(xskin_d);
1136   XDestroyWindow( xskin_d, xskin_w );
1137 
1138   XCloseDisplay( xskin_d );
1139   exit (0);
1140 }
1141