1 /****************************************************************************
2     Copyright (C) 1987-2015 by Jeffery P. Hansen
3 
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License along
15     with this program; if not, write to the Free Software Foundation, Inc.,
16     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 ****************************************************************************/
18 #include <stdlib.h>
19 #include <assert.h>
20 #include <X11/cursorfont.h>
21 #define BEAK_MODES
22 #include "tkgate.h"
23 
24 #define DEBUG_CURSORS 0		/* 0,1 or 2 */
25 
26 
27 /*
28  * IDS for groups of cursors
29  */
30 #define DEFAULT_CURS	-1
31 #define SMALL_CURS	0
32 #define BIG_CURS	1
33 #define PORT_CURS	2
34 #define STREK_CURS	3
35 #define TREK_CURS	4
36 #define BAT_CURS	5
37 
38 /*****************************************************************************
39  *
40  * Description of a cursor.
41  *
42  *****************************************************************************/
43 typedef struct {
44   int			code;		/* code number for cursor */
45   int			pmap;		/* pixmap cursor is on */
46   iconDimensions	icon;		/* icon dimensions for cursor */
47 } CursorDef;
48 
49 /*****************************************************************************
50  *
51  * Description of a pixmap with cursors in it.
52  *
53  *****************************************************************************/
54 typedef struct {
55   int			pm_code;
56   char			*pm_name;
57   char			*pm_file;
58 } CursorPMDef;
59 
60 /*****************************************************************************
61  *
62  * Table of cursor pixmap files
63  *
64  *****************************************************************************/
65 static CursorPMDef cursorPMs[] = {
66   {SMALL_CURS,	"smallcurs",	"smallcurs.b"},
67   {BIG_CURS,	"bigcurs",	"bigcurs.b"},
68   {PORT_CURS,	"portcurs",	"portcurs.b"},
69   {STREK_CURS,	"strekcurs",	"strek.b"},
70   {TREK_CURS,	"trekcurs",	"trek.b"},
71   {BAT_CURS,	"batcurs",	"bat.b"},
72 };
73 static int numPMs = sizeof(cursorPMs)/sizeof(cursorPMs[0]);
74 
75 static CursorDef bigCursors[] = {
76   {ARROWCURSOR,DEFAULT_CURS,	{0,0,0,0,0,0}},
77   {OPENCUTTERS,BIG_CURS,	{0,0,22,26,3,3}},
78   {CLOSEDCUTTERS,BIG_CURS,	{23,0,22,23,3,3}},
79   {IRON,BIG_CURS,		{0,26,31,26,0,25}},
80   {INVERTUPCURSOR,BIG_CURS,	{32,24,30,24,2,15}},
81   {INVERTDNCURSOR,BIG_CURS,	{63,19,31,24,3,15}},
82   {DELETEUPCURSOR,BIG_CURS,	{0,54,25,21,13,20}},
83   {DELETEDNCURSOR,BIG_CURS,	{49,60,16,16,8,15}},
84   {PENCIL,BIG_CURS,		{26,49,21,21,0,21}},
85   {DOWNARROW,SMALL_CURS,	{0,51,16,16,8,16}},
86   {UPARROW,SMALL_CURS,		{17,51,16,16,8,16}},
87   {TRIARROW,SMALL_CURS,		{34,51,16,16,8,16}},
88   {CHANGEDIRCURSOR,SMALL_CURS,	{51,51,16,16,8,16}},
89   {REPCURSOR,BIG_CURS,		{50,47,24,12,10,6}},
90   {SIZECURSOR,BIG_CURS,		{46,0,26,19,0,10}},
91   {WRENCHCURSOR,SMALL_CURS,	{17,17,16,16,3,3}},
92   {TEXTCURSOR,SMALL_CURS,	{68,0,16,16,8,8}},
93   {ARROW0,SMALL_CURS,		{68,17,16,16,8,8}},
94   {ARROW90,SMALL_CURS,		{68,51,16,16,8,8}},
95   {ARROW180,SMALL_CURS,		{51,34,16,16,8,8}},
96   {ARROW270,SMALL_CURS,		{68,34,16,16,8,8}},
97   {BATCURSOR1,BAT_CURS,		{0,0,36,24,18,12}},
98   {BATCURSOR2,BAT_CURS,		{37,0,25,24,13,12}},
99   {BATCURSOR3,BAT_CURS,		{63,0,18,24,10,12}},
100   {TREKDELETEUP,TREK_CURS,	{0,35,77,34,3,29}},
101   {TREKDELETEDN,TREK_CURS,	{0,0,77,34,3,29}},
102   {ADDPORTTOP,PORT_CURS,	{17,0,15,15,7,14}},
103   {ADDPORTBOTTOM,PORT_CURS,	{0,0,15,15,7,0}},
104   {ADDPORTLEFT,PORT_CURS,	{17,17,15,15,14,7}},
105   {ADDPORTRIGHT,PORT_CURS,	{0,17,15,15,0,7}},
106   {SCROLLCURSOR,SMALL_CURS, 	{0,68,16,16,8,8}},
107   {-1}
108 };
109 
110 static CursorDef smallCursors[] = {
111   {ARROWCURSOR,DEFAULT_CURS,	{0,0,0,0,0,0}},
112   {OPENCUTTERS,SMALL_CURS,	{0,0,16,16,1,1}},
113   {CLOSEDCUTTERS,SMALL_CURS,	{17,0,16,16,1,1}},
114   {IRON,SMALL_CURS,		{34,0,16,16,0,16}},
115   {INVERTUPCURSOR,SMALL_CURS,	{51,0,16,16,2,6}},
116   {INVERTDNCURSOR,SMALL_CURS,	{51,0,16,16,2,6}},
117   {DELETEUPCURSOR,SMALL_CURS,	{34,17,16,16,8,16}},
118   {DELETEDNCURSOR,SMALL_CURS,	{51,17,16,16,5,11}},
119   {PENCIL,SMALL_CURS,		{0,34,16,16,0,16}},
120   {DOWNARROW,SMALL_CURS,	{0,51,16,16,8,16}},
121   {UPARROW,SMALL_CURS,		{17,51,16,16,8,16}},
122   {TRIARROW,SMALL_CURS,		{34,51,16,16,8,16}},
123   {CHANGEDIRCURSOR,SMALL_CURS,	{51,51,16,16,8,16}},
124   {REPCURSOR,SMALL_CURS,	{17,34,16,9,8,5}},
125   {SIZECURSOR,SMALL_CURS,	{34,34,16,9,0,4}},
126   {WRENCHCURSOR,SMALL_CURS,	{17,17,16,16,3,3}},
127   {TEXTCURSOR,SMALL_CURS,	{68,0,16,16,8,8}},
128   {ARROW0,SMALL_CURS,		{68,17,16,16,8,8}},
129   {ARROW90,SMALL_CURS,		{68,51,16,16,8,8}},
130   {ARROW180,SMALL_CURS,		{51,34,16,16,8,8}},
131   {ARROW270,SMALL_CURS,		{68,34,16,16,8,8}},
132   {BATCURSOR1,BAT_CURS,		{0,24,16,16,0,0}},
133   {BATCURSOR2,BAT_CURS,		{17,24,16,16,0,0}},
134   {BATCURSOR3,BAT_CURS,		{34,24,16,16,0,0}},
135   {TREKDELETEUP,STREK_CURS,	{0,0,16,16,0,7}},
136   {TREKDELETEDN,STREK_CURS,	{17,0,16,16,0,7}},
137   {ADDPORTTOP,PORT_CURS,	{17,0,15,15,7,14}},
138   {ADDPORTBOTTOM,PORT_CURS,	{0,0,15,15,7,0}},
139   {ADDPORTLEFT,PORT_CURS,	{17,17,15,15,14,7}},
140   {ADDPORTRIGHT,PORT_CURS,	{0,17,15,15,0,7}},
141   {SCROLLCURSOR,SMALL_CURS, 	{0,68,16,16,8,8}},
142   {-1}
143 };
144 
145 static Cursor LastCursor;
146 
147 NHash *GateCursors = 0;
148 
149 int mouseoverState = CANCELMOUSEOVER;
150 
151 
Cursor_register(int id,Cursor C)152 void Cursor_register(int id,Cursor C)
153 {
154   Cursor *pC = (Cursor*)ob_malloc(sizeof(Cursor),"Cursor");
155   *pC = C;
156   NHash_insert(GateCursors,id,pC);
157 }
158 
Cursor_find(int id)159 Cursor Cursor_find(int id)
160 {
161   Cursor *pC = (Cursor*)NHash_find(GateCursors,id);
162   if (!pC) return None;
163   return *pC;
164 }
165 
init_cursors(void)166 void init_cursors(void)
167 {
168   XColor FGC,BGC,FGCreal,BGCreal;
169   unsigned int MaxW,MaxH;
170   Cursor default_cursor = XCreateFontCursor(TkGate.D,XC_top_left_arrow);
171   CursorDef *CSet;
172   int i;
173 
174   GateCursors = new_NHash();
175 
176   for (i = 0;i < numPMs;i++) {
177     CursorPMDef *pmd = &cursorPMs[i];
178     assert(pmd->pm_code == i);
179 #if 0
180     Pixmap_register(pmd->pm_name,pmd->bits,pmd->width,pmd->height);
181 #endif
182     Pixmap_registerFromFile(pmd->pm_name,pmd->pm_file);
183   }
184 
185   XQueryBestCursor(TkGate.D,TkGate.root,32,32,&MaxW,&MaxH);
186 #if DEBUG_CURSORS
187     printf("[Max cursor size is %dx%d]\n",MaxW,MaxH);
188 #endif
189   if (MaxW >= 32 || MaxH >= 32) {
190 #if DEBUG_CURSORS
191     printf("using bigCursors\n");
192 #endif
193     CSet = bigCursors;
194   } else {
195     if (MaxW < 16 && MaxH < 16) {
196       printf("[Warning: hardware cursors limited to "
197 	     "%ux%u (need at least 16x16).]\n",MaxW,MaxH);
198     }
199 #if DEBUG_CURSORS
200     printf("using smallCursors\n");
201 #endif
202     CSet = smallCursors;
203   }
204 
205   XAllocNamedColor(TkGate.D,TkGate.CM,"black",&FGCreal,&FGC);
206   XAllocNamedColor(TkGate.D,TkGate.CM,"white",&BGCreal,&BGC);
207 
208   for (;CSet->code >= 0;CSet++) {
209     Cursor C;
210 
211     if (CSet->pmap == DEFAULT_CURS || CSet->icon.w <= 0) {
212       C = default_cursor;
213 #if DEBUG_CURSORS
214       printf("curor %d: default\n",CSet->code);
215 #endif
216     } else {
217       Pixmap iconPM = Pixmap_find(cursorPMs[CSet->pmap].pm_name);
218       Pixmap srcPM = XCreatePixmap(TkGate.D,TkGate.root,CSet->icon.w,CSet->icon.h,1);
219       XCopyArea(TkGate.D,iconPM,srcPM,TkGate.bitGC,
220 		CSet->icon.x,CSet->icon.y,
221 		CSet->icon.w,CSet->icon.h,0,0);
222 
223       C = XCreatePixmapCursor(TkGate.D,srcPM,srcPM,&FGCreal,&BGCreal,
224 			      CSet->icon.ox,CSet->icon.oy);
225       XFreePixmap(TkGate.D,srcPM);
226 #if DEBUG_CURSORS
227       printf("curor %d: @(%d, %d) %dx%d = %x\n",CSet->code,
228 	     CSet->icon.x,CSet->icon.y,CSet->icon.w,CSet->icon.h,C);
229 #endif
230     }
231     Cursor_register(CSet->code,C);
232   }
233 #if DEBUG_CURSORS
234   printf("cursors done.\n");
235 #endif
236 }
237 
wm_SetCursor(int id)238 void wm_SetCursor(int id)
239 {
240   Cursor C = Cursor_find(id);
241 
242 #if DEBUG_CURSORS > 1
243   printf("wm_SetCursor(%d) = %x\n",id,C);
244 #endif
245   mouseoverState = CANCELMOUSEOVER;
246   XDefineCursor(TkGate.D,TkGate.W,C);
247   LastCursor = C;
248   XFlush(TkGate.D);
249 }
250 
PushCursor(int id)251 void PushCursor(int id)
252 {
253   Cursor C = Cursor_find(id);
254 
255 #if DEBUG_CURSORS > 1
256   printf("PushCursor(%d) = %x\n",id,C);
257 #endif
258 
259   mouseoverState = CANCELMOUSEOVER;
260   XDefineCursor(TkGate.D,TkGate.W,C);
261   LastCursor = C;
262   XFlush(TkGate.D);
263 }
264 
PopCursor()265 void PopCursor()
266 {
267 #if DEBUG_CURSORS > 1
268   printf("PopCursor() = %x\n",LastCursor);
269 #endif
270 
271   XDefineCursor(TkGate.D,TkGate.W,LastCursor);
272   XFlush(TkGate.D);
273 }
274 
MouseoverCursor(int request)275 void MouseoverCursor(int request)
276 {
277   static Cursor link_cursor = 0;
278 
279   if (mouseoverState == request) return;
280   mouseoverState = request;
281 
282   switch (request) {
283   case CANCELMOUSEOVER :
284     PopCursor();
285     break;
286   case HYPERLINKCURSOR :
287     if (link_cursor == 0)
288       link_cursor = XCreateFontCursor(TkGate.D, XC_hand2);
289 
290     XDefineCursor(TkGate.D,TkGate.W, link_cursor);
291     XFlush(TkGate.D);
292     break;
293   default :
294     {
295       Cursor C = Cursor_find(request);
296       XDefineCursor(TkGate.D,TkGate.W,C);
297       XFlush(TkGate.D);
298     }
299     break;
300   }
301 }
302 
303