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 42static 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 53static 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}; 87static 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}; 121static 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}; 139static 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 160static VGLBitmap VGLMouseLargeAndMask = 161 VGLBITMAP_INITIALIZER(MEMBUF, LARGE_MOUSE_IMG_XSIZE, LARGE_MOUSE_IMG_YSIZE, 162 LargeAndMask); 163static VGLBitmap VGLMouseLargeOrMask = 164 VGLBITMAP_INITIALIZER(MEMBUF, LARGE_MOUSE_IMG_XSIZE, LARGE_MOUSE_IMG_YSIZE, 165 LargeOrMask); 166static VGLBitmap VGLMouseSmallAndMask = 167 VGLBITMAP_INITIALIZER(MEMBUF, SMALL_MOUSE_IMG_XSIZE, SMALL_MOUSE_IMG_YSIZE, 168 SmallAndMask); 169static VGLBitmap VGLMouseSmallOrMask = 170 VGLBITMAP_INITIALIZER(MEMBUF, SMALL_MOUSE_IMG_XSIZE, SMALL_MOUSE_IMG_YSIZE, 171 SmallOrMask); 172static VGLBitmap *VGLMouseAndMask, *VGLMouseOrMask; 173static int VGLMouseShown = VGL_MOUSEHIDE; 174static int VGLMouseXpos = 0; 175static int VGLMouseYpos = 0; 176static int VGLMouseButtons = 0; 177static volatile sig_atomic_t VGLMintpending; 178static 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 186int 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 213void 214VGLMouseMode(int mode) 215{ 216 __VGLMouseMode(mode); 217} 218 219static void 220VGLMouseAction(int dummy) 221{ 222 struct mouse_info mouseinfo; 223 int mousemode; 224 225 if (VGLMsuppressint) { 226 VGLMintpending = 1; 227 return; 228 } 229again: 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 253void 254VGLMouseSetImage(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 273void 274VGLMouseSetStdImage() 275{ 276 if (VGLDisplay->VXsize > 800) 277 VGLMouseSetImage(&VGLMouseLargeAndMask, &VGLMouseLargeOrMask); 278 else 279 VGLMouseSetImage(&VGLMouseSmallAndMask, &VGLMouseSmallOrMask); 280} 281 282int 283VGLMouseInit(int mode) 284{ 285 struct mouse_info mouseinfo; 286 VGLBitmap *ormask; 287 int andmask, border, error, i, interior; 288 289 switch (VGLModeInfo.vi_mem_model) { 290 case V_INFO_MM_PACKED: 291 case V_INFO_MM_PLANAR: 292 andmask = 0x0f; 293 border = 0x0f; 294 interior = 0x04; 295 break; 296 case V_INFO_MM_VGAX: 297 andmask = 0x3f; 298 border = 0x3f; 299 interior = 0x24; 300 break; 301 default: 302 andmask = 0xff; 303 border = BORDER; 304 interior = INTERIOR; 305 break; 306 } 307 if (VGLModeInfo.vi_mode == M_BG640x480) 308 border = 0; /* XXX (palette makes 0x04 look like 0x0f) */ 309 if (getenv("VGLMOUSEBORDERCOLOR") != NULL) 310 border = strtoul(getenv("VGLMOUSEBORDERCOLOR"), NULL, 0); 311 if (getenv("VGLMOUSEINTERIORCOLOR") != NULL) 312 interior = strtoul(getenv("VGLMOUSEINTERIORCOLOR"), NULL, 0); 313 ormask = &VGLMouseLargeOrMask; 314 for (i = 0; i < ormask->VXsize * ormask->VYsize; i++) 315 ormask->Bitmap[i] = ormask->Bitmap[i] == BORDER ? border : 316 ormask->Bitmap[i] == INTERIOR ? interior : 0; 317 ormask = &VGLMouseSmallOrMask; 318 for (i = 0; i < ormask->VXsize * ormask->VYsize; i++) 319 ormask->Bitmap[i] = ormask->Bitmap[i] == BORDER ? border : 320 ormask->Bitmap[i] == INTERIOR ? interior : 0; 321 VGLMouseSetStdImage(); 322 mouseinfo.operation = MOUSE_MODE; 323 mouseinfo.u.mode.signal = SIGUSR2; 324 if ((error = ioctl(0, CONS_MOUSECTL, &mouseinfo))) 325 return error; 326 signal(SIGUSR2, VGLMouseAction); 327 mouseinfo.operation = MOUSE_GETINFO; 328 ioctl(0, CONS_MOUSECTL, &mouseinfo); 329 VGLMouseXpos = mouseinfo.u.data.x; 330 VGLMouseYpos = mouseinfo.u.data.y; 331 VGLMouseButtons = mouseinfo.u.data.buttons; 332 VGLMouseMode(mode); 333 return 0; 334} 335 336void 337VGLMouseRestore(void) 338{ 339 struct mouse_info mouseinfo; 340 341 INTOFF(); 342 mouseinfo.operation = MOUSE_GETINFO; 343 if (ioctl(0, CONS_MOUSECTL, &mouseinfo) == 0) { 344 mouseinfo.operation = MOUSE_MOVEABS; 345 mouseinfo.u.data.x = VGLMouseXpos; 346 mouseinfo.u.data.y = VGLMouseYpos; 347 ioctl(0, CONS_MOUSECTL, &mouseinfo); 348 } 349 INTON(); 350} 351 352int 353VGLMouseStatus(int *x, int *y, char *buttons) 354{ 355 INTOFF(); 356 *x = VGLMouseXpos; 357 *y = VGLMouseYpos; 358 *buttons = VGLMouseButtons; 359 INTON(); 360 return VGLMouseShown; 361} 362 363void 364VGLMouseFreeze(void) 365{ 366 INTOFF(); 367} 368 369int 370VGLMouseFreezeXY(int x, int y) 371{ 372 INTOFF(); 373 if (VGLMouseShown != VGL_MOUSESHOW) 374 return 0; 375 if (x >= VGLMouseXpos && x < VGLMouseXpos + VGLMouseAndMask->VXsize && 376 y >= VGLMouseYpos && y < VGLMouseYpos + VGLMouseAndMask->VYsize && 377 VGLMouseAndMask->Bitmap[(y-VGLMouseYpos)*VGLMouseAndMask->VXsize+ 378 (x-VGLMouseXpos)]) 379 return 1; 380 return 0; 381} 382 383int 384VGLMouseOverlap(int x, int y, int width, int hight) 385{ 386 int overlap; 387 388 if (VGLMouseShown != VGL_MOUSESHOW) 389 return 0; 390 if (x > VGLMouseXpos) 391 overlap = (VGLMouseXpos + VGLMouseAndMask->VXsize) - x; 392 else 393 overlap = (x + width) - VGLMouseXpos; 394 if (overlap <= 0) 395 return 0; 396 if (y > VGLMouseYpos) 397 overlap = (VGLMouseYpos + VGLMouseAndMask->VYsize) - y; 398 else 399 overlap = (y + hight) - VGLMouseYpos; 400 return overlap > 0; 401} 402 403void 404VGLMouseMerge(int x, int y, int width, byte *line) 405{ 406 int pos, x1, xend, xstart; 407 408 xstart = x; 409 if (xstart < VGLMouseXpos) 410 xstart = VGLMouseXpos; 411 xend = x + width; 412 if (xend > VGLMouseXpos + VGLMouseAndMask->VXsize) 413 xend = VGLMouseXpos + VGLMouseAndMask->VXsize; 414 for (x1 = xstart; x1 < xend; x1++) { 415 pos = (y - VGLMouseYpos) * VGLMouseAndMask->VXsize + x1 - VGLMouseXpos; 416 if (VGLMouseAndMask->Bitmap[pos]) 417 bcopy(&VGLMouseOrMask->Bitmap[pos * VGLDisplay->PixelBytes], 418 &line[(x1 - x) * VGLDisplay->PixelBytes], VGLDisplay->PixelBytes); 419 } 420} 421 422void 423VGLMouseUnFreeze() 424{ 425 INTON(); 426} 427