/*
 * Copyright (C) 2000,2002 Sasha Vasko <sasha at aftercode.net>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 */

#define LOCAL_DEBUG

#include "../configure.h"
#include "asapp.h"
#include "afterstep.h"
#include "parser.h"
#include "mystyle.h"
#include "screen.h"
#include "balloon.h"
#include "event.h"
#include "wmprops.h"
#include "../libAfterImage/afterimage.h"

int _as_frame_corner_xref[FRAME_SIDES + 1] =
		{ FR_NW, FR_NE, FR_SE, FR_SW, FR_NW };

unsigned int _as_default_button_xref[TITLE_BUTTONS] =
		{ C_TButton1, C_TButton3, C_TButton5, C_TButton7, C_TButton9,
	C_TButton0, C_TButton8, C_TButton6, C_TButton4, C_TButton2
};



/* TODO: fix MyLook loading to store everything in ARGB and thus be multiscreen
 * compatible */
char *get_default_obj_name (unsigned long type_magic, Bool icon,
														Bool vertical)
{
	static char *normal_name = NULL;
	static char *icon_name = NULL;
	static char *vertical_name = NULL;
	static char *vertical_icon_name = NULL;
	char **res = NULL;
	char hex[sizeof (unsigned long) * 2 + 1];
	register char *ptr;

	if (icon) {
		if (vertical)
			res = &vertical_icon_name;
		else
			res = &icon_name;
	} else if (vertical)
		res = &vertical_name;
	else
		res = &normal_name;
	if (*res == NULL) {
		if (icon) {
			if (vertical)
				*res = mystrdup ("0." DEFAULT_ICON_VERTICAL ".0000000");
			else
				*res = mystrdup ("0." DEFAULT_ICON_OBJ_NAME ".0000000");
		} else if (vertical)
			*res = mystrdup ("0." DEFAULT_VERTICAL ".0000000");
		else
			*res = mystrdup ("0." DEFAULT_OBJ_NAME ".0000000");
	}
	NUMBER2HEX (type_magic, hex);
	(*res)[0] = hex[sizeof (unsigned long) * 2 - 1];
	for (ptr = &((*res)[2]); *ptr != '.'; ++ptr) ;
	memcpy (ptr + 1, &(hex[sizeof (unsigned long) * 2 - 8]), 7);
	return &((*res)[0]);
}

/***********************************************************************
 * Generic object destructor :
 **********************************************************************/
void myobj_destroy (ASHashableValue value, void *data)
{
	if (data) {
		union {
			void *vptr;
			ASMagic *obj;
			MyFrame *myframe;
			MyBackground *myback;
			MyDesktopConfig *mydesk;
			MyLook *mylook;
		} variant;

		variant.vptr = data;

		switch (variant.obj->magic) {
		case MAGIC_MYFRAME:
			destroy_myframe (&variant.myframe);
			break;
		case MAGIC_MYBACKGROUND:
			myback_delete (&variant.myback, NULL);
			break;
		case MAGIC_MYDESKTOPCONFIG:
			mydeskconfig_delete (&variant.mydesk);
			break;
		case MAGIC_MYLOOK:
			mylook_destroy (&variant.mylook);
			break;
		}
	}
}

ARGB32 get_random_tint_color ()
{
	static ARGB32 tint_colors[6] =
			{ 0xFFFF0000, 0xFFFFFF00, 0xFFFF00FF, 0xFF00FFFF, 0xFF00FF00,
		0xFF0000FF
	};
	return tint_colors[time (NULL) % 6];
}


