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 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 212 VGLMouseMode(int mode) 213 { 214 __VGLMouseMode(mode); 215 } 216 217 static void 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 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 272 VGLMouseSetStdImage() 273 { 274 if (VGLDisplay->VXsize > 800) 275 VGLMouseSetImage(&VGLMouseLargeAndMask, &VGLMouseLargeOrMask); 276 else 277 VGLMouseSetImage(&VGLMouseSmallAndMask, &VGLMouseSmallOrMask); 278 } 279 280 int 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 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 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 359 VGLMouseFreeze(void) 360 { 361 INTOFF(); 362 } 363 364 int 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 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 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 418 VGLMouseUnFreeze() 419 { 420 INTON(); 421 } 422