xref: /freebsd/lib/libvgl/mouse.c (revision 3b30feba4548f34e3676cb14601462dd97428960)
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   if (!VGLMouseVisible) {
109     INTOFF();
110     VGLMouseVisible = 1;
111     __VGLBitmapCopy(&VGLVDisplay, VGLMouseXpos, VGLMouseYpos, VGLDisplay,
112 		  VGLMouseXpos, VGLMouseYpos, MOUSE_IMG_SIZE, -MOUSE_IMG_SIZE);
113     INTON();
114   }
115 }
116 
117 void
118 VGLMousePointerHide()
119 {
120   if (VGLMouseVisible) {
121     INTOFF();
122     VGLMouseVisible = 0;
123     __VGLBitmapCopy(&VGLVDisplay, VGLMouseXpos, VGLMouseYpos, VGLDisplay,
124                     VGLMouseXpos, VGLMouseYpos, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE);
125     INTON();
126   }
127 }
128 
129 void
130 VGLMouseMode(int mode)
131 {
132   if (mode == VGL_MOUSESHOW) {
133     if (VGLMouseShown == VGL_MOUSEHIDE) {
134       VGLMousePointerShow();
135       VGLMouseShown = VGL_MOUSESHOW;
136     }
137   }
138   else {
139     if (VGLMouseShown == VGL_MOUSESHOW) {
140       VGLMousePointerHide();
141       VGLMouseShown = VGL_MOUSEHIDE;
142     }
143   }
144 }
145 
146 void
147 VGLMouseAction(int dummy)
148 {
149   struct mouse_info mouseinfo;
150 
151   if (VGLMsuppressint) {
152     VGLMintpending = 1;
153     return;
154   }
155 again:
156   INTOFF();
157   VGLMintpending = 0;
158   mouseinfo.operation = MOUSE_GETINFO;
159   ioctl(0, CONS_MOUSECTL, &mouseinfo);
160   if (VGLMouseShown == VGL_MOUSESHOW)
161     VGLMousePointerHide();
162   VGLMouseXpos = mouseinfo.u.data.x;
163   VGLMouseYpos = mouseinfo.u.data.y;
164   VGLMouseButtons = mouseinfo.u.data.buttons;
165   if (VGLMouseShown == VGL_MOUSESHOW)
166     VGLMousePointerShow();
167 
168   /*
169    * Loop to handle any new (suppressed) signals.  This is INTON() without
170    * recursion.  !SA_RESTART prevents recursion in signal handling.  So the
171    * maximum recursion is 2 levels.
172    */
173   VGLMsuppressint = 0;
174   if (VGLMintpending)
175     goto again;
176 }
177 
178 void
179 VGLMouseSetImage(VGLBitmap *AndMask, VGLBitmap *OrMask)
180 {
181   if (VGLMouseShown == VGL_MOUSESHOW)
182     VGLMousePointerHide();
183 
184   VGLMouseAndMask = AndMask;
185 
186   if (VGLMouseOrMask != NULL) {
187     free(VGLMouseOrMask->Bitmap);
188     free(VGLMouseOrMask);
189   }
190   VGLMouseOrMask = VGLBitmapCreate(MEMBUF, OrMask->VXsize, OrMask->VYsize, 0);
191   VGLBitmapAllocateBits(VGLMouseOrMask);
192   VGLBitmapCvt(OrMask, VGLMouseOrMask);
193 
194   if (VGLMouseShown == VGL_MOUSESHOW)
195     VGLMousePointerShow();
196 }
197 
198 void
199 VGLMouseSetStdImage()
200 {
201   VGLMouseSetImage(&VGLMouseStdAndMask, &VGLMouseStdOrMask);
202 }
203 
204 int
205 VGLMouseInit(int mode)
206 {
207   struct mouse_info mouseinfo;
208   int andmask, border, error, i, interior;
209 
210   switch (VGLModeInfo.vi_mem_model) {
211   case V_INFO_MM_PACKED:
212   case V_INFO_MM_PLANAR:
213     andmask = 0x0f;
214     border = 0x0f;
215     interior = 0x04;
216     break;
217   case V_INFO_MM_VGAX:
218     andmask = 0x3f;
219     border = 0x3f;
220     interior = 0x24;
221     break;
222   default:
223     andmask = 0xff;
224     border = BORDER;
225     interior = INTERIOR;
226     break;
227   }
228   if (VGLModeInfo.vi_mode == M_BG640x480)
229     border = 0;		/* XXX (palette makes 0x04 look like 0x0f) */
230   if (getenv("VGLMOUSEBORDERCOLOR") != NULL)
231     border = strtoul(getenv("VGLMOUSEBORDERCOLOR"), NULL, 0);
232   if (getenv("VGLMOUSEINTERIORCOLOR") != NULL)
233     interior = strtoul(getenv("VGLMOUSEINTERIORCOLOR"), NULL, 0);
234   for (i = 0; i < MOUSE_IMG_SIZE*MOUSE_IMG_SIZE; i++)
235     VGLMouseStdOrMask.Bitmap[i] = VGLMouseStdOrMask.Bitmap[i] == BORDER ?
236       border : VGLMouseStdOrMask.Bitmap[i] == INTERIOR ? interior : 0;
237   VGLMouseSetStdImage();
238   mouseinfo.operation = MOUSE_MODE;
239   mouseinfo.u.mode.signal = SIGUSR2;
240   if ((error = ioctl(0, CONS_MOUSECTL, &mouseinfo)))
241     return error;
242   signal(SIGUSR2, VGLMouseAction);
243   mouseinfo.operation = MOUSE_GETINFO;
244   ioctl(0, CONS_MOUSECTL, &mouseinfo);
245   VGLMouseXpos = mouseinfo.u.data.x;
246   VGLMouseYpos = mouseinfo.u.data.y;
247   VGLMouseButtons = mouseinfo.u.data.buttons;
248   VGLMouseMode(mode);
249   return 0;
250 }
251 
252 void
253 VGLMouseRestore(void)
254 {
255   struct mouse_info mouseinfo;
256 
257   INTOFF();
258   mouseinfo.operation = MOUSE_GETINFO;
259   if (ioctl(0, CONS_MOUSECTL, &mouseinfo) == 0) {
260     mouseinfo.operation = MOUSE_MOVEABS;
261     mouseinfo.u.data.x = VGLMouseXpos;
262     mouseinfo.u.data.y = VGLMouseYpos;
263     ioctl(0, CONS_MOUSECTL, &mouseinfo);
264   }
265   INTON();
266 }
267 
268 int
269 VGLMouseStatus(int *x, int *y, char *buttons)
270 {
271   INTOFF();
272   *x =  VGLMouseXpos;
273   *y =  VGLMouseYpos;
274   *buttons =  VGLMouseButtons;
275   INTON();
276   return VGLMouseShown;
277 }
278 
279 void
280 VGLMouseFreeze(void)
281 {
282   INTOFF();
283 }
284 
285 int
286 VGLMouseFreezeXY(int x, int y)
287 {
288   INTOFF();
289   if (VGLMouseShown != VGL_MOUSESHOW)
290     return 0;
291   if (x >= VGLMouseXpos && x < VGLMouseXpos + MOUSE_IMG_SIZE &&
292       y >= VGLMouseYpos && y < VGLMouseYpos + MOUSE_IMG_SIZE &&
293       VGLMouseAndMask->Bitmap[(y-VGLMouseYpos)*MOUSE_IMG_SIZE+(x-VGLMouseXpos)])
294     return 1;
295   return 0;
296 }
297 
298 int
299 VGLMouseOverlap(int x, int y, int width, int hight)
300 {
301   int overlap;
302 
303   if (VGLMouseShown != VGL_MOUSESHOW)
304     return 0;
305   if (x > VGLMouseXpos)
306     overlap = (VGLMouseXpos + MOUSE_IMG_SIZE) - x;
307   else
308     overlap = (x + width) - VGLMouseXpos;
309   if (overlap <= 0)
310     return 0;
311   if (y > VGLMouseYpos)
312     overlap = (VGLMouseYpos + MOUSE_IMG_SIZE) - y;
313   else
314     overlap = (y + hight) - VGLMouseYpos;
315   return overlap > 0;
316 }
317 
318 void
319 VGLMouseMerge(int x, int y, int width, byte *line)
320 {
321   int pos, x1, xend, xstart;
322 
323   xstart = x;
324   if (xstart < VGLMouseXpos)
325     xstart = VGLMouseXpos;
326   xend = x + width;
327   if (xend > VGLMouseXpos + MOUSE_IMG_SIZE)
328     xend = VGLMouseXpos + MOUSE_IMG_SIZE;
329   for (x1 = xstart; x1 < xend; x1++) {
330     pos = (y - VGLMouseYpos) * MOUSE_IMG_SIZE + x1 - VGLMouseXpos;
331     if (VGLMouseAndMask->Bitmap[pos])
332       bcopy(&VGLMouseOrMask->Bitmap[pos * VGLDisplay->PixelBytes],
333             &line[(x1 - x) * VGLDisplay->PixelBytes], VGLDisplay->PixelBytes);
334   }
335 }
336 
337 void
338 VGLMouseUnFreeze()
339 {
340   INTON();
341 }
342