/*************************************************************************/
/* MyLook :                                                              */
/*************************************************************************/
void
mylook_init (MyLook * look, Bool free_resources,
						 unsigned long what_flags /*see LookLoadFlags in mylook.h */ )
{
	register int i;
	ScreenInfo *scr = ASDefaultScr;
	int display_dpcmx = 0, display_dpcmy = 0;

	if (look == NULL)
		return;
	if (look->magic != MAGIC_MYLOOK)
		return;

	if (look->scr)
		scr = look->scr;

	if (scr && dpy) {							/* dots per cm ) */
		display_dpcmx =
				(scr->MyDisplayWidth * 10) / DisplayWidthMM (dpy, scr->screen);
		display_dpcmy =
				(scr->MyDisplayHeight * 10) / DisplayHeightMM (dpy, scr->screen);
	}

	if (get_flags (what_flags, LL_Balloons) && free_resources)
		cleanup_default_balloons ();

	if (free_resources) {
		if (get_flags (what_flags, LL_MyStyles) && look->styles_list) {
			mystyle_list_destroy_all (&(look->styles_list));
		}

		if (get_flags (what_flags, LL_DeskBacks))
			destroy_ashash (&(look->backs_list));

		if (get_flags (what_flags, LL_DeskConfigs))
			destroy_ashash (&(look->desk_configs));

		if (get_flags (what_flags, LL_MenuIcons)) {
			if (look->MenuArrow != NULL) {
				destroy_icon (&(look->MenuArrow));
				look->MenuArrow = NULL;
			}
		}

		if (get_flags (what_flags, LL_Buttons)) {
			for (i = 0; i < TITLE_BUTTONS; i++)
				free_button_resources (&(look->buttons[i]));
		}
		if (get_flags (what_flags, LL_SupportedHints) && look->supported_hints)
			destroy_hints_list (&(look->supported_hints));

		if (get_flags (what_flags, LL_Layouts)) {
			if (look->DefaultFrameName)
				free (look->DefaultFrameName);
			if (look->FramesList)
				destroy_ashash (&(look->FramesList));
		}
		if (look->configured_icon_areas && get_flags (what_flags, LL_Icons)) {
			free (look->configured_icon_areas);
			if (look->DefaultIcon)
				free (look->DefaultIcon);
		}

		if (look->balloon_look && get_flags (what_flags, LL_Balloons)) {
			destroy_balloon_look (look->balloon_look);
			look->balloon_look = NULL;
		}

		if (get_flags (what_flags, LL_Misc)) {
			if (look->CursorFore)
				free (look->CursorFore);
			if (look->CursorBack)
				free (look->CursorBack);
		}
	}
	/* free_resources */
	if (get_flags (what_flags, LL_MyStyles)) {
		look->styles_list = NULL;

		if (get_flags (what_flags, LL_MSMenu)) {	/* menu MyStyles */
			for (i = 0; i < MENU_BACK_STYLES; i++)
				look->MSMenu[i] = NULL;
		}

		if (get_flags (what_flags, LL_MSWindow)) {	/* focussed, unfocussed, sticky window styles */
			for (i = 0; i < BACK_STYLES; i++)
				look->MSWindow[i] = NULL;
		}
	}
	if (get_flags (what_flags, LL_DeskBacks))
		look->backs_list = NULL;
	if (get_flags (what_flags, LL_DeskConfigs))
		look->desk_configs = NULL;
	if (get_flags (what_flags, LL_MenuIcons)) {
		look->MenuArrow = NULL;
		look->minipixmap_width = 48;
		look->minipixmap_height = 48;
		if (display_dpcmx >= 44)
			look->minipixmap_width = display_dpcmx - 20;
		else if (display_dpcmx > 0)
			look->minipixmap_width = max (display_dpcmx / 2, 12);
		if (display_dpcmy >= 44)
			look->minipixmap_height = display_dpcmy - 20;
		else if (display_dpcmy > 0)
			look->minipixmap_height = max (display_dpcmy / 2, 12);
	}

	if (get_flags (what_flags, LL_Buttons)) {	/* TODO: Titlebuttons - we 'll move them into  MyStyles */
		/* we will translate button numbers from the user input */
		look->TitleButtonSpacing[0] = look->TitleButtonSpacing[1] = 2;
		look->TitleButtonStyle = 0;
		for (i = 0; i < TITLE_BUTTONS; i++) {
			memset (&(look->buttons[i]), 0x00, sizeof (MyButton));
			look->button_xref[i] = _as_default_button_xref[i];
			look->ordered_buttons[i] = NULL;
		}
		look->button_first_right = DEFAULT_FIRST_RIGHT_BUTTON;
	}

	if (get_flags (what_flags, LL_Layouts)) {
		look->DefaultFrameName = NULL;
		look->FramesList = NULL;
		look->TitleTextAlign = 0;
		look->TitleButtonStyle = 0;
		look->TitleButtonSpacing[0] = look->TitleButtonSpacing[1] = 0;
		look->TitleButtonXOffset[0] = look->TitleButtonXOffset[1] = 0;
		look->TitleButtonYOffset[0] = look->TitleButtonYOffset[1] = 0;
	}

	if (get_flags (what_flags, LL_SizeWindow)) {
		memset (&(look->resize_move_geometry), 0x00, sizeof (ASGeometry));
	}

	if (get_flags (what_flags, LL_MenuParams)) {
		look->DrawMenuBorders = 1;
		look->StartMenuSortMode = DEFAULTSTARTMENUSORT;
		look->menu_icm = TEXTURE_TRANSPIXMAP_ALPHA;
		look->menu_hcm = TEXTURE_TRANSPIXMAP_ALPHA;
		look->menu_scm = TEXTURE_TRANSPIXMAP_ALPHA;
	}

	if (get_flags (what_flags, LL_Icons)) {
		look->configured_icon_areas = NULL;
		look->configured_icon_areas_num = 0;
		look->ButtonWidth = (display_dpcmx > 0
												 && display_dpcmx < 50) ? 48 : 64;
		look->ButtonHeight = (display_dpcmy > 0
													&& display_dpcmy < 50) ? 48 : 64;
		look->ButtonIconSpacing = 2;
		look->ButtonAlign = ALIGN_CENTER | RESIZE_H_SCALE | RESIZE_V_SCALE;
		look->ButtonBevel = DEFAULT_TBAR_HILITE;

		look->DefaultIcon = NULL;
	}

	if (get_flags (what_flags, LL_Misc)) {
		CARD32 Base;

		look->RubberBand = 0;
		look->CursorFore = NULL;
		look->CursorBack = NULL;
		if (!get_custom_color ("Base", &Base))
			look->desktop_animation_tint = get_random_tint_color ();
		else {
			int Base_hue;

			Base_hue = asxml_var_get ("ascs.Base.hue");
			if (Base_hue < 30 || Base_hue >= 330)
				look->desktop_animation_tint = 0xFFFF0000;
			else if (Base_hue < 90)
				look->desktop_animation_tint = 0xFFFFFF00;
			else if (Base_hue < 150)
				look->desktop_animation_tint = 0xFF00FF00;
			else if (Base_hue < 210)
				look->desktop_animation_tint = 0xFF00FFFF;
			else if (Base_hue < 270)
				look->desktop_animation_tint = 0xFF0000FF;
			else
				look->desktop_animation_tint = 0xFFFF00FF;
		}
	}
	LOCAL_DEBUG_OUT ("desk_anime_tint = %lX", look->desktop_animation_tint);
	if (get_flags (what_flags, LL_Flags))
		look->flags = SeparateButtonTitle | TxtrMenuItmInd;

	if (get_flags (what_flags, LL_SupportedHints))
		look->supported_hints = NULL;

	if (look->balloon_look && get_flags (what_flags, LL_Balloons))
		look->balloon_look = create_balloon_look ();
}

