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