Fixed typos in comments.
[AROS.git] / workbench / libs / icon / support.c
blob5ca32944f8789148d8219a470a5dddf5f7fc2371
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Miscellaneous support functions.
6 */
8 #include <string.h>
9 #include <stdio.h>
11 #include "icon_intern.h"
12 #include "support.h"
14 #include <aros/debug.h>
16 extern const IPTR IconDesc[];
18 BPTR __OpenIcon_WB(CONST_STRPTR name, LONG mode, struct IconBase *IconBase)
20 BPTR file = BNULL;
21 ULONG nameLength = strlen(name);
23 if (name[nameLength - 1] == ':')
25 BPTR lock = Lock(name, ACCESS_READ);
27 if (lock != BNULL)
29 BPTR cd = CurrentDir(lock);
31 file = Open("Disk.info", mode);
33 CurrentDir(cd);
34 UnLock(lock);
37 else
39 ULONG length = nameLength + 5 /* strlen(".info") */ + 1 /* '\0' */;
40 STRPTR path = AllocVec(length, MEMF_PUBLIC);
42 if(path != NULL)
44 strlcpy(path, name, length);
45 strlcat(path, ".info", length);
47 file = Open(path, mode);
49 FreeVec(path);
51 else
53 SetIoErr(ERROR_NO_FREE_STORE);
54 return BNULL;
58 return file;
61 BOOL __CloseIcon_WB(BPTR file, struct IconBase *IconBase)
63 return Close(file);
66 BPTR __OpenDefaultIcon_WB(CONST_STRPTR name, LONG mode, struct IconBase *IconBase)
68 static const char * const readPaths[] = { "ENV:SYS", "ENVARC:SYS", NULL };
69 static const char * const writePaths[] = { "ENV:SYS", NULL };
70 const char * const *paths = NULL;
71 CONST_STRPTR path = NULL;
72 BPTR file = BNULL;
73 UBYTE i;
75 /* Make sure it's a plain filename; paths are not allowed */
76 if (strpbrk(name, "/:") != NULL) return BNULL;
78 if (mode == MODE_OLDFILE) paths = readPaths;
79 else paths = writePaths;
81 /* Attempt to open the icon from each path in turn */
82 for (i = 0, path = paths[0]; path != NULL; i++, path = paths[i])
84 TEXT buffer[256]; /* Filename buffer; should be more than large enough */
85 ULONG copied; /* Number of bytes copied */
87 copied = snprintf(buffer, sizeof(buffer), "%s/def_%s.info", path, name);
89 if (copied < sizeof(buffer)) /* check for truncation */
91 if ((file = Open(buffer, mode)) != BNULL)
93 break;
98 return file;
101 BOOL __CloseDefaultIcon_WB(BPTR file, struct IconBase *IconBase)
103 return Close(file);
106 static const struct ColorRegister ehb_palette[] =
108 { 0x00, 0x00, 0x00 },
109 { 0x00, 0x00, 0x7f },
110 { 0x00, 0x7f, 0x00 },
111 { 0x00, 0x7f, 0x7f },
112 { 0x7f, 0x00, 0x00 },
113 { 0x7f, 0x00, 0x7f },
114 { 0x7f, 0x7f, 0x00 },
115 { 0x7f, 0x7f, 0x7f },
116 { 0xb0, 0xb0, 0xb0 },
117 { 0x00, 0x00, 0xf0 },
118 { 0x00, 0xf0, 0x00 },
119 { 0x00, 0xf0, 0xf0 },
120 { 0xf0, 0x00, 0x00 },
121 { 0xf0, 0x00, 0xf0 },
122 { 0xf0, 0xf0, 0x00 },
123 { 0xf0, 0xf0, 0xf0 },
124 { 0x00, 0x00, 0x00 }, /* 'Transparent' */
127 VOID __FetchIconARGB_WB(struct DiskObject *icon, int id, struct IconBase *IconBase)
129 struct NativeIcon *ni = NATIVEICON(icon);
130 struct NativeIconImage *image;
132 image = &ni->ni_Image[id];
134 if (image->ARGB)
135 return;
137 if (ni->ni_Extra.Data != NULL && ni->ni_Extra.PNG[id].Offset >= 0) {
138 image->ARGB = ReadMemPNG(icon, ni->ni_Extra.Data + ni->ni_Extra.PNG[id].Offset,
139 &ni->ni_Face.Width, &ni->ni_Face.Height,
140 NULL, NULL, IconBase);
143 /* Prepare ARGB selected imagery, if needed */
144 if (image->ARGB == NULL && ni->ni_Image[0].ARGB != NULL) {
145 /* Synthesize a selected ARGB icon */
146 ULONG area = ni->ni_Face.Width * ni->ni_Face.Height;
147 image->ARGB = AllocMemIcon(icon, area * sizeof(UBYTE) * 4, MEMF_PUBLIC);
148 if (image->ARGB) {
149 CopyMem(ni->ni_Image[0].ARGB, (APTR)image->ARGB, area * sizeof(UBYTE) * 4);
150 UBYTE *cp;
151 for (cp = (APTR)image->ARGB; area > 0; area--, cp += 4) {
152 struct ColorRegister *cr = (APTR)&cp[1];
153 ChangeToSelectedIconColor(cr);
158 return;
161 /* If we have ARGB imagery, but no Palettized imagery,
162 * synthesize some. Use an EHB palette, similar to the
163 * VGA-16 color palette.
165 * The goal here is to be fast & usable, not slow and accurate.
167 VOID __FetchIconImage_WB(struct DiskObject *icon, int id, struct IconBase *IconBase)
169 struct NativeIcon *ni = NATIVEICON(icon);
170 struct NativeIconImage *image;
171 UBYTE *pixel, *idata;
172 ULONG count;
174 image = &ni->ni_Image[id];
176 if (image->ImageData)
177 return;
179 FetchIconARGB(icon, id);
181 /* If no ARGB, and we're the selected image... */
182 if (!image->ARGB) {
183 if (id == 1 &&
184 image->Palette == NULL &&
185 image->ImageData == NULL &&
186 ni->ni_Image[0].Palette != NULL &&
187 ni->ni_Image[0].ImageData != NULL) {
189 ULONG pens = ni->ni_Image[0].Pens;
190 struct ColorRegister *newpal;
192 newpal = AllocMemIcon(icon, sizeof(struct ColorRegister)*pens, MEMF_PUBLIC);
193 if (newpal) {
194 ULONG i;
196 image->Pens = pens;
197 image->TransparentColor = ni->ni_Image[0].TransparentColor;
198 image->ImageData = ni->ni_Image[0].ImageData;
199 CopyMem(ni->ni_Image[0].Palette, newpal, sizeof(struct ColorRegister)*image->Pens);
200 for (i = 0; i < image->Pens; i++) {
201 if (i == image->TransparentColor)
202 continue;
203 ChangeToSelectedIconColor(&newpal[i]);
205 image->Palette = newpal;
208 } else if (image->ARGB) {
209 image->ImageData = AllocMemIcon(icon, ni->ni_Face.Width * ni->ni_Face.Height, MEMF_PUBLIC);
210 image->Pens = 17;
211 image->Palette = ehb_palette;
212 image->TransparentColor = 17;
213 pixel = (UBYTE *)image->ARGB;
214 idata = (UBYTE *)image->ImageData;
215 for (count = 0; count < ni->ni_Face.Width * ni->ni_Face.Height; count++, pixel+=4, idata++) {
216 if (pixel[0] == 0) {
217 *idata = image->TransparentColor;
218 } else {
219 UBYTE i,r,g,b;
221 r = pixel[1];
222 g = pixel[2];
223 b = pixel[3];
225 /* Determine max intensity */
226 i = (r > g) ? r : g;
227 i = (i > b) ? i : b;
229 /* Rescale by the intensity */
230 if (i == 0) {
231 *idata = 0;
232 } else {
233 r = (r > (i/4*3)) ? 1 : 0;
234 g = (g > (i/4*3)) ? 1 : 0;
235 b = (b > (i/4*3)) ? 1 : 0;
236 i = (i > 0xd0) ? 1 : 0;
238 *idata = (i << 3) | (r << 2) | (g << 1) | (b << 0);
246 /* Any last-minute changes to the Icon go here before it
247 * is returned.
249 VOID __PrepareIcon_WB(struct DiskObject *icon, struct IconBase *IconBase)
251 /* Ensure that do_DrawerData exists for WBDISK and WBDRAWER objects */
252 if ((icon->do_Type == WBDISK || icon->do_Type == WBDRAWER) &&
253 icon->do_DrawerData == NULL) {
254 icon->do_DrawerData = AllocMemIcon(icon, sizeof(struct DrawerData), MEMF_PUBLIC | MEMF_CLEAR);
255 icon->do_DrawerData->dd_NewWindow.LeftEdge = 50;
256 icon->do_DrawerData->dd_NewWindow.TopEdge = 50;
257 icon->do_DrawerData->dd_NewWindow.Width = 400;
258 icon->do_DrawerData->dd_NewWindow.Height = 150;
261 /* Clean out dangling pointers that should no long be
262 * present
264 if (icon->do_DrawerData) {
265 icon->do_DrawerData->dd_NewWindow.FirstGadget = NULL;
266 icon->do_DrawerData->dd_NewWindow.Screen = NULL;
267 icon->do_DrawerData->dd_NewWindow.BitMap = NULL;
270 return;
275 struct DiskObject *__ReadIcon_WB(BPTR file, struct IconBase *IconBase)
277 struct DiskObject *icon;
279 icon = NewDiskObject(0);
280 if (icon == NULL)
281 return NULL;
283 Seek(file, 0, OFFSET_BEGINNING);
284 if (ReadStruct(&(LB(IconBase)->dsh), (APTR *) &icon, (APTR)file, IconDesc))
286 D(bug("[ReadIcon] Return classic icon %p\n", icon));
287 return icon;
289 FreeDiskObject(icon);
291 if (CyberGfxBase) {
292 /* PNG icons don't have any fallback renders, so if we
293 * don't have CyberGfxBase, we couldn't draw them on-screen
294 * anyway.
296 icon = NewDiskObject(0);
297 if (icon == NULL)
298 return NULL;
300 if (ReadIconPNG(icon, file, IconBase))
302 D(bug("[ReadIcon] Return PNG icon %p\n", icon));
303 return icon;
306 FreeDiskObject(icon);
309 D(bug("[ReadIcon] No icon found\n"));
311 return NULL;
314 /* Absolute offsets for the 'only update position' mode */
315 #define OFFSET_DO_CURRENTX 0x3a
316 #define OFFSET_DO_CURRENTY 0x3e
318 #define is_png(ni) (ni && ni->ni_Extra.Data && ni->ni_Extra.PNG[0].Size && ni->ni_Extra.PNG[0].Offset == 0)
319 #define is_aos(ni) (!is_png(ni))
321 BOOL __WriteIcon_WB(BPTR file, struct DiskObject *icon, struct TagItem *tags, struct IconBase *IconBase)
323 struct NativeIcon *ni;
324 struct DiskObject *itmp, *oldicon = NULL;
325 BOOL success;
327 D(bug("[%s] icon=%p\n", __func__, icon));
329 ni = GetNativeIcon(icon, IconBase);
330 /* Fast position update, for non-PNG icons */
331 if (is_aos(ni) && GetTagData(ICONPUTA_OnlyUpdatePosition, FALSE, tags)) {
332 LONG tmp;
333 D(bug("[%s] FastUpdate x,y\n", __func__, icon));
334 Seek(file, OFFSET_DO_CURRENTX, OFFSET_BEGINNING);
335 tmp = AROS_LONG2BE((LONG)icon->do_CurrentX);
336 if (Write(file, &tmp, sizeof(tmp)) == sizeof(tmp)) {
337 Seek(file, OFFSET_DO_CURRENTY, OFFSET_BEGINNING);
338 tmp = AROS_LONG2BE((LONG)icon->do_CurrentY);
339 if (Write(file, &tmp, sizeof(tmp)) == sizeof(tmp)) {
340 return TRUE;
343 return FALSE;
346 itmp = DupDiskObject(icon, ICONDUPA_DuplicateImages, TRUE,
347 ICONDUPA_DuplicateImageData, TRUE,
348 TAG_END);
350 ni = GetNativeIcon(itmp, IconBase);
352 if (GetTagData(ICONPUTA_DropPlanarIconImage, FALSE, tags)) {
353 itmp->do_Gadget.Flags &= ~(GFLG_GADGIMAGE | GFLG_GADGHIMAGE);
354 itmp->do_Gadget.GadgetRender = NULL;
355 itmp->do_Gadget.SelectRender = NULL;
356 } else if (is_aos(ni)) {
357 if (itmp->do_Gadget.GadgetRender == NULL) {
358 SetIoErr(ERROR_OBJECT_WRONG_TYPE);
359 return FALSE;
363 if (ni && GetTagData(ICONPUTA_DropChunkyIconImage, FALSE, tags)) {
364 ni->ni_Image[0].ImageData = NULL;
365 ni->ni_Image[1].ImageData = NULL;
368 if (itmp->do_ToolTypes && GetTagData(ICONPUTA_DropNewIconToolTypes, FALSE, tags)) {
369 int i;
370 for (i = 0; itmp->do_ToolTypes[i] != NULL; i++) {
371 if (strcmp(itmp->do_ToolTypes[i],"*** DON'T EDIT THE FOLLOWING LINES!! ***") == 0) {
372 itmp->do_ToolTypes[i] = NULL;
373 break;
378 if (is_aos(ni) && GetTagData(ICONPUTA_OptimizeImageSpace, FALSE, tags)) {
379 /* TODO: Compress the palette for the icon */
382 if (is_aos(ni) && GetTagData(ICONPUTA_PreserveOldIconImages, TRUE, tags)) {
383 oldicon = ReadIcon(file);
384 Seek(file, 0, OFFSET_BEGINNING);
385 if (oldicon) {
386 itmp->do_Gadget.GadgetRender = oldicon->do_Gadget.GadgetRender;
387 itmp->do_Gadget.SelectRender = oldicon->do_Gadget.SelectRender;
391 if (is_png(ni))
393 D(bug("[%s] Write as PNG\n", __func__));
394 success = WriteIconPNG(file, itmp, IconBase);
396 else
398 D(bug("[%s] Write as AOS 3.5\n", __func__));
399 success = WriteStruct(&(LB(IconBase)->dsh), (APTR) itmp, (APTR) file, IconDesc);
402 if (oldicon)
403 FreeDiskObject(oldicon);
405 FreeDiskObject(itmp);
407 return success;
410 BPTR __LockObject_WB(CONST_STRPTR name, LONG mode, struct IconBase *IconBase)
412 BPTR lock;
414 if (name == NULL)
415 return BNULL;
417 lock = Lock(name, mode);
419 if (lock == BNULL && (strlen(name) >= 5) && strcasecmp(name + strlen(name) - 5, ":Disk") == 0)
421 // FIXME: perhaps allocate buffer from heap?
422 TEXT buffer[256]; /* Path buffer */
423 ULONG length = strlen(name) - 3; /* Amount to copy + NULL */
425 if (sizeof(buffer) >= length)
427 strlcpy(buffer, name, length);
428 lock = Lock(buffer, mode);
432 return lock;
435 VOID __UnLockObject_WB(BPTR lock, struct IconBase *IconBase)
437 if (lock != BNULL) UnLock(lock);
440 CONST_STRPTR GetDefaultIconName(LONG type)
442 static const char * const defaultNames[] =
444 "Disk", /* WBDISK (1) */
445 "Drawer", /* WBDRAWER (2) */
446 "Tool", /* WBTOOL (3) */
447 "Project", /* WBPROJECT (4) */
448 "Trashcan", /* WBGARBAGE (5) */
449 "Device", /* WBDEVICE (6) */
450 "Kick", /* WBKICK (7) */
451 "AppIcon" /* WBAPPICON (8) */
454 if (type >= 1 && type <= 8)
456 return defaultNames[type - 1];
458 else
460 return NULL;
464 /* Use the FNV-1 hash function over the object's pointer.
465 * http://en.wikipedia.org/wiki/Fowler-Noll-Vo_hash_function
467 LONG CalcIconHash(struct DiskObject *dobj)
469 const ULONG FNV1_32_Offset = 2166136261UL;
470 const ULONG FNV1_32_Prime = 16777619UL;
471 IPTR data = (IPTR)dobj;
472 ULONG hash;
473 int i;
475 hash = FNV1_32_Offset;
476 for (i = 0; i < AROS_SIZEOFPTR; i++) {
477 hash *= FNV1_32_Prime;
478 hash ^= data & 0xff;
479 data >>= 8;
482 return hash & (ICONLIST_HASHSIZE-1);
485 VOID AddIconToList(struct NativeIcon *icon, struct IconBase *IconBase)
487 LONG hash;
489 hash = CalcIconHash(&icon->ni_DiskObject);
491 ObtainSemaphore(&IconBase->iconlistlock);
492 AddTail((struct List *)&IconBase->iconlists[hash], (struct Node *)&icon->ni_Node);
493 ReleaseSemaphore(&IconBase->iconlistlock);
496 VOID RemoveIconFromList(struct NativeIcon *icon, struct IconBase *IconBase)
498 ObtainSemaphore(&IconBase->iconlistlock);
499 Remove((struct Node *)&icon->ni_Node);
500 ReleaseSemaphore(&IconBase->iconlistlock);
503 struct NativeIcon *GetNativeIcon(struct DiskObject *dobj, struct IconBase *IconBase)
505 struct NativeIcon *icon, *reticon = NULL;
506 LONG hash;
507 LONG i = 0;
509 hash = CalcIconHash(dobj);
511 ObtainSemaphoreShared(&IconBase->iconlistlock);
512 ForeachNode((struct List *)&IconBase->iconlists[hash], icon)
514 i++;
515 if (dobj == &icon->ni_DiskObject)
517 reticon = icon;
518 break;
521 ReleaseSemaphore(&IconBase->iconlistlock);
523 return reticon;