MyLook *mylook_create ()
{
	MyLook *look;
	static unsigned long next_look_id = 0;

	look = (MyLook *) safecalloc (1, sizeof (MyLook));
	look->magic = MAGIC_MYLOOK;
	look->look_id = next_look_id++;
	mylook_init (look, False, LL_Everything);
	return look;
}

void mylook_destroy (MyLook ** look)
{
	if (look)
		if (*look) {
			mylook_init (*look, True, LL_Everything);
			if ((*look)->name)
				free ((*look)->name);
			(*look)->magic = 0;				/* invalidating object */
			free (*look);
			*look = NULL;
		}
}

void mylook_set_font_size_var (MyLook * look)
{
	if (look) {
		int i, tbar_font_size = 0;

		for (i = 0; i < BACK_STYLES; ++i)
			if (look->MSWindow[i])
				if (look->MSWindow[i]->font.as_font)
					if (look->MSWindow[i]->font.as_font->max_height > tbar_font_size)
						tbar_font_size = look->MSWindow[i]->font.as_font->max_height;
		asxml_var_insert (ASXMLVAR_TitleFontSize, tbar_font_size);
	}
}

/*************************************************************************/
/* MyFrame management :                                                  */
/*************************************************************************/
MyFrame *create_myframe ()
{
	MyFrame *frame = safecalloc (1, sizeof (MyFrame));

	frame->magic = MAGIC_MYFRAME;

	frame->left_layout = MYFRAME_DEFAULT_TITLE_LAYOUT;
	frame->right_layout = MYFRAME_DEFAULT_TITLE_LAYOUT;

	frame->title_fsat = frame->title_usat = frame->title_ssat = -1;
	frame->title_fhue = frame->title_uhue = frame->title_shue = -1;

	frame->title_h_spacing = DEFAULT_TBAR_HSPACING;
	frame->title_v_spacing = DEFAULT_TBAR_VSPACING;

	return frame;

}

