grub2: bring back build of aros-side grub2 tools
[AROS.git] / workbench / libs / icon / support.c
blobc46c6be2e4628196ffdddc64bb9b709dc1ca2cfb
1 /*
2 Copyright © 1995-2014, 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,
148 MEMF_PUBLIC, IconBase);
149 if (image->ARGB) {
150 CopyMem(ni->ni_Image[0].ARGB, (APTR)image->ARGB, area * sizeof(UBYTE) * 4);
151 UBYTE *cp;
152 for (cp = (APTR)image->ARGB; area > 0; area--, cp += 4) {
153 struct ColorRegister *cr = (APTR)&cp[1];
154 ChangeToSelectedIconColor(cr);
159 return;
162 /* If we have ARGB imagery, but no Palettized imagery,
163 * synthesize some. Use an EHB palette, similar to the
164 * VGA-16 color palette.
166 * The goal here is to be fast & usable, not slow and accurate.
168 VOID __FetchIconImage_WB(struct DiskObject *icon, int id, struct IconBase *IconBase)
170 struct NativeIcon *ni = NATIVEICON(icon);
171 struct NativeIconImage *image;
172 UBYTE *pixel, *idata;
173 ULONG count;
175 image = &ni->ni_Image[id];
177 if (image->ImageData)
178 return;
180 FetchIconARGB(icon, id);
182 /* If no ARGB, and we're the selected image... */
183 if (!image->ARGB) {
184 if (id == 1 &&
185 image->Palette == NULL &&
186 image->ImageData == NULL &&
187 ni->ni_Image[0].Palette != NULL &&
188 ni->ni_Image[0].ImageData != NULL) {
190 ULONG pens = ni->ni_Image[0].Pens;
191 struct ColorRegister *newpal;
193 newpal = AllocMemIcon(icon, sizeof(struct ColorRegister) * pens,
194 MEMF_PUBLIC, IconBase);
195 if (newpal) {
196 ULONG i;
198 image->Pens = pens;
199 image->TransparentColor = ni->ni_Image[0].TransparentColor;
200 image->ImageData = ni->ni_Image[0].ImageData;
201 CopyMem(ni->ni_Image[0].Palette, newpal, sizeof(struct ColorRegister)*image->Pens);
202 for (i = 0; i < image->Pens; i++) {
203 if (i == image->TransparentColor)
204 continue;
205 ChangeToSelectedIconColor(&newpal[i]);
207 image->Palette = newpal;
210 } else if (image->ARGB) {
211 image->ImageData =
212 AllocMemIcon(icon, ni->ni_Face.Width * ni->ni_Face.Height,
213 MEMF_PUBLIC, IconBase);
214 image->Pens = 17;
215 image->Palette = ehb_palette;
216 image->TransparentColor = 17;
217 pixel = (UBYTE *)image->ARGB;
218 idata = (UBYTE *)image->ImageData;
219 for (count = 0; count < ni->ni_Face.Width * ni->ni_Face.Height; count++, pixel+=4, idata++) {
220 if (pixel[0] == 0) {
221 *idata = image->TransparentColor;
222 } else {
223 UBYTE i,r,g,b;
225 r = pixel[1];
226 g = pixel[2];
227 b = pixel[3];
229 /* Determine max intensity */
230 i = (r > g) ? r : g;
231 i = (i > b) ? i : b;
233 /* Rescale by the intensity */
234 if (i == 0) {
235 *idata = 0;
236 } else {
237 r = (r > (i/4*3)) ? 1 : 0;
238 g = (g > (i/4*3)) ? 1 : 0;
239 b = (b > (i/4*3)) ? 1 : 0;
240 i = (i > 0xd0) ? 1 : 0;
242 *idata = (i << 3) | (r << 2) | (g << 1) | (b << 0);
250 /* Any last-minute changes to the Icon go here before it
251 * is returned.
253 VOID __PrepareIcon_WB(struct DiskObject *icon, struct IconBase *IconBase)
255 /* Ensure that do_DrawerData exists for WBDISK and WBDRAWER objects */
256 if ((icon->do_Type == WBDISK || icon->do_Type == WBDRAWER) &&
257 icon->do_DrawerData == NULL) {
258 icon->do_DrawerData = AllocMemIcon(icon, sizeof(struct DrawerData),
259 MEMF_PUBLIC | MEMF_CLEAR, IconBase);
260 icon->do_DrawerData->dd_NewWindow.LeftEdge = 50;
261 icon->do_DrawerData->dd_NewWindow.TopEdge = 50;
262 icon->do_DrawerData->dd_NewWindow.Width = 400;
263 icon->do_DrawerData->dd_NewWindow.Height = 150;
266 /* Clean out dangling pointers that should no longer be
267 * present
269 if (icon->do_DrawerData) {
270 icon->do_DrawerData->dd_NewWindow.FirstGadget = NULL;
271 icon->do_DrawerData->dd_NewWindow.Screen = NULL;
272 icon->do_DrawerData->dd_NewWindow.BitMap = NULL;
275 return;
280 struct DiskObject *__ReadIcon_WB(BPTR file, struct IconBase *IconBase)
282 struct DiskObject *icon;
284 icon = NewDiskObject(0);
285 if (icon == NULL)
286 return NULL;
288 Seek(file, 0, OFFSET_BEGINNING);
289 if (ReadStruct(&(LB(IconBase)->dsh), (APTR *) &icon, (APTR)file, IconDesc))
291 D(bug("[ReadIcon] Return classic icon %p\n", icon));
292 return icon;
294 FreeDiskObject(icon);
296 if (CyberGfxBase) {
297 /* PNG icons don't have any fallback renders, so if we
298 * don't have CyberGfxBase, we couldn't draw them on-screen
299 * anyway.
301 icon = NewDiskObject(0);
302 if (icon == NULL)
303 return NULL;
305 if (ReadIconPNG(icon, file, IconBase))
307 D(bug("[ReadIcon] Return PNG icon %p\n", icon));
308 return icon;
311 FreeDiskObject(icon);
314 D(bug("[ReadIcon] No icon found\n"));
316 return NULL;
319 /* Absolute offsets for the 'only update position' mode */
320 #define OFFSET_DO_CURRENTX 0x3a
321 #define OFFSET_DO_CURRENTY 0x3e
323 #define is_png(ni) (ni && ni->ni_Extra.Data && ni->ni_Extra.PNG[0].Size && ni->ni_Extra.PNG[0].Offset == 0)
324 #define is_aos(ni) (!is_png(ni))
326 BOOL __WriteIcon_WB(BPTR file, struct DiskObject *icon, struct TagItem *tags, struct IconBase *IconBase)
328 struct NativeIcon *ni;
329 struct DiskObject *itmp, *oldicon = NULL;
330 BOOL success;
331 LONG error = 0;
333 D(bug("[%s] icon=%p\n", __func__, icon));
335 ni = GetNativeIcon(icon, IconBase);
336 /* Fast position update, for non-PNG icons */
337 if (is_aos(ni) && GetTagData(ICONPUTA_OnlyUpdatePosition, FALSE, tags)) {
338 LONG tmp;
339 D(bug("[%s] FastUpdate x,y\n", __func__, icon));
340 Seek(file, OFFSET_DO_CURRENTX, OFFSET_BEGINNING);
341 tmp = AROS_LONG2BE((LONG)icon->do_CurrentX);
342 if (Write(file, &tmp, sizeof(tmp)) == sizeof(tmp)) {
343 Seek(file, OFFSET_DO_CURRENTY, OFFSET_BEGINNING);
344 tmp = AROS_LONG2BE((LONG)icon->do_CurrentY);
345 if (Write(file, &tmp, sizeof(tmp)) == sizeof(tmp)) {
346 return TRUE;
349 return FALSE;
352 itmp = DupDiskObject(icon, ICONDUPA_DuplicateImages, TRUE,
353 ICONDUPA_DuplicateImageData, TRUE,
354 TAG_END);
356 ni = GetNativeIcon(itmp, IconBase);
358 if (GetTagData(ICONPUTA_DropPlanarIconImage, FALSE, tags)) {
359 itmp->do_Gadget.Flags &= ~(GFLG_GADGIMAGE | GFLG_GADGHIMAGE);
360 itmp->do_Gadget.GadgetRender = NULL;
361 itmp->do_Gadget.SelectRender = NULL;
362 } else if (is_aos(ni)) {
363 if (itmp->do_Gadget.GadgetRender == NULL) {
364 SetIoErr(ERROR_OBJECT_WRONG_TYPE);
365 return FALSE;
369 if (ni && GetTagData(ICONPUTA_DropChunkyIconImage, FALSE, tags)) {
370 ni->ni_Image[0].ImageData = NULL;
371 ni->ni_Image[1].ImageData = NULL;
374 if (itmp->do_ToolTypes && GetTagData(ICONPUTA_DropNewIconToolTypes, FALSE, tags)) {
375 int i;
376 for (i = 0; itmp->do_ToolTypes[i] != NULL; i++) {
377 if (strcmp(itmp->do_ToolTypes[i],"*** DON'T EDIT THE FOLLOWING LINES!! ***") == 0) {
378 itmp->do_ToolTypes[i] = NULL;
379 break;
384 if (is_aos(ni) && GetTagData(ICONPUTA_OptimizeImageSpace, FALSE, tags)) {
385 /* TODO: Compress the palette for the icon */
388 if (is_aos(ni) && GetTagData(ICONPUTA_PreserveOldIconImages, TRUE, tags)) {
389 oldicon = ReadIcon(file);
390 Seek(file, 0, OFFSET_BEGINNING);
391 if (oldicon) {
392 itmp->do_Gadget.GadgetRender = oldicon->do_Gadget.GadgetRender;
393 itmp->do_Gadget.SelectRender = oldicon->do_Gadget.SelectRender;
397 if (is_png(ni))
399 D(bug("[%s] Write as PNG\n", __func__));
400 success = WriteIconPNG(file, itmp, IconBase);
402 else
404 D(bug("[%s] Write as AOS 3.5\n", __func__));
405 success = WriteStruct(&(LB(IconBase)->dsh), (APTR) itmp, (APTR) file, IconDesc);
407 if (!success)
408 error = IoErr();
410 if (oldicon)
411 FreeDiskObject(oldicon);
413 FreeDiskObject(itmp);
415 SetIoErr(error);
416 return success;
419 BPTR __LockObject_WB(CONST_STRPTR name, LONG mode, struct IconBase *IconBase)
421 BPTR lock;
423 if (name == NULL)
424 return BNULL;
426 lock = Lock(name, mode);
428 if (lock == BNULL && (strlen(name) >= 5) && strcasecmp(name + strlen(name) - 5, ":Disk") == 0)
430 // FIXME: perhaps allocate buffer from heap?
431 TEXT buffer[256]; /* Path buffer */
432 ULONG length = strlen(name) - 3; /* Amount to copy + NULL */
434 if (sizeof(buffer) >= length)
436 strlcpy(buffer, name, length);
437 lock = Lock(buffer, mode);
441 return lock;
444 VOID __UnLockObject_WB(BPTR lock, struct IconBase *IconBase)
446 if (lock != BNULL) UnLock(lock);
449 CONST_STRPTR GetDefaultIconName(LONG type)
451 static const char * const defaultNames[] =
453 "Disk", /* WBDISK (1) */
454 "Drawer", /* WBDRAWER (2) */
455 "Tool", /* WBTOOL (3) */
456 "Project", /* WBPROJECT (4) */
457 "Trashcan", /* WBGARBAGE (5) */
458 "Device", /* WBDEVICE (6) */
459 "Kick", /* WBKICK (7) */
460 "AppIcon" /* WBAPPICON (8) */
463 if (type >= 1 && type <= 8)
465 return defaultNames[type - 1];
467 else
469 return NULL;
473 /* Use the FNV-1 hash function over the object's pointer.
474 * http://en.wikipedia.org/wiki/Fowler-Noll-Vo_hash_function
476 LONG CalcIconHash(struct DiskObject *dobj)
478 const ULONG FNV1_32_Offset = 2166136261UL;
479 const ULONG FNV1_32_Prime = 16777619UL;
480 IPTR data = (IPTR)dobj;
481 ULONG hash;
482 int i;
484 hash = FNV1_32_Offset;
485 for (i = 0; i < AROS_SIZEOFPTR; i++) {
486 hash *= FNV1_32_Prime;
487 hash ^= data & 0xff;
488 data >>= 8;
491 return hash & (ICONLIST_HASHSIZE-1);
494 /* Allocate memory, and save to an icon's freelist
496 APTR AllocMemIcon(struct DiskObject *icon, IPTR size, ULONG req,
497 struct IconBase *IconBase)
499 APTR mem;
501 mem = AllocMem(size, req);
502 if (mem != NULL)
504 if (!AddFreeList((struct FreeList *)&icon[1], mem, size))
506 FreeMem(mem, size);
507 mem = NULL;
511 return mem;
514 VOID AddIconToList(struct NativeIcon *icon, struct IconBase *IconBase)
516 LONG hash;
518 hash = CalcIconHash(&icon->ni_DiskObject);
520 ObtainSemaphore(&IconBase->iconlistlock);
521 AddTail((struct List *)&IconBase->iconlists[hash], (struct Node *)&icon->ni_Node);
522 ReleaseSemaphore(&IconBase->iconlistlock);
525 VOID RemoveIconFromList(struct NativeIcon *icon, struct IconBase *IconBase)
527 ObtainSemaphore(&IconBase->iconlistlock);
528 Remove((struct Node *)&icon->ni_Node);
529 ReleaseSemaphore(&IconBase->iconlistlock);
532 struct NativeIcon *GetNativeIcon(struct DiskObject *dobj, struct IconBase *IconBase)
534 struct NativeIcon *icon, *reticon = NULL;
535 LONG hash;
536 LONG i = 0;
538 hash = CalcIconHash(dobj);
540 ObtainSemaphoreShared(&IconBase->iconlistlock);
541 ForeachNode(&IconBase->iconlists[hash], icon)
543 i++;
544 if (dobj == &icon->ni_DiskObject)
546 reticon = icon;
547 break;
550 ReleaseSemaphore(&IconBase->iconlistlock);
552 return reticon;