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