MyFrame *create_default_myframe (ASFlagType default_title_align)
{
	MyFrame *frame = create_myframe ();

	frame->set_parts = 0xFFFFFFFF;
	frame->parts_mask = C_SIDEBAR;
	frame->set_part_size = C_SIDEBAR;
	frame->part_width[FR_S] = BOUNDARY_WIDTH;
	frame->part_width[FR_SW] = 0;
	frame->part_width[FR_SE] = 0;
	frame->part_length[FR_S] = 1;
	frame->part_length[FR_SW] = BOUNDARY_WIDTH;
	frame->part_length[FR_SE] = BOUNDARY_WIDTH;
	frame->set_part_align = C_SIDEBAR;
	frame->part_align[FR_S] = 0;
	frame->part_align[FR_SW] = 0;
	frame->part_align[FR_SE] = 0;
	SetPartFBevelMask (frame, C_SIDEBAR);
	SetPartUBevelMask (frame, C_SIDEBAR);
	SetPartSBevelMask (frame, C_SIDEBAR);
	frame->part_fbevel[FR_S] = DEFAULT_TBAR_HILITE;
	frame->part_fbevel[FR_SW] = DEFAULT_TBAR_HILITE;
	frame->part_fbevel[FR_SE] = DEFAULT_TBAR_HILITE;
	frame->part_ubevel[FR_S] = DEFAULT_TBAR_HILITE;
	frame->part_ubevel[FR_SE] = DEFAULT_TBAR_HILITE;
	frame->part_ubevel[FR_SW] = DEFAULT_TBAR_HILITE;
	frame->part_sbevel[FR_S] = DEFAULT_TBAR_HILITE;
	frame->part_sbevel[FR_SW] = DEFAULT_TBAR_HILITE;
	frame->part_sbevel[FR_SE] = DEFAULT_TBAR_HILITE;
	set_flags (frame->set_title_attr, MYFRAME_TitleFBevelSet |
						 MYFRAME_TitleUBevelSet |
						 MYFRAME_TitleSBevelSet |
						 MYFRAME_TitleAlignSet | MYFRAME_TitleFCMSet |
						 MYFRAME_TitleUCMSet | MYFRAME_TitleSCMSet);

	frame->title_fbevel = DEFAULT_TBAR_HILITE;
	frame->title_ubevel = DEFAULT_TBAR_HILITE;
	frame->title_sbevel = DEFAULT_TBAR_HILITE;
	frame->title_align = default_title_align;
	frame->left_btn_align = ALIGN_VCENTER;
	frame->right_btn_align = ALIGN_VCENTER;
	frame->title_fcm = TEXTURE_TRANSPIXMAP_ALPHA;
	frame->title_ucm = TEXTURE_TRANSPIXMAP_ALPHA;
	frame->title_scm = TEXTURE_TRANSPIXMAP_ALPHA;
	frame->condense_titlebar = 0;
	frame->left_layout = MYFRAME_DEFAULT_TITLE_LAYOUT;
	frame->right_layout = MYFRAME_DEFAULT_TITLE_LAYOUT;
	frame->title_h_spacing = DEFAULT_TBAR_HSPACING;
	frame->title_v_spacing = DEFAULT_TBAR_VSPACING;
	return frame;
}

