1/*-
2 * Copyright (c) 1991-1997 Søren Schmidt
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer
10 *    in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 *    derived from this software without specific prior written permission
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <sys/cdefs.h>
30__FBSDID("$FreeBSD$");
31
32#include <stdio.h>
33#include <sys/types.h>
34#include <sys/ioctl.h>
35#include <sys/signal.h>
36#include <sys/consio.h>
37#include <sys/fbio.h>
38#include "vgl.h"
39
40#define X 0xff
41static byte StdAndMask[MOUSE_IMG_SIZE*MOUSE_IMG_SIZE] = {
42	X,X,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
43	X,X,X,0,0,0,0,0,0,0,0,0,0,0,0,0,
44	X,X,X,X,0,0,0,0,0,0,0,0,0,0,0,0,
45	X,X,X,X,X,0,0,0,0,0,0,0,0,0,0,0,
46	X,X,X,X,X,X,0,0,0,0,0,0,0,0,0,0,
47	X,X,X,X,X,X,X,0,0,0,0,0,0,0,0,0,
48	X,X,X,X,X,X,X,X,0,0,0,0,0,0,0,0,
49	X,X,X,X,X,X,X,X,X,0,0,0,0,0,0,0,
50	X,X,X,X,X,X,X,0,0,0,0,0,0,0,0,0,
51	0,0,0,X,X,X,X,0,0,0,0,0,0,0,0,0,
52	0,0,0,X,X,X,X,X,0,0,0,0,0,0,0,0,
53	0,0,0,0,X,X,X,X,0,0,0,0,0,0,0,0,
54	0,0,0,0,X,X,X,X,0,0,0,0,0,0,0,0,
55	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
56	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
57	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
58};
59static byte StdOrMask[MOUSE_IMG_SIZE*MOUSE_IMG_SIZE] = {
60	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
61	0,X,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
62	0,X,X,0,0,0,0,0,0,0,0,0,0,0,0,0,
63	0,X,X,X,0,0,0,0,0,0,0,0,0,0,0,0,
64	0,X,X,X,X,0,0,0,0,0,0,0,0,0,0,0,
65	0,X,X,X,X,X,0,0,0,0,0,0,0,0,0,0,
66	0,X,X,X,X,X,X,0,0,0,0,0,0,0,0,0,
67	0,X,X,0,X,0,0,0,0,0,0,0,0,0,0,0,
68	0,0,0,0,X,X,0,0,0,0,0,0,0,0,0,0,
69	0,0,0,0,X,X,0,0,0,0,0,0,0,0,0,0,
70	0,0,0,0,0,X,X,0,0,0,0,0,0,0,0,0,
71	0,0,0,0,0,X,X,0,0,0,0,0,0,0,0,0,
72	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
73	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
74	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
75	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
76};
77#undef X
78static VGLBitmap VGLMouseStdAndMask =
79    VGLBITMAP_INITIALIZER(MEMBUF, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE, StdAndMask);
80static VGLBitmap VGLMouseStdOrMask =
81    VGLBITMAP_INITIALIZER(MEMBUF, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE, StdOrMask);
82static VGLBitmap *VGLMouseAndMask, *VGLMouseOrMask;
83static byte map[MOUSE_IMG_SIZE*MOUSE_IMG_SIZE];
84static VGLBitmap VGLMouseSave =
85    VGLBITMAP_INITIALIZER(MEMBUF, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE, map);
86static int VGLMouseVisible = 0;
87static int VGLMouseFrozen = 0;
88static int VGLMouseShown = 0;
89static int VGLMouseXpos = 0;
90static int VGLMouseYpos = 0;
91static int VGLMouseButtons = 0;
92
93void
94VGLMousePointerShow()
95{
96  byte buf[MOUSE_IMG_SIZE*MOUSE_IMG_SIZE];
97  VGLBitmap buffer =
98    VGLBITMAP_INITIALIZER(MEMBUF, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE, buf);
99  byte crtcidx, crtcval, gdcidx, gdcval;
100  int pos;
101
102  if (!VGLMouseVisible) {
103    VGLMouseVisible = 1;
104    crtcidx = inb(0x3c4);
105    crtcval = inb(0x3c5);
106    gdcidx = inb(0x3ce);
107    gdcval = inb(0x3cf);
108    __VGLBitmapCopy(VGLDisplay, VGLMouseXpos, VGLMouseYpos,
109		  &VGLMouseSave, 0, 0, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE);
110    bcopy(VGLMouseSave.Bitmap, buffer.Bitmap, MOUSE_IMG_SIZE*MOUSE_IMG_SIZE);
111    for (pos = 0; pos <  MOUSE_IMG_SIZE*MOUSE_IMG_SIZE; pos++)
112      buffer.Bitmap[pos]=(buffer.Bitmap[pos]&~(VGLMouseAndMask->Bitmap[pos])) |
113			   VGLMouseOrMask->Bitmap[pos];
114    __VGLBitmapCopy(&buffer, 0, 0, VGLDisplay,
115		  VGLMouseXpos, VGLMouseYpos, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE);
116    outb(0x3c4, crtcidx);
117    outb(0x3c5, crtcval);
118    outb(0x3ce, gdcidx);
119    outb(0x3cf, gdcval);
120  }
121}
122
123void
124VGLMousePointerHide()
125{
126  byte crtcidx, crtcval, gdcidx, gdcval;
127
128  if (VGLMouseVisible) {
129    VGLMouseVisible = 0;
130    crtcidx = inb(0x3c4);
131    crtcval = inb(0x3c5);
132    gdcidx = inb(0x3ce);
133    gdcval = inb(0x3cf);
134    __VGLBitmapCopy(&VGLMouseSave, 0, 0, VGLDisplay,
135		  VGLMouseXpos, VGLMouseYpos, MOUSE_IMG_SIZE, MOUSE_IMG_SIZE);
136    outb(0x3c4, crtcidx);
137    outb(0x3c5, crtcval);
138    outb(0x3ce, gdcidx);
139    outb(0x3cf, gdcval);
140  }
141}
142
143void
144VGLMouseMode(int mode)
145{
146  if (mode == VGL_MOUSESHOW) {
147    if (VGLMouseShown == VGL_MOUSEHIDE) {
148      VGLMousePointerShow();
149      VGLMouseShown = VGL_MOUSESHOW;
150    }
151  }
152  else {
153    if (VGLMouseShown == VGL_MOUSESHOW) {
154      VGLMousePointerHide();
155      VGLMouseShown = VGL_MOUSEHIDE;
156    }
157  }
158}
159
160void
161VGLMouseAction(int dummy)
162{
163  struct mouse_info mouseinfo;
164
165  if (VGLMouseFrozen) {
166    VGLMouseFrozen++;
167    return;
168  }
169  mouseinfo.operation = MOUSE_GETINFO;
170  ioctl(0, CONS_MOUSECTL, &mouseinfo);
171  if (VGLMouseShown == VGL_MOUSESHOW)
172    VGLMousePointerHide();
173  VGLMouseXpos = mouseinfo.u.data.x;
174  VGLMouseYpos = mouseinfo.u.data.y;
175  VGLMouseButtons = mouseinfo.u.data.buttons;
176  if (VGLMouseShown == VGL_MOUSESHOW)
177    VGLMousePointerShow();
178}
179
180void
181VGLMouseSetImage(VGLBitmap *AndMask, VGLBitmap *OrMask)
182{
183  if (VGLMouseShown == VGL_MOUSESHOW)
184    VGLMousePointerHide();
185  VGLMouseAndMask = AndMask;
186  VGLMouseOrMask = OrMask;
187  if (VGLMouseShown == VGL_MOUSESHOW)
188    VGLMousePointerShow();
189}
190
191void
192VGLMouseSetStdImage()
193{
194  if (VGLMouseShown == VGL_MOUSESHOW)
195    VGLMousePointerHide();
196  VGLMouseAndMask = &VGLMouseStdAndMask;
197  VGLMouseOrMask = &VGLMouseStdOrMask;
198  if (VGLMouseShown == VGL_MOUSESHOW)
199    VGLMousePointerShow();
200}
201
202int
203VGLMouseInit(int mode)
204{
205  struct mouse_info mouseinfo;
206  int error;
207
208  VGLMouseSetStdImage();
209  mouseinfo.operation = MOUSE_MODE;
210  mouseinfo.u.mode.signal = SIGUSR2;
211  if ((error = ioctl(0, CONS_MOUSECTL, &mouseinfo)))
212    return error;
213  signal(SIGUSR2, VGLMouseAction);
214  mouseinfo.operation = MOUSE_GETINFO;
215  ioctl(0, CONS_MOUSECTL, &mouseinfo);
216  VGLMouseXpos = mouseinfo.u.data.x;
217  VGLMouseYpos = mouseinfo.u.data.y;
218  VGLMouseButtons = mouseinfo.u.data.buttons;
219  VGLMouseMode(mode);
220  return 0;
221}
222
223int
224VGLMouseStatus(int *x, int *y, char *buttons)
225{
226  signal(SIGUSR2, SIG_IGN);
227  *x =  VGLMouseXpos;
228  *y =  VGLMouseYpos;
229  *buttons =  VGLMouseButtons;
230  signal(SIGUSR2, VGLMouseAction);
231  return VGLMouseShown;
232}
233
234int
235VGLMouseFreeze(int x, int y, int width, int hight, byte color)
236{
237  if (!VGLMouseFrozen) {
238    VGLMouseFrozen = 1;
239    if (width > 1 || hight > 1) {		/* bitmap */
240      if (VGLMouseShown == 1) {
241        int overlap;
242
243        if (x > VGLMouseXpos)
244          overlap = (VGLMouseXpos + MOUSE_IMG_SIZE) - x;
245        else
246          overlap = (x + width) - VGLMouseXpos;
247        if (overlap > 0) {
248          if (y > VGLMouseYpos)
249            overlap = (VGLMouseYpos + MOUSE_IMG_SIZE) - y;
250          else
251            overlap = (y + hight) - VGLMouseYpos;
252          if (overlap > 0)
253            VGLMousePointerHide();
254        }
255      }
256    }
257    else {				/* bit */
258      if (VGLMouseShown &&
259          x >= VGLMouseXpos && x < VGLMouseXpos + MOUSE_IMG_SIZE &&
260          y >= VGLMouseYpos && y < VGLMouseYpos + MOUSE_IMG_SIZE) {
261        VGLMouseSave.Bitmap[(y-VGLMouseYpos)*MOUSE_IMG_SIZE+(x-VGLMouseXpos)] =
262          (color);
263        if (VGLMouseAndMask->Bitmap
264          [(y-VGLMouseYpos)*MOUSE_IMG_SIZE+(x-VGLMouseXpos)]) {
265          return 1;
266        }
267      }
268    }
269  }
270  return 0;
271}
272
273void
274VGLMouseUnFreeze()
275{
276  if (VGLMouseFrozen > 1) {
277    VGLMouseFrozen = 0;
278    VGLMouseAction(0);
279  }
280  else {
281    VGLMouseFrozen = 0;
282    if (VGLMouseShown == VGL_MOUSESHOW && !VGLMouseVisible)
283      VGLMousePointerShow();
284  }
285}
286