1 /* OpenCP Module Player
2 * copyright (c) '94-'10 Niklas Beisert <nbeisert@physik.tu-muenchen.de>
3 *
4 * CPIFace text modes master mode and window handler
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., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 * revision history: (please note changes here)
21 * -nb980510 Niklas Beisert <nbeisert@physik.tu-muenchen.de>
22 * -first release
23 * -fd981119 Felix Domke <tmbinc@gmx.net>
24 * -added the really important 'NO_CPIFACE_IMPORT'
25 * -ss040825 Stian Skjelstad <stian@nixia.no>
26 * -upgraded the IQ of cpiTextRecalc to make it try fill more of the screen
27 */
28
29 #include "config.h"
30 #include <string.h>
31 #include "types.h"
32 #include "stuff/poutput.h"
33 #include "filesel/pfilesel.h"
34 #include "cpiface.h"
35 #include "boot/psetting.h"
36 #include "boot/plinkman.h"
37
38 static struct cpitextmoderegstruct *cpiTextActModes;
39 static struct cpitextmoderegstruct *cpiTextModes = 0;
40 static struct cpitextmoderegstruct *cpiTextDefModes = 0;
41 static struct cpitextmoderegstruct *cpiFocus;
42 static char cpiFocusHandle[9];
43 static int modeactive;
44
45 static unsigned int LastWidth, LastHeight;
46
cpiTextRegisterMode(struct cpitextmoderegstruct * mode)47 void cpiTextRegisterMode(struct cpitextmoderegstruct *mode)
48 {
49 if (mode->Event&&!mode->Event(cpievInit))
50 return;
51 mode->next=cpiTextModes;
52 cpiTextModes=mode;
53 }
54
cpiTextUnregisterMode(struct cpitextmoderegstruct * m)55 void cpiTextUnregisterMode(struct cpitextmoderegstruct *m)
56 {
57 if (cpiTextModes==m)
58 {
59 cpiTextModes=m->next;
60 return;
61 } else {
62 struct cpitextmoderegstruct *p = cpiTextModes;
63 while (p)
64 {
65 if (p->next==m)
66 {
67 p->next=m->next;
68 return;
69 }
70 p=p->next;
71 }
72 }
73 }
74
cpiTextRegisterDefMode(struct cpitextmoderegstruct * mode)75 void cpiTextRegisterDefMode(struct cpitextmoderegstruct *mode)
76 {
77 mode->nextdef=cpiTextDefModes;
78 cpiTextDefModes=mode;
79 }
80
cpiTextVerifyDefModes(void)81 static void cpiTextVerifyDefModes(void)
82 {
83 struct cpitextmoderegstruct *p;
84
85 while (cpiTextDefModes)
86 {
87 if (cpiTextDefModes->Event&&!cpiTextDefModes->Event(cpievInitAll))
88 cpiTextDefModes=cpiTextDefModes->nextdef;
89 else
90 break;
91 }
92 p = cpiTextDefModes;
93 while (p)
94 {
95 if (p->nextdef)
96 {
97 if (p->nextdef->Event&&!p->nextdef->Event(cpievInitAll))
98 p->nextdef=p->nextdef->nextdef;
99 else
100 p=p->nextdef;
101 } else
102 break;
103 }
104 }
105
cpiTextUnregisterDefMode(struct cpitextmoderegstruct * m)106 void cpiTextUnregisterDefMode(struct cpitextmoderegstruct *m)
107 {
108 if (cpiTextDefModes==m)
109 {
110 cpiTextDefModes=m->next;
111 return;
112 } else {
113 struct cpitextmoderegstruct *p = cpiTextDefModes;
114 while (p)
115 {
116 if (p->nextdef==m)
117 {
118 p->nextdef=m->nextdef;
119 return;
120 }
121 p=p->nextdef;
122 }
123 }
124 }
125
cpiSetFocus(const char * name)126 static void cpiSetFocus(const char *name)
127 {
128 struct cpitextmoderegstruct *mode;
129
130 if (cpiFocus&&cpiFocus->Event)
131 cpiFocus->Event(cpievLoseFocus);
132 cpiFocus=0;
133 if (!name)
134 {
135 *cpiFocusHandle=0;
136 return;
137 }
138 for (mode=cpiTextActModes; mode; mode=mode->nextact)
139 if (!strcasecmp(name, mode->handle))
140 break;
141 *cpiFocusHandle=0;
142 if (!mode||(mode->Event&&!mode->Event(cpievGetFocus)))
143 return;
144 cpiFocus=mode;
145 mode->active=1;
146 strcpy(cpiFocusHandle, cpiFocus->handle);
147 cpiTextRecalc();
148 }
149
cpiTextSetMode(const char * name)150 void cpiTextSetMode(const char *name)
151 {
152 if (!name)
153 name=cpiFocusHandle;
154 if (!modeactive)
155 {
156 strcpy(cpiFocusHandle, name);
157 cpiSetMode("text");
158 } else
159 cpiSetFocus(name);
160 }
161
cpiTextRecalc(void)162 void cpiTextRecalc(void)
163 {
164 unsigned int i;
165 int winfirst=5;
166 int winheight=plScrHeight-winfirst;
167 int sidefirst=5;
168 int sideheight=plScrHeight-sidefirst;
169 struct cpitextmodequerystruct win[10];
170 unsigned int nwin=0;
171 struct cpitextmoderegstruct *mode;
172
173 int sidemin,sidemax,sidesize;
174 int winmin,winmax,winsize;
175
176 plChanChanged=1;
177
178 LastWidth=plScrWidth;
179 LastHeight=plScrHeight;
180
181 for (mode=cpiTextActModes; mode; mode=mode->nextact)
182 {
183 mode->active=0;
184 if (mode->GetWin(&win[nwin]))
185 win[nwin++].owner=mode;
186 }
187 #ifdef CPIFACE_DEBUG
188 fprintf (stderr, "cpiTextRecalc\n");
189 fprintf (stderr, "step 1, found all active modes\n");
190 for (i=0; i<nwin; i++)
191 {
192 fprintf (stderr, "[%d] %-8s xmode=%d\n", i, win[i].owner->handle, win[i].xmode);
193 };
194 #endif
195
196 /* xmode bit0 = left column request
197 * bit1 = right column request
198 */
199 if (plScrWidth<132)
200 for (i=0; i<nwin; i++)
201 win[i].xmode&=1;
202
203 #ifdef CPIFACE_DEBUG
204 fprintf (stderr, "step 2, masked away xmode bit1 if display can not fit 132 width\n");
205 for (i=0; i<nwin; i++)
206 {
207 fprintf (stderr, "[%d] %-8s xmode=%d\n", i, win[i].owner->handle, win[i].xmode);
208 }
209 #endif
210
211 /* can we fit all the columned windows (not checking the header ones)? */
212 while (1)
213 {
214 /* initialize all the probes back to zero */
215 sidemin=sidemax=sidesize=0;
216 winmin=winmax=winsize=0;
217 /* sum all the left and right windows */
218 for (i=0; i<nwin; i++)
219 {
220 if (win[i].xmode&1)
221 {
222 winmin+=win[i].hgtmin;
223 winmax+=win[i].hgtmax;
224 winsize+=win[i].size;
225 }
226 if (win[i].xmode&2)
227 {
228 sidemin+=win[i].hgtmin;
229 sidemax+=win[i].hgtmax;
230 sidesize+=win[i].size;
231 }
232 }
233 if ((winmin<=winheight)&&(sidemin<=sideheight))
234 break;
235 /* if we were too heigh, hide windows by setting the xmode to 0 */
236 if (sidemin>sideheight)
237 {
238 int worst=0;
239 for (i=0; i<nwin; i++)
240 if (win[i].xmode&2)
241 if (win[i].killprio>win[worst].killprio)
242 worst=i;
243 win[i].xmode=0;
244 continue;
245 }
246 if (winmin>winheight)
247 {
248 int worst=0;
249 for (i=0; i<nwin; i++)
250 if (win[i].xmode&1)
251 if (win[i].killprio>win[worst].killprio)
252 worst=i;
253 win[i].xmode=0;
254 continue;
255 }
256 }
257
258 /* Disable all windows. We are about to actually pick out one and one window until the screen is full */
259 for (i=0; i<nwin; i++)
260 win[i].owner->active=0;
261
262 /* first we want to fill the screen with all the windows that requested both left and right column, starting with the highest priority ones */
263 #ifdef CPIFACE_DEBUG
264 fprintf (stderr, "step 3, place all xmode==3 windows\n");
265 #endif
266 while (1)
267 {
268 int best=-1;
269 int whgt,shgt,hgt;
270
271 for (i=0; i<nwin; i++)
272 if ((win[i].xmode==3)&&!win[i].owner->active)
273 if ((best==-1)||(win[i].viewprio>win[best].viewprio))
274 best=i;
275 if (best==-1)
276 break;
277 if (!win[best].size)
278 hgt=win[best].hgtmin;
279 else {
280 whgt=win[best].hgtmin+(winheight-winmin)*win[best].size/winsize;
281 if ((winheight-whgt)>(winmax-win[best].hgtmax))
282 whgt=winheight-(winmax-win[best].hgtmax);
283 shgt=win[best].hgtmin+(sideheight-sidemin)*win[best].size/sidesize;
284 if ((sideheight-shgt)>(sidemax-win[best].hgtmax))
285 shgt=sideheight-(sidemax-win[best].hgtmax);
286 hgt=(whgt<shgt)?whgt:shgt;
287 }
288 if (hgt>win[best].hgtmax)
289 hgt=win[best].hgtmax;
290 if (win[best].top)
291 {
292 #ifdef CPIFACE_DEBUG
293 fprintf (stderr, "Placing window %-8s top %d %d %d %d\n", win[best].owner->handle, 0, plScrWidth, winfirst, hgt);
294 #endif
295 win[best].owner->SetWin(0, plScrWidth, winfirst, hgt);
296 winfirst+=hgt;
297 sidefirst+=hgt;
298 } else {
299 #ifdef CPIFACE_DEBUG
300 fprintf (stderr, "Placing window %-8s bot %d %d %d %d\n", win[best].owner->handle, 0, plScrWidth, winfirst+winheight-hgt, hgt);
301 #endif
302 win[best].owner->SetWin(0, plScrWidth, winfirst+winheight-hgt, hgt);
303 }
304 win[best].owner->active=1;
305 winheight-=hgt;
306 sideheight-=hgt;
307 winmin-=win[best].hgtmin;
308 winsize-=win[best].size;
309 sidemin-=win[best].hgtmin;
310 sidesize-=win[best].size;
311
312 winmax-=win[best].hgtmax;
313 sidemax-=win[best].hgtmax;
314 }
315 #ifdef CPIFACE_DEBUG
316 fprintf (stderr, "step 4, place all xmode==2 windows (right column)\n");
317 #endif
318
319 while (1)
320 {
321 int best=-1;
322 int hgt;
323
324 for (i=0; i<nwin; i++)
325 if ((win[i].xmode==2)&&!win[i].owner->active)
326 if ((best==-1)||(win[i].viewprio>win[best].viewprio)) /* can crash in theory, TODO */
327 best=i;
328 if (best==-1)
329 break;
330 hgt=win[best].hgtmin;
331 if (win[best].size)
332 {
333 hgt+=(sideheight-sidemin)*win[best].size/sidesize;
334 if ((sideheight-hgt)>(sidemax-win[best].hgtmax))
335 hgt=sideheight-(sidemax-win[best].hgtmax);
336 }
337 if (hgt>win[best].hgtmax)
338 hgt=win[best].hgtmax;
339 if (win[best].top)
340 {
341 #ifdef CPIFACE_DEBUG
342 fprintf (stderr, "Placing window %-8s top %d %d %d %d\n", win[best].owner->handle, plScrWidth-52, 52, sidefirst, hgt);
343 #endif
344 win[best].owner->SetWin(plScrWidth-52, 52, sidefirst, hgt);
345 sidefirst+=hgt;
346 } else {
347 #ifdef CPIFACE_DEBUG
348 fprintf (stderr, "Placing window %-8s bot %d %d %d %d\n", win[best].owner->handle, plScrWidth-52, 52, sidefirst+sideheight-hgt, hgt);
349 #endif
350 win[best].owner->SetWin(plScrWidth-52, 52, sidefirst+sideheight-hgt, hgt);
351 }
352 win[best].owner->active=1;
353 sideheight-=hgt;
354 sidemin-=win[best].hgtmin;
355 sidesize-=win[best].size;
356 sidemax-=win[best].hgtmax;
357 }
358
359 #ifdef CPIFACE_DEBUG
360 fprintf (stderr, "step 5, place all xmode==1 windows (left column)\n");
361 #endif
362
363 while (1)
364 {
365 int best=-1;
366 int hgt;
367 int wid;
368
369 for (i=0; i<nwin; i++)
370 if ((win[i].xmode==1)&&!win[i].owner->active)
371 if ((best==-1)||(win[i].viewprio>win[best].viewprio))
372 best=i;
373 if (best==-1)
374 break;
375 if (winmax<=winheight)
376 hgt=win[best].hgtmax;
377 else {
378 hgt=win[best].hgtmin;
379 if (win[best].size) /* if size were requested, we try to adjust up from minsize */
380 {
381 /*
382 / free space left
383 | / min space that has to be used
384 | | / size requested
385 | | | / total size requested
386 */
387 hgt+=(winheight-winmin)*win[best].size/winsize;
388 if ((winheight-hgt)>(winmax-win[best].hgtmax))
389 hgt=winheight-(winmax-win[best].hgtmax);
390 }
391 if (hgt>win[best].hgtmax)
392 hgt=win[best].hgtmax;
393 }
394 if (win[best].top)
395 {
396
397 if (plScrWidth < 132)
398 {
399 wid=plScrWidth;
400 } else {
401 /*
402 /-------------- does our new window start below (the last used) sidewindow?
403 | /-- does our new window stop before the sidewindow have anything to display?
404 | | /-- then use the hole width
405 | | | /-- or make room for the sidewindow
406 */
407 wid=((winfirst>=sidefirst)&&((winfirst+hgt)<=(sidefirst+sideheight)))?plScrWidth:plScrWidth-52;
408 }
409 #ifdef CPIFACE_DEBUG
410 fprintf (stderr, "Placing window %-8s top %d %d %d %d\n", win[best].owner->handle, 0, wid, winfirst, hgt);
411 #endif
412
413 win[best].owner->SetWin(0, wid, winfirst, hgt);
414 winfirst+=hgt;
415 } else {
416 if (plScrWidth < 132)
417 {
418 wid=plScrWidth;
419 } else {
420 wid=(((winfirst+winheight)<=(sidefirst+sideheight))&&((winfirst+winheight-hgt)>=sidefirst))?plScrWidth:plScrWidth-52;
421 }
422 #ifdef CPIFACE_DEBUG
423 fprintf (stderr, "Placing window %-8s bot %d %d %d %d\n", win[best].owner->handle, 0, wid, winfirst+winheight-hgt, hgt);
424 #endif
425
426 win[best].owner->SetWin(0, wid, winfirst+winheight-hgt, hgt);
427 }
428 win[best].owner->active=1;
429 winheight-=hgt;
430 winmin-=win[best].hgtmin;
431 winsize-=win[best].size;
432 winmax-=win[best].hgtmax;
433
434 /*
435 Old code for filling the void. It does not work well with dynamic resolutions
436 if (wid>=132)
437 {
438 if (win[best].top)
439 {
440 for (i=sidefirst; i<winfirst; i++)
441 displayvoid(i, plScrWidth-52, 52);
442 sideheight=sidefirst+sideheight-winfirst;
443 sidefirst=winfirst;
444 } else {
445 for (i=winfirst+hgt; i<(sidefirst+sideheight); i++)
446 displayvoid(i, plScrWidth-52, 52);
447 sideheight=winfirst+winheight-sidefirst;
448 }
449 }*/
450 }
451 #if 0
452 for (i=0; i<winheight; i++)
453 displayvoid(winfirst+i, 0, plScrWidth-52);
454 for (i=0; i<sideheight; i++)
455 displayvoid(sidefirst+i, plScrWidth-52, 52);
456 if (!nwin)
457 for (i=0;i<plScrHeight;i++)
458 displayvoid(i, 0, plScrWidth);
459 #else
460 for (i=0;i<plScrHeight;i++)
461 displayvoid(i, 0, plScrWidth);
462 #endif
463 }
464
txtSetMode(void)465 static void txtSetMode(void)
466 {
467 struct cpitextmoderegstruct *mode;
468 plSetTextMode(fsScrType);
469 fsScrType=plScrType;
470 for (mode=cpiTextActModes; mode; mode=mode->nextact)
471 if (mode->Event)
472 mode->Event(cpievSetMode);
473 cpiTextRecalc();
474 }
475
txtDraw(void)476 static void txtDraw(void)
477 {
478 struct cpitextmoderegstruct *mode;
479
480 if ((LastWidth!=plScrWidth)||(LastHeight!=plScrHeight)) /* xterms as so fun */
481 cpiTextRecalc();
482
483 cpiDrawGStrings();
484 for (mode=cpiTextActModes; mode; mode=mode->nextact)
485 if (mode->active)
486 mode->Draw(mode==cpiFocus);
487 for (mode=cpiTextModes; mode; mode=mode->next)
488 mode->Event(cpievKeepalive);
489 }
490
txtIProcessKey(uint16_t key)491 static int txtIProcessKey(uint16_t key)
492 {
493 struct cpitextmoderegstruct *mode;
494 #ifdef KEYBOARDTEXT_DEBUG
495 fprintf(stderr, "txtIProcessKey:START\n");
496 #endif
497 for (mode=cpiTextModes; mode; mode=mode->next)
498 {
499 #ifdef KEYBOARDTEXT_DEBUG
500 fprintf(stderr, "Checking mode %s\n", mode->handle);
501 #endif
502 if (mode->IProcessKey(key))
503 {
504 #ifdef KEYBOARDTEXT_DEBUG
505 fprintf(stderr, "Mode swallowed event\ntxtIProcessKey:STOP\n");
506 #endif
507 return 1;
508 }
509 }
510 #ifdef KEYBOARDTEXT_DEBUG
511 fprintf(stderr, "txtIProcessKey:STOP\n");
512 #endif
513 switch (key)
514 {
515 case 'x': case 'X':
516 fsScrType=7;
517 cpiTextSetMode(cpiFocusHandle);
518 return 1;
519 case KEY_ALT_X:
520 fsScrType=0;
521 cpiTextSetMode(cpiFocusHandle);
522 return 1;
523 case 'z': case 'Z':
524 cpiTextSetMode(cpiFocusHandle);
525 break;
526 default:
527 return 0;
528 }
529 return 1;
530 }
531
txtAProcessKey(uint16_t key)532 static int txtAProcessKey(uint16_t key)
533 {
534 #ifdef KEYBOARDTEXT_DEBUG
535 fprintf(stderr, "txtAProcessKey:START\ncpiFocus is %s\n", cpiFocus?"set":"unset");
536 #endif
537 if (cpiFocus)
538 if (cpiFocus->active)
539 if (cpiFocus->AProcessKey(key))
540 {
541 #ifdef KEYBOARDTEXT_DEBUG
542 fprintf(stderr, "cpiFocus %s swallowed event\ntxtAProcessKey:STOP\n", cpiFocus->handle);
543 #endif
544 return 1;
545 }
546 #ifdef KEYBOARDTEXT_DEBUG
547 fprintf(stderr, "nobody swallowed the event\ntxtAProcessKey:STOP\n");
548 #endif
549 switch (key)
550 {
551 case KEY_ALT_K:
552 cpiKeyHelp('x', "Set screen text mode (set mode 7)");
553 cpiKeyHelp('X', "Set screen text mode (set mode 7)");
554 cpiKeyHelp('z', "Set screen text mode (toggle bit 1)");
555 cpiKeyHelp('Z', "Set screen text mode (toggle bit 1)");
556 cpiKeyHelp(KEY_ALT_X, "Set screen text screen mode (set mode 0)");
557 cpiKeyHelp(KEY_ALT_Z, "Set screen text screen mode (toggle bit 2)");
558 cpiKeyHelp(KEY_CTRL_Z, "Set screen text screen mode (toggle bit 1)");
559 return 0;
560 case 'x': case 'X':
561 fsScrType=7;
562 cpiForwardIProcessKey (key);
563 cpiResetScreen();
564 return 1;
565 case KEY_ALT_X:
566 fsScrType=0;
567 cpiForwardIProcessKey (key);
568 cpiResetScreen();
569 return 1;
570 case 'z': case 'Z':
571 fsScrType^=2;
572 cpiForwardIProcessKey (key);
573 cpiResetScreen();
574 break;
575 case KEY_ALT_Z:
576 fsScrType^=4;
577 cpiForwardIProcessKey (key);
578 cpiResetScreen();
579 break;
580 case KEY_CTRL_Z:
581 fsScrType^=1;
582 cpiForwardIProcessKey (key);
583 cpiResetScreen();
584 break;
585 default:
586 return 0;
587 }
588 return 1;
589 }
590
txtInit(void)591 static int txtInit(void)
592 {
593 struct cpitextmoderegstruct *mode;
594 for (mode=cpiTextDefModes; mode; mode=mode->nextdef)
595 cpiTextRegisterMode(mode);
596 cpiSetFocus(cpiFocusHandle);
597 return 1;
598 }
599
txtClose(void)600 static void txtClose(void)
601 {
602 struct cpitextmoderegstruct *mode;
603 for (mode=cpiTextModes; mode; mode=mode->next)
604 if (mode->Event)
605 mode->Event(cpievDone);
606 cpiTextModes=0;
607 }
608
txtInitAll(void)609 static int txtInitAll(void)
610 {
611 cpiTextVerifyDefModes();
612 return 1;
613 }
614
txtCloseAll(void)615 static void txtCloseAll(void)
616 {
617 struct cpitextmoderegstruct *mode;
618 for (mode=cpiTextDefModes; mode; mode=mode->nextdef)
619 if (mode->Event)
620 mode->Event(cpievDoneAll);
621 cpiTextDefModes=0;
622 }
623
txtOpenMode(void)624 static int txtOpenMode(void)
625 {
626 struct cpitextmoderegstruct *mode;
627
628 modeactive=1;
629 cpiTextActModes=0;
630 for (mode=cpiTextModes; mode; mode=mode->next)
631 {
632 if (mode->Event&&!mode->Event(cpievOpen))
633 continue;
634 mode->nextact=cpiTextActModes;
635 cpiTextActModes=mode;
636 }
637 cpiSetFocus(cpiFocusHandle);
638
639 return 1;
640 }
641
txtCloseMode(void)642 static void txtCloseMode(void)
643 {
644 struct cpitextmoderegstruct *mode;
645
646 cpiSetFocus(0);
647 for (mode=cpiTextActModes; mode; mode=mode->nextact)
648 if (mode->Event)
649 mode->Event(cpievClose);
650 cpiTextActModes=0;
651 modeactive=0;
652 }
653
txtEvent(int ev)654 static int txtEvent(int ev)
655 {
656 switch (ev)
657 {
658 case cpievOpen:
659 return txtOpenMode();
660 case cpievClose:
661 txtCloseMode();
662 return 1;
663 case cpievInit:
664 return txtInit();
665 case cpievDone:
666 txtClose();
667 return 1;
668 case cpievInitAll:
669 return txtInitAll();
670 case cpievDoneAll:
671 txtCloseAll();
672 return 1;
673 }
674 return 1;
675 }
676
677 struct cpimoderegstruct cpiModeText = {"text", txtSetMode, txtDraw, txtIProcessKey, txtAProcessKey, txtEvent CPIMODEREGSTRUCT_TAIL};
678