void inherit_myframe (MyFrame * frame, MyFrame * ancestor)
{
	if (frame && ancestor) {
		int i;

		frame->parts_mask =
				(frame->
				 parts_mask & (~ancestor->set_parts)) | ancestor->parts_mask;
		frame->set_parts |= ancestor->set_parts;

		for (i = 0; i < FRAME_PARTS; ++i) {
			if (ancestor->part_filenames[i])
				set_string (&(frame->part_filenames[i]),
										mystrdup (ancestor->part_filenames[i]));
			if (get_flags (ancestor->set_part_size, 0x01 << i)) {
				frame->part_width[i] = ancestor->part_width[i];
				frame->part_length[i] = ancestor->part_length[i];
			}
			if (IsPartFBevelSet (ancestor, i))
				frame->part_fbevel[i] = ancestor->part_fbevel[i];
			if (IsPartUBevelSet (ancestor, i))
				frame->part_ubevel[i] = ancestor->part_ubevel[i];
			if (IsPartSBevelSet (ancestor, i))
				frame->part_sbevel[i] = ancestor->part_sbevel[i];
			if (get_flags (ancestor->set_part_align, 0x01 << i))
				frame->part_align[i] = ancestor->part_align[i];
		}

		for (i = 0; i < FRAME_SIDES; ++i) {
			if (ancestor->part_slicing[i].flags != 0)
				frame->part_slicing[i] = ancestor->part_slicing[i];
		}

		frame->set_part_size |= ancestor->set_part_size;
		frame->set_part_bevel |= ancestor->set_part_bevel;
		frame->set_part_align |= ancestor->set_part_align;

		for (i = 0; i < BACK_STYLES; ++i) {
			if (ancestor->title_style_names)
				set_string (&(frame->title_style_names[i]),
										mystrdup (ancestor->title_style_names[i]));
			if (ancestor->frame_style_names)
				set_string (&(frame->frame_style_names[i]),
										mystrdup (ancestor->frame_style_names[i]));
		}

		for (i = 0; i < MYFRAME_TITLE_BACKS; ++i) {
			if (ancestor->title_back_filenames[i])
				set_string (&(frame->title_back_filenames[i]),
										mystrdup (ancestor->title_back_filenames[i]));
			if (get_flags
					(ancestor->set_title_attr, MYFRAME_TitleBackAlignSet_Start << i))
				frame->title_backs_align[i] = ancestor->title_backs_align[i];
			if (ancestor->title_backs_slicing[i].flags != 0)
				frame->title_backs_slicing[i] = ancestor->title_backs_slicing[i];
		}

		if (get_flags (ancestor->set_title_attr, MYFRAME_TitleFBevelSet))
			frame->title_fbevel = ancestor->title_fbevel;
		if (get_flags (ancestor->set_title_attr, MYFRAME_TitleUBevelSet))
			frame->title_ubevel = ancestor->title_ubevel;
		if (get_flags (ancestor->set_title_attr, MYFRAME_TitleSBevelSet))
			frame->title_sbevel = ancestor->title_sbevel;

		if (get_flags (ancestor->set_title_attr, MYFRAME_TitleAlignSet))
			frame->title_align = ancestor->title_align;

		if (get_flags (ancestor->set_title_attr, MYFRAME_LeftBtnAlignSet))
			frame->left_btn_align = ancestor->left_btn_align;
		if (get_flags (ancestor->set_title_attr, MYFRAME_RightBtnAlignSet))
			frame->right_btn_align = ancestor->right_btn_align;

		if (get_flags (ancestor->set_title_attr, MYFRAME_CondenseTitlebarSet))
			frame->condense_titlebar = ancestor->condense_titlebar;

		if (get_flags (ancestor->set_title_attr, MYFRAME_TitleFCMSet))
			frame->title_fcm = ancestor->title_fcm;
		if (get_flags (ancestor->set_title_attr, MYFRAME_TitleUCMSet))
			frame->title_ucm = ancestor->title_ucm;
		if (get_flags (ancestor->set_title_attr, MYFRAME_TitleSCMSet))
			frame->title_scm = ancestor->title_scm;

		if (get_flags (ancestor->set_title_attr, MYFRAME_TitleFHueSet))
			frame->title_fhue = ancestor->title_fhue;
		if (get_flags (ancestor->set_title_attr, MYFRAME_TitleUHueSet))
			frame->title_uhue = ancestor->title_uhue;
		if (get_flags (ancestor->set_title_attr, MYFRAME_TitleSHueSet))
			frame->title_shue = ancestor->title_shue;
		if (get_flags (ancestor->set_title_attr, MYFRAME_TitleFSatSet))
			frame->title_fsat = ancestor->title_fsat;
		if (get_flags (ancestor->set_title_attr, MYFRAME_TitleUSatSet))
			frame->title_usat = ancestor->title_uhue;
		if (get_flags (ancestor->set_title_attr, MYFRAME_TitleSSatSet))
			frame->title_ssat = ancestor->title_ssat;

		if (get_flags (ancestor->set_title_attr, MYFRAME_TitleHSpacingSet))
			frame->title_h_spacing = ancestor->title_h_spacing;
		if (get_flags (ancestor->set_title_attr, MYFRAME_TitleVSpacingSet))
			frame->title_v_spacing = ancestor->title_v_spacing;

		frame->set_title_attr |= ancestor->set_title_attr;

		clear_flags (frame->flags, ~ancestor->set_flags);
		set_flags (frame->flags, ancestor->flags);
		frame->set_flags |= ancestor->set_flags;
	}
}

