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