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