Generic_Window_Manager/wl_pixmap.c

678 lines
20 KiB
C

/* Copyright 1989 GROUPE BULL -- See license conditions in file COPYRIGHT
* Copyright 1989 Massachusetts Institute of Technology
*/
/***********************\
* *
* WOOL_OBJECT: Pixmap *
* BODY *
* *
\***********************/
#define INCLUDE_PIXMAP_H
#include <string.h>
#include "EXTERN.h"
#include <stdio.h>
#include <X11/xpm.h>
#include "wool.h"
#include "wl_string.h"
#include "wl_atom.h"
#include "wl_pointer.h"
#include "wl_active.h"
#include "wl_number.h"
#include "wl_label.h"
#include "wl_list.h"
#include "gwm.h"
#include <X11/Xatom.h>
#include <X11/Xutil.h>
#include "INTERN.h"
#undef INCLUDE_PIXMAP_H
#include "wl_pixmap.h"
#include "def_bitmap.h"
/* local prototyping */
WOOL_OBJECT wool_default_bitmap_make();
WOOL_OBJECT wool_default_pixmap_make();
/* when debugging, maintain the screen to which belongs the pixmap */
#ifdef DEBUG
#define StorePixmapScreen(pixmap, root) \
pixmap -> screen = ScreenOfRoot(root)
#else
#define StorePixmapScreen(pixmap, root)
#endif /* DEBUG */
/*
* makes a WOOL pixmap out of a X11 bitmap (or appropriate depth pixmap)
*/
WOOL_Pixmap
WLPixmap_make(pixmap)
Pixmap pixmap;
{
WOOL_Pixmap object = (WOOL_Pixmap)
Malloc(sizeof(struct _WOOL_Pixmap));
unsigned int bw, depth;
Window root;
zrt_put(object);
object -> type = WLPixmap;
object->mask = 0;
XGetGeometry(dpy, pixmap, &root, &object -> x_hot, &object -> y_hot,
&object -> width, &object -> height, &bw, &depth);
if (!object -> width || !object -> height || !depth) { /* ERROR */
wool_default_pixmap_make(object, "invalid pixmap %s", "size");
} else if (depth == 1) { /* BITMAP */
Trace('p', ("WLPixmap_make: create pixmap %d %d %d\n",
object -> width,
object -> height, Context->depth));
object -> pixmap = XCreatePixmap(dpy, Context->root, object -> width,
object -> height, Context->depth);
XSetForeground(dpy, Context->gc.Work, Context -> pixel.Back);
XFillRectangle(dpy, object -> pixmap, Context->gc.Work, 0, 0,
object -> width, object -> height);
XSetForeground(dpy, Context->gc.Set, Context -> pixel.Fore);
XSetStipple(dpy, Context->gc.Set, pixmap);
XFillRectangle(dpy, object -> pixmap, Context->gc.Set, 0, 0,
object -> width, object -> height);
} else if (depth == Context->depth) { /* PIXMAP */
Trace('p', ("WLPixmap_make: create pixmap %d %d %d\n",
object -> width,
object -> height, Context->depth));
object -> pixmap = XCreatePixmap(dpy, Context->root, object -> width,
object -> height, Context->depth);
XCopyArea(dpy, pixmap, object->pixmap, Context->gc.Work, 0, 0,
object->width, object->height, 0, 0);
} else { /* ERROR */
wool_default_pixmap_make(object, "Pixmap is of depth %d", depth);
}
StorePixmapScreen(object, root);
return object;
}
/*
* the physical reading of a bitmap. Used for bitmaps & cursors
* if parameter is a label returns it!
*/
WOOL_OBJECT
wool_raw_bitmap_make(filename)
WOOL_String filename;
{
char *name;
WOOL_Pixmap object;
char temp_filename[MAX_TEMP_STRING_SIZE];
must_be_string(filename, 0);
object = (WOOL_Pixmap) Malloc(sizeof(struct _WOOL_Pixmap));
zrt_put(object);
object -> type = WLPixmap;
object->mask = 0;
name = (char *) file_in_path(filename -> string,
BITMAP_EXTENSION, wool_path, temp_filename);
if (!name) {
return wool_default_bitmap_make(object,
"GWM: Cannot find Bitmap %s", filename -> string);
}
switch (XReadBitmapFile(dpy, Context->root, name,
&object -> width, &object -> height, &object -> pixmap,
&object -> x_hot, &object -> y_hot)) {
case BitmapOpenFailed:
return wool_default_bitmap_make(object,
"Cannot open file %s", name);
case BitmapFileInvalid:
return wool_default_bitmap_make(object,
"File %s is not a bitmap", name);
case BitmapNoMemory:
wool_error("No memory to load file %s", name);
break;
}
return (WOOL_OBJECT) object;
}
/* Given a pre-allocated WOOL_Pixmap, fill it with the default
* bitmap or pixmap, rexpectively
*/
WOOL_OBJECT
wool_default_bitmap_make(object, reason_format, reason)
WOOL_Pixmap object; /* empty wool structure */
char *reason_format; /* text of the error message or 0 */
char *reason; /* data for %s in reason format */
{
if (reason_format) {
wool_printf(reason_format, reason);
wool_puts(", using default instead\n");
}
object -> width = def_bitmap_width;
object -> height = def_bitmap_height;
object -> x_hot = def_bitmap_x_hot;
object -> y_hot = def_bitmap_y_hot;
object -> pixmap = Context -> DefaultBitmap;
return (WOOL_OBJECT) object;
}
WOOL_OBJECT
wool_default_pixmap_make(object, reason_format, reason)
WOOL_Pixmap object; /* empty wool structure */
char *reason_format; /* text of the error message or 0 */
char *reason; /* data for %s in reason format */
{
if (reason_format) {
wool_printf(reason_format, reason);
wool_puts(", using default instead\n");
}
object -> width = def_bitmap_width;
object -> height = def_bitmap_height;
XSetForeground(dpy, Context->gc.Work, Context -> pixel.Back);
Trace('p', ("wool_default_pixmap_make: create pixmap %d %d %d\n",
object -> width, object -> height,
Context->depth));
object -> pixmap = XCreatePixmap(dpy, Context->root,
object -> width, object -> height,
Context->depth);
XFillRectangle(dpy, object -> pixmap, Context->gc.Work, 0, 0,
object -> width, object -> height);
XSetForeground(dpy, Context->gc.Set, Context -> pixel.Fore);
XSetStipple(dpy, Context->gc.Set, Context -> DefaultBitmap);
XFillRectangle(dpy, object -> pixmap, Context->gc.Set, 0, 0,
object -> width, object -> height);
StorePixmapScreen(object, Context -> root);
return (WOOL_OBJECT) object;
}
/*
* to overlay bitmaps:
* (layered-bitmap-make back "file1" color1 "file2" color2 ...)
* filenames can be active-labels
*/
WOOL_Pixmap
wool_layered_bitmap_make(argc, argv)
int argc;
WOOL_Pixmap argv[];
{
Pixmap pix;
int i;
unsigned int width = 0, height = 0;
WOOL_Pixmap object;
struct _Box box;
WOOL_Label label;
Graphic_desc *graphics;
if ((argc == 0) || (argc > 2 && (argc % 2 == 0)))
wool_error(BAD_NUMBER_OF_ARGS, argc);
if (argc == 1) { /* one args re-calls with default colors */
WOOL_Number new_argv[3];
new_argv[0] = WLNumber_make(Context -> pixel.Back);
new_argv[2] = WLNumber_make(Context -> pixel.Fore);
new_argv[1] = (WOOL_Number) argv[0];
return (WOOL_Pixmap) wool_layered_bitmap_make(3, new_argv);
}
if (argc == 2) { /* two args make a blank bitmaps */
return wool_make_blank_bitmap(argv[0], argv[1]);
}
/* multi-args form */
must_be_number(argv[0], 0);
must_be_number(argv[2], 2);
graphics = (Graphic_desc *) Malloc(sizeof(Graphic_desc) * argc);
/* first determine the size of the final pixmap and load the bitmaps */
for (i = 1; i < argc; i += 2) {
if (is_a_string(argv[i])) {
graphics[i].is_bitmap = 1;
argv[i] = (WOOL_Pixmap) wool_raw_bitmap_make(argv[i]);
} else {
graphics[i].is_bitmap = 0;
}
WOOL_send(WOOL_get_dimensions, argv[i], (argv[i], &box));
graphics[i].width = box.width;
graphics[i].height = box.height;
width = Max(width, box.width);
height = Max(height, box.height);
}
/* then lay the graphics one on top of another */
XSetForeground(dpy, Context->gc.Work, ((WOOL_Number) argv[0]) -> number);
Trace('p', ("wool_layered_bitmap_make: create pixmap %d %d %d\n",
width, height, Context->depth));
pix = XCreatePixmap(dpy, Context->root, width, height, Context->depth);
XFillRectangle(dpy, pix, Context->gc.Work, 0, 0, width, height);
for (i = 1; i < argc; i += 2) {
must_be_number(argv[i + 1], i + 1);
if (graphics[i].is_bitmap) {
XSetForeground(dpy, Context->gc.Set,
((WOOL_Number) argv[i + 1]) -> number);
XSetStipple(dpy, Context->gc.Set, argv[i] -> pixmap);
XSetTSOrigin(dpy, Context->gc.Set, (width - argv[i] -> width) / 2, (height - argv[i] -> height) / 2);
XFillRectangle(dpy, pix, Context->gc.Set,
(width - argv[i] -> width) / 2, (height - argv[i] -> height) / 2,
argv[i] -> width, argv[i] -> height);
XSetTSOrigin(dpy, Context->gc.Set, 0, 0);
} else if (argv[i] -> type == WLPixmap) {
XCopyArea(dpy, argv[i] -> pixmap, pix, Context->gc.Work, 0, 0,
argv[i] -> width, argv[i] -> height,
(width - argv[i] -> width) / 2,
(height - argv[i] -> height) / 2);
} else if (argv[i] -> type == WLLabel) { /* label */
label = (WOOL_Label) argv[i];
XSetFont(dpy, Context->gc.Work, label -> font);
XSetForeground(dpy, Context->gc.Work,
((WOOL_Number) argv[i + 1]) -> number);
XDrawString(dpy, pix, Context->gc.Work,
label -> x, label -> y, label -> label -> string,
strlen(label -> label -> string));
}
}
/* then creates the WOOL_Pixmap */
object = (WOOL_Pixmap) Malloc(sizeof(struct _WOOL_Pixmap));
zrt_put(object);
object -> type = WLPixmap;
object->mask = 0;
object -> pixmap = pix;
object -> x_hot = object -> y_hot = 0;
object -> width = width;
object -> height = height;
Free(graphics);
StorePixmapScreen(object, Context -> root);
return object;
}
/*
* makes a pixmap of "foreground" color of a given size
*/
WOOL_Pixmap
wool_make_blank_bitmap(width, height)
WOOL_Number width;
WOOL_Number height;
{
WOOL_Pixmap object;
Pixmap pix;
WOOL_Pixmap tile;
get_val_from_context(tile, WA_tile);
Trace('p', ("wool_make_blank_bitmap: create pixmap %d %d %d\n",
width -> number, height -> number, Context->depth));
pix = XCreatePixmap(dpy, Context->root,
width -> number, height -> number, Context->depth);
if (tile->type != WLPixmap) {
/* no tile = use solid color */
XSetForeground(dpy, Context->gc.Work, Context -> pixel.Fore);
XFillRectangle(dpy, pix, Context->gc.Work, 0, 0,
width -> number, height -> number);
} else {
/* tile overrides color */
XSetTile(dpy, Context->gc.Tile, tile->pixmap);
XFillRectangle(dpy, pix, Context->gc.Tile, 0, 0,
width -> number, height -> number);
}
object = (WOOL_Pixmap) Malloc(sizeof(struct _WOOL_Pixmap));
zrt_put(object);
object -> type = WLPixmap;
object->mask = 0;
object -> pixmap = pix;
object -> x_hot = object -> y_hot = 0;
object -> width = width -> number;
object -> height = height -> number;
StorePixmapScreen(object, Context -> root);
return object;
}
/*
* A stamp is a string "stamped" on the background to yield a bitmap
*/
WOOL_OBJECT
wool_stamp_make(argc, argv)
int argc;
WOOL_String argv[];
{
int up, down, dir, x, y, width, height, font;
XCharStruct extent;
WOOL_Pixmap object;
if (argc == 0 || argc > 2)
return wool_error(BAD_NUMBER_OF_ARGS, argc);
must_be_string(argv[0], 0);
if (argc == 2) {
must_be_number(argv[1], 1);
font = ((WOOL_Number) argv[1]) -> number;
} else
font = DefaultFont;
object = (WOOL_Pixmap) Malloc(sizeof(struct _WOOL_Pixmap));
XQueryTextExtents(dpy, font,
argv[0] -> string, strlen(argv[0] -> string),
&dir, &up, &down, &extent);
x = DefaultLabelHorizontalMargin - extent.lbearing;
y = DefaultLabelVerticalMargin + up;
width = Max(1, extent.width + 2 * DefaultLabelHorizontalMargin);
height = Max(1, up + down + 2 * DefaultLabelVerticalMargin);
zrt_put(object);
object -> type = WLPixmap;
object->mask = 0;
Trace('p', ("wool_make_blank_bitmap: create pixmap %d %d %d\n",
width, height, Context->depth));
object -> pixmap = XCreatePixmap(dpy, Context->root, width, height,
Context->depth);
object -> x_hot = object -> y_hot = 0;
object -> width = width;
object -> height = height;
XSetForeground(dpy, Context->gc.Work, Context -> pixel.Back);
XFillRectangle(dpy, object -> pixmap, Context->gc.Work,
0, 0, width, height);
XSetFont(dpy, Context->gc.Work, font);
XSetForeground(dpy, Context->gc.Work, Context -> pixel.Fore);
XDrawString(dpy, object -> pixmap, Context->gc.Work,
x, y, argv[0] -> string,
strlen(argv[0] -> string));
StorePixmapScreen(object, Context -> root);
return (WOOL_OBJECT) object;
}
/*
* WLPixmap_print:
* a / bitmap prints as [PIXMAP widthxheight id]
*/
WOOL_OBJECT
WLPixmap_print(obj)
WOOL_Pixmap obj;
{
wool_printf("{PIXMAP %dx", obj -> width);
wool_printf("%d", obj -> height);
wool_printf(" 0x%x", obj -> pixmap);
#ifdef DEBUG
wool_printf(", on screen %d", obj -> screen);
#endif /* DEBUG */
wool_puts("}");
return (WOOL_OBJECT) obj;
}
/*
* WLPixmap_free:
* The structure is just freed, and string released.
*/
WOOL_OBJECT
WLPixmap_free(obj)
WOOL_Pixmap obj;
{
if (obj->pixmap != Context -> DefaultBitmap)
XFreePixmap(dpy, obj->pixmap);
if (obj->mask)
XFreePixmap(dpy, obj->mask);
Free(obj);
return NULL;
}
/*
* returns the dimensions of the strings in the font + margins
* x,y is the start of the string (baseline) in the box.
*/
WOOL_OBJECT
WLPixmap_get_dimensions(bitmap, box)
WOOL_Pixmap bitmap;
Box box; /* RETURN the dimensions */
{
box -> x = 0;
box -> y = 0;
box -> width = bitmap -> width;
box -> height = bitmap -> height;
box -> shape = bitmap -> mask;
return NULL;
}
/*
* opening a bitmap is putting it in backgroud
*/
WOOL_OBJECT
WLPixmap_open(bitmap, wob)
WOOL_Pixmap bitmap;
Wob wob;
{
XSetWindowBackgroundPixmap(dpy, wob -> hook, bitmap -> pixmap);
XClearWindow(dpy, wob -> hook);
return NULL; /* 0 means no exposure necessary */
}
/*
* drawing a bitmap (not needed ?)
*/
WOOL_OBJECT
WLPixmap_draw(bitmap, wob)
WOOL_Pixmap bitmap;
Wob wob;
{
XClearWindow(dpy, wob -> hook);
return NULL;
}
/*
* Reading of a Pixmap file (xpm v3 format)
*/
WOOL_OBJECT
wool_xpm_pixmap_make(argc, argv)
int argc;
WOOL_String argv[];
{
char *name;
WOOL_Pixmap object;
char temp_filename[MAX_TEMP_STRING_SIZE];
unsigned int npixels_return;
unsigned long *pixels_return;
WOOL_String filename;
XpmAttributes xpmatt;
XpmColorSymbol *colorsymbols = 0;
int ncolorsymbols = 0;
Pixmap pixmapshape;
int i;
int res;
if ((argc == 0) || (argc > 2 && (argc % 2 == 0)))
wool_error(BAD_NUMBER_OF_ARGS, argc);
filename = argv[0];
must_be_string(filename, 0);
if (argc > 1) {
ncolorsymbols = (argc-1)/2;
colorsymbols = (XpmColorSymbol *) Malloc(sizeof(XpmColorSymbol)
* ncolorsymbols);
for (i=0; i<ncolorsymbols; i++) {
must_be_string(argv[i*2+1], i*2+1);
colorsymbols[i].name = argv[i*2+1] -> string;
if (argv[i*2+2]->type == WLNumber) {
colorsymbols[i].value = 0;
colorsymbols[i].pixel = ((WOOL_Number) argv[i*2+2])->number;
} else {
must_be_string(argv[i*2+2], i*2+2);
colorsymbols[i].value = argv[i*2+2] -> string;
}
}
}
object = (WOOL_Pixmap) Malloc(sizeof(struct _WOOL_Pixmap));
zrt_put(object);
object -> type = WLPixmap;
object -> x_hot = 0;
object -> y_hot = 0;
object -> mask = 0;
name = (char *) file_in_path(filename -> string,
PIXMAP_EXTENSION, wool_path, temp_filename);
if (!name) {
return wool_default_pixmap_make(object,
"GWM: Cannot find Pixmap %s", filename -> string);
}
xpmatt.valuemask = XpmVisual|XpmColormap|XpmDepth|XpmColorSymbols;
xpmatt.visual = DefaultVisual(dpy, Context->screen);
xpmatt.colormap = DefaultColormap(dpy, Context->screen);
xpmatt.depth = Context->depth;
xpmatt.colorsymbols = colorsymbols;
xpmatt.numsymbols = ncolorsymbols;
if (GWM_xpm_closeness) {
xpmatt.closeness = GWM_xpm_closeness;
xpmatt.valuemask |= XpmCloseness;
}
Trace('p', ("Reading pixmap file: %s\n", name));
switch (
res = XpmReadFileToPixmap(dpy, Context->root, name,
&object -> pixmap, &pixmapshape, &xpmatt),
(colorsymbols ? (Free(colorsymbols), 0) : 0),
res
) {
case PixmapSuccess:
break;
case PixmapOpenFailed:
return wool_default_pixmap_make(object,
"Cannot open file %s", name);
case PixmapFileInvalid:
return wool_default_pixmap_make(object,
"File %s is not a XPM pixmap", name);
case PixmapNoMemory:
wool_error("No memory to load file %s", name);
break;
default:
wool_error("Error while reading pixmap %s", name);
break;
}
if (pixmapshape)
object->mask = pixmapshape;
object->width = xpmatt.width;
object->height = xpmatt.height;
return (WOOL_OBJECT) object;
}
MakeDefaultBitmap()
{
if (!(Context -> DefaultBitmap = XCreateBitmapFromData(dpy, Context->root,
def_bitmap_bits, def_bitmap_width, def_bitmap_height)))
wool_error(NO_MEMORY, "");
}
/* Graphical primitives
*/
/* draws a line in a pixmap:
* syntax (draw-line pixmap x1 y1 x2 y2)
* uses "foreground" color
*/
WOOL_OBJECT
wool_draw_line(argc, argv)
int argc;
WOOL_Number argv[];
{
int i;
if (argc != 5)
wool_error(BAD_NUMBER_OF_ARGS, argc);
must_be(WLPixmap, argv[0], 0);
for (i = 1; i < 5; i++)
must_be(WLNumber, argv[i], i);
XSetForeground(dpy, Context->gc.Work, Context -> pixel.Fore);
XDrawLine(dpy, ((WOOL_Pixmap) argv[0]) -> pixmap, Context->gc.Work,
argv[1] -> number, argv[2] -> number,
argv[3] -> number, argv[4] -> number);
return (WOOL_OBJECT) argv[0];
}
/* draws a filled rectangle in a pixmap:
* syntax (draw-rectangle pixmap x1 y1 width height border style)
* uses "foreground" color for border
* uses "background" color for rectangle
* style: 0 = nothing, 1 = outline, 2 = filled, 3 = outline+filled
*/
WOOL_OBJECT
wool_draw_rectangle(argc, argv)
int argc;
WOOL_Number argv[];
{
int i;
if (argc != 7)
wool_error(BAD_NUMBER_OF_ARGS, argc);
must_be(WLPixmap, argv[0], 0);
for (i = 1; i < 7; i++)
must_be(WLNumber, argv[i], i);
if (argv[6] -> number & 2) { /* inside rectangle */
XSetForeground(dpy, Context->gc.Work, Context -> pixel.Back);
XFillRectangle(dpy, ((WOOL_Pixmap) argv[0]) -> pixmap,
Context->gc.Work,
argv[1] -> number, argv[2] -> number,
argv[3] -> number, argv[4] -> number);
}
if (argv[6] -> number & 1) { /* ouline rectangle */
int linewidth = argv[5] -> number ? argv[5] -> number : 1;
XPoint points[5];
points[0].x = argv[1] -> number - 1;
points[0].y = argv[2] -> number - 1;
points[1].x = points[0].x + argv[3] -> number + 1;
points[1].y = points[0].y;
points[2].x = points[1].x;
points[2].y = points[0].y + argv[4] -> number + 1;
points[3].x = points[0].x;
points[3].y = points[2].y;
points[4].x = points[0].x;
points[4].y = points[0].y;
XSetForeground(dpy, Context->gc.Work, Context -> pixel.Fore);
XDrawLines(dpy, ((WOOL_Pixmap) argv[0]) -> pixmap,
Context->gc.Work, points, 5, CoordModeOrigin);
for (i = 1; i < linewidth; i++) {
points[0].x -= 1; points[0].y -= 1;
points[1].x += 1; points[1].y -= 1;
points[2].x += 1; points[2].y += 1;
points[3].x -= 1; points[3].y += 1;
points[4].x -= 1; points[4].y -= 1;
XDrawLines(dpy, ((WOOL_Pixmap) argv[0]) -> pixmap,
Context->gc.Work, points, 5, CoordModeOrigin);
}
}
return (WOOL_OBJECT) argv[0];
}
/* prints a text in a pixmap:
* syntax (draw-text pixmap x1 y1 font text)
* uses "foreground" color for text color
*/
WOOL_OBJECT
wool_draw_text(argc, argv)
int argc;
WOOL_Number argv[];
{
int i;
if (argc != 5)
wool_error(BAD_NUMBER_OF_ARGS, argc);
must_be(WLPixmap, argv[0], 0);
for (i = 1; i < 4; i++)
must_be(WLNumber, argv[i], i);
must_be_string(argv[4], 4);
XSetForeground(dpy, Context->gc.Work, Context -> pixel.Fore);
XSetFont(dpy, Context->gc.Work, argv[3]->number);
XDrawString(dpy, ((WOOL_Pixmap) argv[0]) -> pixmap, Context->gc.Work,
argv[1] -> number, argv[2] -> number,
((WOOL_String) argv[4]) -> string,
strlen(((WOOL_String) argv[4]) -> string));
return (WOOL_OBJECT) argv[0];
}