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