/** Shutdown icon support. */ void ShutdownIcons(void) { unsigned int x; for(x = 0; x < HASH_SIZE; x++) { while(iconHash[x]) { DoDestroyIcon(x, iconHash[x]); } } JXFreeGC(display, iconGC); }
/** Shutdown font support. */ void ShutdownFonts(void) { unsigned int x; for(x = 0; x < FONT_COUNT; x++) { if(fonts[x]) { #ifdef USE_XFT JXftFontClose(display, fonts[x]); #else JXFreeFont(display, fonts[x]); #endif fonts[x] = NULL; } } #ifdef USE_XFT XftDrawDestroy(xd); #else JXFreeGC(display, fontGC); #endif }
/** Create a scaled icon. */ ScaledIconNode *CreateScaledRenderIcon(IconNode *icon, int width, int height) { ScaledIconNode *result = NULL; #ifdef USE_XRENDER XRenderPictFormat *fp; XColor color; GC maskGC; XImage *destImage; XImage *destMask; unsigned long alpha; int index, yindex; int x, y; int imageLine; int maskLine; Assert(icon); if(!haveRender || !icon->useRender) { return NULL; } result = Allocate(sizeof(ScaledIconNode)); result->next = icon->nodes; icon->nodes = result; result->width = width; result->height = height; width = icon->image->width; height = icon->image->height; result->mask = JXCreatePixmap(display, rootWindow, width, height, 8); maskGC = JXCreateGC(display, result->mask, 0, NULL); result->image = JXCreatePixmap(display, rootWindow, width, height, rootDepth); destImage = JXCreateImage(display, rootVisual, rootDepth, ZPixmap, 0, NULL, width, height, 8, 0); destImage->data = Allocate(sizeof(unsigned long) * width * height); destMask = JXCreateImage(display, rootVisual, 8, ZPixmap, 0, NULL, width, height, 8, 0); destMask->data = Allocate(width * height); imageLine = 0; maskLine = 0; for(y = 0; y < height; y++) { yindex = y * icon->image->width; for(x = 0; x < width; x++) { index = 4 * (yindex + x); alpha = icon->image->data[index]; color.red = icon->image->data[index + 1]; color.red |= color.red << 8; color.green = icon->image->data[index + 2]; color.green |= color.green << 8; color.blue = icon->image->data[index + 3]; color.blue |= color.blue << 8; color.red = (color.red * alpha) >> 8; color.green = (color.green * alpha) >> 8; color.blue = (color.blue * alpha) >> 8; GetColor(&color); XPutPixel(destImage, x, y, color.pixel); destMask->data[maskLine + x] = alpha; } imageLine += destImage->bytes_per_line; maskLine += destMask->bytes_per_line; } /* Render the image data to the image pixmap. */ JXPutImage(display, result->image, rootGC, destImage, 0, 0, 0, 0, width, height); Release(destImage->data); destImage->data = NULL; JXDestroyImage(destImage); /* Render the alpha data to the mask pixmap. */ JXPutImage(display, result->mask, maskGC, destMask, 0, 0, 0, 0, width, height); Release(destMask->data); destMask->data = NULL; JXDestroyImage(destMask); JXFreeGC(display, maskGC); /* Create the alpha picture. */ fp = JXRenderFindStandardFormat(display, PictStandardA8); Assert(fp); result->alphaPicture = JXRenderCreatePicture(display, result->mask, fp, 0, NULL); /* Create the render picture. */ fp = JXRenderFindVisualFormat(display, rootVisual); Assert(fp); result->imagePicture = JXRenderCreatePicture(display, result->image, fp, 0, NULL); /* Free unneeded pixmaps. */ JXFreePixmap(display, result->image); result->image = None; JXFreePixmap(display, result->mask); result->mask = None; #endif return result; }
/** Draw a button. */ void DrawButton(ButtonNode *bp) { ColorType fg; long bg1, bg2; long up, down; DecorationsType decorations; Drawable drawable; GC gc; int x, y; int width, height; int xoffset, yoffset; int iconWidth, iconHeight; int textWidth, textHeight; Assert(bp); drawable = bp->drawable; x = bp->x; y = bp->y; width = bp->width; height = bp->height; gc = JXCreateGC(display, drawable, 0, NULL); /* Determine the colors to use. */ switch(bp->type) { case BUTTON_LABEL: fg = COLOR_MENU_FG; bg1 = colors[COLOR_MENU_BG]; bg2 = colors[COLOR_MENU_BG]; up = colors[COLOR_MENU_UP]; down = colors[COLOR_MENU_DOWN]; decorations = settings.menuDecorations; break; case BUTTON_MENU_ACTIVE: fg = COLOR_MENU_ACTIVE_FG; bg1 = colors[COLOR_MENU_ACTIVE_BG1]; bg2 = colors[COLOR_MENU_ACTIVE_BG2]; down = colors[COLOR_MENU_ACTIVE_UP]; up = colors[COLOR_MENU_ACTIVE_DOWN]; decorations = settings.menuDecorations; break; case BUTTON_TRAY: fg = COLOR_TRAYBUTTON_FG; bg1 = colors[COLOR_TRAYBUTTON_BG1]; bg2 = colors[COLOR_TRAYBUTTON_BG2]; up = colors[COLOR_TRAYBUTTON_UP]; down = colors[COLOR_TRAYBUTTON_DOWN]; decorations = settings.trayDecorations; break; case BUTTON_TRAY_ACTIVE: fg = COLOR_TRAYBUTTON_ACTIVE_FG; bg1 = colors[COLOR_TRAYBUTTON_ACTIVE_BG1]; bg2 = colors[COLOR_TRAYBUTTON_ACTIVE_BG2]; down = colors[COLOR_TRAYBUTTON_ACTIVE_UP]; up = colors[COLOR_TRAYBUTTON_ACTIVE_DOWN]; decorations = settings.trayDecorations; break; case BUTTON_TASK: fg = COLOR_TASKLIST_FG; bg1 = colors[COLOR_TASKLIST_BG1]; bg2 = colors[COLOR_TASKLIST_BG2]; up = colors[COLOR_TASKLIST_UP]; down = colors[COLOR_TASKLIST_DOWN]; decorations = settings.trayDecorations; break; case BUTTON_TASK_ACTIVE: fg = COLOR_TASKLIST_ACTIVE_FG; bg1 = colors[COLOR_TASKLIST_ACTIVE_BG1]; bg2 = colors[COLOR_TASKLIST_ACTIVE_BG2]; down = colors[COLOR_TASKLIST_ACTIVE_UP]; up = colors[COLOR_TASKLIST_ACTIVE_DOWN]; decorations = settings.trayDecorations; break; case BUTTON_MENU: default: fg = COLOR_MENU_FG; bg1 = colors[COLOR_MENU_BG]; bg2 = colors[COLOR_MENU_BG]; up = colors[COLOR_MENU_UP]; down = colors[COLOR_MENU_DOWN]; decorations = settings.menuDecorations; break; } /* Draw the background. */ if(bp->fill) { /* Draw the button background. */ JXSetForeground(display, gc, bg1); if(bg1 == bg2) { /* single color */ JXFillRectangle(display, drawable, gc, x, y, width, height); } else { /* gradient */ DrawHorizontalGradient(drawable, gc, bg1, bg2, x, y, width, height); } } /* Draw the border. */ if(bp->border) { if(decorations == DECO_MOTIF) { JXSetForeground(display, gc, up); JXDrawLine(display, drawable, gc, x, y, x + width - 1, y); JXDrawLine(display, drawable, gc, x, y, x, y + height - 1); JXSetForeground(display, gc, down); JXDrawLine(display, drawable, gc, x, y + height - 1, x + width - 1, y + height - 1); JXDrawLine(display, drawable, gc, x + width - 1, y, x + width - 1, y + height - 1); } else { JXSetForeground(display, gc, down); JXDrawRectangle(display, drawable, gc, x, y, width - 1, height - 1); } } /* Determine the size of the icon (if any) to display. */ iconWidth = 0; iconHeight = 0; if(bp->icon) { if(bp->icon == &emptyIcon) { iconWidth = Min(width - 4, height - 4); iconHeight = iconWidth; } else { const int ratio = (bp->icon->width << 16) / bp->icon->height; iconHeight = height - 4; iconWidth = (iconHeight * ratio) >> 16; if(iconWidth > width - 4) { iconWidth = width - 4; iconHeight = (iconWidth << 16) / ratio; } } } /* Determine how much room is left for text. */ textWidth = 0; textHeight = 0; if(bp->text && (width > height || !bp->icon)) { textWidth = GetStringWidth(bp->font, bp->text); textHeight = GetStringHeight(bp->font); if(iconWidth > 0 && textWidth + iconWidth + 7 > width) { textWidth = width - iconWidth - 7; } else if(iconWidth == 0 && textWidth + 5 > width) { textWidth = width - 5; } textWidth = textWidth < 0 ? 0 : textWidth; } /* Determine the offset of the text in the button. */ if(bp->alignment == ALIGN_CENTER || width <= height) { xoffset = (width - iconWidth - textWidth + 1) / 2; if(xoffset < 0) { xoffset = 0; } } else { xoffset = 2; } /* Display the icon. */ if(bp->icon) { yoffset = (height - iconHeight + 1) / 2; PutIcon(bp->icon, drawable, colors[fg], x + xoffset, y + yoffset, iconWidth, iconHeight); xoffset += iconWidth + 2; } /* Display the label. */ if(textWidth > 0) { yoffset = (height - textHeight + 1) / 2; RenderString(drawable, bp->font, fg, x + xoffset, y + yoffset, textWidth, bp->text); } JXFreeGC(display, gc); }
/** Display a string. */ void RenderString(Drawable d, FontType font, ColorType color, int x, int y, int width, const char *str) { XRectangle rect; Region renderRegion; int len; char *output; #ifdef USE_FRIBIDI FriBidiChar *temp_i; FriBidiChar *temp_o; FriBidiParType type = FRIBIDI_PAR_ON; int unicodeLength; #endif #ifdef USE_XFT XftDraw *xd; XGlyphInfo extents; #else XGCValues gcValues; unsigned long gcMask; GC gc; #endif char *utf8String; /* Early return for empty strings. */ if(!str || !str[0]) { return; } /* Convert to UTF-8 if necessary. */ utf8String = GetUTF8String(str); /* Get the length of the UTF-8 string. */ len = strlen(utf8String); #ifdef USE_XFT xd = XftDrawCreate(display, d, rootVisual, rootColormap); #else gcMask = GCGraphicsExposures; gcValues.graphics_exposures = False; gc = JXCreateGC(display, d, gcMask, &gcValues); #endif /* Apply the bidi algorithm if requested. */ #ifdef USE_FRIBIDI temp_i = AllocateStack((len + 1) * sizeof(FriBidiChar)); temp_o = AllocateStack((len + 1) * sizeof(FriBidiChar)); unicodeLength = fribidi_charset_to_unicode(FRIBIDI_CHAR_SET_UTF8, utf8String, len, temp_i); fribidi_log2vis(temp_i, unicodeLength, &type, temp_o, NULL, NULL, NULL); output = AllocateStack(4 * len + 1); fribidi_unicode_to_charset(FRIBIDI_CHAR_SET_UTF8, temp_o, unicodeLength, (char*)output); len = strlen(output); #else output = utf8String; #endif /* Get the bounds for the string based on the specified width. */ rect.x = x; rect.y = y; rect.height = GetStringHeight(font); #ifdef USE_XFT JXftTextExtentsUtf8(display, fonts[font], (const unsigned char*)output, len, &extents); rect.width = extents.xOff; #else rect.width = XTextWidth(fonts[font], output, len); #endif rect.width = Min(rect.width, width) + 2; /* Combine the width bounds with the region to use. */ renderRegion = XCreateRegion(); XUnionRectWithRegion(&rect, renderRegion, renderRegion); /* Display the string. */ #ifdef USE_XFT JXftDrawSetClip(xd, renderRegion); JXftDrawStringUtf8(xd, GetXftColor(color), fonts[font], x, y + fonts[font]->ascent, (const unsigned char*)output, len); JXftDrawChange(xd, rootWindow); #else JXSetForeground(display, gc, colors[color]); JXSetRegion(display, gc, renderRegion); JXSetFont(display, gc, fonts[font]->fid); JXDrawString(display, d, gc, x, y + fonts[font]->ascent, output, len); #endif /* Free any memory used for UTF conversion. */ #ifdef USE_FRIBIDI ReleaseStack(temp_i); ReleaseStack(temp_o); ReleaseStack(output); #endif ReleaseUTF8String(utf8String); XDestroyRegion(renderRegion); #ifdef USE_XFT XftDrawDestroy(xd); #else JXFreeGC(display, gc); #endif }
/** Draw a button. */ void DrawButton(ButtonNode *bp) { ColorType fg; long bg1, bg2; long up, down; DecorationsType decorations; Drawable drawable; GC gc; int x, y; int width, height; int xoffset, yoffset; int iconWidth, iconHeight; int textWidth, textHeight; Assert(bp); char *printableName = bp->text; /* Check for E2 80 AA (LEFT-TO-RIGHT-EMBEDDING) character in the beginning and trim it (for Midori) */ if(strncmp(printableName, "\xe2\x80\xaa", 3) == 0) { printableName += 3; } drawable = bp->drawable; x = bp->x; y = bp->y; width = bp->width; height = bp->height; gc = JXCreateGC(display, drawable, 0, NULL); /* Determine the colors to use. */ switch(bp->type) { case BUTTON_LABEL: fg = COLOR_MENU_FG; bg1 = colors[COLOR_MENU_BG]; bg2 = colors[COLOR_MENU_BG]; up = colors[COLOR_MENU_UP]; down = colors[COLOR_MENU_DOWN]; decorations = settings.menuDecorations; break; case BUTTON_MENU_ACTIVE: fg = COLOR_MENU_ACTIVE_FG; bg1 = colors[COLOR_MENU_ACTIVE_BG1]; bg2 = colors[COLOR_MENU_ACTIVE_BG2]; down = colors[COLOR_MENU_ACTIVE_UP]; up = colors[COLOR_MENU_ACTIVE_DOWN]; decorations = settings.menuDecorations; break; case BUTTON_TRAY: case BUTTON_TASK: fg = COLOR_TRAY_FG; bg1 = colors[COLOR_TRAY_BG1]; bg2 = colors[COLOR_TRAY_BG2]; up = colors[COLOR_TRAY_UP]; down = colors[COLOR_TRAY_DOWN]; decorations = settings.trayDecorations; break; case BUTTON_TRAY_ACTIVE: case BUTTON_TASK_ACTIVE: fg = COLOR_TRAY_ACTIVE_FG; bg1 = colors[COLOR_TRAY_ACTIVE_BG1]; bg2 = colors[COLOR_TRAY_ACTIVE_BG2]; down = colors[COLOR_TRAY_ACTIVE_UP]; up = colors[COLOR_TRAY_ACTIVE_DOWN]; decorations = settings.trayDecorations; break; case BUTTON_MENU: default: fg = COLOR_MENU_FG; bg1 = colors[COLOR_MENU_BG]; bg2 = colors[COLOR_MENU_BG]; up = colors[COLOR_MENU_UP]; down = colors[COLOR_MENU_DOWN]; decorations = settings.menuDecorations; break; } /* Draw the background. */ if(bp->fill) { /* Draw the button background. */ JXSetForeground(display, gc, bg1); /* single color */ JXFillRectangle(display, drawable, gc, x, y, width, height); } /* Draw the border. */ if(bp->border) { JXSetForeground(display, gc, down); JXDrawRectangle(display, drawable, gc, x, y, width - 1, height - 1); } /* Determine the size of the icon (if any) to display. */ iconWidth = 0; iconHeight = 0; if(bp->icon) { if(bp->icon == &emptyIcon) { iconWidth = Min(width/2, height/2); iconHeight = iconWidth; } else { const int ratio = (bp->icon->images->width << 16) / bp->icon->images->height; iconHeight = height/2; iconWidth = (iconHeight * ratio) >> 16; if(iconWidth > width/2) { iconWidth = width/2; iconHeight = (iconWidth << 16) / ratio; } } } /* Determine how much room is left for text. */ textWidth = 0; textHeight = 0; if(printableName) { textWidth = GetStringWidth(bp->font, printableName); textHeight = GetStringHeight(bp->font); if(iconWidth > 0 && textWidth + iconWidth + 7 > width) { textWidth = width - iconWidth - textHeight*3/2; } else if(iconWidth == 0 && textWidth + 5 > width) { textWidth = width - 5; } textWidth = textWidth < 0 ? 0 : textWidth; } /* Determine the offset of the text in the button. */ if(bp->alignment == ALIGN_CENTER) { xoffset = (width - iconWidth - textWidth + 1) / 2; if(xoffset < 0) { xoffset = 0; } } else { xoffset = textHeight/2; } /* Display the icon. */ if(bp->icon) { yoffset = (height - iconHeight + 1) / 2; PutIcon(bp->icon, drawable, colors[fg], x + xoffset, y + yoffset, iconWidth, iconHeight); xoffset += iconWidth + textHeight/2; } /* Display the label. */ if(textWidth > 0) { yoffset = (height - textHeight + 1) / 2; RenderString(drawable, bp->font, fg, x + xoffset, y + yoffset, textWidth, printableName); } JXFreeGC(display, gc); }
/** Shutdown outlines. */ void ShutdownOutline() { JXFreeGC(display, outlineGC); }