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 int pos; 112 113 if (!VGLMouseVisible) { 114 INTOFF(); 115 VGLMouseVisible = 1; 116 buffer.PixelBytes = VGLDisplay->PixelBytes; 117 __VGLBitmapCopy(&VGLVDisplay, VGLMouseXpos, VGLMouseYpos, 118 &buffer, 0, 0, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE); 119 for (pos = 0; pos < MOUSE_IMG_SIZE*MOUSE_IMG_SIZE; pos++) 120 if (VGLMouseAndMask->Bitmap[pos]) 121 bcopy(&VGLMouseOrMask->Bitmap[pos*VGLDisplay->PixelBytes], 122 &buffer.Bitmap[pos*VGLDisplay->PixelBytes], 123 VGLDisplay->PixelBytes); 124 __VGLBitmapCopy(&buffer, 0, 0, VGLDisplay, 125 VGLMouseXpos, VGLMouseYpos, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE); 126 INTON(); 127 } 128 } 129 130 void 131 VGLMousePointerHide() 132 { 133 if (VGLMouseVisible) { 134 INTOFF(); 135 VGLMouseVisible = 0; 136 __VGLBitmapCopy(&VGLVDisplay, VGLMouseXpos, VGLMouseYpos, VGLDisplay, 137 VGLMouseXpos, VGLMouseYpos, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE); 138 INTON(); 139 } 140 } 141 142 void 143 VGLMouseMode(int mode) 144 { 145 if (mode == VGL_MOUSESHOW) { 146 if (VGLMouseShown == VGL_MOUSEHIDE) { 147 VGLMousePointerShow(); 148 VGLMouseShown = VGL_MOUSESHOW; 149 } 150 } 151 else { 152 if (VGLMouseShown == VGL_MOUSESHOW) { 153 VGLMousePointerHide(); 154 VGLMouseShown = VGL_MOUSEHIDE; 155 } 156 } 157 } 158 159 void 160 VGLMouseAction(int dummy) 161 { 162 struct mouse_info mouseinfo; 163 164 if (VGLMsuppressint) { 165 VGLMintpending = 1; 166 return; 167 } 168 again: 169 INTOFF(); 170 VGLMintpending = 0; 171 mouseinfo.operation = MOUSE_GETINFO; 172 ioctl(0, CONS_MOUSECTL, &mouseinfo); 173 if (VGLMouseShown == VGL_MOUSESHOW) 174 VGLMousePointerHide(); 175 VGLMouseXpos = mouseinfo.u.data.x; 176 VGLMouseYpos = mouseinfo.u.data.y; 177 VGLMouseButtons = mouseinfo.u.data.buttons; 178 if (VGLMouseShown == VGL_MOUSESHOW) 179 VGLMousePointerShow(); 180 181 /* 182 * Loop to handle any new (suppressed) signals. This is INTON() without 183 * recursion. !SA_RESTART prevents recursion in signal handling. So the 184 * maximum recursion is 2 levels. 185 */ 186 VGLMsuppressint = 0; 187 if (VGLMintpending) 188 goto again; 189 } 190 191 void 192 VGLMouseSetImage(VGLBitmap *AndMask, VGLBitmap *OrMask) 193 { 194 if (VGLMouseShown == VGL_MOUSESHOW) 195 VGLMousePointerHide(); 196 197 VGLMouseAndMask = AndMask; 198 199 if (VGLMouseOrMask != NULL) { 200 free(VGLMouseOrMask->Bitmap); 201 free(VGLMouseOrMask); 202 } 203 VGLMouseOrMask = VGLBitmapCreate(MEMBUF, OrMask->VXsize, OrMask->VYsize, 0); 204 VGLBitmapAllocateBits(VGLMouseOrMask); 205 VGLBitmapCvt(OrMask, VGLMouseOrMask); 206 207 if (VGLMouseShown == VGL_MOUSESHOW) 208 VGLMousePointerShow(); 209 } 210 211 void 212 VGLMouseSetStdImage() 213 { 214 VGLMouseSetImage(&VGLMouseStdAndMask, &VGLMouseStdOrMask); 215 } 216 217 int 218 VGLMouseInit(int mode) 219 { 220 struct mouse_info mouseinfo; 221 int andmask, border, error, i, interior; 222 223 switch (VGLModeInfo.vi_mem_model) { 224 case V_INFO_MM_PACKED: 225 case V_INFO_MM_PLANAR: 226 andmask = 0x0f; 227 border = 0x0f; 228 interior = 0x04; 229 break; 230 case V_INFO_MM_VGAX: 231 andmask = 0x3f; 232 border = 0x3f; 233 interior = 0x24; 234 break; 235 default: 236 andmask = 0xff; 237 border = BORDER; 238 interior = INTERIOR; 239 break; 240 } 241 if (VGLModeInfo.vi_mode == M_BG640x480) 242 border = 0; /* XXX (palette makes 0x04 look like 0x0f) */ 243 if (getenv("VGLMOUSEBORDERCOLOR") != NULL) 244 border = strtoul(getenv("VGLMOUSEBORDERCOLOR"), NULL, 0); 245 if (getenv("VGLMOUSEINTERIORCOLOR") != NULL) 246 interior = strtoul(getenv("VGLMOUSEINTERIORCOLOR"), NULL, 0); 247 for (i = 0; i < MOUSE_IMG_SIZE*MOUSE_IMG_SIZE; i++) 248 VGLMouseStdOrMask.Bitmap[i] = VGLMouseStdOrMask.Bitmap[i] == BORDER ? 249 border : VGLMouseStdOrMask.Bitmap[i] == INTERIOR ? interior : 0; 250 VGLMouseSetStdImage(); 251 mouseinfo.operation = MOUSE_MODE; 252 mouseinfo.u.mode.signal = SIGUSR2; 253 if ((error = ioctl(0, CONS_MOUSECTL, &mouseinfo))) 254 return error; 255 signal(SIGUSR2, VGLMouseAction); 256 mouseinfo.operation = MOUSE_GETINFO; 257 ioctl(0, CONS_MOUSECTL, &mouseinfo); 258 VGLMouseXpos = mouseinfo.u.data.x; 259 VGLMouseYpos = mouseinfo.u.data.y; 260 VGLMouseButtons = mouseinfo.u.data.buttons; 261 VGLMouseMode(mode); 262 return 0; 263 } 264 265 void 266 VGLMouseRestore(void) 267 { 268 struct mouse_info mouseinfo; 269 270 INTOFF(); 271 mouseinfo.operation = MOUSE_GETINFO; 272 if (ioctl(0, CONS_MOUSECTL, &mouseinfo) == 0) { 273 mouseinfo.operation = MOUSE_MOVEABS; 274 mouseinfo.u.data.x = VGLMouseXpos; 275 mouseinfo.u.data.y = VGLMouseYpos; 276 ioctl(0, CONS_MOUSECTL, &mouseinfo); 277 } 278 INTON(); 279 } 280 281 int 282 VGLMouseStatus(int *x, int *y, char *buttons) 283 { 284 INTOFF(); 285 *x = VGLMouseXpos; 286 *y = VGLMouseYpos; 287 *buttons = VGLMouseButtons; 288 INTON(); 289 return VGLMouseShown; 290 } 291 292 void 293 VGLMouseFreeze(void) 294 { 295 INTOFF(); 296 } 297 298 int 299 VGLMouseFreezeXY(int x, int y) 300 { 301 INTOFF(); 302 if (VGLMouseShown != VGL_MOUSESHOW) 303 return 0; 304 if (x >= VGLMouseXpos && x < VGLMouseXpos + MOUSE_IMG_SIZE && 305 y >= VGLMouseYpos && y < VGLMouseYpos + MOUSE_IMG_SIZE && 306 VGLMouseAndMask->Bitmap[(y-VGLMouseYpos)*MOUSE_IMG_SIZE+(x-VGLMouseXpos)]) 307 return 1; 308 return 0; 309 } 310 311 int 312 VGLMouseOverlap(int x, int y, int width, int hight) 313 { 314 int overlap; 315 316 if (VGLMouseShown != VGL_MOUSESHOW) 317 return 0; 318 if (x > VGLMouseXpos) 319 overlap = (VGLMouseXpos + MOUSE_IMG_SIZE) - x; 320 else 321 overlap = (x + width) - VGLMouseXpos; 322 if (overlap <= 0) 323 return 0; 324 if (y > VGLMouseYpos) 325 overlap = (VGLMouseYpos + MOUSE_IMG_SIZE) - y; 326 else 327 overlap = (y + hight) - VGLMouseYpos; 328 return overlap > 0; 329 } 330 331 void 332 VGLMouseMerge(int x, int y, int width, byte *line) 333 { 334 int pos, x1, xend, xstart; 335 336 xstart = x; 337 if (xstart < VGLMouseXpos) 338 xstart = VGLMouseXpos; 339 xend = x + width; 340 if (xend > VGLMouseXpos + MOUSE_IMG_SIZE) 341 xend = VGLMouseXpos + MOUSE_IMG_SIZE; 342 for (x1 = xstart; x1 < xend; x1++) { 343 pos = (y - VGLMouseYpos) * MOUSE_IMG_SIZE + x1 - VGLMouseXpos; 344 if (VGLMouseAndMask->Bitmap[pos]) 345 bcopy(&VGLMouseOrMask->Bitmap[pos * VGLDisplay->PixelBytes], 346 &line[(x1 - x) * VGLDisplay->PixelBytes], VGLDisplay->PixelBytes); 347 } 348 } 349 350 void 351 VGLMouseUnFreeze() 352 { 353 INTON(); 354 } 355