xref: /freebsd/lib/libvgl/mouse.c (revision a07067ea3fa29178090b8b75d984f231c7a442d7)
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 <stdio.h>
35 #include <sys/types.h>
36 #include <sys/ioctl.h>
37 #include <sys/signal.h>
38 #include <sys/consio.h>
39 #include <sys/fbio.h>
40 #include "vgl.h"
41 
42 #define BORDER	0xff	/* default border -- light white in rgb 3:3:2 */
43 #define INTERIOR 0xa0	/* default interior -- red in rgb 3:3:2 */
44 #define X	0xff	/* any nonzero in And mask means part of cursor */
45 #define B	BORDER
46 #define I	INTERIOR
47 static byte StdAndMask[MOUSE_IMG_SIZE*MOUSE_IMG_SIZE] = {
48 	X,X,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
49 	X,X,X,0,0,0,0,0,0,0,0,0,0,0,0,0,
50 	X,X,X,X,0,0,0,0,0,0,0,0,0,0,0,0,
51 	X,X,X,X,X,0,0,0,0,0,0,0,0,0,0,0,
52 	X,X,X,X,X,X,0,0,0,0,0,0,0,0,0,0,
53 	X,X,X,X,X,X,X,0,0,0,0,0,0,0,0,0,
54 	X,X,X,X,X,X,X,X,0,0,0,0,0,0,0,0,
55 	X,X,X,X,X,X,X,X,X,0,0,0,0,0,0,0,
56 	X,X,X,X,X,X,X,X,X,X,0,0,0,0,0,0,
57 	X,X,X,X,X,X,X,X,X,X,0,0,0,0,0,0,
58 	X,X,X,X,X,X,X,0,0,0,0,0,0,0,0,0,
59 	X,X,X,0,X,X,X,X,0,0,0,0,0,0,0,0,
60 	X,X,0,0,X,X,X,X,0,0,0,0,0,0,0,0,
61 	0,0,0,0,0,X,X,X,X,0,0,0,0,0,0,0,
62 	0,0,0,0,0,X,X,X,X,0,0,0,0,0,0,0,
63 	0,0,0,0,0,0,X,X,0,0,0,0,0,0,0,0,
64 };
65 static byte StdOrMask[MOUSE_IMG_SIZE*MOUSE_IMG_SIZE] = {
66 	B,B,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
67 	B,I,B,0,0,0,0,0,0,0,0,0,0,0,0,0,
68 	B,I,I,B,0,0,0,0,0,0,0,0,0,0,0,0,
69 	B,I,I,I,B,0,0,0,0,0,0,0,0,0,0,0,
70 	B,I,I,I,I,B,0,0,0,0,0,0,0,0,0,0,
71 	B,I,I,I,I,I,B,0,0,0,0,0,0,0,0,0,
72 	B,I,I,I,I,I,I,B,0,0,0,0,0,0,0,0,
73 	B,I,I,I,I,I,I,I,B,0,0,0,0,0,0,0,
74 	B,I,I,I,I,I,I,I,I,B,0,0,0,0,0,0,
75 	B,I,I,I,I,I,B,B,B,B,0,0,0,0,0,0,
76 	B,I,I,B,I,I,B,0,0,0,0,0,0,0,0,0,
77 	B,I,B,0,B,I,I,B,0,0,0,0,0,0,0,0,
78 	B,B,0,0,B,I,I,B,0,0,0,0,0,0,0,0,
79 	0,0,0,0,0,B,I,I,B,0,0,0,0,0,0,0,
80 	0,0,0,0,0,B,I,I,B,0,0,0,0,0,0,0,
81 	0,0,0,0,0,0,B,B,0,0,0,0,0,0,0,0,
82 };
83 #undef X
84 #undef B
85 #undef I
86 static VGLBitmap VGLMouseStdAndMask =
87     VGLBITMAP_INITIALIZER(MEMBUF, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE, StdAndMask);
88 static VGLBitmap VGLMouseStdOrMask =
89     VGLBITMAP_INITIALIZER(MEMBUF, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE, StdOrMask);
90 static VGLBitmap *VGLMouseAndMask, *VGLMouseOrMask;
91 static int VGLMouseVisible = 0;
92 static int VGLMouseShown = VGL_MOUSEHIDE;
93 static int VGLMouseXpos = 0;
94 static int VGLMouseYpos = 0;
95 static int VGLMouseButtons = 0;
96 static volatile sig_atomic_t VGLMintpending;
97 static volatile sig_atomic_t VGLMsuppressint;
98 
99 #define	INTOFF()	(VGLMsuppressint++)
100 #define	INTON()		do { 						\
101 				if (--VGLMsuppressint == 0 && VGLMintpending) \
102 					VGLMouseAction(0);		\
103 			} while (0)
104 
105 void
106 VGLMousePointerShow()
107 {
108   byte buf[MOUSE_IMG_SIZE*MOUSE_IMG_SIZE*4];
109   VGLBitmap buffer =
110     VGLBITMAP_INITIALIZER(MEMBUF, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE, buf);
111   byte crtcidx, crtcval, gdcidx, gdcval;
112   int pos;
113 
114   if (!VGLMouseVisible) {
115     INTOFF();
116     VGLMouseVisible = 1;
117     if (VGLModeInfo.vi_mem_model != V_INFO_MM_DIRECT) {
118       crtcidx = inb(0x3c4);
119       crtcval = inb(0x3c5);
120       gdcidx = inb(0x3ce);
121       gdcval = inb(0x3cf);
122     }
123     buffer.PixelBytes = VGLDisplay->PixelBytes;
124     __VGLBitmapCopy(&VGLVDisplay, VGLMouseXpos, VGLMouseYpos,
125                     &buffer, 0, 0, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE);
126     for (pos = 0; pos <  MOUSE_IMG_SIZE*MOUSE_IMG_SIZE; pos++)
127       if (VGLMouseAndMask->Bitmap[pos])
128         bcopy(&VGLMouseOrMask->Bitmap[pos*VGLDisplay->PixelBytes],
129               &buffer.Bitmap[pos*VGLDisplay->PixelBytes],
130               VGLDisplay->PixelBytes);
131     __VGLBitmapCopy(&buffer, 0, 0, VGLDisplay,
132 		  VGLMouseXpos, VGLMouseYpos, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE);
133     if (VGLModeInfo.vi_mem_model != V_INFO_MM_DIRECT) {
134       outb(0x3c4, crtcidx);
135       outb(0x3c5, crtcval);
136       outb(0x3ce, gdcidx);
137       outb(0x3cf, gdcval);
138     }
139     INTON();
140   }
141 }
142 
143 void
144 VGLMousePointerHide()
145 {
146   byte crtcidx, crtcval, gdcidx, gdcval;
147 
148   if (VGLMouseVisible) {
149     INTOFF();
150     VGLMouseVisible = 0;
151     if (VGLModeInfo.vi_mem_model != V_INFO_MM_DIRECT) {
152       crtcidx = inb(0x3c4);
153       crtcval = inb(0x3c5);
154       gdcidx = inb(0x3ce);
155       gdcval = inb(0x3cf);
156     }
157     __VGLBitmapCopy(&VGLVDisplay, VGLMouseXpos, VGLMouseYpos, VGLDisplay,
158                     VGLMouseXpos, VGLMouseYpos, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE);
159     if (VGLModeInfo.vi_mem_model != V_INFO_MM_DIRECT) {
160       outb(0x3c4, crtcidx);
161       outb(0x3c5, crtcval);
162       outb(0x3ce, gdcidx);
163       outb(0x3cf, gdcval);
164     }
165     INTON();
166   }
167 }
168 
169 void
170 VGLMouseMode(int mode)
171 {
172   if (mode == VGL_MOUSESHOW) {
173     if (VGLMouseShown == VGL_MOUSEHIDE) {
174       VGLMousePointerShow();
175       VGLMouseShown = VGL_MOUSESHOW;
176     }
177   }
178   else {
179     if (VGLMouseShown == VGL_MOUSESHOW) {
180       VGLMousePointerHide();
181       VGLMouseShown = VGL_MOUSEHIDE;
182     }
183   }
184 }
185 
186 void
187 VGLMouseAction(int dummy)
188 {
189   struct mouse_info mouseinfo;
190 
191   if (VGLMsuppressint) {
192     VGLMintpending = 1;
193     return;
194   }
195 again:
196   INTOFF();
197   VGLMintpending = 0;
198   mouseinfo.operation = MOUSE_GETINFO;
199   ioctl(0, CONS_MOUSECTL, &mouseinfo);
200   if (VGLMouseShown == VGL_MOUSESHOW)
201     VGLMousePointerHide();
202   VGLMouseXpos = mouseinfo.u.data.x;
203   VGLMouseYpos = mouseinfo.u.data.y;
204   VGLMouseButtons = mouseinfo.u.data.buttons;
205   if (VGLMouseShown == VGL_MOUSESHOW)
206     VGLMousePointerShow();
207 
208   /*
209    * Loop to handle any new (suppressed) signals.  This is INTON() without
210    * recursion.  !SA_RESTART prevents recursion in signal handling.  So the
211    * maximum recursion is 2 levels.
212    */
213   VGLMsuppressint = 0;
214   if (VGLMintpending)
215     goto again;
216 }
217 
218 void
219 VGLMouseSetImage(VGLBitmap *AndMask, VGLBitmap *OrMask)
220 {
221   if (VGLMouseShown == VGL_MOUSESHOW)
222     VGLMousePointerHide();
223 
224   VGLMouseAndMask = AndMask;
225 
226   if (VGLMouseOrMask != NULL) {
227     free(VGLMouseOrMask->Bitmap);
228     free(VGLMouseOrMask);
229   }
230   VGLMouseOrMask = VGLBitmapCreate(MEMBUF, OrMask->VXsize, OrMask->VYsize, 0);
231   VGLBitmapAllocateBits(VGLMouseOrMask);
232   VGLBitmapCvt(OrMask, VGLMouseOrMask);
233 
234   if (VGLMouseShown == VGL_MOUSESHOW)
235     VGLMousePointerShow();
236 }
237 
238 void
239 VGLMouseSetStdImage()
240 {
241   VGLMouseSetImage(&VGLMouseStdAndMask, &VGLMouseStdOrMask);
242 }
243 
244 int
245 VGLMouseInit(int mode)
246 {
247   struct mouse_info mouseinfo;
248   int andmask, border, error, i, interior;
249 
250   switch (VGLModeInfo.vi_mem_model) {
251   case V_INFO_MM_PACKED:
252   case V_INFO_MM_PLANAR:
253     andmask = 0x0f;
254     border = 0x0f;
255     interior = 0x04;
256     break;
257   case V_INFO_MM_VGAX:
258     andmask = 0x3f;
259     border = 0x3f;
260     interior = 0x24;
261     break;
262   default:
263     andmask = 0xff;
264     border = BORDER;
265     interior = INTERIOR;
266     break;
267   }
268   if (VGLModeInfo.vi_mode == M_BG640x480)
269     border = 0;		/* XXX (palette makes 0x04 look like 0x0f) */
270   if (getenv("VGLMOUSEBORDERCOLOR") != NULL)
271     border = strtoul(getenv("VGLMOUSEBORDERCOLOR"), NULL, 0);
272   if (getenv("VGLMOUSEINTERIORCOLOR") != NULL)
273     interior = strtoul(getenv("VGLMOUSEINTERIORCOLOR"), NULL, 0);
274   for (i = 0; i < MOUSE_IMG_SIZE*MOUSE_IMG_SIZE; i++)
275     VGLMouseStdOrMask.Bitmap[i] = VGLMouseStdOrMask.Bitmap[i] == BORDER ?
276       border : VGLMouseStdOrMask.Bitmap[i] == INTERIOR ? interior : 0;
277   VGLMouseSetStdImage();
278   mouseinfo.operation = MOUSE_MODE;
279   mouseinfo.u.mode.signal = SIGUSR2;
280   if ((error = ioctl(0, CONS_MOUSECTL, &mouseinfo)))
281     return error;
282   signal(SIGUSR2, VGLMouseAction);
283   mouseinfo.operation = MOUSE_GETINFO;
284   ioctl(0, CONS_MOUSECTL, &mouseinfo);
285   VGLMouseXpos = mouseinfo.u.data.x;
286   VGLMouseYpos = mouseinfo.u.data.y;
287   VGLMouseButtons = mouseinfo.u.data.buttons;
288   VGLMouseMode(mode);
289   return 0;
290 }
291 
292 void
293 VGLMouseRestore(void)
294 {
295   struct mouse_info mouseinfo;
296 
297   INTOFF();
298   mouseinfo.operation = MOUSE_GETINFO;
299   if (ioctl(0, CONS_MOUSECTL, &mouseinfo) == 0) {
300     mouseinfo.operation = MOUSE_MOVEABS;
301     mouseinfo.u.data.x = VGLMouseXpos;
302     mouseinfo.u.data.y = VGLMouseYpos;
303     ioctl(0, CONS_MOUSECTL, &mouseinfo);
304   }
305   INTON();
306 }
307 
308 int
309 VGLMouseStatus(int *x, int *y, char *buttons)
310 {
311   INTOFF();
312   *x =  VGLMouseXpos;
313   *y =  VGLMouseYpos;
314   *buttons =  VGLMouseButtons;
315   INTON();
316   return VGLMouseShown;
317 }
318 
319 void
320 VGLMouseFreeze(void)
321 {
322   INTOFF();
323 }
324 
325 int
326 VGLMouseFreezeXY(int x, int y)
327 {
328   INTOFF();
329   if (VGLMouseShown != VGL_MOUSESHOW)
330     return 0;
331   if (x >= VGLMouseXpos && x < VGLMouseXpos + MOUSE_IMG_SIZE &&
332       y >= VGLMouseYpos && y < VGLMouseYpos + MOUSE_IMG_SIZE &&
333       VGLMouseAndMask->Bitmap[(y-VGLMouseYpos)*MOUSE_IMG_SIZE+(x-VGLMouseXpos)])
334     return 1;
335   return 0;
336 }
337 
338 int
339 VGLMouseOverlap(int x, int y, int width, int hight)
340 {
341   int overlap;
342 
343   if (VGLMouseShown != VGL_MOUSESHOW)
344     return 0;
345   if (x > VGLMouseXpos)
346     overlap = (VGLMouseXpos + MOUSE_IMG_SIZE) - x;
347   else
348     overlap = (x + width) - VGLMouseXpos;
349   if (overlap <= 0)
350     return 0;
351   if (y > VGLMouseYpos)
352     overlap = (VGLMouseYpos + MOUSE_IMG_SIZE) - y;
353   else
354     overlap = (y + hight) - VGLMouseYpos;
355   return overlap > 0;
356 }
357 
358 void
359 VGLMouseMerge(int x, int y, int width, byte *line)
360 {
361   int pos, x1, xend, xstart;
362 
363   xstart = x;
364   if (xstart < VGLMouseXpos)
365     xstart = VGLMouseXpos;
366   xend = x + width;
367   if (xend > VGLMouseXpos + MOUSE_IMG_SIZE)
368     xend = VGLMouseXpos + MOUSE_IMG_SIZE;
369   for (x1 = xstart; x1 < xend; x1++) {
370     pos = (y - VGLMouseYpos) * MOUSE_IMG_SIZE + x1 - VGLMouseXpos;
371     if (VGLMouseAndMask->Bitmap[pos])
372       bcopy(&VGLMouseOrMask->Bitmap[pos * VGLDisplay->PixelBytes],
373             &line[(x1 - x) * VGLDisplay->PixelBytes], VGLDisplay->PixelBytes);
374   }
375 }
376 
377 void
378 VGLMouseUnFreeze()
379 {
380   INTON();
381 }
382