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