/*
* pixmap_image.cc
*
* Copyright (C) 1995, 1996, 1997, 1997, 1998, 1999, 2000, 2001, 2002 Kenichi Kourai
* Copyright (C) 1999, 2000, 2001, 2002 Luiz Blanes
*
* 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 blwm; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/xpm.h>
#include "main.h"
#include "pixmap_image.h"
//
// Xpm file format able to be read
// " <width> <height> <num_colors> <chars_per_pixel> "
// "<char> c <color>"
// ...
// "data for line0"
// ...
//
// - ignore lines not beginning with "
// - " must be the first character of a line
//
PixmapImage::PixmapImage(char* filename)
{
FILE* fp;
struct stat st;
char* raw;
if ((fp = fopen(filename, "r")) == NULL) {
BlwmError("cannot open file: '%s'", filename);
m_error = IMG_OPEN_ERROR;
return;
}
if (fstat(fileno(fp), &st) < 0) {
BlwmError("cannot access file: '%s'", filename);
m_error = IMG_FILE_ERROR;
fclose(fp);
return;
}
raw = new char[st.st_size];
if (fread(raw, st.st_size, 1, fp) < 1) {
BlwmError("cannot read file: '%s'", filename);
m_error = IMG_FILE_ERROR;
fclose(fp);
return;
}
m_error = CreateImage(raw, st.st_size);
fclose(fp);
OutputError(filename);
}
PixmapImage::PixmapImage(char** data)
{
m_error = CreatePixmap(data);
}
PixmapImage::PixmapImage(char* raw, int len)
{
m_error = CreateImage(raw, len);
}
// ~BlImage is not executed when using Imlib
PixmapImage::~PixmapImage()
{
}
int PixmapImage::CreateImage(char* raw, int len)
{
char** data;
int error;
data = ParseXpmData(raw, len);
if (data == NULL)
return IMG_DATA_ERROR;
error = CreatePixmap(data);
for (int i = 0; data[i] != NULL; i++)
delete data[i];
delete [] data;
return error;
}
int PixmapImage::CreatePixmap(char** data)
{
XpmAttributes attr;
int error;
attr.valuemask = XpmColormap | XpmDepth;
attr.colormap = DefaultColormap(display, screen);
attr.depth = DefaultDepth(display, screen);
error = XpmCreatePixmapFromData(display, root, data, &m_pix, &m_mask, &attr);
if (error == XpmSuccess || error == XpmColorError) {
XGCValues gcv;
gcv.clip_mask = m_mask;
m_gc = XCreateGC(display, root, GCClipMask, &gcv);
m_size = Dim(attr.width, attr.height);
return 0;
}
switch (error) {
case XpmColorFailed:
return IMG_COLOR_ERROR;
case XpmNoMemory:
return IMG_MEMORY_ERROR;
default:
return IMG_UNKNOWN_ERROR;
}
}
char** PixmapImage::ParseXpmData(char* raw, int len)
{
char* ptr;
int width, height, num_colors, chars_per_pixel;
char** data;
int i, dlen;
// parse pixmap information
if ((ptr = GetNextData(raw, len)) != NULL) {
if (sscanf(ptr, "%d %d %d %d", &width, &height, &num_colors,
&chars_per_pixel) != 4)
return NULL;
}
else
return NULL;
// allocate data buffer
data = new char*[1 + num_colors + height + 1];
data[1 + num_colors + height] = NULL; // terminate
data[0] = new char[80];
sprintf(data[0], "%d %d %d %d", width, height, num_colors, chars_per_pixel);
// parse color data
for (i = 1; i < 1 + num_colors; i++) {
if ((ptr = GetNextData(raw, len)) != NULL) {
data[i] = new char[raw - ptr];
memcpy(data[i], ptr, raw - ptr - 1);
data[i][raw - ptr - 1] = '\0';
}
else {
for (int j = 0; j < i; j++)
delete data[j];
delete [] data;
return NULL;
}
}
// parse pixel data
dlen = width * chars_per_pixel;
for (; i < 1 + num_colors + height; i++) {
if ((ptr = GetNextData(raw, len)) != NULL) {
data[i] = new char[dlen + 1];
memcpy(data[i], ptr, dlen);
data[i][dlen] = '\0';
}
else {
for (int j = 0; j < i; j++)
delete data[j];
delete [] data;
return NULL;
}
}
return data;
}
// return the next data enclosed with "
char* PixmapImage::GetNextData(char*& raw, int& len)
{
char* ptr;
while (*raw != '\"' && len > 0) {
raw++;
len--;
}
raw++;
len--;
if (len > 0)
ptr = raw;
else
return NULL;
while (*raw != '\"' && len > 0) {
raw++;
len--;
}
raw++;
len--;
if (len > 0)
return ptr;
else
return NULL;
}
syntax highlighted by Code2HTML, v. 0.9.1