2 Copyright © 1995-2014, The AROS Development Team. All rights reserved.
5 Miscellaneous support functions.
11 #include "icon_intern.h"
14 #include <aros/debug.h>
16 extern const IPTR IconDesc
[];
18 BPTR
__OpenIcon_WB(CONST_STRPTR name
, LONG mode
, struct IconBase
*IconBase
)
21 ULONG nameLength
= strlen(name
);
23 if (name
[nameLength
- 1] == ':')
25 BPTR lock
= Lock(name
, ACCESS_READ
);
29 BPTR cd
= CurrentDir(lock
);
31 file
= Open("Disk.info", mode
);
39 ULONG length
= nameLength
+ 5 /* strlen(".info") */ + 1 /* '\0' */;
40 STRPTR path
= AllocVec(length
, MEMF_PUBLIC
);
44 strlcpy(path
, name
, length
);
45 strlcat(path
, ".info", length
);
47 file
= Open(path
, mode
);
53 SetIoErr(ERROR_NO_FREE_STORE
);
61 BOOL
__CloseIcon_WB(BPTR file
, struct IconBase
*IconBase
)
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
;
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
)
101 BOOL
__CloseDefaultIcon_WB(BPTR file
, struct IconBase
*IconBase
)
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
];
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
);
150 CopyMem(ni
->ni_Image
[0].ARGB
, (APTR
)image
->ARGB
, area
* sizeof(UBYTE
) * 4);
152 for (cp
= (APTR
)image
->ARGB
; area
> 0; area
--, cp
+= 4) {
153 struct ColorRegister
*cr
= (APTR
)&cp
[1];
154 ChangeToSelectedIconColor(cr
);
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
;
175 image
= &ni
->ni_Image
[id
];
177 if (image
->ImageData
)
180 FetchIconARGB(icon
, id
);
182 /* If no ARGB, and we're the selected image... */
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
);
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
)
205 ChangeToSelectedIconColor(&newpal
[i
]);
207 image
->Palette
= newpal
;
210 } else if (image
->ARGB
) {
212 AllocMemIcon(icon
, ni
->ni_Face
.Width
* ni
->ni_Face
.Height
,
213 MEMF_PUBLIC
, IconBase
);
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
++) {
221 *idata
= image
->TransparentColor
;
229 /* Determine max intensity */
233 /* Rescale by the intensity */
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
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
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
;
280 struct DiskObject
*__ReadIcon_WB(BPTR file
, struct IconBase
*IconBase
)
282 struct DiskObject
*icon
;
284 icon
= NewDiskObject(0);
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
));
294 FreeDiskObject(icon
);
297 /* PNG icons don't have any fallback renders, so if we
298 * don't have CyberGfxBase, we couldn't draw them on-screen
301 icon
= NewDiskObject(0);
305 if (ReadIconPNG(icon
, file
, IconBase
))
307 D(bug("[ReadIcon] Return PNG icon %p\n", icon
));
311 FreeDiskObject(icon
);
314 D(bug("[ReadIcon] No icon found\n"));
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
;
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
)) {
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
)) {
352 itmp
= DupDiskObject(icon
, ICONDUPA_DuplicateImages
, TRUE
,
353 ICONDUPA_DuplicateImageData
, TRUE
,
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
);
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
)) {
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
;
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
);
392 itmp
->do_Gadget
.GadgetRender
= oldicon
->do_Gadget
.GadgetRender
;
393 itmp
->do_Gadget
.SelectRender
= oldicon
->do_Gadget
.SelectRender
;
399 D(bug("[%s] Write as PNG\n", __func__
));
400 success
= WriteIconPNG(file
, itmp
, IconBase
);
404 D(bug("[%s] Write as AOS 3.5\n", __func__
));
405 success
= WriteStruct(&(LB(IconBase
)->dsh
), (APTR
) itmp
, (APTR
) file
, IconDesc
);
411 FreeDiskObject(oldicon
);
413 FreeDiskObject(itmp
);
419 BPTR
__LockObject_WB(CONST_STRPTR name
, LONG mode
, struct IconBase
*IconBase
)
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
);
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];
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
;
484 hash
= FNV1_32_Offset
;
485 for (i
= 0; i
< AROS_SIZEOFPTR
; i
++) {
486 hash
*= FNV1_32_Prime
;
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
)
501 mem
= AllocMem(size
, req
);
504 if (!AddFreeList((struct FreeList
*)&icon
[1], mem
, size
))
514 VOID
AddIconToList(struct NativeIcon
*icon
, struct IconBase
*IconBase
)
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
;
538 hash
= CalcIconHash(dobj
);
540 ObtainSemaphoreShared(&IconBase
->iconlistlock
);
541 ForeachNode(&IconBase
->iconlists
[hash
], icon
)
544 if (dobj
== &icon
->ni_DiskObject
)
550 ReleaseSemaphore(&IconBase
->iconlistlock
);