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