]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libvgl/main.c
Fix missing restoring of the mouse cursor position, the border color and the
[FreeBSD/FreeBSD.git] / lib / libvgl / main.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1991-1997 Søren Schmidt
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer
12  *    in this position and unchanged.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <signal.h>
35 #include <stdio.h>
36 #include <sys/types.h>
37 #include <sys/file.h>
38 #include <sys/ioctl.h>
39 #include <sys/mman.h>
40 #include <sys/fbio.h>
41 #include <sys/kbio.h>
42 #include <sys/consio.h>
43 #include "vgl.h"
44
45 /* XXX Direct Color 24bits modes unsupported */
46
47 #define min(x, y)       (((x) < (y)) ? (x) : (y))
48 #define max(x, y)       (((x) > (y)) ? (x) : (y))
49
50 VGLBitmap *VGLDisplay;
51 video_info_t VGLModeInfo;
52 video_adapter_info_t VGLAdpInfo;
53 byte *VGLBuf;
54
55 static int VGLMode;
56 static int VGLOldMode;
57 static size_t VGLBufSize;
58 static byte *VGLMem = MAP_FAILED;
59 static int VGLSwitchPending;
60 static int VGLAbortPending;
61 static int VGLOnDisplay;
62 static unsigned int VGLCurWindow;
63 static int VGLInitDone = 0;
64 static video_info_t VGLOldModeInfo;
65 static vid_info_t VGLOldVInfo;
66
67 void
68 VGLEnd()
69 {
70 struct vt_mode smode;
71   int size[3];
72
73   if (!VGLInitDone)
74     return;
75   VGLInitDone = 0;
76   VGLSwitchPending = 0;
77   VGLAbortPending = 0;
78
79   signal(SIGUSR1, SIG_IGN);
80
81   if (VGLMem != MAP_FAILED) {
82     VGLClear(VGLDisplay, 0);
83     munmap(VGLMem, VGLAdpInfo.va_window_size);
84   }
85
86   if (VGLOldMode >= M_VESA_BASE)
87     ioctl(0, _IO('V', VGLOldMode - M_VESA_BASE), 0);
88   else
89     ioctl(0, _IO('S', VGLOldMode), 0);
90   if (VGLOldModeInfo.vi_flags & V_INFO_GRAPHICS) {
91     size[0] = VGLOldVInfo.mv_csz;
92     size[1] = VGLOldVInfo.mv_rsz;
93     size[2] = VGLOldVInfo.font_size;;
94     ioctl(0, KDRASTER, size);
95   }
96   if (VGLModeInfo.vi_mem_model != V_INFO_MM_DIRECT)
97     ioctl(0, KDDISABIO, 0);
98   ioctl(0, KDSETMODE, KD_TEXT);
99   smode.mode = VT_AUTO;
100   ioctl(0, VT_SETMODE, &smode);
101   if (VGLBuf)
102     free(VGLBuf);
103   VGLBuf = NULL;
104   free(VGLDisplay);
105   VGLDisplay = NULL;
106   VGLKeyboardEnd();
107 }
108
109 static void 
110 VGLAbort(int arg)
111 {
112   sigset_t mask;
113
114   VGLAbortPending = 1;
115   signal(SIGINT, SIG_IGN);
116   signal(SIGTERM, SIG_IGN);
117   signal(SIGUSR2, SIG_IGN);
118   if (arg == SIGBUS || arg == SIGSEGV) {
119     signal(arg, SIG_DFL);
120     sigemptyset(&mask);
121     sigaddset(&mask, arg);
122     sigprocmask(SIG_UNBLOCK, &mask, NULL);
123     VGLEnd();
124     kill(getpid(), arg);
125   }
126 }
127
128 static void
129 VGLSwitch(int arg __unused)
130 {
131   if (!VGLOnDisplay)
132     VGLOnDisplay = 1;
133   else
134     VGLOnDisplay = 0;
135   VGLSwitchPending = 1;
136   signal(SIGUSR1, VGLSwitch);
137 }
138
139 int
140 VGLInit(int mode)
141 {
142   struct vt_mode smode;
143   int adptype, depth;
144
145   if (VGLInitDone)
146     return -1;
147
148   signal(SIGUSR1, VGLSwitch);
149   signal(SIGINT, VGLAbort);
150   signal(SIGTERM, VGLAbort);
151   signal(SIGSEGV, VGLAbort);
152   signal(SIGBUS, VGLAbort);
153   signal(SIGUSR2, SIG_IGN);
154
155   VGLOnDisplay = 1;
156   VGLSwitchPending = 0;
157   VGLAbortPending = 0;
158
159   if (ioctl(0, CONS_GET, &VGLOldMode) || ioctl(0, CONS_CURRENT, &adptype))
160     return -1;
161   if (IOCGROUP(mode) == 'V')    /* XXX: this is ugly */
162     VGLModeInfo.vi_mode = (mode & 0x0ff) + M_VESA_BASE;
163   else
164     VGLModeInfo.vi_mode = mode & 0x0ff;
165   if (ioctl(0, CONS_MODEINFO, &VGLModeInfo))    /* FBIO_MODEINFO */
166     return -1;
167
168   /* Save info for old mode to restore font size if old mode is graphics. */
169   VGLOldModeInfo.vi_mode = VGLOldMode;
170   if (ioctl(0, CONS_MODEINFO, &VGLOldModeInfo))
171     return -1;
172   VGLOldVInfo.size = sizeof(VGLOldVInfo);
173   if (ioctl(0, CONS_GETINFO, &VGLOldVInfo))
174     return -1;
175
176   VGLDisplay = (VGLBitmap *)malloc(sizeof(VGLBitmap));
177   if (VGLDisplay == NULL)
178     return -2;
179
180   if (VGLModeInfo.vi_mem_model != V_INFO_MM_DIRECT && ioctl(0, KDENABIO, 0)) {
181     free(VGLDisplay);
182     return -3;
183   }
184
185   VGLInitDone = 1;
186
187   /*
188    * vi_mem_model specifies the memory model of the current video mode
189    * in -CURRENT.
190    */
191   switch (VGLModeInfo.vi_mem_model) {
192   case V_INFO_MM_PLANAR:
193     /* we can handle EGA/VGA planner modes only */
194     if (VGLModeInfo.vi_depth != 4 || VGLModeInfo.vi_planes != 4
195         || (adptype != KD_EGA && adptype != KD_VGA)) {
196       VGLEnd();
197       return -4;
198     }
199     VGLDisplay->Type = VIDBUF4;
200     VGLDisplay->PixelBytes = 1;
201     break;
202   case V_INFO_MM_PACKED:
203     /* we can do only 256 color packed modes */
204     if (VGLModeInfo.vi_depth != 8) {
205       VGLEnd();
206       return -4;
207     }
208     VGLDisplay->Type = VIDBUF8;
209     VGLDisplay->PixelBytes = 1;
210     break;
211   case V_INFO_MM_VGAX:
212     VGLDisplay->Type = VIDBUF8X;
213     VGLDisplay->PixelBytes = 1;
214     break;
215   case V_INFO_MM_DIRECT:
216     VGLDisplay->PixelBytes = VGLModeInfo.vi_pixel_size;
217     switch (VGLDisplay->PixelBytes) {
218     case 2:
219       VGLDisplay->Type = VIDBUF16;
220       break;
221 #if notyet
222     case 3:
223       VGLDisplay->Type = VIDBUF24;
224       break;
225 #endif
226     case 4:
227       VGLDisplay->Type = VIDBUF32;
228       break;
229     default:
230       VGLEnd();
231       return -4;
232     }
233     break;
234   default:
235     VGLEnd();
236     return -4;
237   }
238
239   ioctl(0, VT_WAITACTIVE, 0);
240   ioctl(0, KDSETMODE, KD_GRAPHICS);
241   if (ioctl(0, mode, 0)) {
242     VGLEnd();
243     return -5;
244   }
245   if (ioctl(0, CONS_ADPINFO, &VGLAdpInfo)) {    /* FBIO_ADPINFO */
246     VGLEnd();
247     return -6;
248   }
249
250   /*
251    * Calculate the shadow screen buffer size.  In -CURRENT, va_buffer_size
252    * always holds the entire frame buffer size, wheather it's in the linear
253    * mode or windowed mode.  
254    *     VGLBufSize = VGLAdpInfo.va_buffer_size;
255    * In -STABLE, va_buffer_size holds the frame buffer size, only if
256    * the linear frame buffer mode is supported. Otherwise the field is zero.
257    * We shall calculate the minimal size in this case:
258    *     VGLAdpInfo.va_line_width*VGLModeInfo.vi_height*VGLModeInfo.vi_planes
259    * or
260    *     VGLAdpInfo.va_window_size*VGLModeInfo.vi_planes;
261    * Use whichever is larger.
262    */
263   if (VGLAdpInfo.va_buffer_size != 0)
264     VGLBufSize = VGLAdpInfo.va_buffer_size;
265   else
266     VGLBufSize = max(VGLAdpInfo.va_line_width*VGLModeInfo.vi_height,
267                      VGLAdpInfo.va_window_size)*VGLModeInfo.vi_planes;
268   /*
269    * The above is for old -CURRENT.  Current -CURRENT since r203535 and/or
270    * r248799 restricts va_buffer_size to the displayed size in VESA modes to
271    * avoid wasting kva for mapping unused parts of the frame buffer.  But all
272    * parts were usable here.  Applying the same restriction to user mappings
273    * makes our virtualization useless and breaks our panning, but large frame
274    * buffers are also difficult for us to manage (clearing and switching may
275    * be too slow, and malloc() may fail).  Restrict ourselves similarly to
276    * get the same efficiency and bugs for all kernels.
277    */
278   if (VGLModeInfo.vi_mode >= M_VESA_BASE)
279     VGLBufSize = VGLAdpInfo.va_line_width*VGLModeInfo.vi_height*
280                  VGLModeInfo.vi_planes;
281   VGLBuf = malloc(VGLBufSize);
282   if (VGLBuf == NULL) {
283     VGLEnd();
284     return -7;
285   }
286
287 #ifdef LIBVGL_DEBUG
288   fprintf(stderr, "VGLBufSize:0x%x\n", VGLBufSize);
289 #endif
290
291   /* see if we are in the windowed buffer mode or in the linear buffer mode */
292   if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size) {
293     switch (VGLDisplay->Type) {
294     case VIDBUF4:
295       VGLDisplay->Type = VIDBUF4S;
296       break;
297     case VIDBUF8:
298       VGLDisplay->Type = VIDBUF8S;
299       break;
300     case VIDBUF16:
301       VGLDisplay->Type = VIDBUF16S;
302       break;
303     case VIDBUF24:
304       VGLDisplay->Type = VIDBUF24S;
305       break;
306     case VIDBUF32:
307       VGLDisplay->Type = VIDBUF32S;
308       break;
309     default:
310       VGLEnd();
311       return -8;
312     }
313   }
314
315   VGLMode = mode;
316   VGLCurWindow = 0;
317
318   VGLDisplay->Xsize = VGLModeInfo.vi_width;
319   VGLDisplay->Ysize = VGLModeInfo.vi_height;
320   depth = VGLModeInfo.vi_depth;
321   if (depth == 15)
322     depth = 16;
323   VGLDisplay->VXsize = VGLAdpInfo.va_line_width
324                            *8/(depth/VGLModeInfo.vi_planes);
325   VGLDisplay->VYsize = VGLBufSize/VGLModeInfo.vi_planes/VGLAdpInfo.va_line_width;
326   VGLDisplay->Xorigin = 0;
327   VGLDisplay->Yorigin = 0;
328
329   VGLMem = (byte*)mmap(0, VGLAdpInfo.va_window_size, PROT_READ|PROT_WRITE,
330                        MAP_FILE | MAP_SHARED, 0, 0);
331   if (VGLMem == MAP_FAILED) {
332     VGLEnd();
333     return -7;
334   }
335   VGLDisplay->Bitmap = VGLMem;
336
337   VGLSavePalette();
338
339 #ifdef LIBVGL_DEBUG
340   fprintf(stderr, "va_line_width:%d\n", VGLAdpInfo.va_line_width);
341   fprintf(stderr, "VGLXsize:%d, Ysize:%d, VXsize:%d, VYsize:%d\n",
342           VGLDisplay->Xsize, VGLDisplay->Ysize, 
343           VGLDisplay->VXsize, VGLDisplay->VYsize);
344 #endif
345
346   smode.mode = VT_PROCESS;
347   smode.waitv = 0;
348   smode.relsig = SIGUSR1;
349   smode.acqsig = SIGUSR1;
350   smode.frsig  = SIGINT;        
351   if (ioctl(0, VT_SETMODE, &smode)) {
352     VGLEnd();
353     return -9;
354   }
355   VGLTextSetFontFile((byte*)0);
356   VGLClear(VGLDisplay, 0);
357   return 0;
358 }
359
360 void
361 VGLCheckSwitch()
362 {
363   if (VGLAbortPending) {
364     VGLEnd();
365     exit(0);
366   }
367   while (VGLSwitchPending) {
368     unsigned int offset;
369     unsigned int len;
370     int i;
371
372     VGLSwitchPending = 0;
373     if (VGLOnDisplay) {
374       if (VGLModeInfo.vi_mem_model != V_INFO_MM_DIRECT)
375         ioctl(0, KDENABIO, 0);
376       ioctl(0, KDSETMODE, KD_GRAPHICS);
377       ioctl(0, VGLMode, 0);
378       VGLCurWindow = 0;
379       VGLMem = (byte*)mmap(0, VGLAdpInfo.va_window_size, PROT_READ|PROT_WRITE,
380                            MAP_FILE | MAP_SHARED, 0, 0);
381
382       /* XXX: what if mmap() has failed! */
383       VGLDisplay->Type = VIDBUF8;       /* XXX */
384       switch (VGLModeInfo.vi_mem_model) {
385       case V_INFO_MM_PLANAR:
386         if (VGLModeInfo.vi_depth == 4 && VGLModeInfo.vi_planes == 4) {
387           if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size)
388             VGLDisplay->Type = VIDBUF4S;
389           else
390             VGLDisplay->Type = VIDBUF4;
391         } else {
392           /* shouldn't be happening */
393         }
394         break;
395       case V_INFO_MM_PACKED:
396         if (VGLModeInfo.vi_depth == 8) {
397           if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size)
398             VGLDisplay->Type = VIDBUF8S;
399           else
400             VGLDisplay->Type = VIDBUF8;
401         }
402         break;
403       case V_INFO_MM_VGAX:
404         VGLDisplay->Type = VIDBUF8X;
405         break;
406       case V_INFO_MM_DIRECT:
407         switch (VGLModeInfo.vi_pixel_size) {
408           case 2:
409             if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size)
410               VGLDisplay->Type = VIDBUF16S;
411             else
412               VGLDisplay->Type = VIDBUF16;
413             break;
414           case 3:
415             if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size)
416               VGLDisplay->Type = VIDBUF24S;
417             else
418               VGLDisplay->Type = VIDBUF24;
419             break;
420           case 4:
421             if (VGLBufSize/VGLModeInfo.vi_planes > VGLAdpInfo.va_window_size)
422               VGLDisplay->Type = VIDBUF32S;
423             else
424               VGLDisplay->Type = VIDBUF32;
425             break;
426           default:
427           /* shouldn't be happening */
428           break;
429         }
430       default:
431         /* shouldn't be happening */
432         break;
433       }
434
435       VGLDisplay->Bitmap = VGLMem;
436       VGLDisplay->Xsize = VGLModeInfo.vi_width;
437       VGLDisplay->Ysize = VGLModeInfo.vi_height;
438       VGLSetVScreenSize(VGLDisplay, VGLDisplay->VXsize, VGLDisplay->VYsize);
439       VGLRestoreBlank();
440       VGLRestoreBorder();
441       VGLMouseRestore();
442       VGLPanScreen(VGLDisplay, VGLDisplay->Xorigin, VGLDisplay->Yorigin);
443       switch (VGLDisplay->Type) {
444       case VIDBUF4S:
445         outb(0x3c6, 0xff);
446         outb(0x3ce, 0x01); outb(0x3cf, 0x00);           /* set/reset enable */
447         outb(0x3ce, 0x08); outb(0x3cf, 0xff);           /* bit mask */
448         for (offset = 0; offset < VGLBufSize/VGLModeInfo.vi_planes;
449              offset += len) {
450           VGLSetSegment(offset);
451           len = min(VGLBufSize/VGLModeInfo.vi_planes - offset,
452                     VGLAdpInfo.va_window_size);
453           for (i = 0; i < VGLModeInfo.vi_planes; i++) {
454             outb(0x3c4, 0x02);
455             outb(0x3c5, 0x01<<i);
456             bcopy(&VGLBuf[i*VGLBufSize/VGLModeInfo.vi_planes + offset],
457                   VGLMem, len);
458           }
459         }
460         break;
461       case VIDBUF4:
462       case VIDBUF8X:
463         outb(0x3c6, 0xff);
464         outb(0x3ce, 0x01); outb(0x3cf, 0x00);           /* set/reset enable */
465         outb(0x3ce, 0x08); outb(0x3cf, 0xff);           /* bit mask */
466         for (i = 0; i < VGLModeInfo.vi_planes; i++) {
467           outb(0x3c4, 0x02);
468           outb(0x3c5, 0x01<<i);
469           bcopy(&VGLBuf[i*VGLAdpInfo.va_window_size], VGLMem,
470                 VGLAdpInfo.va_window_size);
471         }
472         break;
473       case VIDBUF8:
474       case VIDBUF8S:
475       case VIDBUF16:
476       case VIDBUF16S:
477       case VIDBUF24:
478       case VIDBUF24S:
479       case VIDBUF32:
480       case VIDBUF32S:
481         for (offset = 0; offset < VGLBufSize; offset += len) {
482           VGLSetSegment(offset);
483           len = min(VGLBufSize - offset, VGLAdpInfo.va_window_size);
484           bcopy(&VGLBuf[offset], VGLMem, len);
485         }
486         break;
487       }
488       VGLRestorePalette();
489       ioctl(0, VT_RELDISP, VT_ACKACQ);
490     }
491     else {
492       switch (VGLDisplay->Type) {
493       case VIDBUF4S:
494         for (offset = 0; offset < VGLBufSize/VGLModeInfo.vi_planes;
495              offset += len) {
496           VGLSetSegment(offset);
497           len = min(VGLBufSize/VGLModeInfo.vi_planes - offset,
498                     VGLAdpInfo.va_window_size);
499           for (i = 0; i < VGLModeInfo.vi_planes; i++) {
500             outb(0x3ce, 0x04);
501             outb(0x3cf, i);
502             bcopy(VGLMem, &VGLBuf[i*VGLBufSize/VGLModeInfo.vi_planes + offset],
503                   len);
504           }
505         }
506         break;
507       case VIDBUF4:
508       case VIDBUF8X:
509         /*
510          * NOTE: the saved buffer is NOT in the MEMBUF format which 
511          * the ordinary memory bitmap object is stored in. XXX
512          */
513         for (i = 0; i < VGLModeInfo.vi_planes; i++) {
514           outb(0x3ce, 0x04);
515           outb(0x3cf, i);
516           bcopy(VGLMem, &VGLBuf[i*VGLAdpInfo.va_window_size],
517                 VGLAdpInfo.va_window_size);
518         }
519         break;
520       case VIDBUF8:
521       case VIDBUF8S:
522       case VIDBUF16:
523       case VIDBUF16S:
524       case VIDBUF24:
525       case VIDBUF24S:
526       case VIDBUF32:
527       case VIDBUF32S:
528         for (offset = 0; offset < VGLBufSize; offset += len) {
529           VGLSetSegment(offset);
530           len = min(VGLBufSize - offset, VGLAdpInfo.va_window_size);
531           bcopy(VGLMem, &VGLBuf[offset], len);
532         }
533         break;
534       }
535       VGLMem = MAP_FAILED;
536       munmap(VGLDisplay->Bitmap, VGLAdpInfo.va_window_size);
537       ioctl(0, VGLOldMode, 0);
538       ioctl(0, KDSETMODE, KD_TEXT);
539       if (VGLModeInfo.vi_mem_model != V_INFO_MM_DIRECT)
540         ioctl(0, KDDISABIO, 0);
541       ioctl(0, VT_RELDISP, VT_TRUE);
542       VGLDisplay->Bitmap = VGLBuf;
543       VGLDisplay->Type = MEMBUF;
544       VGLDisplay->Xsize = VGLDisplay->VXsize;
545       VGLDisplay->Ysize = VGLDisplay->VYsize;
546       while (!VGLOnDisplay) pause();
547     }
548   }
549 }
550
551 int
552 VGLSetSegment(unsigned int offset)
553 {
554   if (offset/VGLAdpInfo.va_window_size != VGLCurWindow) {
555     ioctl(0, CONS_SETWINORG, offset);           /* FBIO_SETWINORG */
556     VGLCurWindow = offset/VGLAdpInfo.va_window_size;
557   }
558   return (offset%VGLAdpInfo.va_window_size);
559 }
560
561 int
562 VGLSetVScreenSize(VGLBitmap *object, int VXsize, int VYsize)
563 {
564   int depth;
565
566   if (VXsize < object->Xsize || VYsize < object->Ysize)
567     return -1;
568   if (object->Type == MEMBUF)
569     return -1;
570   if (ioctl(0, FBIO_SETLINEWIDTH, &VXsize))
571     return -1;
572   ioctl(0, CONS_ADPINFO, &VGLAdpInfo);  /* FBIO_ADPINFO */
573   depth = VGLModeInfo.vi_depth;
574   if (depth == 15)
575     depth = 16;
576   object->VXsize = VGLAdpInfo.va_line_width
577                            *8/(depth/VGLModeInfo.vi_planes);
578   object->VYsize = VGLBufSize/VGLModeInfo.vi_planes/VGLAdpInfo.va_line_width;
579   if (VYsize < object->VYsize)
580     object->VYsize = VYsize;
581
582 #ifdef LIBVGL_DEBUG
583   fprintf(stderr, "new size: VGLXsize:%d, Ysize:%d, VXsize:%d, VYsize:%d\n",
584           object->Xsize, object->Ysize, object->VXsize, object->VYsize);
585 #endif
586
587   return 0;
588 }
589
590 int
591 VGLPanScreen(VGLBitmap *object, int x, int y)
592 {
593   video_display_start_t origin;
594
595   if (x < 0 || x + object->Xsize > object->VXsize
596       || y < 0 || y + object->Ysize > object->VYsize)
597     return -1;
598   if (object->Type == MEMBUF)
599     return 0;
600   origin.x = x;
601   origin.y = y;
602   if (ioctl(0, FBIO_SETDISPSTART, &origin))
603     return -1;
604   object->Xorigin = x;
605   object->Yorigin = y;
606
607 #ifdef LIBVGL_DEBUG
608   fprintf(stderr, "new origin: (%d, %d)\n", x, y);
609 #endif
610
611   return 0;
612 }