Merge commit 'origin/master' into gallium-0.2
[mesa.git] / src / glut / fbdev / fbdev.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5
4 * Copyright (C) 1995-2006 Brian Paul
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library 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 GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the Free
18 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 /*
22 * Library for glut using mesa fbdev driver
23 *
24 * Written by Sean D'Epagnier (c) 2006
25 *
26 * To improve on this library, maybe support subwindows or overlays,
27 * I (sean at depagnier dot com) will do my best to help.
28 */
29
30 #include <errno.h>
31 #include <signal.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <fcntl.h>
36 #include <unistd.h>
37 #include <inttypes.h>
38
39 #include <sys/mman.h>
40 #include <sys/time.h>
41 #include <sys/kd.h>
42
43 #include <linux/fb.h>
44 #include <linux/vt.h>
45
46 #include <GL/gl.h>
47 #include <GL/glut.h>
48
49 #include "internal.h"
50
51 #define FBMODES "/etc/fb.modes"
52
53 struct fb_fix_screeninfo FixedInfo;
54 struct fb_var_screeninfo VarInfo;
55 static struct fb_var_screeninfo OrigVarInfo;
56
57 static int DesiredDepth = 0;
58
59 int FrameBufferFD = -1;
60 unsigned char *FrameBuffer;
61 unsigned char *BackBuffer = NULL;
62 int DisplayMode;
63
64 struct GlutTimer *GlutTimers = NULL;
65
66 struct timeval StartTime;
67
68 /* per window data */
69 GLFBDevContextPtr Context;
70 GLFBDevBufferPtr Buffer;
71 GLFBDevVisualPtr Visual;
72
73 int Redisplay;
74 int Visible;
75 int VisibleSwitch;
76 int Active;
77 static int Resized;
78 /* we have to poll to see if we are visible
79 on a framebuffer that is not active */
80 int VisiblePoll;
81 int Swapping, VTSwitch;
82 static int FramebufferIndex;
83
84 static int Initialized;
85
86 char exiterror[256];
87
88 /* test if the active console is attached to the same framebuffer */
89 void TestVisible(void) {
90 struct fb_con2fbmap confb;
91 struct vt_stat st;
92 int ret;
93 ioctl(ConsoleFD, VT_GETSTATE, &st);
94 confb.console = st.v_active;
95
96 ret = ioctl(FrameBufferFD, FBIOGET_CON2FBMAP, &confb);
97
98 if(ret == -1 || confb.framebuffer == FramebufferIndex) {
99 VisibleSwitch = 1;
100 Visible = 0;
101 VisiblePoll = 0;
102 }
103 }
104
105 static void Cleanup(void)
106 {
107 /* do not handle this signal when cleaning up */
108 signal(SIGWINCH, SIG_IGN);
109
110 if(GameMode)
111 glutLeaveGameMode();
112
113 if(ConsoleFD != -1)
114 RestoreVT();
115
116 /* close mouse */
117 CloseMouse();
118
119 if(Visual)
120 glutDestroyWindow(1);
121
122 /* restore original variable screen info */
123 if(FrameBufferFD != -1) {
124 OrigVarInfo.xoffset = 0;
125 OrigVarInfo.yoffset = 0;
126
127 if (ioctl(FrameBufferFD, FBIOPUT_VSCREENINFO, &OrigVarInfo))
128 fprintf(stderr, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
129 strerror(errno));
130
131 if(FrameBuffer)
132 munmap(FrameBuffer, FixedInfo.smem_len);
133 close(FrameBufferFD);
134
135 }
136
137 /* free allocated back buffer */
138 if(DisplayMode & GLUT_DOUBLE)
139 free(BackBuffer);
140
141 /* free menu items */
142 FreeMenus();
143
144 if(exiterror[0])
145 fprintf(stderr, "[glfbdev glut] %s", exiterror);
146 }
147
148 static void CrashHandler(int sig)
149 {
150 sprintf(exiterror, "Caught signal %d, cleaning up\n", sig);
151 exit(0);
152 }
153
154 static void removeArgs(int *argcp, char **argv, int num)
155 {
156 int i;
157 for (i = 0; argv[i+num]; i++)
158 argv[i] = argv[i+num];
159
160 argv[i] = NULL;
161 *argcp -= num;
162 }
163
164 #define REQPARAM(PARAM) \
165 if (i >= *argcp - 1) { \
166 fprintf(stderr, PARAM" requires a parameter\n"); \
167 exit(0); \
168 }
169
170 void glutInit (int *argcp, char **argv)
171 {
172 int i, nomouse = 0, nokeyboard = 0, usestdin = 0;
173 int RequiredWidth = 0, RequiredHeight;
174 char *fbdev;
175
176 stack_t stack;
177 struct sigaction sa;
178
179 /* parse out args */
180 for (i = 1; i < *argcp;) {
181 if (!strcmp(argv[i], "-geometry")) {
182 REQPARAM("geometry");
183 if(sscanf(argv[i+1], "%dx%d", &RequiredWidth,
184 &RequiredHeight) != 2) {
185 fprintf(stderr,"Please specify geometry as widthxheight\n");
186 exit(0);
187 }
188 removeArgs(argcp, &argv[i], 2);
189 } else
190 if (!strcmp(argv[i], "-bpp")) {
191 REQPARAM("bpp");
192 if(sscanf(argv[i+1], "%d", &DesiredDepth) != 1) {
193 fprintf(stderr, "Please specify a parameter for bpp\n");
194 exit(0);
195 }
196 removeArgs(argcp, &argv[i], 2);
197 } else
198 if (!strcmp(argv[i], "-vt")) {
199 REQPARAM("vt");
200 if(sscanf(argv[i+1], "%d", &CurrentVT) != 1) {
201 fprintf(stderr, "Please specify a parameter for vt\n");
202 exit(0);
203 }
204 removeArgs(argcp, &argv[i], 2);
205 } else
206 if (!strcmp(argv[i], "-mousespeed")) {
207 REQPARAM("mousespeed");
208 if(sscanf(argv[i+1], "%lf", &MouseSpeed) != 1) {
209 fprintf(stderr, "Please specify a mouse speed, eg: 2.5\n");
210 exit(0);
211 }
212 removeArgs(argcp, &argv[i], 2);
213 } else
214 if (!strcmp(argv[i], "-nomouse")) {
215 nomouse = 1;
216 removeArgs(argcp, &argv[i], 1);
217 } else
218 if (!strcmp(argv[i], "-nokeyboard")) {
219 nokeyboard = 1;
220 removeArgs(argcp, &argv[i], 1);
221 } else
222 if (!strcmp(argv[i], "-stdin")) {
223 usestdin = 1;
224 removeArgs(argcp, &argv[i], 1);
225 } else
226 if (!strcmp(argv[i], "-gpmmouse")) {
227 #ifdef HAVE_GPM
228 GpmMouse = 1;
229 #else
230 fprintf(stderr, "gpm support not compiled\n");
231 exit(0);
232 #endif
233 removeArgs(argcp, &argv[i], 1);
234 } else
235 if (!strcmp(argv[i], "--")) {
236 removeArgs(argcp, &argv[i], 1);
237 break;
238 } else
239 i++;
240 }
241
242 gettimeofday(&StartTime, 0);
243 atexit(Cleanup);
244
245 /* set up SIGSEGV to use alternate stack */
246 stack.ss_flags = 0;
247 stack.ss_size = SIGSTKSZ;
248 if(!(stack.ss_sp = malloc(SIGSTKSZ)))
249 sprintf(exiterror, "Failed to allocate alternate stack for SIGSEGV!\n");
250
251 sigaltstack(&stack, NULL);
252
253 sa.sa_handler = CrashHandler;
254 sa.sa_flags = SA_ONSTACK;
255 sigemptyset(&sa.sa_mask);
256 sigaction(SIGSEGV, &sa, NULL);
257
258 signal(SIGINT, CrashHandler);
259 signal(SIGTERM, CrashHandler);
260 signal(SIGABRT, CrashHandler);
261
262 if(nomouse == 0)
263 InitializeMouse();
264 if(nokeyboard == 0)
265 InitializeVT(usestdin);
266
267 fbdev = getenv("FRAMEBUFFER");
268 if(fbdev) {
269 #ifdef MULTIHEAD
270 if(!sscanf(fbdev, "/dev/fb%d", &FramebufferIndex))
271 if(!sscanf(fbdev, "/dev/fb/%d", &FramebufferIndex))
272 sprintf(exiterror, "Could not determine Framebuffer index!\n");
273 #endif
274 } else {
275 static char fb[128];
276 struct fb_con2fbmap confb;
277 int fd = open("/dev/fb0", O_RDWR);
278
279 FramebufferIndex = 0;
280
281 confb.console = CurrentVT;
282 if(ioctl(fd, FBIOGET_CON2FBMAP, &confb) != -1)
283 FramebufferIndex = confb.framebuffer;
284 sprintf(fb, "/dev/fb%d", FramebufferIndex);
285 fbdev = fb;
286 close(fd);
287 }
288
289 /* open the framebuffer device */
290 FrameBufferFD = open(fbdev, O_RDWR);
291 if (FrameBufferFD < 0) {
292 sprintf(exiterror, "Error opening %s: %s\n", fbdev, strerror(errno));
293 exit(0);
294 }
295
296 /* get the fixed screen info */
297 if (ioctl(FrameBufferFD, FBIOGET_FSCREENINFO, &FixedInfo)) {
298 sprintf(exiterror, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
299 strerror(errno));
300 exit(0);
301 }
302
303 /* get the variable screen info */
304 if (ioctl(FrameBufferFD, FBIOGET_VSCREENINFO, &OrigVarInfo)) {
305 sprintf(exiterror, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
306 strerror(errno));
307 exit(0);
308 }
309
310 /* operate on a copy */
311 VarInfo = OrigVarInfo;
312
313 /* set the depth, resolution, etc */
314 if(RequiredWidth)
315 if(!ParseFBModes(RequiredWidth, RequiredWidth, RequiredHeight,
316 RequiredHeight, 0, MAX_VSYNC)) {
317 sprintf(exiterror, "No mode (%dx%d) found in "FBMODES"\n",
318 RequiredWidth, RequiredHeight);
319 exit(0);
320 }
321
322 Initialized = 1;
323 }
324
325 void glutInitDisplayMode (unsigned int mode)
326 {
327 DisplayMode = mode;
328 }
329
330 static const char *GetStrVal(const char *p, int *set, int min, int max)
331 {
332 char *endptr;
333 int comp = *p, val;
334
335 if(p[1] == '=')
336 p++;
337
338 if(*p == '\0')
339 return p;
340
341 val = strtol(p+1, &endptr, 10);
342
343 if(endptr == p+1)
344 return p;
345
346 switch(comp) {
347 case '!':
348 if(val == min)
349 val = max;
350 else
351 val = min;
352 break;
353 case '<':
354 val = min;
355 break;
356 case '>':
357 val = max;
358 break;
359 }
360
361 if(val < min || val > max) {
362 sprintf(exiterror, "display string value out of range\n");
363 exit(0);
364 }
365
366 *set = val;
367
368 return endptr;
369 }
370
371 static void SetAttrib(int val, int attr)
372 {
373 if(val)
374 DisplayMode |= attr;
375 else
376 DisplayMode &= ~attr;
377 }
378
379 void glutInitDisplayString(const char *string)
380 {
381 const char *p = string;
382 int val;
383 while(*p) {
384 if(*p == ' ')
385 p++;
386 else
387 if(memcmp(p, "acca", 4) == 0) {
388 p = GetStrVal(p+4, &AccumSize, 1, 32);
389 SetAttrib(AccumSize, GLUT_ACCUM);
390 } else
391 if(memcmp(p, "acc", 3) == 0) {
392 p = GetStrVal(p+3, &AccumSize, 1, 32);
393 SetAttrib(AccumSize, GLUT_ACCUM);
394 } else
395 if(memcmp(p, "depth", 5) == 0) {
396 p = GetStrVal(p+5, &DepthSize, 12, 32);
397 SetAttrib(DepthSize, GLUT_DEPTH);
398 } else
399 if(memcmp(p, "double", 6) == 0) {
400 val = 1;
401 p = GetStrVal(p+6, &val, 0, 1);
402 SetAttrib(val, GLUT_DOUBLE);
403 } else
404 if(memcmp(p, "index", 5) == 0) {
405 val = 1;
406 p = GetStrVal(p+5, &val, 0, 1);
407 SetAttrib(val, GLUT_INDEX);
408 } else
409 if(memcmp(p, "stencil", 7) == 0) {
410 p = GetStrVal(p+7, &StencilSize, 0, 1);
411 SetAttrib(StencilSize, GLUT_STENCIL);
412 } else
413 if(memcmp(p, "samples", 7) == 0) {
414 NumSamples = 1;
415 p = GetStrVal(p+7, &NumSamples, 0, 16);
416 SetAttrib(NumSamples, GLUT_MULTISAMPLE);
417 } else
418 if(p = strchr(p, ' '))
419 p++;
420 else
421 break;
422 }
423 }
424
425 void glutInitWindowPosition (int x, int y)
426 {
427 }
428
429 void glutInitWindowSize (int width, int height)
430 {
431 }
432
433 static void ProcessTimers(void)
434 {
435 while(GlutTimers && GlutTimers->time <= glutGet(GLUT_ELAPSED_TIME)) {
436 struct GlutTimer *timer = GlutTimers;
437 GlutTimers = timer->next;
438 timer->func(timer->value);
439 free(timer);
440 }
441 }
442
443 void glutMainLoop(void)
444 {
445 int idleiters;
446
447 if(ReshapeFunc)
448 ReshapeFunc(VarInfo.xres, VarInfo.yres);
449
450 if(!DisplayFunc) {
451 sprintf(exiterror, "Fatal Error: No Display Function registered\n");
452 exit(0);
453 }
454
455 for(;;) {
456 ProcessTimers();
457
458 if(Active)
459 ReceiveInput();
460 else
461 if(VisiblePoll)
462 TestVisible();
463
464 if(IdleFunc)
465 IdleFunc();
466
467 if(VisibleSwitch) {
468 VisibleSwitch = 0;
469 if(VisibilityFunc)
470 VisibilityFunc(Visible ? GLUT_VISIBLE : GLUT_NOT_VISIBLE);
471 }
472
473 if(Resized) {
474 SetVideoMode();
475 CreateBuffer();
476
477 if(!glFBDevMakeCurrent( Context, Buffer, Buffer )) {
478 sprintf(exiterror, "Failure to Make Current\n");
479 exit(0);
480 }
481
482 InitializeMenus();
483
484 if(ReshapeFunc)
485 ReshapeFunc(VarInfo.xres, VarInfo.yres);
486
487 Redisplay = 1;
488 Resized = 0;
489 }
490
491 if(Visible && Redisplay) {
492 Redisplay = 0;
493 EraseCursor();
494 DisplayFunc();
495 if(!(DisplayMode & GLUT_DOUBLE)) {
496 if(ActiveMenu)
497 DrawMenus();
498 DrawCursor();
499 }
500 idleiters = 0;
501 } else {
502 /* we sleep if not receiving redisplays, and
503 the main loop is running faster than 2khz */
504
505 static int lasttime;
506 int time = glutGet(GLUT_ELAPSED_TIME);
507 if(time > lasttime) {
508 if(idleiters >= 2)
509 usleep(100);
510
511 idleiters = 0;
512 lasttime = time;
513 }
514 idleiters++;
515 }
516 }
517 }
518
519 int ParseFBModes(int minw, int maxw, int minh, int maxh, int minf, int maxf)
520 {
521 char buf[1024];
522 struct fb_var_screeninfo vi = VarInfo;
523
524 FILE *fbmodes = fopen(FBMODES, "r");
525
526 if(!fbmodes) {
527 sprintf(exiterror, "Warning: could not open "FBMODES"\n");
528 return 0;
529 }
530
531 while(fgets(buf, sizeof buf, fbmodes)) {
532 char *c;
533 int v, bpp, freq;
534
535 if(!(c = strstr(buf, "geometry")))
536 continue;
537 v = sscanf(c, "geometry %d %d %d %d %d", &vi.xres, &vi.yres,
538 &vi.xres_virtual, &vi.yres_virtual, &bpp);
539 if(v != 5)
540 continue;
541
542 if(maxw < minw) {
543 if(maxw < vi.xres && minw > vi.xres)
544 continue;
545 } else
546 if(maxw < vi.xres || minw > vi.xres)
547 continue;
548
549 if(maxh < minh) {
550 if(maxh < vi.yres && minh > vi.yres)
551 continue;
552 } else
553 if(maxh < vi.yres || minh > vi.yres)
554 continue;
555
556 fgets(buf, sizeof buf, fbmodes);
557 if(!(c = strstr(buf, "timings")))
558 continue;
559
560 v = sscanf(c, "timings %d %d %d %d %d %d %d", &vi.pixclock,
561 &vi.left_margin, &vi.right_margin, &vi.upper_margin,
562 &vi.lower_margin, &vi.hsync_len, &vi.vsync_len);
563
564 if(v != 7)
565 continue;
566
567 freq = 1E12/vi.pixclock
568 /(vi.left_margin + vi.xres + vi.right_margin + vi.hsync_len)
569 /(vi.upper_margin + vi.yres + vi.lower_margin + vi.vsync_len);
570
571 if(maxf < minf) {
572 if(maxf < freq && minf > freq)
573 continue;
574 } else
575 if(maxf < freq || minf > freq)
576 continue;
577
578 VarInfo = vi;
579 fclose(fbmodes);
580 return 1;
581 }
582
583 fclose(fbmodes);
584
585 return 0;
586 }
587
588 void SetVideoMode(void)
589 {
590 /* set new variable screen info */
591 if (ioctl(FrameBufferFD, FBIOPUT_VSCREENINFO, &VarInfo)) {
592 sprintf(exiterror, "FBIOPUT_VSCREENINFO failed: %s\n", strerror(errno));
593 strcat(exiterror, "Perhaps the device does not support the selected mode\n");
594 exit(0);
595 }
596
597 /* reload the screen info to update rgb bits */
598 if (ioctl(FrameBufferFD, FBIOGET_VSCREENINFO, &VarInfo)) {
599 sprintf(exiterror, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
600 strerror(errno));
601 exit(0);
602 }
603
604 /* reload the fixed info to update color mode */
605 if (ioctl(FrameBufferFD, FBIOGET_FSCREENINFO, &FixedInfo)) {
606 sprintf(exiterror, "error: ioctl(FBIOGET_FSCREENINFO) failed: %s\n",
607 strerror(errno));
608 exit(0);
609 }
610
611 if (DesiredDepth && DesiredDepth != VarInfo.bits_per_pixel) {
612 sprintf(exiterror, "error: Could not set set %d bpp\n", DesiredDepth);
613 exit(0);
614 }
615
616 if(DisplayMode & GLUT_INDEX && FixedInfo.visual == FB_VISUAL_DIRECTCOLOR) {
617 sprintf(exiterror, "error: Could not set 8 bit color mode\n");
618 exit(0);
619 }
620
621 /* initialize colormap */
622 LoadColorMap();
623 }
624
625 void CreateBuffer(void)
626 {
627 int size = VarInfo.xres_virtual * VarInfo.yres_virtual
628 * VarInfo.bits_per_pixel / 8;
629
630 /* mmap the framebuffer into our address space */
631 if(FrameBuffer)
632 munmap(FrameBuffer, FixedInfo.smem_len);
633 FrameBuffer = mmap(0, FixedInfo.smem_len, PROT_READ | PROT_WRITE,
634 MAP_SHARED, FrameBufferFD, 0);
635 if (FrameBuffer == MAP_FAILED) {
636 sprintf(exiterror, "error: unable to mmap framebuffer: %s\n",
637 strerror(errno));
638 exit(0);
639 }
640
641 if(DisplayMode & GLUT_DOUBLE) {
642 free(BackBuffer);
643 if(!(BackBuffer = malloc(size))) {
644 sprintf(exiterror, "Failed to allocate double buffer\n");
645 exit(0);
646 }
647 } else
648 BackBuffer = FrameBuffer;
649
650 if(Buffer)
651 glFBDevDestroyBuffer(Buffer);
652
653 if(!(Buffer = glFBDevCreateBuffer( &FixedInfo, &VarInfo, Visual,
654 FrameBuffer, BackBuffer, size))) {
655 sprintf(exiterror, "Failure to create Buffer\n");
656 exit(0);
657 }
658 }
659
660 void CreateVisual(void)
661 {
662 int i, mask = DisplayMode;
663 int attribs[20];
664 for(i=0; i<sizeof(attribs)/sizeof(*attribs) && mask; i++) {
665 if(mask & GLUT_DOUBLE) {
666 attribs[i] = GLFBDEV_DOUBLE_BUFFER;
667 mask &= ~GLUT_DOUBLE;
668 continue;
669 }
670
671 if(mask & GLUT_INDEX) {
672 attribs[i] = GLFBDEV_COLOR_INDEX;
673 mask &= ~GLUT_INDEX;
674 continue;
675 }
676
677 if(mask & GLUT_DEPTH) {
678 attribs[i] = GLFBDEV_DEPTH_SIZE;
679 attribs[++i] = DepthSize;
680 mask &= ~GLUT_DEPTH;
681 continue;
682 }
683
684 if(mask & GLUT_STENCIL) {
685 attribs[i] = GLFBDEV_STENCIL_SIZE;
686 attribs[++i] = StencilSize;
687 mask &= ~GLUT_STENCIL;
688 continue;
689 }
690
691 if(mask & GLUT_ACCUM) {
692 attribs[i] = GLFBDEV_ACCUM_SIZE;
693 attribs[++i] = AccumSize;
694 mask &= ~GLUT_ACCUM;
695 continue;
696 }
697
698 if(mask & GLUT_ALPHA)
699 if(!(DisplayMode & GLUT_INDEX)) {
700 mask &= ~GLUT_ALPHA;
701 i--;
702 continue;
703 }
704
705 if(mask & GLUT_MULTISAMPLE) {
706 attribs[i] = GLFBDEV_MULTISAMPLE;
707 attribs[++i] = NumSamples;
708 mask &= ~GLUT_MULTISAMPLE;
709 continue;
710 }
711
712 sprintf(exiterror, "Invalid mode from glutInitDisplayMode\n");
713 exit(0);
714 }
715
716 attribs[i] = GLFBDEV_NONE;
717
718 if(!(Visual = glFBDevCreateVisual( &FixedInfo, &VarInfo, attribs ))) {
719 sprintf(exiterror, "Failure to create Visual\n");
720 exit(0);
721 }
722 }
723
724 static void SignalWinch(int arg)
725 {
726 /* we can't change bitdepth without destroying the visual */
727 int bits_per_pixel = VarInfo.bits_per_pixel;
728 struct fb_bitfield red = VarInfo.red, green = VarInfo.green,
729 blue = VarInfo.blue, transp = VarInfo.transp;
730
731 /* get the variable screen info */
732 if (ioctl(FrameBufferFD, FBIOGET_VSCREENINFO, &VarInfo)) {
733 sprintf(exiterror, "error: ioctl(FBIOGET_VSCREENINFO) failed: %s\n",
734 strerror(errno));
735 exit(0);
736 }
737
738 /* restore bitdepth and color masks only */
739 VarInfo.bits_per_pixel = bits_per_pixel;
740 VarInfo.red = red;
741 VarInfo.green = green;
742 VarInfo.blue = blue;
743 VarInfo.transp = transp;
744
745 Resized = 1;
746 }
747
748 int glutCreateWindow (const char *title)
749 {
750 if(Initialized == 0) {
751 int argc = 0;
752 char *argv[] = {NULL};
753 glutInit(&argc, argv);
754 }
755
756 if(Context)
757 return 0;
758
759 if(DisplayMode & GLUT_INDEX)
760 VarInfo.bits_per_pixel = 8;
761 else
762 if(VarInfo.bits_per_pixel == 8)
763 VarInfo.bits_per_pixel = 32;
764
765 if (DesiredDepth)
766 VarInfo.bits_per_pixel = DesiredDepth;
767
768 VarInfo.xoffset = 0;
769 VarInfo.yoffset = 0;
770 VarInfo.nonstd = 0;
771 VarInfo.vmode &= ~FB_VMODE_YWRAP; /* turn off scrolling */
772
773 SetVideoMode();
774 CreateVisual();
775 CreateBuffer();
776
777 if(!(Context = glFBDevCreateContext(Visual, NULL))) {
778 sprintf(exiterror, "Failure to create Context\n");
779 exit(0);
780 }
781
782 if(!glFBDevMakeCurrent( Context, Buffer, Buffer )) {
783 sprintf(exiterror, "Failure to Make Current\n");
784 exit(0);
785 }
786
787 InitializeCursor();
788 InitializeMenus();
789
790 glutSetWindowTitle(title);
791
792 signal(SIGWINCH, SignalWinch);
793
794 Visible = 1;
795 VisibleSwitch = 1;
796 Redisplay = 1;
797 return 1;
798 }
799
800 int glutCreateSubWindow(int win, int x, int y, int width, int height)
801 {
802 return 0;
803 }
804
805 void glutSetWindow(int win)
806 {
807 }
808
809 int glutGetWindow(void)
810 {
811 return 1;
812 }
813
814 void glutDestroyWindow(int win)
815 {
816 glFBDevMakeCurrent( NULL, NULL, NULL);
817 glFBDevDestroyContext(Context);
818 glFBDevDestroyBuffer(Buffer);
819 glFBDevDestroyVisual(Visual);
820
821 Visual = NULL;
822 }
823
824 void glutPostRedisplay(void)
825 {
826 Redisplay = 1;
827 }
828
829 void glutPostWindowRedisplay(int win)
830 {
831 Redisplay = 1;
832 }
833
834 void glutSwapBuffers(void)
835 {
836 glFlush();
837
838 if(!(DisplayMode & GLUT_DOUBLE))
839 return;
840
841 if(ActiveMenu)
842 DrawMenus();
843 DrawCursor();
844
845 if(Visible) {
846 Swapping = 1;
847 glFBDevSwapBuffers(Buffer);
848 Swapping = 0;
849 }
850
851 /* if there was a vt switch while swapping, switch now */
852 if(VTSwitch) {
853 if(ioctl(ConsoleFD, VT_ACTIVATE, VTSwitch) < 0)
854 sprintf(exiterror, "Error switching console\n");
855 VTSwitch = 0;
856 }
857 }
858
859 void glutPositionWindow(int x, int y)
860 {
861 }
862
863 void glutReshapeWindow(int width, int height)
864 {
865 if(GameMode)
866 return;
867
868 if(!ParseFBModes(width, width, height, height, 0, MAX_VSYNC))
869 return;
870
871 signal(SIGWINCH, SIG_IGN);
872
873 SetVideoMode();
874 signal(SIGWINCH, SignalWinch);
875 Resized = 1;
876 }
877
878 void glutFullScreen(void)
879 {
880 }
881
882 void glutPopWindow(void)
883 {
884 }
885
886 void glutPushWindow(void)
887 {
888 }
889
890 void glutShowWindow(void)
891 {
892 Visible = 1;
893 }
894
895 void glutHideWindow(void)
896 {
897 Visible = 0;
898 }
899
900 static void UnIconifyWindow(int sig)
901 {
902 if(ConsoleFD == 0)
903 InitializeVT(1);
904 else
905 if(ConsoleFD > 0)
906 InitializeVT(0);
907 if (ioctl(FrameBufferFD, FBIOPUT_VSCREENINFO, &VarInfo)) {
908 sprintf(exiterror, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
909 strerror(errno));
910 exit(0);
911 }
912
913 RestoreColorMap();
914
915 Redisplay = 1;
916 VisibleSwitch = 1;
917 Visible = 1;
918 }
919
920 void glutIconifyWindow(void)
921 {
922 RestoreVT();
923 signal(SIGCONT, UnIconifyWindow);
924 if (ioctl(FrameBufferFD, FBIOPUT_VSCREENINFO, &OrigVarInfo))
925 fprintf(stderr, "ioctl(FBIOPUT_VSCREENINFO failed): %s\n",
926 strerror(errno));
927
928 raise(SIGSTOP);
929 }
930
931 void glutSetWindowTitle(const char *name)
932 {
933 /* escape code to set title in screen */
934 if(getenv("TERM") && memcmp(getenv("TERM"), "screen", 6) == 0)
935 printf("\033k%s\033\\", name);
936 }
937
938 void glutSetIconTitle(const char *name)
939 {
940 }