MyFrame *myframe_find (const char *name)
{
	ASHashData hdata;

	hdata.vptr = NULL;
	if (ASDefaultScr->Look.FramesList) {
		if (name)
			if (get_hash_item
					(ASDefaultScr->Look.FramesList, AS_HASHABLE (name),
					 &hdata.vptr) != ASH_Success)
				hdata.vptr = NULL;
		if (hdata.vptr == NULL && ASDefaultScr->Look.DefaultFrameName != NULL)
			get_hash_item (ASDefaultScr->Look.FramesList,
										 AS_HASHABLE (ASDefaultScr->Look.DefaultFrameName),
										 &hdata.vptr);
	}
	return (MyFrame *) hdata.vptr;
}

void myframe_load (MyFrame * frame, ASImageManager * imman)
{
	register int i;

	if (frame == NULL)
		return;
	for (i = 0; i < FRAME_PARTS; i++)
		if (frame->part_filenames[i]) {
			frame->parts[i] = safecalloc (1, sizeof (icon_t));
			if (!load_icon (frame->parts[i], frame->part_filenames[i], imman)) {
				free (frame->parts[i]);
				frame->parts[i] = NULL;
			}
#ifdef LOCAL_DEBUG
			LOCAL_DEBUG_OUT ("syncing %s", "");
			ASSync (False);
#endif

		}
	for (i = 0; i < MYFRAME_TITLE_BACKS; ++i) {
		if (frame->title_back_filenames[i]) {
			frame->title_backs[i] = safecalloc (1, sizeof (icon_t));
			if (!load_icon
					(frame->title_backs[i], frame->title_back_filenames[i], imman)) {
				free (frame->title_backs[i]);
				frame->title_backs[i] = NULL;
			}
#ifdef LOCAL_DEBUG
			LOCAL_DEBUG_OUT ("syncing %s", "");
			ASSync (False);
#endif
		}
	}
}

Bool filename2myframe_part (MyFrame * frame, int part, char *filename)
{
	char **dst = NULL;

	if (filename && frame && part >= 0 && part < FRAME_PARTS)
		dst = &(frame->part_filenames[part]);
	if (dst) {
		if (*dst)
			free (*dst);
		*dst = mystrdup (filename);
		return True;
	}
	return False;
}

Bool
set_myframe_style (MyFrame * frame, unsigned int style, Bool title,
									 char *stylename)
{
	char **dst = NULL;

	if (style >= BACK_STYLES)
		style = BACK_DEFAULT;
	if (title)
		dst = &(frame->title_style_names[style]);
	else
		dst = &(frame->frame_style_names[style]);
	if (dst) {
		if (*dst)
			free (*dst);
		*dst = mystrdup (stylename);
		return True;
	}
	return False;
}


