1 /*  MikMod module player
2 	(c) 1998 - 2000 Miodrag Vallat and others - see file AUTHORS for
3 	complete list.
4 
5 	This program is free software; you can redistribute it and/or modify
6 	it under the terms of the GNU General Public License as published by
7 	the Free Software Foundation; either version 2 of the License, or
8 	(at your option) any later version.
9 
10 	This program is distributed in the hope that it will be useful,
11 	but WITHOUT ANY WARRANTY; without even the implied warranty of
12 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 	GNU General Public License for more details.
14 
15 	You should have received a copy of the GNU General Public License
16 	along with this program; if not, write to the Free Software
17 	Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
18 	02111-1307, USA.
19 */
20 
21 /*==============================================================================
22 
23   $Id: mwindow.c,v 1.1.1.1 2004/01/16 02:07:36 raph Exp $
24 
25   Some window functions
26 
27 ==============================================================================*/
28 
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
32 #include <signal.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <stdarg.h>
36 #include <string.h>
37 
38 #if !defined(__OS2__)&&!defined(__EMX__)&&!defined(__DJGPP__)&&!defined(_WIN32)
39 #ifdef HAVE_SYS_IOCTL_H
40 #include <sys/ioctl.h>
41 #endif
42 #if !defined(GWINSZ_IN_SYS_IOCTL) && defined(HAVE_TERMIOS_H)
43 #include <termios.h>
44 #endif
45 #endif
46 
47 #if defined(__OS2__)||defined(__EMX__)||defined(__DJGPP__)||defined(_WIN32)
48 #if defined(__OS2__)||defined(__EMX__)
49 #define INCL_VIO
50 #define INCL_DOS
51 #define INCL_KBD
52 #define INCL_DOSPROCESS
53 #endif
54 #include <conio.h>
55 #endif
56 
57 #ifdef HAVE_UNISTD_H
58 #include <unistd.h>
59 #endif
60 
61 #include <mikmod.h>
62 #include "display.h"
63 #include "player.h"
64 #include "mwindow.h"
65 #include "mutilities.h"
66 #include "keys.h"
67 #include "mthreads.h"
68 
69 #define INVISIBLE(w)		(win_quiet || ((w)!=cur_window && (w)!=panel[0]))
70 #define INVISIBLE_RET(w)	if (win_quiet || ((w)!=cur_window && (w)!=panel[0])) return;
71 
72 #ifdef ACS_ULCORNER
73 
74 #define BOX_UL		ACS_ULCORNER
75 #define BOX_UR		ACS_URCORNER
76 #define BOX_LL		ACS_LLCORNER
77 #define BOX_LR		ACS_LRCORNER
78 #define BOX_HLINE	ACS_HLINE
79 #define BOX_VLINE	ACS_VLINE
80 
81 #else
82 
83 #if defined(__OS2__)||defined(__EMX__)||defined(__DJGPP__)||defined(_WIN32)
84 #define BOX_UL		'\xda'
85 #define BOX_UR		'\xbf'
86 #define BOX_LL		'\xc0'
87 #define BOX_LR		'\xd9'
88 #define BOX_HLINE	'\xc4'
89 #define BOX_VLINE	'\xb3'
90 #else
91 #define BOX_UL		'+'
92 #define BOX_UR		'+'
93 #define BOX_LL		'+'
94 #define BOX_LR		'+'
95 #define BOX_HLINE	'-'
96 #define BOX_VLINE	'|'
97 #endif
98 
99 #endif
100 
101 void win_do_resize(int dx, int dy, BOOL root);
102 
103 /* text creation buffer */
104 char storage[STORAGELEN+2];
105 
106 static int root_y1 = 7, root_y2 = 0;	/* size of visible root window partions */
107 static BOOL curses_on = 0, win_quiet = 1;
108 static int cur_panel = 0, old_panel = 0;
109 static MWINDOW *panel[DISPLAY_COUNT], *cur_window = NULL;
110 
111 static BOOL use_colors = 1;
112 static int act_color = A_NORMAL;
113 static THEME *theme = NULL;
114 
115 static int winx = 0, winy = 0;			/* screen size */
116 
117 typedef struct TIMEOUT {
118 	WinTimeoutFunc func;
119 	void *data;
120 	int interval;
121 	/* remaining time for the execution of this timeout compared
122 	   to the timeout located in the timeouts array before this one */
123 	int remaining;
124 } TIMEOUT;
125 
126 static int cnt_timeouts = 0;
127 static TIMEOUT *timeouts = NULL;
128 
129 /*========== Display routines */
130 
131 #if defined(__OS2__)||defined(__EMX__)
132 #include "os2video.inc"
133 
134 #elif defined(__DJGPP__)
135 #include "dosvideo.inc"
136 
137 #elif defined(_WIN32)
138 #include "winvideo.inc"
139 
140 #else /* unix, ncurses */
141 
142 static int cursor_old = 0;
143 static BOOL resize = 0;
144 
145 /* old AIX curses are very limited */
146 #if defined(AIX) && !defined(mvaddnstr)
mvaddnstr(int y,int x,const char * str,int len)147 void mvaddnstr(int y, int x, const char *str, int len)
148 {
149 	char buffer[STORAGELEN];
150 	int l = strlen(str);
151 
152 	strncpy(buffer, str, len);
153 	if (l < len)
154 		while (l < len)
155 			buffer[l++] = ' ';
156 	buffer[len] = '\0';
157 	mvaddstr(y, x, buffer);
158 }
159 #endif
160 
161 /* HP-UX curses macros don't work with every cpp */
162 #if defined(__hpux)
getmaxyx_hpux(MWINDOW * win,int * y,int * x)163 void getmaxyx_hpux(MWINDOW * win, int *y, int *x)
164 {
165 	*y = __getmaxy(win);
166 	*x = __getmaxx(win);
167 }
168 
169 #define getmaxyx(win,y,x) getmaxyx_hpux((win),&(y),&(x))
170 #endif
171 
172 #if defined(AIX) && !defined(NCURSES_VERSION) && !defined(getmaxyx)
173 #define getmaxyx(win,y,x) (y = LINES, x = COLS)
174 #endif
175 
176 #if !defined(getmaxyx)
177 #define getmaxyx(w,y,x) ((y) = getmaxy(w), (x) = getmaxx(w))
178 #endif
179 
180 /* handler for terminal resize events */
sigwinch_handler(int signum)181 RETSIGTYPE sigwinch_handler(int signum)
182 {
183 	/* schedule a resizeterm() */
184 	resize = 1;
185 
186 	signal(SIGWINCH, sigwinch_handler);
187 }
188 
189 /* update window */
win_refresh(void)190 void win_refresh(void)
191 {
192 	if (win_quiet)
193 		return;
194 	refresh();
195 }
196 
win_cursor_set(BOOL visible)197 void win_cursor_set(BOOL visible)
198 {
199 	if (cursor_old != MIK_CURSES_ERROR) {
200 		if (visible)
201 			curs_set(cursor_old);
202 		else
203 			curs_set(0);
204 	}
205 }
206 
207 #define COLOR_CNT 8
init_curses(void)208 static void init_curses(void)
209 {
210 	initscr();
211 	cbreak();
212 	noecho();
213 	nonl();
214 	nodelay(stdscr, TRUE);
215 #if !defined(AIX) || defined(NCURSES_VERSION)
216 	timeout(0);
217 #endif
218 	keypad(stdscr, TRUE);
219 	cursor_old = curs_set(0);
220 	curses_on = 1;
221 
222 	/* Color setup */
223 	start_color();
224 	if (has_colors() && (COLOR_PAIRS >= COLOR_CNT*COLOR_CNT)) {
225 		static short colors[] = {
226 			COLOR_BLACK,
227 			COLOR_BLUE,
228 			COLOR_GREEN,
229 			COLOR_CYAN,
230 			COLOR_RED,
231 			COLOR_MAGENTA,
232 			COLOR_YELLOW,
233 			COLOR_WHITE
234 		};
235 		int i,j;
236 		for (i = 0; i < COLOR_CNT; i++)
237 			for (j = 0; j < COLOR_CNT; j++)
238 				if (i*COLOR_CNT+j+1 < COLOR_CNT*COLOR_CNT)
239 					init_pair(i*COLOR_CNT+j+1, colors[j], colors[i]);
240 		use_colors = 1;
241 	} else
242 		use_colors = 0;
243 }
244 
color_to_pair(int attrs)245 static int color_to_pair (int attrs)
246 {
247 	return 1 +
248 		((attrs & COLOR_FMASK) >> COLOR_FSHIFT) +
249 		((attrs & COLOR_BMASK) >> COLOR_BSHIFT) * COLOR_CNT;
250 }
251 
252 /* system dependant window init function */
win_init_system(void)253 void win_init_system(void)
254 {
255 	if (!win_quiet) {
256 		init_curses();
257 		getmaxyx(stdscr, winy, winx);
258 		signal(SIGWINCH, sigwinch_handler);
259 	}
260 }
261 
262 /* clean up (e.g. exit curses) */
win_exit(void)263 void win_exit(void)
264 {
265 	if (win_quiet || !curses_on)
266 		return;
267 
268 	signal(SIGWINCH, SIG_DFL);
269 	clear();
270 	mvaddnstr(winy - 2, 0, mikversion, winx);
271 	win_refresh();
272 	win_cursor_set(1);
273 	endwin();
274 	curses_on = 0;
275 }
276 
277 /* clear to end of line on window win */
win_clrtoeol(MWINDOW * win,int x,int y)278 void win_clrtoeol(MWINDOW *win, int x, int y)
279 {
280 	int len = win->width - x;
281 
282 	INVISIBLE_RET(win);
283 
284 	if (len > 0) {
285 		memset(storage, ' ', len);
286 		storage[len] = '\0';
287 		mvaddnstr(win->y + y, win->x + x, storage, len);
288 	}
289 }
290 
291 /* check if a resize was scheduled and do it */
win_check_resize(void)292 BOOL win_check_resize(void)
293 {
294 	static BOOL in_check_resize = 0;
295 
296 	if (win_quiet || in_check_resize)
297 		return 0;
298 	in_check_resize = 1;
299 
300 	/* if a resize was scheduled, do it now */
301 	if (resize) {
302 		int oldx, oldy;
303 #if (NCURSES_VERSION_MAJOR >= 4) && defined(TIOCGWINSZ) && defined(HAVE_NCURSES_RESIZETERM)
304 		struct winsize ws;
305 
306 		ws.ws_col = ws.ws_row = 0;
307 		ioctl(0, TIOCGWINSZ, &ws);
308 		if (ws.ws_col && ws.ws_row)
309 			resizeterm(ws.ws_row, ws.ws_col);
310 #else
311 		endwin();
312 		init_curses();
313 		win_refresh();
314 #endif
315 		resize = 0;
316 		oldx = winx;
317 		oldy = winy;
318 		getmaxyx(stdscr, winy, winx);
319 		win_do_resize(winx - oldx, winy - oldy, 1);
320 		in_check_resize = 0;
321 		return 1;
322 	}
323 	in_check_resize = 0;
324 	return 0;
325 }
326 
win_getch(void)327 static int win_getch(void)
328 {
329 	int c = getch();
330 	win_check_resize();
331 /*	if (c>0) fprintf (stderr," %d ",c);*/
332 	return c == MIK_CURSES_ERROR ? 0 : c;
333 }
334 
335 #endif /* #ifdef unix */
336 
337 /*========== Windowing system */
338 
339 /* init window functions (e.g. init curses) */
win_init(BOOL quiet)340 void win_init(BOOL quiet)
341 {
342 	win_quiet = quiet;
343 
344 	win_init_system();
345 
346 	win_open(0, 0, winx, winy, 0, NULL, ATTR_SONG_STATUS);
347 	win_set_resize(1, NULL);
348 }
349 
350 /* Does the terminal support colors? */
win_has_colors(void)351 BOOL win_has_colors (void)
352 {
353 	return use_colors;
354 }
355 
356 /* set the attribute translation table */
win_set_theme(THEME * new_theme)357 void win_set_theme (THEME *new_theme)
358 {
359 	theme = new_theme;
360 }
361 
362 /* clear window win */
win_clear(MWINDOW * win)363 BOOL win_clear(MWINDOW * win)
364 {
365 	if (INVISIBLE(win)) return 1;
366 
367 	if ((win->width > 0) && (win->height > 0)) {
368 		int i;
369 
370 		win_attrset(win->attrs);
371 		memset(storage, ' ', win->width);
372 		storage[win->width] = '\0';
373 
374 		if (win==panel[0]) {
375 			for (i = 0; i < win->height && i < root_y1; i++)
376 				mvaddnstr(win->y + i, win->x, storage, win->width);
377 			i = win->height - root_y2;
378 			if (i < 0)
379 				i = 0;
380 			for (; i < win->height; i++)
381 				mvaddnstr(win->y + i, win->x, storage, win->width);
382 		} else {
383 			for (i = 0; i < win->height; i++)
384 				mvaddnstr(win->y + i, win->x, storage, win->width);
385 		}
386 	}
387 	return 1;
388 }
389 
win_box_win(int x1,int y1,int x2,int y2,const char * title)390 void win_box_win(int x1, int y1, int x2, int y2, const char *title)
391 {
392 	int i, sx1, sx2, sy1, sy2;
393 
394 	if (win_quiet)
395 		return;
396 
397 	sx1 = x1 >= 0 ? x1 + 1 : 0;
398 	sx2 = x2 < winx ? x2 - 1 : winx - 1;
399 	sy1 = y1 >= root_y1 ? y1 + 1 : root_y1;
400 	sy2 = y2 < winy - root_y2 ? y2 - 1 : winy - root_y2;
401 
402 	if (y2 < winy - root_y2) {
403 		if (x1 >= 0)
404 			mvaddch(y2, x1, BOX_LL);
405 		if (x2 < winx)
406 			mvaddch(y2, x2, BOX_LR);
407 
408 		for (i = sx1; i <= sx2; i++)
409 			mvaddch(y2, i, BOX_HLINE);
410 	}
411 	if (y1 >= root_y1) {
412 		if (x1 >= 0)
413 			mvaddch(y1, x1, BOX_UL);
414 		if (x2 < winx)
415 			mvaddch(y1, x2, BOX_UR);
416 
417 		i = sx1;
418 		if (title)
419 			for (; i <= sx2 && *title; i++)
420 				mvaddch(y1, i, *title++);
421 		for (; i <= sx2; i++)
422 			mvaddch(y1, i, BOX_HLINE);
423 	}
424 	for (i = sy1; i <= sy2; i++) {
425 		if (x1 >= 0)
426 			mvaddch(i, x1, BOX_VLINE);
427 		if (x2 < winx)
428 			mvaddch(i, x2, BOX_VLINE);
429 	}
430 }
431 
432 /* open new window on panel 'panel' */
win_panel_open(int dst_panel,int x,int y,int width,int height,BOOL border,const char * title,ATTRS attrs)433 MWINDOW *win_panel_open(int dst_panel, int x, int y, int width, int height,
434 				BOOL border, const char *title, ATTRS attrs)
435 {
436 	MWINDOW *win = (MWINDOW *) malloc(sizeof(MWINDOW)), *help;
437 
438 	int ofs = (border ? 1 : 0);
439 
440 	if (x < ofs)
441 		x = ofs;
442 	if (!dst_panel) {			/* root panel */
443 		if (y < ofs)
444 			y = ofs;
445 		if (y + height > winy - ofs)
446 			height = winy - y - ofs;
447 	} else {
448 		if (y < ofs + root_y1)
449 			y = ofs + root_y1;
450 		if (y + height > winy - ofs - root_y2)
451 			height = winy - y - ofs - root_y2;
452 	}
453 	if (x + width > winx - ofs)
454 		width = winx - x - ofs;
455 	if (width < 0)
456 		width = 0;
457 
458 	if (height < 0)
459 		height = 0;
460 
461 	win_attrset(attrs);
462 	if (border && (dst_panel == cur_panel))
463 		win_box_win(x - 1, y - 1, x + width, y + height, title);
464 
465 	win->x = x;
466 	win->y = y;
467 	win->width = width;
468 	win->height = height;
469 	win->attrs = attrs;
470 	win->border = border;
471 	win->resize = 0;
472 	if (title)
473 		win->title = strdup(title);
474 	else
475 		win->title = NULL;
476 	win->next = NULL;
477 	win->repaint = win_clear;
478 	win->handle_key = NULL;
479 	win->handle_resize = NULL;
480 	for (help = panel[dst_panel]; help && help->next; help = help->next);
481 	if (help)
482 		help->next = win;
483 	else
484 		panel[dst_panel] = win;
485 	if (dst_panel == cur_panel)
486 		cur_window = win;
487 	return win;
488 }
489 
490 /* open new window on current panel */
win_open(int x,int y,int width,int height,BOOL border,const char * title,ATTRS attrs)491 MWINDOW *win_open(int x, int y, int width, int height, BOOL border,
492 				  const char *title, ATTRS attrs)
493 {
494 	return win_panel_open(cur_panel, x, y, width, height, border, title, attrs);
495 }
496 
win_get_first(int dst_panel)497 MWINDOW *win_get_first(int dst_panel)
498 {
499 	MWINDOW *win;
500 	for (win = panel[dst_panel]; win && win->next; win = win->next);
501 	return win;
502 }
503 
504 /* set function which sould be called on a repaint request */
win_set_repaint(WinRepaintFunc func)505 void win_set_repaint(WinRepaintFunc func)
506 {
507 	cur_window->repaint = func;
508 }
win_panel_set_repaint(int _panel,WinRepaintFunc func)509 void win_panel_set_repaint(int _panel, WinRepaintFunc func)
510 {
511 	win_get_first(_panel)->repaint = func;
512 }
513 
514 /* set function which sould be called on a key press */
win_set_handle_key(WinKeyFunc func)515 void win_set_handle_key(WinKeyFunc func)
516 {
517 	cur_window->handle_key = func;
518 }
win_panel_set_handle_key(int _panel,WinKeyFunc func)519 void win_panel_set_handle_key(int _panel, WinKeyFunc func)
520 {
521 	win_get_first(_panel)->handle_key = func;
522 }
523 
524 /* should window be automatically resized?
525    should a function be called on resize? */
win_set_resize(BOOL auto_resize,WinResizeFunc func)526 void win_set_resize(BOOL auto_resize, WinResizeFunc func)
527 {
528 	cur_window->resize = auto_resize;
529 	cur_window->handle_resize = func;
530 }
win_panel_set_resize(int _panel,BOOL auto_resize,WinResizeFunc func)531 void win_panel_set_resize(int _panel, BOOL auto_resize, WinResizeFunc func)
532 {
533 	MWINDOW *win = win_get_first(_panel);
534 	win->resize = auto_resize;
535 	win->handle_resize = func;
536 }
537 
538 /* set private data */
win_set_data(void * data)539 void win_set_data(void *data)
540 {
541 	cur_window->data = data;
542 }
543 
win_panel_set_data(int _panel,void * data)544 void win_panel_set_data(int _panel, void *data)
545 {
546 	win_get_first(_panel)->data = data;
547 }
548 
win_do_resize(int dx,int dy,BOOL root)549 void win_do_resize(int dx, int dy, BOOL root)
550 {
551 	MWINDOW *win;
552 	int i = root ? 0 : 1;
553 
554 	if (win_quiet)
555 		return;
556 
557 	for (; i < DISPLAY_COUNT; i++)
558 		for (win = panel[i]; win; win = win->next) {
559 			if (win->resize) {
560 				win->width += dx;
561 				win->height += dy;
562 			}
563 			if (win->handle_resize)
564 				win->handle_resize(win, dx, dy);
565 		}
566 	win_panel_repaint_force();
567 }
568 
569 static char status_message[MAXWIDTH + 2];
570 
win_status_repaint(void)571 static void win_status_repaint(void)
572 {
573 	MWINDOW *win = panel[0];
574 	int i;
575 	if (win_quiet)
576 		return;
577 
578 	if ((root_y2 > 1) && (win->height > root_y1+1)) {
579 		win_attrset(ATTR_STATUS_LINE);
580 		for (i = 0; i < win->width; i++)
581 			mvaddch(win->height - 2, i, BOX_HLINE);
582 	}
583 }
584 
585 /* init the status line(height=0,1,2  0: no status line) */
win_init_status(int height)586 void win_init_status(int height)
587 {
588 	int old_y2 = root_y2;
589 
590 	if (height != root_y2) {
591 		root_y2 = height < 0 ? 0 : (height > 2 ? 2 : height);
592 #if defined(__OS2__)||defined(__EMX__)||defined(__DJGPP__)||defined(_WIN32)
593 		status_message[0] = '\0';
594 #else
595 		status_message[0] = '\n';
596 		status_message[1] = '\0';
597 #endif
598 		win_do_resize(0, old_y2 - root_y2, 0);
599 	}
600 }
601 
602 /* set the status line */
win_status(const char * msg)603 void win_status(const char *msg)
604 {
605 	MWINDOW *win = panel[0];
606 	int len;
607 
608 	if (msg) {
609 		len = strlen(msg);
610 		if (len > MAXWIDTH)
611 			len = MAXWIDTH;
612 		strncpy(status_message, msg, len);
613 	} else
614 		len = strlen(status_message);
615 	status_message[len] = '\0';
616 
617 	if (win_quiet)
618 		return;
619 	if ((root_y2 > 0) && (win->height > root_y1) && (win->width>0)) {
620 		win_attrset(ATTR_STATUS_TEXT);
621 		mvaddnstr(win->y + win->height - 1, win->x, status_message,
622 				  win->width);
623 		win_clrtoeol(win, win->x + len, win->y + win->height - 1);
624 	}
625 }
626 
627 /* repaint the whole panel */
win_panel_repaint(void)628 void win_panel_repaint(void)
629 {
630 	if (win_quiet)
631 		return;
632 
633 	if (panel[cur_panel])
634 		win_clear(panel[cur_panel]);
635 
636 	if (panel[0]->repaint)
637 		if (!panel[0]->repaint(panel[0]))
638 			return;
639 	for (cur_window = panel[cur_panel]; cur_window;
640 		 cur_window = cur_window->next) {
641 		win_attrset(cur_window->attrs);
642 		if (cur_window->border && cur_window->width >= 0 &&
643 			cur_window->height >= 0)
644 			win_box_win(cur_window->x - 1, cur_window->y - 1,
645 						cur_window->x + cur_window->width,
646 						cur_window->y + cur_window->height, cur_window->title);
647 		if (cur_window->repaint && cur_window->width > 0 &&
648 			cur_window->height > 0)
649 			if (!cur_window->repaint(cur_window))
650 				return;
651 	}
652 	win_status_repaint();
653 	win_status(NULL);
654 	for (cur_window = panel[cur_panel]; cur_window && cur_window->next;
655 		 cur_window = cur_window->next);
656 }
657 
658 /* repaint the whole panel, clear whole panel before */
win_panel_repaint_force(void)659 void win_panel_repaint_force(void)
660 {
661 	if (win_quiet) return;
662 	clear();
663 	win_panel_repaint();
664 }
665 
666 /* close window win */
win_close(MWINDOW * win)667 void win_close(MWINDOW * win)
668 {
669 	int i;
670 	MWINDOW *pos;
671 
672 	for (i = 0; i < DISPLAY_COUNT; i++)
673 		for (pos = panel[i]; pos; pos = pos->next)
674 			if (pos == win) {
675 				if (win == cur_window)
676 					for (cur_window = panel[i]; cur_window->next != win;
677 						 cur_window = cur_window->next);
678 				for (pos = panel[i]; pos->next != win; pos = pos->next);
679 				pos->next = win->next;
680 				if (win->title)
681 					free(win->title);
682 				free(win);
683 				if (i == cur_panel)
684 					win_panel_repaint();
685 				return;
686 			}
687 }
688 
689 /* get size of window win */
win_get_size(MWINDOW * win,int * x,int * y)690 void win_get_size(MWINDOW *win, int *x, int *y)
691 {
692 	*x = win->width;
693 	*y = win->height;
694 }
695 
696 /* get maximal size of a new window without a border and therefore the needed
697    minimal y position */
win_get_size_max(int * y,int * width,int * height)698 void win_get_size_max(int *y, int *width, int *height)
699 {
700 	*y = root_y1;
701 	*width = panel[0]->width;
702 	*height = panel[0]->height - root_y1 - root_y2;
703 	if (*height < 0)
704 		*height = 0;
705 }
706 
707 /* get uppermost window */
win_get_window(void)708 MWINDOW *win_get_window(void)
709 {
710 	return cur_window;
711 }
712 
713 /* get root window */
win_get_window_root(void)714 MWINDOW *win_get_window_root(void)
715 {
716 	return panel[0];
717 }
718 
719 /* print string in window win */
win_print(MWINDOW * win,int x,int y,const char * str)720 void win_print(MWINDOW *win, int x, int y, const char *str)
721 {
722 	int len = strlen(str);
723 
724 #if defined(__OS2__)||defined(__EMX__)||defined(__DJGPP__)||defined(_WIN32)
725 	if (len > 1 && str[len - 1] == '\n' && str[len - 2] == '\r')
726 		len--;
727 #endif
728 	INVISIBLE_RET(win);
729 
730 	if ((x >= win->width) || (y >= win->height) ||
731 		((win != panel[0]) && (y + win->y >= winy - root_y2)) ||
732 		(!len))
733 		return;
734 
735 	if (len + x > win->width)
736 		len = win->width - x;
737 	if (len > 0 && (str[len - 1] == '\n' || str[len - 1] == '\r'))
738 #if !defined(__OS2__)&&!defined(__EMX__)&&!defined(__DJGPP__)&&!defined(_WIN32)
739 		if (win->x + win->width < winx)
740 #endif
741 		{
742 			len--;
743 			win_clrtoeol(win, x + len, y);
744 		}
745 	mvaddnstr(y + win->y, x + win->x, str, len);
746 }
747 
748 /* draw horizontal/verticall line */
win_line(MWINDOW * win,int x1,int y1,int x2,int y2)749 void win_line(MWINDOW *win, int x1, int y1, int x2, int y2)
750 {
751 	int i;
752 
753 	INVISIBLE_RET(win);
754 
755 	if (y1 == y2) {
756 		if (y1 < cur_window->height)
757 			for (i = x1; i <= x2 && i < cur_window->width; i++)
758 				mvaddch(y1 + cur_window->y, i + cur_window->x, BOX_HLINE);
759 	} else {
760 		if (x1 < cur_window->width)
761 			for (i = y1; i <= y2 && i < cur_window->height; i++)
762 				mvaddch(i + cur_window->y, x1 + cur_window->x, BOX_VLINE);
763 	}
764 }
765 
766 /* draw a box with colored background
767    back:  background colors from UL UR LR LL to UL */
win_box_color(MWINDOW * win,int x1,int y1,int x2,int y2,ATTRS * back)768 void win_box_color(MWINDOW *win, int x1, int y1, int x2, int y2, ATTRS *back)
769 {
770 	int i, j, k, sx1, sx2, sy1, sy2, maxx, maxy;
771 
772 	INVISIBLE_RET(win);
773 
774 	x1 += win->x;
775 	x2 += win->x;
776 	y1 += win->y;
777 	y2 += win->y;
778 
779 	maxx = win->x+win->width-1;
780 	maxy = win->y+win->height-1;
781 
782 	sx1 = x1>=win->x ? x1+1 : win->x;
783 	sy1 = y1>=win->y ? y1+1 : win->y;
784 	sx2 = x2<=maxx ? x2 - 1 : maxx;
785 	sy2 = y2<=maxy ? y2 - 1 : maxy;
786 
787 	if (y2 <= maxy) {
788 		if (x1 >= win->x) {
789 			if (back)
790 				win_set_background (back[x2-x1+x2-x1+y2-y1]);
791 			mvaddch(y2, x1, BOX_LL);
792 		}
793 		if (x2 <= maxx) {
794 			if (back)
795 				win_set_background (back[x2-x1+y2-y1]);
796 			mvaddch(y2, x2, BOX_LR);
797 		}
798 		j = x2-x1+x2-sx1+y2-y1;
799 		for (i = sx1; i <= sx2; i++) {
800 			if (back)
801 				win_set_background (back[j--]);
802 			mvaddch(y2, i, BOX_HLINE);
803 		}
804 	}
805 	if (y1 >= win->y) {
806 		if (x1 >= win->x) {
807 			if (back)
808 				win_set_background (back[0]);
809 			mvaddch(y1, x1, BOX_UL);
810 		}
811 		if (x2 <= maxx) {
812 			if (back)
813 				win_set_background (back[x2-x1]);
814 			mvaddch(y1, x2, BOX_UR);
815 		}
816 		j = sx1-x1;
817 		for (i=sx1; i <= sx2; i++) {
818 			if (back)
819 				win_set_background (back[j++]);
820 			mvaddch(y1, i, BOX_HLINE);
821 		}
822 	}
823 	j = x2-x1+sy1-y1;
824 	k = x2-x1+x2-x1+y2-y1+y2-sy1;
825 	for (i = sy1; i <= sy2; i++) {
826 		if (x1 >= win->x) {
827 			if (back)
828 				win_set_background (back[k--]);
829 			mvaddch(i, x1, BOX_VLINE);
830 		}
831 		if (x2 <= maxx) {
832 			if (back)
833 				win_set_background (back[j++]);
834 			mvaddch(i, x2, BOX_VLINE);
835 		}
836 	}
837 }
838 /* draw a box */
win_box(MWINDOW * win,int x1,int y1,int x2,int y2)839 void win_box(MWINDOW *win, int x1, int y1, int x2, int y2)
840 {
841 	win_box_color (win, x1, y1, x2, y2, NULL);
842 }
843 
844 /* set attribute for the following output operations,
845    "attrs" is an index into the theme->attr translation table */
win_attrset(ATTRS attrs)846 void win_attrset(ATTRS attrs)
847 {
848 	if (theme && !win_quiet) {
849 		int theme_attr = theme->attrs[attrs];
850 		act_color = theme_attr;
851 #if !defined(__OS2__)&&!defined(__EMX__)&&!defined(__DJGPP__)&&!defined(_WIN32)
852 		if (theme->color) {
853 			int pair;
854 			if (theme_attr == ((COLOR_CNT-1) << COLOR_BSHIFT) + ((COLOR_CNT-1) << COLOR_FSHIFT))
855 				theme_attr = ((COLOR_CNT-1) << COLOR_BSHIFT) + ((COLOR_CNT-2) << COLOR_FSHIFT);
856 			act_color = theme_attr;
857 			pair = COLOR_PAIR(color_to_pair(theme_attr));
858 			if (theme_attr & COLOR_BOLDMASK)
859 				attrset(pair | A_BOLD);
860 			else
861 				attrset(pair);
862 		} else
863 #endif
864 			attrset(theme_attr);
865 	}
866 }
867 
win_get_theme_color(ATTRS attrs)868 ATTRS win_get_theme_color (ATTRS attrs)
869 {
870 	if (theme) {
871 		int theme_attr = theme->attrs[attrs];
872 #if !defined(__OS2__)&&!defined(__EMX__)&&!defined(__DJGPP__)&&!defined(_WIN32)
873 		if (theme->color)
874 			if (theme_attr == ((COLOR_CNT-1) << COLOR_BSHIFT) + ((COLOR_CNT-1) << COLOR_FSHIFT))
875 				theme_attr = ((COLOR_CNT-1) << COLOR_BSHIFT) + ((COLOR_CNT-2) << COLOR_FSHIFT);
876 #endif
877 		return theme_attr;
878 	} else
879 		return 0;
880 }
881 
882 /* set color for the following output operations */
win_set_color(ATTRS attrs)883 void win_set_color(ATTRS attrs)
884 {
885 	if (win_quiet) return;
886 
887 	act_color = attrs;
888 #if !defined(__OS2__)&&!defined(__EMX__)&&!defined(__DJGPP__)&&!defined(_WIN32)
889 	if (win_has_colors()) {
890 		int pair;
891 		if (attrs == ((COLOR_CNT-1) << COLOR_BSHIFT) + ((COLOR_CNT-1) << COLOR_FSHIFT))
892 			attrs = ((COLOR_CNT-1) << COLOR_BSHIFT) + ((COLOR_CNT-2) << COLOR_FSHIFT);
893 		act_color = attrs;
894 		pair = COLOR_PAIR(color_to_pair(attrs));
895 		if (attrs & COLOR_BOLDMASK)
896 			attrset(pair | A_BOLD);
897 		else
898 			attrset(pair);
899 	} else
900 #endif
901 		attrset(attrs);
902 }
903 
win_set_forground(ATTRS fg)904 void win_set_forground(ATTRS fg)
905 {
906 	if (win_has_colors())
907 		win_set_color ((act_color & COLOR_BMASK) + (fg << COLOR_FSHIFT));
908 }
909 
win_set_background(ATTRS bg)910 void win_set_background(ATTRS bg)
911 {
912 	if (win_has_colors())
913 		win_set_color ((act_color & COLOR_FMASK) + (bg << COLOR_BSHIFT));
914 }
915 
916 /* change current panel */
win_change_panel(int new_panel)917 void win_change_panel(int new_panel)
918 {
919 	if (new_panel == cur_panel)
920 		new_panel = old_panel;
921 	old_panel = cur_panel;
922 	if (new_panel != cur_panel) {
923 		cur_panel = new_panel;
924 		for (cur_window = panel[cur_panel]; cur_window && cur_window->next;
925 			 cur_window = cur_window->next);
926 		win_panel_repaint();
927 	}
928 }
929 
win_get_panel(void)930 int win_get_panel(void)
931 {
932 	return cur_panel;
933 }
934 
935 /* handle key press(panel change and call of key handler
936    of uppermost window),return: was key handled */
win_handle_key(int ch)937 BOOL win_handle_key(int ch)
938 {
939 	int ret;
940 	switch (ch) {
941 	  case KEY_F(1):
942 		win_change_panel(DISPLAY_HELP);
943 		break;
944 	  case KEY_F(2):
945 		win_change_panel(DISPLAY_SAMPLE);
946 		break;
947 	  case KEY_F(3):
948 		win_change_panel(DISPLAY_INST);
949 		break;
950 	  case KEY_F(4):
951 #if defined(__OS2__)||defined(__EMX__)||defined(__DJGPP__)||defined(_WIN32)
952 	  case KEY_SF(9):			/* shift-F9 */
953 #else
954 	  case KEY_F(19):			/* shift-F9 on some curses implementations */
955 #endif
956 		win_change_panel(DISPLAY_MESSAGE);
957 		break;
958 	  case KEY_F(5):
959 		win_change_panel(DISPLAY_LIST);
960 		break;
961 	  case KEY_F(6):
962 		win_change_panel(DISPLAY_CONFIG);
963 		break;
964 #if LIBMIKMOD_VERSION >= 0x030200
965 	  case KEY_F(7):
966 		win_change_panel(DISPLAY_VOLBARS);
967 		break;
968 #endif
969 	  default:
970 		ret = 0;
971 		if (cur_window->handle_key)
972 			ret = cur_window->handle_key(cur_window, ch);
973 		if (!ret && panel[0]->handle_key)
974 			ret = panel[0]->handle_key(panel[0], ch);
975 		return ret;
976 	}
977 	return 1;
978 }
979 
980 /* Insert src (src!=NULL) or timeouts[0] (src==NULL) sorted after next
981    execution in timeouts and set remaining appropriate.
982    Expand timeouts array if src!=NULL. */
win_timeout_insert(TIMEOUT * src)983 static void win_timeout_insert (TIMEOUT *src)
984 {
985 	int time;
986 	int sum = 0, oldsum = 0, pos = 0, i;
987 
988 	if (!src) {
989 		time = timeouts[0].interval;
990 		pos++;
991 	} else
992 		time = src->interval;
993 
994 	for (; pos<=cnt_timeouts; pos++) {
995 		oldsum = sum;
996 		if (pos<cnt_timeouts)
997 			sum += timeouts[pos].remaining;
998 		if (sum>time || pos==cnt_timeouts) {
999 			if (src) {
1000 				timeouts = (TIMEOUT *) realloc (timeouts,
1001 									sizeof(TIMEOUT)*(++cnt_timeouts));
1002 				for (i=cnt_timeouts-1; i>pos; i--)
1003 					timeouts[i] = timeouts[i-1];
1004 				timeouts[pos] = *src;
1005 			} else {
1006 				TIMEOUT help = timeouts[0];
1007 				pos--;
1008 				for (i=0; i<pos; i++)
1009 					timeouts[i] = timeouts[i+1];
1010 				timeouts[pos] = help;
1011 			}
1012 			timeouts[pos].remaining = time-oldsum;
1013 			return;
1014 		}
1015 	}
1016 }
1017 
1018 /* add a new timeout function called approx. every interval ms */
win_timeout_add(int interval,WinTimeoutFunc func,void * data)1019 void win_timeout_add (int interval, WinTimeoutFunc func, void *data)
1020 {
1021 	TIMEOUT new_timeout;
1022 	new_timeout.func = func;
1023 	new_timeout.data = data;
1024 	new_timeout.interval = interval;
1025 	win_timeout_insert (&new_timeout);
1026 }
1027 
win_timeout_remove(int number)1028 static void win_timeout_remove (int number)
1029 {
1030 	int i;
1031 	for (i=number+1; i<cnt_timeouts; i++)
1032 		timeouts[i-1] = timeouts[i];
1033 	cnt_timeouts--;
1034 	if (cnt_timeouts) {
1035 		timeouts = (TIMEOUT *) realloc (timeouts,sizeof(TIMEOUT)*cnt_timeouts);
1036 	} else {
1037 		free (timeouts);
1038 		timeouts = NULL;
1039 	}
1040 }
1041 
1042 /* Handle scheduled timeouts and up to one key press,
1043    return 1 if key presses are pending */
win_main_iteration(void)1044 BOOL win_main_iteration(void)
1045 {
1046 	static unsigned long last_time = 0, time;
1047 	static int last_ch = 0;
1048 	int ch;
1049 
1050 	time = Time1000();
1051 	if (timeouts && last_time)
1052 		timeouts[0].remaining -= time-last_time;
1053 	last_time = time;
1054 
1055 	while (timeouts && timeouts[0].remaining <= 0) {
1056 		if (timeouts[0].func &&
1057 			! timeouts[0].func (cur_window, timeouts[0].data)) {
1058 			win_timeout_remove (0);
1059 		} else
1060 			win_timeout_insert (NULL);
1061 	}
1062 
1063 	if (win_quiet) return 0;
1064 
1065 	if (last_ch)
1066 		ch = last_ch;
1067 	else
1068 		ch = win_getch();
1069 	if (ch) {
1070 		win_handle_key(ch);
1071 #if !defined(__OS2__)&&!defined(__EMX__)&&!defined(__DJGPP__)&&!defined(_WIN32)
1072 /*		flushinp(); */
1073 #endif
1074 		last_ch = win_getch();
1075 	}
1076 
1077 	return last_ch != 0;
1078 }
1079 
win_run(void)1080 void win_run(void)
1081 {
1082 	do {
1083 		while (win_main_iteration());
1084 		SLEEP(1);
1085 	} while (1);
1086 }
1087 
1088 /* ex:set ts=4: */
1089