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 border, error, i, interior;
286
287 switch (VGLModeInfo.vi_mem_model) {
288 case V_INFO_MM_PACKED:
289 case V_INFO_MM_PLANAR:
290 border = 0x0f;
291 interior = 0x04;
292 break;
293 case V_INFO_MM_VGAX:
294 border = 0x3f;
295 interior = 0x24;
296 break;
297 default:
298 border = BORDER;
299 interior = INTERIOR;
300 break;
301 }
302 if (VGLModeInfo.vi_mode == M_BG640x480)
303 border = 0; /* XXX (palette makes 0x04 look like 0x0f) */
304 if (getenv("VGLMOUSEBORDERCOLOR") != NULL)
305 border = strtoul(getenv("VGLMOUSEBORDERCOLOR"), NULL, 0);
306 if (getenv("VGLMOUSEINTERIORCOLOR") != NULL)
307 interior = strtoul(getenv("VGLMOUSEINTERIORCOLOR"), NULL, 0);
308 ormask = &VGLMouseLargeOrMask;
309 for (i = 0; i < ormask->VXsize * ormask->VYsize; i++)
310 ormask->Bitmap[i] = ormask->Bitmap[i] == BORDER ? border :
311 ormask->Bitmap[i] == INTERIOR ? interior : 0;
312 ormask = &VGLMouseSmallOrMask;
313 for (i = 0; i < ormask->VXsize * ormask->VYsize; i++)
314 ormask->Bitmap[i] = ormask->Bitmap[i] == BORDER ? border :
315 ormask->Bitmap[i] == INTERIOR ? interior : 0;
316 VGLMouseSetStdImage();
317 mouseinfo.operation = MOUSE_MODE;
318 mouseinfo.u.mode.signal = SIGUSR2;
319 if ((error = ioctl(0, CONS_MOUSECTL, &mouseinfo)))
320 return error;
321 signal(SIGUSR2, VGLMouseAction);
322 mouseinfo.operation = MOUSE_GETINFO;
323 ioctl(0, CONS_MOUSECTL, &mouseinfo);
324 VGLMouseXpos = mouseinfo.u.data.x;
325 VGLMouseYpos = mouseinfo.u.data.y;
326 VGLMouseButtons = mouseinfo.u.data.buttons;
327 VGLMouseMode(mode);
328 return 0;
329 }
330
331 void
VGLMouseRestore(void)332 VGLMouseRestore(void)
333 {
334 struct mouse_info mouseinfo;
335
336 INTOFF();
337 mouseinfo.operation = MOUSE_GETINFO;
338 if (ioctl(0, CONS_MOUSECTL, &mouseinfo) == 0) {
339 mouseinfo.operation = MOUSE_MOVEABS;
340 mouseinfo.u.data.x = VGLMouseXpos;
341 mouseinfo.u.data.y = VGLMouseYpos;
342 ioctl(0, CONS_MOUSECTL, &mouseinfo);
343 }
344 INTON();
345 }
346
347 int
VGLMouseStatus(int * x,int * y,char * buttons)348 VGLMouseStatus(int *x, int *y, char *buttons)
349 {
350 INTOFF();
351 *x = VGLMouseXpos;
352 *y = VGLMouseYpos;
353 *buttons = VGLMouseButtons;
354 INTON();
355 return VGLMouseShown;
356 }
357
358 void
VGLMouseFreeze(void)359 VGLMouseFreeze(void)
360 {
361 INTOFF();
362 }
363
364 int
VGLMouseFreezeXY(int x,int y)365 VGLMouseFreezeXY(int x, int y)
366 {
367 INTOFF();
368 if (VGLMouseShown != VGL_MOUSESHOW)
369 return 0;
370 if (x >= VGLMouseXpos && x < VGLMouseXpos + VGLMouseAndMask->VXsize &&
371 y >= VGLMouseYpos && y < VGLMouseYpos + VGLMouseAndMask->VYsize &&
372 VGLMouseAndMask->Bitmap[(y-VGLMouseYpos)*VGLMouseAndMask->VXsize+
373 (x-VGLMouseXpos)])
374 return 1;
375 return 0;
376 }
377
378 int
VGLMouseOverlap(int x,int y,int width,int hight)379 VGLMouseOverlap(int x, int y, int width, int hight)
380 {
381 int overlap;
382
383 if (VGLMouseShown != VGL_MOUSESHOW)
384 return 0;
385 if (x > VGLMouseXpos)
386 overlap = (VGLMouseXpos + VGLMouseAndMask->VXsize) - x;
387 else
388 overlap = (x + width) - VGLMouseXpos;
389 if (overlap <= 0)
390 return 0;
391 if (y > VGLMouseYpos)
392 overlap = (VGLMouseYpos + VGLMouseAndMask->VYsize) - y;
393 else
394 overlap = (y + hight) - VGLMouseYpos;
395 return overlap > 0;
396 }
397
398 void
VGLMouseMerge(int x,int y,int width,byte * line)399 VGLMouseMerge(int x, int y, int width, byte *line)
400 {
401 int pos, x1, xend, xstart;
402
403 xstart = x;
404 if (xstart < VGLMouseXpos)
405 xstart = VGLMouseXpos;
406 xend = x + width;
407 if (xend > VGLMouseXpos + VGLMouseAndMask->VXsize)
408 xend = VGLMouseXpos + VGLMouseAndMask->VXsize;
409 for (x1 = xstart; x1 < xend; x1++) {
410 pos = (y - VGLMouseYpos) * VGLMouseAndMask->VXsize + x1 - VGLMouseXpos;
411 if (VGLMouseAndMask->Bitmap[pos])
412 bcopy(&VGLMouseOrMask->Bitmap[pos * VGLDisplay->PixelBytes],
413 &line[(x1 - x) * VGLDisplay->PixelBytes], VGLDisplay->PixelBytes);
414 }
415 }
416
417 void
VGLMouseUnFreeze()418 VGLMouseUnFreeze()
419 {
420 INTON();
421 }
422