Bool myframe_has_parts (const MyFrame * frame, ASFlagType mask)
{
	if (frame) {
		register int i;

		for (i = 0; i < FRAME_PARTS; ++i) {
			if (get_flags (mask, (0x01 << i))) {
				LOCAL_DEBUG_OUT ("i = %d", i);
				if (get_flags (frame->parts_mask, (0x01 << i))) {
					LOCAL_DEBUG_OUT ("parts[i] = %p", frame->parts[i]);
					if (frame->parts[i]
							|| ((frame->part_width[i] || i >= FRAME_SIDES)
									&& frame->part_length[i])) {
						return True;
					}
				}
			}
		}
	}
	return False;
}

void destroy_myframe (MyFrame ** pframe)
{
	MyFrame *pf = *pframe;

	if (pf) {
		register int i = FRAME_PARTS;

		while (--i >= 0) {
			if (pf->parts[i])
				destroy_icon (&(pf->parts[i]));
			if (pf->part_filenames[i])
				free (pf->part_filenames[i]);
		}
		for (i = 0; i < MYFRAME_TITLE_BACKS; ++i) {
			if (pf->title_backs[i])
				destroy_icon (&(pf->title_backs[i]));
			if (pf->title_back_filenames[i])
				free (pf->title_back_filenames[i]);
		}

		for (i = 0; i < BACK_STYLES; ++i) {
			if (pf->title_style_names[i])
				free (pf->title_style_names[i]);
			if (pf->frame_style_names[i])
				free (pf->frame_style_names[i]);
		}
		if (pf->name)
			free (pf->name);

		pf->magic = 0;
		free (pf);
		*pframe = NULL;
	}
}

void check_myframes_list (MyLook * look)
{
	if (look->FramesList == NULL) {
		look->FramesList =
				create_ashash (5, string_hash_value, string_compare,
											 myobj_destroy);
	}
}


/*************************************************************************/

/**********************************************************************/
/******************** MyBackgrounds ***********************************/
MyBackground *create_myback (char *name)
{
	MyBackground *myback = safecalloc (1, sizeof (MyBackground));

	myback->magic = MAGIC_MYBACKGROUND;
	if (name)
		myback->name = mystrdup (name);
	return myback;
}

char *make_myback_image_name (MyLook * look, char *name)
{
	char *im_name = NULL;

	/* creating unique fake filename so that it would not match any
	 * possible real filename : */

	if (name) {
		int len = strlen (name);

		im_name = safemalloc (len + 1 + 4 + 2 + 1 + 4 + 2 + 1);
		sprintf (im_name, "%s#%4.4dAB.%4.4dML", name, look->look_id % 10000,
						 look->deskback_id_base % 10000);
	}
	return im_name;
}

void myback_delete (MyBackground ** myback, ASImageManager * imman)
{
	if (*myback) {
		if ((*myback)->name) {
			free ((*myback)->name);
			if ((*myback)->data)
				free ((*myback)->data);
		}
		if ((*myback)->loaded_im_name)
			free ((*myback)->loaded_im_name);
		if ((*myback)->loaded_pixmap) {
			if (ASDefaultScr->RootBackground
					&& ASDefaultScr->RootBackground->pmap ==
					(*myback)->loaded_pixmap) {
				ASDefaultScr->RootBackground->pmap = None;
			}
			destroy_visual_pixmap (ASDefaultVisual, &((*myback)->loaded_pixmap));
		}
		(*myback)->magic = 0;
		free (*myback);
		*myback = NULL;
	}
}

MyDesktopConfig *create_mydeskconfig (int desk, char *data)
{
	MyDesktopConfig *dc = safecalloc (1, sizeof (MyDesktopConfig));

	dc->magic = MAGIC_MYDESKTOPCONFIG;
	dc->desk = desk;
	if (data)
		dc->back_name = mystrdup (data);
	return dc;
}


void mydeskconfig_delete (MyDesktopConfig ** dc)
{
	if (*dc) {
		if ((*dc)->back_name)
			free ((*dc)->back_name);
		if ((*dc)->layout_name)
			free ((*dc)->layout_name);
		(*dc)->magic = 0;
		free (*dc);
		*dc = NULL;
	}
}

void check_mybacks_list (MyLook * look)
{
	if (look->backs_list == NULL) {
		look->deskback_id_base++;
		look->backs_list =
				create_ashash (5, string_hash_value, string_compare,
											 myobj_destroy);
	}
}

MyBackground *add_myback_to_list (ASHashTable * list,
																				 MyBackground * back,
																				 ASImageManager * imman)
{
	back->magic = MAGIC_MYBACKGROUND;
	if (add_hash_item (list, (ASHashableValue) (back->name), back) !=
			ASH_Success)
		myback_delete (&back, imman);
	return back;
}

MyBackground *add_myback (MyLook * look, MyBackground * back)
{
	check_mybacks_list (look);
	return add_myback_to_list (look->backs_list, back,
														 ASDefaultScr->image_manager);
}


void init_deskconfigs_list (MyLook * look)
{
	look->desk_configs = create_ashash (5, NULL, NULL, myobj_destroy);
}

MyDesktopConfig *add_deskconfig_to_list (ASHashTable * list,
																								MyDesktopConfig * dc)
{
	dc->magic = MAGIC_MYDESKTOPCONFIG;
	if (add_hash_item (list, (ASHashableValue) (dc->desk), dc) !=
			ASH_Success)
		mydeskconfig_delete (&dc);
	return dc;
}

MyDesktopConfig *add_deskconfig (MyLook * look, MyDesktopConfig * dc)
{
	if (look->desk_configs == NULL)
		init_deskconfigs_list (look);
	return add_deskconfig_to_list (look->desk_configs, dc);
}

/********************************************************************************/
/********************       MyLook      *****************************************/
/********************************************************************************/

MyStyle *mylook_get_style (MyLook * look, const char *name)
{
	if (look)
		if (look->magic == MAGIC_MYLOOK)
			return mystyle_list_find_or_default (look->styles_list,
																					 name ? name : "default");

	return NULL;
}

MyDesktopConfig *mylook_get_desk_config (MyLook * look, long desk)
{
	if (look) {
		ASHashData hdata = { 0 };
		LOCAL_DEBUG_OUT ("looking for desk_config for dekstop %ld...", desk);
		if (get_hash_item (look->desk_configs, AS_HASHABLE (desk), &hdata.vptr)
				== ASH_Success)
			return hdata.vptr;
	}
	return NULL;
}


MyBackground *mylook_get_desk_back (MyLook * look, long desk)
{
	MyBackground *myback = NULL;

	if (look) {
		ASHashData hdata = { 0 };
		LOCAL_DEBUG_OUT ("looking for desk_config for dekstop %ld...", desk);
		if (get_hash_item (look->desk_configs, AS_HASHABLE (desk), &hdata.vptr)
				== ASH_Success) {
			MyDesktopConfig *dc = hdata.vptr;

			LOCAL_DEBUG_OUT ("found desk_config %p for dekstop %ld...", dc,
											 desk);
			if (dc->back_name) {
#if defined(LOCAL_DEBUG) && !defined(NO_DEBUG_OUTPUT)
				print_ashash (look->backs_list, string_print);
#endif
				if (get_hash_item
						(look->backs_list, AS_HASHABLE (dc->back_name),
						 &hdata.vptr) == ASH_Success)
					myback = hdata.vptr;
				LOCAL_DEBUG_OUT
						("found back %p for dekstop %ld with name \"%s\". data = \"%s\" ",
						 myback, desk, dc->back_name,
						 myback ? (myback->data ? myback->data : "<null>") : "<null>");
			}
		}
	}
	return myback;
}


MyBackground *mylook_get_back (MyLook * look, char *name)
{
	ASHashData hdata = { 0 };
	if (look && name)
		if (get_hash_item (look->backs_list, AS_HASHABLE (name), &hdata.vptr)
				!= ASH_Success)
			hdata.vptr = NULL;
	return (MyBackground *) hdata.vptr;
}
